-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from DUNE-DAQ/patch/fddaq-v4.4.x
Patch/fddaq v4.4.x
- Loading branch information
Showing
6 changed files
with
311 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/** | ||
* @file TDEEthFrame.hpp | ||
* | ||
* Contains declaration of TDEEthFrame, a class for accessing raw WIB v2 frames, as used in ProtoDUNE-SP-II | ||
* | ||
* The canonical definition of the WIB format is given in EDMS document 2088713: * https://edms.cern.ch/document/2088713/XXX | ||
* | ||
* This is part of the DUNE DAQ Application Framework, copyright 2020. | ||
* Licensing/copyright details are in the COPYING file that you should have | ||
* received with this code. | ||
*/ | ||
|
||
#ifndef FDDETDATAFORMATS_INCLUDE_FDDETDATAFORMATS_TDEETHFRAME_HPP_ | ||
#define FDDETDATAFORMATS_INCLUDE_FDDETDATAFORMATS_TDEETHFRAME_HPP_ | ||
|
||
#include "detdataformats/DAQEthHeader.hpp" | ||
|
||
#include <algorithm> // For std::min | ||
#include <cassert> // For assert() | ||
#include <cstdint> // For uint32_t etc | ||
#include <cstdio> | ||
#include <cstdlib> | ||
#include <stdexcept> // For std::out_of_range | ||
|
||
namespace dunedaq::fddetdataformats { | ||
|
||
/** | ||
* @brief Class for accessing raw WIB eth frames, as used in ProtoDUNE-II | ||
* | ||
* The canonical definition of the WIB format is given in EDMS document 2088713: | ||
* https://edms.cern.ch/document/2088713/XXX | ||
*/ | ||
class TDEEthFrame | ||
{ | ||
public: | ||
// =============================================================== | ||
// Preliminaries | ||
// =============================================================== | ||
|
||
// The definition of the format is in terms of 64-bit words | ||
typedef uint64_t word_t; // NOLINT | ||
|
||
static constexpr int s_bits_per_adc = 14; | ||
static constexpr int s_bits_per_word = 8 * sizeof(word_t); | ||
static constexpr int s_time_samples_per_frame = 64; | ||
static constexpr int s_channels_per_half_femb = 64; | ||
static constexpr int s_half_fembs_per_frame = 1; | ||
static constexpr int s_num_channels = s_channels_per_half_femb * s_half_fembs_per_frame; | ||
static constexpr int s_num_adc_words_per_ts = s_num_channels * s_bits_per_adc / s_bits_per_word; | ||
static constexpr int s_num_adc_words = s_time_samples_per_frame * s_num_channels * s_bits_per_adc / s_bits_per_word; | ||
|
||
|
||
struct TDEEthHeader | ||
{ | ||
uint64_t reserved : 26; | ||
uint64_t tde_errors : 16; | ||
uint64_t tde_header : 10; | ||
uint64_t version : 4; | ||
uint64_t channel : 8; | ||
uint64_t TAItime : 64; | ||
}; | ||
|
||
// =============================================================== | ||
// Data members | ||
// =============================================================== | ||
detdataformats::DAQEthHeader daq_header; | ||
TDEEthHeader header; | ||
// word_t adc_words[s_num_adc_words_per_ts][s_time_samples_per_frame]; // NOLINT | ||
word_t adc_words[s_time_samples_per_frame][s_num_adc_words_per_ts]; // NOLINT | ||
|
||
// =============================================================== | ||
// Accessors | ||
// =============================================================== | ||
|
||
/** | ||
* @brief Get the ith ADC value in the frame | ||
* | ||
* The ADC words are 14 bits long; | ||
* wrod_t stored packed in the data structure. | ||
* The order is: 64 channels repeated for 64 time samples | ||
* | ||
*/ | ||
uint16_t get_adc(int i, int sample=0) const // NOLINT(build/unsigned) | ||
{ | ||
if (i < 0 || i >= s_num_channels) | ||
throw std::out_of_range("ADC index out of range"); | ||
|
||
// The index of the first (and sometimes only) word containing the required ADC value | ||
int word_index = s_bits_per_adc * i / s_bits_per_word; | ||
assert(word_index < s_num_adc_words_per_ts); | ||
// Where in the word the lowest bit of our ADC value is located | ||
int first_bit_position = (s_bits_per_adc * i) % s_bits_per_word; | ||
// How many bits of our desired ADC are located in the `word_index`th word | ||
int bits_from_first_word = std::min(s_bits_per_adc, s_bits_per_word - first_bit_position); | ||
// uint16_t adc = adc_words[word_index][sample] >> first_bit_position; // NOLINT(build/unsigned) | ||
uint16_t adc = adc_words[sample][word_index] >> first_bit_position; // NOLINT(build/unsigned) | ||
// If we didn't get the full 14 bits from this word, we need the rest from the next word | ||
if (bits_from_first_word < s_bits_per_adc) { | ||
assert(word_index + 1 < s_num_adc_words_per_ts); | ||
// adc |= adc_words[word_index + 1][sample] << bits_from_first_word; | ||
adc |= adc_words[sample][word_index + 1] << bits_from_first_word; | ||
} | ||
// Mask out all but the lowest 14 bits; | ||
return adc & 0x3FFFu; | ||
} | ||
|
||
/** | ||
* @brief Set the ith ADC value in the frame to @p val | ||
*/ | ||
void set_adc(int i, int sample, uint16_t val) // NOLINT(build/unsigned) | ||
{ | ||
if (i < 0 || i >= s_num_channels) | ||
throw std::out_of_range("ADC index out of range"); | ||
if (val >= (1 << s_bits_per_adc)) | ||
throw std::out_of_range("ADC value out of range"); | ||
|
||
// The index of the first (and sometimes only) word containing the required ADC value | ||
int word_index = s_bits_per_adc * i / s_bits_per_word; | ||
assert(word_index < s_num_adc_words); | ||
// Where in the word the lowest bit of our ADC value is located | ||
int first_bit_position = (s_bits_per_adc * i) % s_bits_per_word; | ||
// How many bits of our desired ADC are located in the `word_index`th word | ||
int bits_in_first_word = std::min(s_bits_per_adc, s_bits_per_word - first_bit_position); | ||
uint64_t mask = (static_cast<uint64_t>(1) << first_bit_position) - 1; | ||
adc_words[sample][word_index] = ((static_cast<uint64_t>(val) << first_bit_position) & ~mask) | (adc_words[sample][word_index] & mask); | ||
// If we didn't put the full 14 bits in this word, we need to put the rest in the next word | ||
if (bits_in_first_word < s_bits_per_adc) { | ||
assert(word_index + 1 < s_num_adc_words); | ||
mask = (1 << (s_bits_per_adc - bits_in_first_word)) - 1; | ||
adc_words[sample][word_index + 1] = ((val >> bits_in_first_word) & mask) | (adc_words[sample][word_index + 1] & ~mask); | ||
} | ||
} | ||
|
||
/** @brief Get the starting 64-bit timestamp of the frame | ||
*/ | ||
uint64_t get_timestamp() const // NOLINT(build/unsigned) | ||
{ | ||
return daq_header.get_timestamp() ; // NOLINT(build/unsigned) | ||
} | ||
|
||
/** @brief Set the starting 64-bit timestamp of the frame | ||
*/ | ||
void set_timestamp(const uint64_t new_timestamp) // NOLINT(build/unsigned) | ||
{ | ||
daq_header.timestamp = new_timestamp; | ||
} | ||
|
||
/** @brief Get the channel identifier of the frame | ||
*/ | ||
uint8_t get_channel() const // NOLINT(build/unsigned) | ||
{ | ||
return header.channel ; // NOLINT(build/unsigned) | ||
} | ||
|
||
/** @brief Set the channel identifier of the frame | ||
*/ | ||
void set_channel(const uint8_t new_channel) // NOLINT(build/unsigned) | ||
{ | ||
header.channel = new_channel; | ||
} | ||
|
||
}; | ||
|
||
} // namespace dunedaq::fddetdataformats | ||
|
||
#endif // FDDETDATAFORMATS_INCLUDE_FDDETDATAFORMATS_TDEETHFRAME_HPP_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/** | ||
* @file wibeth.cpp Python bindings for the TDEEthFrame format | ||
* | ||
* This is part of the DUNE DAQ Software Suite, copyright 2020. | ||
* Licensing/copyright details are in the COPYING file that you should have | ||
* received with this code. | ||
*/ | ||
|
||
#include "fddetdataformats/TDEEthFrame.hpp" | ||
|
||
#include <pybind11/pybind11.h> | ||
#include <pybind11/stl.h> | ||
|
||
namespace py = pybind11; | ||
|
||
namespace dunedaq::fddetdataformats::python { | ||
|
||
void | ||
register_tdeeth(py::module& m) | ||
{ | ||
|
||
|
||
// py::class_<TDEEthFrame::TDEHeader>(m, "TDEHeader") | ||
// .def_property("channel", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.channel;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t channel) {self.channel = channel;} | ||
// ) | ||
// .def_property("version", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.version;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t version) {self.version = version;} | ||
// ) | ||
// // .def_property("reserved", | ||
// // [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.reserved;}, | ||
// // [](TDEEthFrame::TDEHeader& self, uint32_t reserved) {self.reserved = reserved;} | ||
// // ) | ||
// .def_property("cd", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.cd;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t cd) {self.version = cd;} | ||
// ) | ||
// .def_property("context", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.context;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t context) {self.version = context;} | ||
// ) | ||
// .def_property("ready", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.ready;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t ready) {self.ready = ready;} | ||
// ) | ||
// .def_property("calibration", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.calibration;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t calibration) {self.calibration = calibration;} | ||
// ) | ||
// .def_property("pulser", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.pulser;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t pulser) {self.pulser = pulser;} | ||
// ) | ||
// .def_property("femb_sync", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.femb_sync;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t femb_sync) {self.femb_sync = femb_sync;} | ||
// ) | ||
// .def_property("wib_sync", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.wib_sync;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t wib_sync) {self.wib_sync = wib_sync;} | ||
// ) | ||
// .def_property("lol", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.lol;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t lol) {self.lol = lol;} | ||
// ) | ||
// .def_property("link_valid", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.link_valid;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t link_valid) {self.link_valid = link_valid;} | ||
// ) | ||
// .def_property("crc_err", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.crc_err;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t crc_err) {self.crc_err = crc_err;} | ||
// ) | ||
// .def_property("colddata_timestamp_1", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.colddata_timestamp_1;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t colddata_timestamp_1) {self.lol = colddata_timestamp_1;} | ||
// ) | ||
// .def_property("colddata_timestamp_0", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint32_t {return self.colddata_timestamp_0;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint32_t colddata_timestamp_0) {self.colddata_timestamp_0 = colddata_timestamp_0;} | ||
// ) | ||
// .def_property("extra_data", | ||
// [](TDEEthFrame::TDEHeader& self) -> uint64_t {return self.extra_data;}, | ||
// [](TDEEthFrame::TDEHeader& self, uint64_t extra_data) {self.extra_data = extra_data;} | ||
// ) | ||
// ; | ||
|
||
py::class_<TDEEthFrame::TDEEthHeader>(m, "TDEEthHeader") | ||
.def_property("channel", | ||
[](TDEEthFrame::TDEEthHeader& self) -> uint16_t {return self.channel;}, | ||
[](TDEEthFrame::TDEEthHeader& self, uint16_t channel) {self.channel = channel;} | ||
) | ||
.def_property("version", | ||
[](TDEEthFrame::TDEEthHeader& self) -> uint16_t {return self.version;}, | ||
[](TDEEthFrame::TDEEthHeader& self, uint16_t version) {self.version = version;} | ||
) | ||
.def_property("tde_header", | ||
[](TDEEthFrame::TDEEthHeader& self) -> uint16_t {return self.tde_header;}, | ||
[](TDEEthFrame::TDEEthHeader& self, uint16_t tde_header) {self.tde_header = tde_header;} | ||
) | ||
.def_property("tde_errors", | ||
[](TDEEthFrame::TDEEthHeader& self) -> uint16_t {return self.tde_errors;}, | ||
[](TDEEthFrame::TDEEthHeader& self, uint16_t tde_errors) {self.tde_errors = tde_errors;} | ||
) | ||
.def_property("TAItime", | ||
[](TDEEthFrame::TDEEthHeader& self) -> uint64_t {return self.TAItime;}, | ||
[](TDEEthFrame::TDEEthHeader& self, uint64_t TAItime) {self.TAItime = TAItime;} | ||
) | ||
; | ||
|
||
|
||
py::class_<TDEEthFrame>(m, "TDEEthFrame", py::buffer_protocol()) | ||
.def(py::init()) | ||
.def(py::init([](py::capsule capsule) { | ||
auto tfp = *static_cast<TDEEthFrame*>(capsule.get_pointer()); | ||
return tfp; | ||
} )) | ||
.def(py::init([](py::bytes bytes){ | ||
py::buffer_info info(py::buffer(bytes).request()); | ||
auto tfp = *static_cast<TDEEthFrame*>(info.ptr); | ||
return tfp; | ||
})) | ||
.def("get_daqheader", [](TDEEthFrame& self) -> const detdataformats::DAQEthHeader& {return self.daq_header;}, py::return_value_policy::reference_internal) | ||
.def("get_tdeheader", [](TDEEthFrame& self) -> const TDEEthFrame::TDEEthHeader& {return self.header;}, py::return_value_policy::reference_internal) | ||
.def("get_adc", &TDEEthFrame::get_adc) | ||
.def("set_adc", &TDEEthFrame::set_adc) | ||
.def("get_timestamp", &TDEEthFrame::get_timestamp) | ||
.def("set_timestamp", &TDEEthFrame::set_timestamp) | ||
.def("get_channel", &TDEEthFrame::get_channel) | ||
.def("set_channel", &TDEEthFrame::set_channel) | ||
.def_static("sizeof", [](){ return sizeof(TDEEthFrame); }) | ||
.def("get_bytes", | ||
[](TDEEthFrame* fr) -> py::bytes { | ||
return py::bytes(reinterpret_cast<char*>(fr), sizeof(TDEEthFrame)); | ||
}) | ||
; | ||
} | ||
|
||
} // namespace dunedaq::fddetdataformats::python |