|
| 1 | +#ifndef DataFormats_FEDRawData_SLinkRocketHeaders_h |
| 2 | +#define DataFormats_FEDRawData_SLinkRocketHeaders_h |
| 3 | + |
| 4 | +#include "FWCore/Utilities/interface/Exception.h" |
| 5 | + |
| 6 | +//#include <memory> |
| 7 | +#include <span> |
| 8 | + |
| 9 | +/* |
| 10 | + * DTH Orbit header, event fragment trailer and SlinkRocket Header and Trailer accompanying |
| 11 | + * slink payload. Format that is sent is is low-endian for multi-byte fields |
| 12 | + * |
| 13 | + * Version 1 DTH and Version 3 SLinkRocket |
| 14 | + * |
| 15 | + * */ |
| 16 | + |
| 17 | +constexpr uint32_t SLR_MAX_EVENT_LEN = (1 << 20) - 1; |
| 18 | +constexpr uint32_t SLR_WORD_NUM_BYTES_SHIFT = 4; |
| 19 | + |
| 20 | +//SLinkExpress classes |
| 21 | + |
| 22 | +//begin and end event markers |
| 23 | +constexpr uint8_t SLR_BOE = 0x55; |
| 24 | +constexpr uint8_t SLR_EOE = 0xaa; |
| 25 | + |
| 26 | +//minimal SLinkRocket version overlay |
| 27 | +class SLinkRocketHeader_version { |
| 28 | +public: |
| 29 | + SLinkRocketHeader_version() {} |
| 30 | + uint8_t version() const { return version_; } |
| 31 | + bool verifyMarker() const { return boe_ == SLR_BOE; } |
| 32 | + |
| 33 | +private: |
| 34 | + uint32_t source_id_; |
| 35 | + uint16_t l1a_types_; |
| 36 | + uint8_t phys_type_; |
| 37 | + uint8_t emu_status_ : 2, res1_ : 6; |
| 38 | + uint64_t event_id_ : 44, res2_ : 8, version_ : 4, boe_ : 8; |
| 39 | +}; |
| 40 | + |
| 41 | +class SLinkRocketHeader_v3 { |
| 42 | +public: |
| 43 | + SLinkRocketHeader_v3(uint32_t source_id, uint16_t l1a_types, uint8_t l1a_phys, uint8_t emu_status, uint64_t event_id) |
| 44 | + : source_id_(source_id), |
| 45 | + l1a_types_(l1a_types), |
| 46 | + phys_type_(l1a_phys), |
| 47 | + emu_status_(emu_status), |
| 48 | + event_id_(event_id) {} |
| 49 | + |
| 50 | + uint32_t sourceID() const { return source_id_; } |
| 51 | + uint16_t l1aTypes() const { return l1a_types_; } |
| 52 | + uint8_t l1aPhysType() const { return phys_type_; } |
| 53 | + uint8_t emuStatus() const { return emu_status_; } |
| 54 | + uint64_t globalEventID() const { return event_id_; } |
| 55 | + uint8_t version() const { return version_; } |
| 56 | + bool verifyMarker() const { return boe_ == SLR_BOE; } |
| 57 | + |
| 58 | +private: |
| 59 | + uint32_t source_id_; |
| 60 | + uint16_t l1a_types_; |
| 61 | + uint8_t phys_type_; |
| 62 | + uint8_t emu_status_ : 2, res1_ : 6; |
| 63 | + uint64_t event_id_ : 44, res2_ : 8, version_ : 4 = 3, boe_ : 8 = SLR_BOE; |
| 64 | +}; |
| 65 | + |
| 66 | +class SLinkRocketTrailer_v3 { |
| 67 | +public: |
| 68 | + SLinkRocketTrailer_v3( |
| 69 | + uint16_t status, uint16_t crc, uint32_t orbit_id, uint16_t bx_id, uint32_t evtlen_word_count, uint16_t daq_crc) |
| 70 | + : crc_(crc), orbit_id_(orbit_id), bx_id_(bx_id), event_length_wcount_(evtlen_word_count), daq_crc_(daq_crc) { |
| 71 | + status_.all_ = status; |
| 72 | + } |
| 73 | + |
| 74 | + uint16_t status() const { return status_.all_; } |
| 75 | + uint16_t crc() const { return crc_; } |
| 76 | + uint32_t orbitID() const { return orbit_id_; } |
| 77 | + uint16_t bxID() const { return bx_id_; } |
| 78 | + uint32_t eventLenBytes() const { return uint32_t(event_length_wcount_) << SLR_WORD_NUM_BYTES_SHIFT; } |
| 79 | + uint16_t daqCRC() const { return daq_crc_; } |
| 80 | + bool verifyMarker() const { return eoe_ == SLR_EOE; } |
| 81 | + |
| 82 | +private: |
| 83 | + union { |
| 84 | + struct { |
| 85 | + uint16_t fed_crc_error_ : 1, /* FED CRC error was detected by DTH and corrected */ |
| 86 | + slink_crc_error_ : 1, /* Set when the slink receviver finds a mistmatch between calculated crc and daq_crc. It should never happen */ |
| 87 | + source_id_error_ : 1, /* SOURCE_ID is not expected */ |
| 88 | + sync_lost_error_ : 1, /* Sync lost detected by DTH */ |
| 89 | + fragment_cut_ : 1, /* Fragment was cut */ |
| 90 | + res_ : 11; |
| 91 | + } bits_; |
| 92 | + uint16_t all_; |
| 93 | + } status_; |
| 94 | + uint16_t crc_; /* CRC filled by the FED */ |
| 95 | + uint32_t orbit_id_; |
| 96 | + uint32_t bx_id_ : 12, |
| 97 | + event_length_wcount_ : 20; /* Length is encoded in multiples of 128 bits (16 bytes). I.e needs to be shifter by 4 */ |
| 98 | + uint32_t reserved_ : 8, daq_crc_ : 16, /* CRC filled by the slink sender */ |
| 99 | + eoe_ : 8 = SLR_EOE; |
| 100 | +}; |
| 101 | + |
| 102 | +/* |
| 103 | + * version-independent header view parent class |
| 104 | + * */ |
| 105 | + |
| 106 | +class SLinkRocketHeaderView { |
| 107 | +public: |
| 108 | + virtual ~SLinkRocketHeaderView() = default; |
| 109 | + virtual uint32_t sourceID() const = 0; |
| 110 | + virtual uint16_t l1aTypes() const = 0; |
| 111 | + virtual uint8_t l1aPhysType() const = 0; |
| 112 | + virtual uint8_t emuStatus() const = 0; |
| 113 | + virtual uint64_t globalEventID() const = 0; |
| 114 | + virtual uint8_t version() const = 0; |
| 115 | + virtual bool verifyMarker() const = 0; |
| 116 | +}; |
| 117 | + |
| 118 | +/* |
| 119 | + * header v3 view abstraction |
| 120 | + * */ |
| 121 | + |
| 122 | +class SLinkRocketHeaderView_v3 : public SLinkRocketHeaderView { |
| 123 | +public: |
| 124 | + SLinkRocketHeaderView_v3(const void* header) : header_(static_cast<const SLinkRocketHeader_v3*>(header)) {} |
| 125 | + |
| 126 | + uint32_t sourceID() const override { return header_->sourceID(); } |
| 127 | + uint16_t l1aTypes() const override { return header_->l1aTypes(); } |
| 128 | + uint8_t l1aPhysType() const override { return header_->l1aPhysType(); } |
| 129 | + uint8_t emuStatus() const override { return header_->emuStatus(); } |
| 130 | + uint64_t globalEventID() const override { return header_->globalEventID(); } |
| 131 | + uint8_t version() const override { return header_->version(); } |
| 132 | + bool verifyMarker() const override { return header_->verifyMarker(); } |
| 133 | + |
| 134 | +private: |
| 135 | + const SLinkRocketHeader_v3* header_; |
| 136 | +}; |
| 137 | + |
| 138 | +static inline std::unique_ptr<SLinkRocketHeaderView> makeSLinkRocketHeaderView(const void* buf) { |
| 139 | + auto version = static_cast<const SLinkRocketHeader_version*>(buf)->version(); |
| 140 | + if (version == 3) |
| 141 | + return std::unique_ptr<SLinkRocketHeaderView>( |
| 142 | + static_cast<SLinkRocketHeaderView*>(new SLinkRocketHeaderView_v3(buf))); |
| 143 | + throw cms::Exception("SLinkRocketHeaderView::makeView") |
| 144 | + << "unknown SLinkRocketHeader version: " << (unsigned int)version; |
| 145 | +} |
| 146 | + |
| 147 | +static inline std::unique_ptr<SLinkRocketHeaderView> makeSLinkRocketHeaderView(std::span<const unsigned char> const& s) { |
| 148 | + if (s.size() < sizeof(SLinkRocketHeader_version)) |
| 149 | + throw cms::Exception("SLinkRocketHeaderView::makeView") |
| 150 | + << "size is smaller than SLink header version fields: " << s.size(); |
| 151 | + auto version = static_cast<const SLinkRocketHeader_version*>(static_cast<const void*>(&s[0]))->version(); |
| 152 | + if (version == 3 && s.size() != sizeof(SLinkRocketHeader_v3)) |
| 153 | + throw cms::Exception("SLinkRocketHeaderView::makeView") << "SLinkRocketHeader v3 size mismatch: got " << s.size() |
| 154 | + << " expected:" << sizeof(SLinkRocketHeader_v3) << " bytes"; |
| 155 | + |
| 156 | + return makeSLinkRocketHeaderView(static_cast<const void*>(&s[0])); |
| 157 | +} |
| 158 | + |
| 159 | +/* |
| 160 | + * version-independent trailer view parent class |
| 161 | + * */ |
| 162 | + |
| 163 | +class SLinkRocketTrailerView { |
| 164 | +public: |
| 165 | + virtual ~SLinkRocketTrailerView() = default; |
| 166 | + virtual uint16_t status() const = 0; |
| 167 | + virtual uint16_t crc() const = 0; |
| 168 | + virtual uint32_t orbitID() const = 0; |
| 169 | + virtual uint16_t bxID() const = 0; |
| 170 | + virtual uint32_t eventLenBytes() const = 0; |
| 171 | + virtual uint16_t daqCRC() const = 0; |
| 172 | + virtual bool verifyMarker() const = 0; |
| 173 | +}; |
| 174 | + |
| 175 | +/* |
| 176 | + * trailer v3 view abstraction |
| 177 | + * */ |
| 178 | + |
| 179 | +class SLinkRocketTrailerView_v3 : public SLinkRocketTrailerView { |
| 180 | +public: |
| 181 | + SLinkRocketTrailerView_v3(const void* trailer) : trailer_(static_cast<const SLinkRocketTrailer_v3*>(trailer)) {} |
| 182 | + uint16_t status() const override { return trailer_->status(); } |
| 183 | + uint16_t crc() const override { return trailer_->crc(); } |
| 184 | + uint32_t orbitID() const override { return trailer_->orbitID(); } |
| 185 | + uint16_t bxID() const override { return trailer_->bxID(); } |
| 186 | + uint32_t eventLenBytes() const override { return trailer_->eventLenBytes(); } |
| 187 | + uint16_t daqCRC() const override { return trailer_->daqCRC(); } |
| 188 | + bool verifyMarker() const override { return trailer_->verifyMarker(); } |
| 189 | + |
| 190 | +private: |
| 191 | + const SLinkRocketTrailer_v3* trailer_; |
| 192 | +}; |
| 193 | + |
| 194 | +static inline std::unique_ptr<SLinkRocketTrailerView> makeSLinkRocketTrailerView(const void* buf, uint8_t version) { |
| 195 | + if (version == 3) |
| 196 | + return std::unique_ptr<SLinkRocketTrailerView>( |
| 197 | + static_cast<SLinkRocketTrailerView*>(new SLinkRocketTrailerView_v3(buf))); |
| 198 | + throw cms::Exception("SLinkRocketTrailerView::makeView") |
| 199 | + << "unknown SLinkRocketHeader version: " << (unsigned int)version; |
| 200 | +} |
| 201 | + |
| 202 | +static inline std::unique_ptr<SLinkRocketTrailerView> makeSLinkRocketTrailerView( |
| 203 | + std::span<const unsigned char> const& s, uint8_t version) { |
| 204 | + if (version == 3 && s.size() < sizeof(SLinkRocketTrailer_v3)) |
| 205 | + throw cms::Exception("SLinkRocketTrailerView::makeView") |
| 206 | + << "SLinkRocketTrailer v3 size mismatch: got " << s.size() << " expected " << sizeof(SLinkRocketTrailer_v3) |
| 207 | + << " bytes"; |
| 208 | + return makeSLinkRocketTrailerView(static_cast<const void*>(&s[0]), version); |
| 209 | +} |
| 210 | +#endif |
0 commit comments