Project
Loading...
Searching...
No Matches
MC2RawEncoder.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
15#include "Framework/Logger.h"
16
17using namespace o2::itsmft;
18using namespace o2::raw;
20
22template <class Mapping>
24{
25 assert(mWriter.isReadOutModeSet());
26 mWriter.setCarryOverCallBack(this);
27 mWriter.setNewRDHCallBack(this);
28
29 // limit RUs to convert to existing ones
30 mRUSWMax = (mRUSWMax < uint8_t(mMAP.getNRUs())) ? mRUSWMax : mMAP.getNRUs() - 1;
31 //
32 mNLinks = 0;
33 for (uint8_t ru = mRUSWMin; ru <= mRUSWMax; ru++) {
34 auto& ruData = getCreateRUDecode(ru);
35 int nLinks = 0;
36 for (int il = 0; il < RUDecodeData::MaxLinksPerRU; il++) {
37 auto* link = getGBTLink(ruData.links[il]);
38 if (link) {
39 auto subspec = RDHUtils::getSubSpec(link->cruID, link->idInCRU, link->endPointID, link->feeID);
40 if (!mWriter.isLinkRegistered(subspec)) {
41 LOGF(info, "RU%3d FEEId 0x%04x Link %02d of CRU=0x%94x will be writing to default sink %s",
42 int(ru), link->feeID, link->idInCRU, link->cruID, mDefaultSinkName);
43 mWriter.registerLink(link->feeID, link->cruID, link->idInCRU, link->endPointID, mDefaultSinkName);
44 }
45 nLinks++;
46 if (link->packetCounter < 0) {
47 link->packetCounter = 0; // reset only once
48 }
49 }
50 }
51 mNLinks += nLinks;
52 if (!nLinks) {
53 LOG(warning) << "No GBT links were defined for RU " << int(ru) << " defining automatically";
54 ruData.links[0] = addGBTLink();
55 auto* link = getGBTLink(ruData.links[0]);
56 link->lanes = mMAP.getCablesOnRUType(ruData.ruInfo->ruType);
57 link->idInCRU = 0;
58 link->idInRU = 0;
59 link->cruID = ru;
60 link->feeID = mMAP.RUSW2FEEId(ruData.ruInfo->idSW, 0);
61 link->endPointID = 0;
62 link->packetCounter = 0;
63 mWriter.registerLink(link->feeID, link->cruID, link->idInCRU, link->endPointID, mDefaultSinkName);
64 LOGF(info, "RU%3d FEEId 0x%04x Link %02d of CRU=0x%04x Lanes: %s -> %s", int(ru), link->feeID,
65 link->idInCRU, link->cruID, std::bitset<28>(link->lanes).to_string(), mDefaultSinkName);
66 mNLinks++;
67 }
68 }
69 assert(mNLinks > 0);
70 // create mapping from feeID to links for fast access
71 for (int i = 0; i < mNLinks; i++) {
72 const auto* lnk = getGBTLink(i);
73 mFEEId2Link[lnk->feeID] = lnk;
74 mFEEId2GBTHeader[lnk->feeID].activeLanes = lnk->lanes;
75 }
76}
77
79template <class Mapping>
81{
82 mWriter.close();
83}
84
86template <class Mapping>
87void MC2RawEncoder<Mapping>::digits2raw(gsl::span<const Digit> digits, const o2::InteractionRecord& bcData)
88{
89 // Convert digits to raw data
90 // The digits in the span/vector must be in increasing chipID order
91 // Return the number of pages in the link with smallest amount of pages
92
93 if (!mNLinks) {
94 init();
95 }
96 int nDigTot = digits.size();
97 mCurrIR = bcData;
98 // place digits into corresponding chip buffers
99 ChipPixelData* curChipData = nullptr;
100 ChipInfo chInfo;
101 UShort_t curChipID = 0xffff; // currently processed SW chip id
102 for (const auto& dig : digits) {
103 if (curChipID != dig.getChipIndex()) {
104 mMAP.getChipInfoSW(dig.getChipIndex(), chInfo);
105 if (chInfo.ru < mRUSWMin || chInfo.ru > mRUSWMax) { // ignore this chip?
106 continue;
107 }
108 auto* ru = getRUDecode(chInfo.ru);
109 curChipID = dig.getChipIndex();
110 curChipData = &ru->chipsData[ru->nChipsFired++];
111 curChipData->setChipID(chInfo.chOnRU->id); // set chip ID within the RU
112 }
113 curChipData->getData().emplace_back(&dig); // add new digit to the container
114 }
115
116 // convert digits to alpide data in the per-cable buffers
117 for (int iru = int(mRUSWMin); iru <= int(mRUSWMax); iru++) {
118 auto& ru = *getRUDecode(iru);
119 uint16_t next2Proc = 0, nchTot = mMAP.getNChipsOnRUType(ru.ruInfo->ruType);
120 for (int ich = 0; ich < ru.nChipsFired; ich++) {
121 auto& chipData = ru.chipsData[ich];
122 convertEmptyChips(next2Proc, chipData.getChipID(), ru); // if needed store EmptyChip flags for the empty chips
123 next2Proc = chipData.getChipID() + 1;
124 convertChip(chipData, ru);
125 chipData.clear();
126 }
127 convertEmptyChips(next2Proc, nchTot, ru); // if needed store EmptyChip flags
128 fillGBTLinks(ru); // flush per-lane buffers to link buffers
129 }
130}
131
132//___________________________________________________________________________________
133template <class Mapping>
135{
137 const auto& chip = *mMAP.getChipOnRUInfo(ru.ruInfo->ruType, chipData.getChipID());
138 ru.cableHWID[chip.cableHWPos] = chip.cableHW; // register the cable HW ID
139 auto& pixels = chipData.getData();
140 std::sort(pixels.begin(), pixels.end(),
141 [](auto lhs, auto rhs) {
142 return (lhs.getRow() < rhs.getRow()) ? true : ((lhs.getRow() > rhs.getRow()) ? false : (lhs.getCol() < rhs.getCol()));
143 });
144 ru.cableData[chip.cableHWPos].ensureFreeCapacity(40 * (2 + pixels.size())); // make sure buffer has enough capacity
145 mCoder.encodeChip(ru.cableData[chip.cableHWPos], chipData, chip.chipOnModuleHW, mCurrIR.bc);
146}
147
148//______________________________________________________
149template <class Mapping>
150void MC2RawEncoder<Mapping>::convertEmptyChips(int fromChip, int uptoChip, RUDecodeData& ru)
151{
152 // add empty chip words to respective cable's buffers for all chips of the current RU container
153 for (int chipIDSW = fromChip; chipIDSW < uptoChip; chipIDSW++) { // flag chips w/o data
154 const auto& chip = *mMAP.getChipOnRUInfo(ru.ruInfo->ruType, chipIDSW);
155 ru.cableHWID[chip.cableHWPos] = chip.cableHW; // register the cable HW ID
156 ru.cableData[chip.cableHWPos].ensureFreeCapacity(100);
157 mCoder.addEmptyChip(ru.cableData[chip.cableHWPos], chip.chipOnModuleHW, mCurrIR.bc);
158 }
159}
160
161//___________________________________________________________________________________
162template <class Mapping>
164{
165 // fill data of the RU to links buffer, return the number of pages in the link with smallest amount of pages
166 constexpr uint8_t zero16[GBTPaddedWordLength] = {0}; // to speedup padding
167
168 // trigger word
169 GBTTrigger gbtTrigger;
170 gbtTrigger.bc = mCurrIR.bc;
171 gbtTrigger.orbit = mCurrIR.orbit;
172 gbtTrigger.internal = isContinuousReadout();
173 gbtTrigger.triggerType = 0; //TODO
174
175 for (int il = 0; il < RUDecodeData::MaxLinksPerRU; il++) {
176 auto link = getGBTLink(ru.links[il]);
177 if (!link) {
178 continue;
179 }
180 // estimate real payload size in GBT words
181 int nPayLoadWordsNeeded = 0; // number of payload words filled to link buffer (RDH not included) for current IR
182 for (int icab = ru.ruInfo->nCables; icab--;) { // calculate number of GBT words per link
183 if ((link->lanes & (0x1 << mMAP.cablePos(ru.ruInfo->ruType, icab)))) {
184 int nb = ru.cableData[mMAP.cablePos(ru.ruInfo->ruType, icab)].getSize();
185 nPayLoadWordsNeeded += nb ? 1 + (nb - 1) / 9 : 0; // single GBT word carries at most 9 payload bytes
186 }
187 }
188 // reserve space for payload + trigger + header + trailer
189 link->data.ensureFreeCapacity((3 + nPayLoadWordsNeeded) * link->wordLength);
190
191 link->data.addFast(gbtTrigger.getW8(), link->wordLength); // write GBT trigger
192
193 // now loop over the lanes served by this link, writing each time at most 9 bytes, untill all lanes are copied
194 bool hasData = true;
195 while (hasData) {
196 hasData = false;
197 for (int icab = 0; icab < ru.ruInfo->nCables; icab++) {
198 if ((link->lanes & (0x1 << mMAP.cablePos(ru.ruInfo->ruType, icab)))) {
199 auto& cableData = ru.cableData[mMAP.cablePos(ru.ruInfo->ruType, icab)];
200 int nb = cableData.getUnusedSize();
201 if (!nb) {
202 continue; // write 80b word only if there is something to write
203 }
204 if (nb > 9) {
205 nb = 9;
206 }
207 int gbtWordStart = link->data.getSize(); // beginning of the current GBT word in the link
208 link->data.addFast(cableData.getPtr(), nb); // fill payload of cable
209 link->data.addFast(zero16, link->wordLength - nb); // fill the rest of the GBT word by 0
210 link->data[gbtWordStart + 9] = mMAP.getGBTHeaderRUType(ru.ruInfo->ruType, ru.cableHWID[mMAP.cablePos(ru.ruInfo->ruType, icab)]); // set cable flag
211 cableData.setPtr(cableData.getPtr() + nb);
212 hasData = true;
213 } // storing data of single cable
214 } // loop over cables of this link
215 }; // loop until all links are w/o data
216
217 // all payload was dumped, write final trailer
218 GBTDataTrailer gbtTrailer; // lanes will be set on closing the trigger
219 // gbtTrailer.lanesStops = link->lanes; // RS CURRENTLY NOT USED
220 gbtTrailer.packetDone = true; // RS CURRENTLY NOT USED
221 link->data.addFast(gbtTrailer.getW8(), link->wordLength); // write GBT trailer for the last packet
222 LOGF(debug, "Filled %s with %d GBT words", link->describe(), nPayLoadWordsNeeded + 3);
223
224 // flush to writer
225 mWriter.addData(link->feeID, link->cruID, link->idInCRU, link->endPointID, mCurrIR, gsl::span((char*)link->data.data(), link->data.getSize()));
226 link->data.clear();
227 //
228 } // loop over links of RU
229 ru.clear();
230}
231
233template <class Mapping>
235{
236 assert(ruSW < mMAP.getNRUs());
237 if (mRUEntry[ruSW] < 0) {
238 mRUEntry[ruSW] = mNRUs++;
239 mRUDecodeVec[mRUEntry[ruSW]].ruInfo = mMAP.getRUInfoSW(ruSW); // info on the stave/RU
240 mRUDecodeVec[mRUEntry[ruSW]].chipsData.resize(mMAP.getNChipsOnRUType(mMAP.getRUInfoSW(ruSW)->ruType));
241 LOG(info) << "Defining container for RU " << ruSW << " at slot " << mRUEntry[ruSW];
242 }
243 return mRUDecodeVec[mRUEntry[ruSW]];
244}
245
247template <class Mapping>
248int MC2RawEncoder<Mapping>::carryOverMethod(const header::RDHAny* rdh, const gsl::span<char> data,
249 const char* ptr, int maxSize, int splitID,
250 std::vector<char>& trailer, std::vector<char>& header) const
251{
252 // The RawFileWriter receives from the encoder the payload to format according to the CRU format
253 // In case this payload size does not fit into the CRU page (this may happen even if it is
254 // less than 8KB, since it might be added to already partially populated CRU page of the HBF)
255 // it will write on the page only part of the payload and carry over the rest on extra page(s).
256 // By default the RawFileWriter will simply chunk payload as is considers necessary, but some
257 // detectors want their CRU pages to be self-consistent and in case of payload splitting they
258 // add in the end of page to be closed and beginning of the new page to be opened
259 // (right after the RDH) detector-specific trailer and header respectively.
260 //
261 // The role of this method is to suggest to writer how to split the payload:
262 // If this method was set to the RawFileWriter using
263 // RawFileWriter::setCarryOverCallBack(pointer_on_the_converter_class);
264 // then the RawFileWriter will call it before splitting.
265 //
266 // It provides to carryOverMethod method the following info:
267 // rdh : RDH of the CRU page being written
268 // data : original payload received by the RawFileWriter
269 // ptr : pointer on the data in the payload which was not yet added to the link CRU pages
270 // maxSize : maximum size (multiple of 16 bytes) of the bloc starting at ptr which it can
271 // accomodate at the current CRU page (i.e. what it would write by default)
272 // splitID : number of times this payload was already split, 0 at 1st call
273 // trailer : what it wants to add in the end of the CRU page where the data starting from ptr
274 // will be added. The trailer is supplied as an empy vector, which carryOverMethod
275 // may populate, but its size must be multiple of 16 bytes.
276 // header : what it wants to add right after the RDH of the new CRU page before the rest of
277 // the payload (starting at ptr+actualSize) will be written
278 //
279 // The method must return actual size of the bloc which can be written (<=maxSize).
280 // If this method populates the trailer, it must ensure that it returns the actual size such that
281 // actualSize + trailer.size() <= maxSize
282 // In case returned actualSize == 0, current CRU page will be closed w/o adding anything, and new
283 // query of this method will be done on the new CRU page
284
285 // During the carry-over ITS needs to repeat the GBTTrigger and GBTDataTrailer words.
286 // Also the GBTDataHeader needs to be repeated right after continuation RDH, but it will be provided in the newRDHMethod
287 const int wordSize = RDHUtils::getDataFormat(rdh) == 0 ? o2::itsmft::GBTPaddedWordLength : o2::itsmft::GBTWordLength;
288 uint feed = RDHUtils::getFEEID(rdh);
289
290 int offs = ptr - &data[0]; // offset wrt the head of the payload
291 // make sure ptr and end of the suggested block are within the payload
292 assert(offs >= 0 && size_t(offs + maxSize) <= data.size());
293
294 // this is where we would usually split: account for the trailer to add
295 int actualSize = maxSize - wordSize;
296 // make sure we don't split the GBT word
297 actualSize -= actualSize % wordSize;
298
299 char* trailPtr = &data[data.size() - wordSize]; // pointer on the payload trailer
300
301 if ((maxSize <= 2 * wordSize)) { // we cannot split trigger+header
302 actualSize = 0; // suggest moving the whole payload to the new CRU page
303 if (offs == 0) { // just carry over everything, trigger+header was not yet written
304 return actualSize;
305 }
306 } else {
307 if (ptr + actualSize >= trailPtr) { // we need to split at least 1 GBT word before the trailer
308 actualSize = trailPtr - ptr - wordSize;
309 // make sure we don't split the GBT word
310 actualSize -= actualSize % wordSize;
311 }
312 }
313 // copy the GBTTrigger and GBTHeader from the head of the payload
314 header.resize(wordSize);
315 memcpy(header.data(), &data[0], wordSize);
316
317 // copy the GBTTrailer from the end of the payload
318 trailer.resize(wordSize);
319 memcpy(trailer.data(), trailPtr, wordSize);
320 GBTDataTrailer& gbtTrailer = *reinterpret_cast<GBTDataTrailer*>(&trailer[0]);
321 gbtTrailer.packetDone = false; // intermediate trailers should not have done=true
322 // gbtTrailer.lanesStops = 0; // intermediate trailers should not have lanes closed // RS CURRENTLY NOT USED
323
324 return actualSize;
325}
326
328template <class Mapping>
329void MC2RawEncoder<Mapping>::newRDHMethod(const header::RDHAny* rdh, bool empty, std::vector<char>& toAdd) const
330{
331 // these method is called by the writer when it opens a new RDH page to fill some data.
332 // empty tells if the previous RDH page had some payload (to differentiate between automatic open/close of empty RDH pages, handled by
333 // the emptyHBFFunc and read data filling
334 const int wordSize = RDHUtils::getDataFormat(rdh) == 0 ? o2::itsmft::GBTPaddedWordLength : o2::itsmft::GBTWordLength;
335 if (RDHUtils::getStop(rdh)) { // the RDH was added to close previous HBF, do we want to add diagnostic data?
336 if (!empty) {
337 GBTDiagnostic diag;
338 toAdd.resize(wordSize);
339 memcpy(toAdd.data(), diag.getW8(), wordSize);
340 }
341 } else { // we need to add GBTDataHeader
342 toAdd.resize(wordSize);
343 memcpy(toAdd.data(), mFEEId2GBTHeader.find(RDHUtils::getFEEID(rdh))->second.getW8(), wordSize);
344 }
345}
346
Definition of the 32 Central Trigger System (CTS) Trigger Types defined in https://twiki....
int32_t i
Definition of the ITS/MFT Alpide pixel MC->raw converter.
std::enable_if_t< std::is_signed< T >::value, bool > hasData(const CalArray< T > &cal)
Definition Painter.cxx:515
TBranch * ptr
std::ostringstream debug
void setChipID(uint16_t id)
Definition PixelData.h:119
uint16_t getChipID() const
Definition PixelData.h:108
const std::vector< PixelData > & getData() const
Definition PixelData.h:115
int carryOverMethod(const o2::header::RDHAny *rdh, const gsl::span< char > data, const char *ptr, int maxSize, int splitID, std::vector< char > &trailer, std::vector< char > &header) const
RUDecodeData & getCreateRUDecode(int ruSW)
void digits2raw(gsl::span< const Digit > digits, const o2::InteractionRecord &bcData)
void newRDHMethod(const header::RDHAny *rdh, bool empty, std::vector< char > &toAdd) const
GLboolean * data
Definition glcorearb.h:298
GLint GLint GLsizei GLint GLenum GLenum const void * pixels
Definition glcorearb.h:275
uint8_t itsSharedClusterMap uint8_t
constexpr int GBTPaddedWordLength
Definition GBTWord.h:56
constexpr int GBTWordLength
Definition GBTWord.h:55
void empty(int)
const ChipOnRUInfo * chOnRU
Definition RUInfo.h:59
std::uint16_t ru
Definition RUInfo.h:63
std::uint8_t id
Definition RUInfo.h:42
const uint8_t * getW8() const
Definition GBTWord.h:164
uint64_t internal
0:11 12 lowest bits of trigger type received from CTP
Definition GBTWord.h:92
uint64_t orbit
28:31 reserved
Definition GBTWord.h:98
uint64_t triggerType
Definition GBTWord.h:91
uint64_t bc
15 reserved
Definition GBTWord.h:96
uint64_t packetDone
56:63 reserved
Definition GBTWord.h:81
std::array< int, MaxLinksPerRU > links
std::array< PayLoadCont, MaxCablesPerRU > cableData
static constexpr int MaxLinksPerRU
std::array< uint8_t, MaxCablesPerRU > cableHWID
uint8_t nCables
Definition RUInfo.h:36
uint8_t ruType
Definition RUInfo.h:35
static LinkSubSpec_t getSubSpec(uint16_t cru, uint8_t link, uint8_t endpoint, uint16_t feeId, o2::header::DAQID::ID srcid=o2::header::DAQID::INVALID)
Definition RDHUtils.h:685
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Digit > digits