Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:10:30

0001 /****************************************************************************
0002 *
0003 * This is a part of TOTEM offline software.
0004 * Authors:
0005 *   Jan Kašpar (jan.kaspar@gmail.com)
0006 *   Nicola Minafra
0007 *
0008 ****************************************************************************/
0009 
0010 #include "EventFilter/CTPPSRawToDigi/interface/RawDataUnpacker.h"
0011 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0012 #include "DataFormats/FEDRawData/interface/FEDNumbering.h"
0013 
0014 using namespace std;
0015 using namespace edm;
0016 using namespace pps;
0017 
0018 RawDataUnpacker::RawDataUnpacker(const edm::ParameterSet &iConfig)
0019     : verbosity(iConfig.getUntrackedParameter<unsigned int>("verbosity", 0)) {}
0020 
0021 int RawDataUnpacker::run(int fedId,
0022                          const FEDRawData &data,
0023                          vector<TotemFEDInfo> &fedInfoColl,
0024                          SimpleVFATFrameCollection &coll) const {
0025   unsigned int size_in_words = data.size() / 8;  // bytes -> words
0026   if (size_in_words < 2) {
0027     if (verbosity)
0028       LogWarning("Totem") << "Error in RawDataUnpacker::run > "
0029                           << "Data in FED " << fedId << " too short (size = " << size_in_words << " words).";
0030     return 1;
0031   }
0032 
0033   fedInfoColl.emplace_back(fedId);
0034 
0035   return processOptoRxFrame((const word *)data.data(), size_in_words, fedInfoColl.back(), &coll);
0036 }
0037 
0038 int RawDataUnpacker::processOptoRxFrame(const word *buf,
0039                                         unsigned int frameSize,
0040                                         TotemFEDInfo &fedInfo,
0041                                         SimpleVFATFrameCollection *fc) const {
0042   // get OptoRx metadata
0043   unsigned long long head = buf[0];
0044   unsigned long long foot = buf[frameSize - 1];
0045 
0046   fedInfo.setHeader(head);
0047   fedInfo.setFooter(foot);
0048 
0049   unsigned int boe = (head >> 60) & 0xF;
0050   unsigned int h0 = (head >> 0) & 0xF;
0051 
0052   unsigned long lv1 = (head >> 32) & 0xFFFFFF;
0053   unsigned long bx = (head >> 20) & 0xFFF;
0054   unsigned int optoRxId = (head >> 8) & 0xFFF;
0055   unsigned int fov = (head >> 4) & 0xF;
0056 
0057   unsigned int eoe = (foot >> 60) & 0xF;
0058   unsigned int f0 = (foot >> 0) & 0xF;
0059   unsigned int fSize = (foot >> 32) & 0x3FF;
0060 
0061   // check header and footer structure
0062   if (boe != 5 || h0 != 0 || eoe != 10 || f0 != 0 || fSize != frameSize) {
0063     if (verbosity)
0064       LogWarning("Totem") << "Error in RawDataUnpacker::processOptoRxFrame > "
0065                           << "Wrong structure of OptoRx header/footer: "
0066                           << "BOE=" << boe << ", H0=" << h0 << ", EOE=" << eoe << ", F0=" << f0
0067                           << ", size (OptoRx)=" << fSize << ", size (DATE)=" << frameSize << ". OptoRxID=" << optoRxId
0068                           << ". Skipping frame." << endl;
0069     return 0;
0070   }
0071 
0072   LogDebug("Totem") << "RawDataUnpacker::processOptoRxFrame: "
0073                     << "OptoRxId = " << optoRxId << ", BX = " << bx << ", LV1 = " << lv1
0074                     << ", frameSize = " << frameSize << ", fov = " << fov;
0075 
0076   if ((optoRxId >= FEDNumbering::MINTotemRPTimingVerticalFEDID &&
0077        optoRxId <= FEDNumbering::MAXTotemRPTimingVerticalFEDID)) {
0078     processOptoRxFrameSampic(buf, frameSize, fedInfo, fc);
0079     return 0;
0080   }
0081   if ((optoRxId >= FEDNumbering::MINTotemT2FEDID && optoRxId <= FEDNumbering::MAXTotemT2FEDID)) {
0082     processOptoRxFrameSampic(buf, frameSize, fedInfo, fc);
0083     return 0;
0084   }
0085 
0086   // parallel or serial transmission?
0087   switch (fov) {
0088     case 1:
0089       return processOptoRxFrameSerial(buf, frameSize, fc);
0090     case 2:
0091     case 3:
0092       return processOptoRxFrameParallel(buf, frameSize, fedInfo, fc);
0093     default:
0094       break;
0095   }
0096 
0097   if (verbosity)
0098     LogWarning("Totem") << "Error in RawDataUnpacker::processOptoRxFrame > "
0099                         << "Unknown FOV = " << fov << endl;
0100 
0101   return 0;
0102 }
0103 
0104 int RawDataUnpacker::processOptoRxFrameSerial(const word *buf,
0105                                               unsigned int frameSize,
0106                                               SimpleVFATFrameCollection *fc) const {
0107   // get OptoRx metadata
0108   unsigned int optoRxId = (buf[0] >> 8) & 0xFFF;
0109 
0110   // get number of subframes
0111   unsigned int subFrames = (frameSize - 2) / 194;
0112 
0113   // process all sub-frames
0114   unsigned int errorCounter = 0;
0115   for (unsigned int r = 0; r < subFrames; ++r) {
0116     for (unsigned int c = 0; c < 4; ++c) {
0117       unsigned int head = (buf[1 + 194 * r] >> (16 * c)) & 0xFFFF;
0118       unsigned int foot = (buf[194 + 194 * r] >> (16 * c)) & 0xFFFF;
0119 
0120       LogDebug("Totem") << "r = " << r << ", c = " << c << ": "
0121                         << "S = " << (head & 0x1) << ", BOF = " << (head >> 12) << ", EOF = " << (foot >> 12)
0122                         << ", ID = " << ((head >> 8) & 0xF) << ", ID' = " << ((foot >> 8) & 0xF);
0123 
0124       // stop if this GOH is NOT active
0125       if ((head & 0x1) == 0)
0126         continue;
0127 
0128       LogDebug("Totem") << "Header active (" << head << " -> " << (head & 0x1) << ").";
0129 
0130       // check structure
0131       if (head >> 12 != 0x4 || foot >> 12 != 0xB || ((head >> 8) & 0xF) != ((foot >> 8) & 0xF)) {
0132         std::ostringstream oss;
0133         if (head >> 12 != 0x4)
0134           oss << "\n\tHeader is not 0x4 as expected (0x" << std::hex << head << ").";
0135         if (foot >> 12 != 0xB)
0136           oss << "\n\tFooter is not 0xB as expected (0x" << std::hex << foot << ").";
0137         if (((head >> 8) & 0xF) != ((foot >> 8) & 0xF))
0138           oss << "\n\tIncompatible GOH IDs in header (0x" << std::hex << ((head >> 8) & 0xF) << ") and footer (0x"
0139               << std::hex << ((foot >> 8) & 0xF) << ").";
0140 
0141         if (verbosity)
0142           LogWarning("Totem") << "Error in RawDataUnpacker::processOptoRxFrame > "
0143                               << "Wrong payload structure (in GOH block row " << r << " and column " << c
0144                               << ") in OptoRx frame ID " << optoRxId << ". GOH block omitted." << oss.str() << endl;
0145 
0146         errorCounter++;
0147         continue;
0148       }
0149 
0150       // allocate memory for VFAT frames
0151       unsigned int goh = (head >> 8) & 0xF;
0152       vector<VFATFrame::word *> dataPtrs;
0153       for (unsigned int fi = 0; fi < 16; fi++) {
0154         TotemFramePosition fp(0, 0, optoRxId, goh, fi);
0155         dataPtrs.push_back(fc->InsertEmptyFrame(fp)->getData());
0156       }
0157 
0158       LogDebug("Totem").log([&](auto &l) {
0159         l << "transposing GOH block at prefix: " << (optoRxId * 192 + goh * 16) << ", dataPtrs = ";
0160         for (auto p : dataPtrs) {
0161           l << p << " ";
0162         }
0163       });
0164       // deserialization
0165       for (int i = 0; i < 192; i++) {
0166         int iword = 11 - i / 16;  // number of current word (11...0)
0167         int ibit = 15 - i % 16;   // number of current bit (15...0)
0168         unsigned int w = (buf[i + 2 + 194 * r] >> (16 * c)) & 0xFFFF;
0169 
0170         // Fill the current bit of the current word of all VFAT frames
0171         for (int idx = 0; idx < 16; idx++) {
0172           if (w & (1 << idx))
0173             dataPtrs[idx][iword] |= (1 << ibit);
0174         }
0175       }
0176     }
0177   }
0178 
0179   return errorCounter;
0180 }
0181 
0182 int RawDataUnpacker::processOptoRxFrameParallel(const word *buf,
0183                                                 unsigned int frameSize,
0184                                                 TotemFEDInfo &fedInfo,
0185                                                 SimpleVFATFrameCollection *fc) const {
0186   // get OptoRx metadata
0187   unsigned long long head = buf[0];
0188   unsigned int optoRxId = (head >> 8) & 0xFFF;
0189 
0190   // recast data as buffer or 16bit words, skip header
0191   const uint16_t *payload = (const uint16_t *)(buf + 1);
0192 
0193   // read in OrbitCounter block
0194   const uint32_t *ocPtr = (const uint32_t *)payload;
0195   fedInfo.setOrbitCounter(*ocPtr);
0196   payload += 2;
0197 
0198   // size in 16bit words, without header, footer and orbit counter block
0199   unsigned int nWords = (frameSize - 2) * 4 - 2;
0200 
0201   // process all VFAT data
0202   for (unsigned int offset = 0; offset < nWords;) {
0203     unsigned int wordsProcessed = processVFATDataParallel(payload + offset, nWords, optoRxId, fc);
0204     offset += wordsProcessed;
0205   }
0206 
0207   return 0;
0208 }
0209 
0210 int RawDataUnpacker::processVFATDataParallel(const uint16_t *buf,
0211                                              unsigned int maxWords,
0212                                              unsigned int optoRxId,
0213                                              SimpleVFATFrameCollection *fc) const {
0214   // start counting processed words
0215   unsigned int wordsProcessed = 1;
0216 
0217   // padding word? skip it
0218   if (buf[0] == 0xFFFF)
0219     return wordsProcessed;
0220 
0221   // check header flag
0222   unsigned int hFlag = (buf[0] >> 8) & 0xFF;
0223   if (hFlag != vmCluster && hFlag != vmRaw && hFlag != vmDiamondCompact) {
0224     if (verbosity)
0225       LogWarning("Totem") << "Error in RawDataUnpacker::processVFATDataParallel > "
0226                           << "Unknown header flag " << hFlag << ". Skipping this word." << endl;
0227     return wordsProcessed;
0228   }
0229 
0230   // compile frame position
0231   // NOTE: DAQ group uses terms GOH and fiber in the other way
0232   unsigned int gohIdx = (buf[0] >> 4) & 0xF;
0233   unsigned int fiberIdx = (buf[0] >> 0) & 0xF;
0234   TotemFramePosition fp(0, 0, optoRxId, gohIdx, fiberIdx);
0235 
0236   // prepare temporary VFAT frame
0237   VFATFrame f;
0238   VFATFrame::word *fd = f.getData();
0239 
0240   // copy footprint, BC, EC, Flags, ID, if they exist
0241   uint8_t presenceFlags = 0;
0242 
0243   if (((buf[wordsProcessed] >> 12) & 0xF) == 0xA)  // BC
0244   {
0245     presenceFlags |= 0x1;
0246     fd[11] = buf[wordsProcessed];
0247     wordsProcessed++;
0248   }
0249 
0250   if (((buf[wordsProcessed] >> 12) & 0xF) == 0xC)  // EC, flags
0251   {
0252     presenceFlags |= 0x2;
0253     fd[10] = buf[wordsProcessed];
0254     wordsProcessed++;
0255   }
0256 
0257   if (((buf[wordsProcessed] >> 12) & 0xF) == 0xE)  // ID
0258   {
0259     presenceFlags |= 0x4;
0260     fd[9] = buf[wordsProcessed];
0261     wordsProcessed++;
0262   }
0263 
0264   // save offset where channel data start
0265   unsigned int dataOffset = wordsProcessed;
0266 
0267   // find trailer
0268   switch (hFlag) {
0269     case vmCluster: {
0270       unsigned int nCl = 0;
0271       while ((buf[wordsProcessed + nCl] >> 12) != 0xF && (wordsProcessed + nCl < maxWords))
0272         nCl++;
0273       wordsProcessed += nCl;
0274     } break;
0275     case vmRaw:
0276       wordsProcessed += 9;
0277       break;
0278     case vmDiamondCompact: {
0279       wordsProcessed--;
0280       while ((buf[wordsProcessed] & 0xFFF0) != 0xF000 && (wordsProcessed < maxWords))
0281         wordsProcessed++;
0282     } break;
0283   }
0284 
0285   // process trailer
0286   unsigned int tSig = buf[wordsProcessed] >> 12;
0287   unsigned int tErrFlags = (buf[wordsProcessed] >> 8) & 0xF;
0288   unsigned int tSize = buf[wordsProcessed] & 0xFF;
0289 
0290   f.setDAQErrorFlags(tErrFlags);
0291 
0292   // consistency checks
0293   bool skipFrame = false;
0294   stringstream ess;
0295 
0296   if (tSig != 0xF) {
0297     if (verbosity)
0298       ess << "    Wrong trailer signature (" << tSig << ")." << endl;
0299     skipFrame = true;
0300   }
0301 
0302   if (tErrFlags != 0) {
0303     if (verbosity)
0304       ess << "    Error flags not zero (" << tErrFlags << ")." << endl;
0305     skipFrame = true;
0306   }
0307 
0308   wordsProcessed++;
0309 
0310   if (tSize != wordsProcessed) {
0311     if (verbosity)
0312       ess << "    Trailer size (" << tSize << ") does not match with words processed (" << wordsProcessed << ")."
0313           << endl;
0314     skipFrame = true;
0315   }
0316 
0317   if (skipFrame) {
0318     if (verbosity)
0319       LogWarning("Totem") << "Error in RawDataUnpacker::processVFATDataParallel > Frame at " << fp
0320                           << " has the following problems and will be skipped.\n"
0321                           << endl
0322                           << ess.rdbuf();
0323 
0324     return wordsProcessed;
0325   }
0326 
0327   // get channel data - cluster mode
0328   if (hFlag == vmCluster) {
0329     for (unsigned int nCl = 0; (buf[dataOffset + nCl] >> 12) != 0xF && (dataOffset + nCl < maxWords); ++nCl) {
0330       const uint16_t &w = buf[dataOffset + nCl];
0331       unsigned int upperBlock = w >> 8;
0332       unsigned int clSize = upperBlock & 0x7F;
0333       unsigned int clPos = (w >> 0) & 0xFF;
0334 
0335       // special case: upperBlock=0xD0 => numberOfClusters
0336       if (upperBlock == 0xD0) {
0337         presenceFlags |= 0x10;
0338         f.setNumberOfClusters(clPos);
0339         continue;
0340       }
0341 
0342       // special case: size=0 means chip full
0343       if (clSize == 0)
0344         clSize = 128;
0345 
0346       // activate channels
0347       //  convention - range <pos, pos-size+1>
0348       signed int chMax = clPos;
0349       signed int chMin = clPos - clSize + 1;
0350       if (chMax < 0 || chMax > 127 || chMin < 0 || chMin > 127 || chMin > chMax) {
0351         if (verbosity)
0352           LogWarning("Totem") << "Error in RawDataUnpacker::processVFATDataParallel > "
0353                               << "Invalid cluster (pos=" << clPos << ", size=" << clSize << ", min=" << chMin
0354                               << ", max=" << chMax << ") at " << fp << ". Skipping this cluster." << endl;
0355         continue;
0356       }
0357 
0358       for (signed int ch = chMin; ch <= chMax; ch++) {
0359         unsigned int wi = ch / 16;
0360         unsigned int bi = ch % 16;
0361         fd[wi + 1] |= (1 << bi);
0362       }
0363     }
0364   }
0365 
0366   // get channel data and CRC - raw mode
0367   if (hFlag == vmRaw) {
0368     for (unsigned int i = 0; i < 8; i++)
0369       fd[8 - i] = buf[dataOffset + i];
0370 
0371     // copy CRC
0372     presenceFlags |= 0x8;
0373     fd[0] = buf[dataOffset + 8];
0374   }
0375 
0376   // get channel data for diamond compact mode
0377   if (hFlag == vmDiamondCompact) {
0378     for (unsigned int i = 1; (buf[i + 1] & 0xFFF0) != 0xF000 && (i + 1 < maxWords); i++) {
0379       if ((buf[i] & 0xF000) == VFAT_HEADER_OF_EC) {
0380         // Event Counter word is found
0381         fd[10] = buf[i];
0382         continue;
0383       }
0384       switch (buf[i] & 0xF800) {
0385         case VFAT_DIAMOND_HEADER_OF_WORD_2:
0386           // word 2 of the diamond VFAT frame is found
0387           fd[1] = buf[i + 1];
0388           fd[2] = buf[i];
0389           break;
0390         case VFAT_DIAMOND_HEADER_OF_WORD_3:
0391           // word 3 of the diamond VFAT frame is found
0392           fd[3] = buf[i];
0393           fd[4] = buf[i - 1];
0394           break;
0395         case VFAT_DIAMOND_HEADER_OF_WORD_5:
0396           // word 5 of the diamond VFAT frame is found
0397           fd[5] = buf[i];
0398           fd[6] = buf[i - 1];
0399           break;
0400         case VFAT_DIAMOND_HEADER_OF_WORD_7:
0401           // word 7 of the diamond VFAT frame is found
0402           fd[7] = buf[i];
0403           fd[8] = buf[i - 1];
0404           break;
0405         default:
0406           break;
0407       }
0408       presenceFlags |= 0x8;
0409     }
0410   }
0411 
0412   // save frame to output
0413   f.setPresenceFlags(presenceFlags);
0414   fc->Insert(fp, f);
0415 
0416   return wordsProcessed;
0417 }
0418 
0419 int RawDataUnpacker::processOptoRxFrameSampic(const word *buf,
0420                                               unsigned int frameSize,
0421                                               TotemFEDInfo &fedInfo,
0422                                               SimpleVFATFrameCollection *fc) const {
0423   unsigned int optoRxId = (buf[0] >> 8) & 0xFFF;
0424 
0425   LogDebug("RawDataUnpacker::processOptoRxFrameSampic")
0426       << "Processing sampic frame: OptoRx " << optoRxId << "   framesize: " << frameSize;
0427 
0428   unsigned int orbitCounterVFATFrameWords = 6;
0429   unsigned int sizeofVFATPayload = 12;
0430 
0431   const VFATFrame::word *VFATFrameWordPtr = (const VFATFrame::word *)buf;
0432   VFATFrameWordPtr += orbitCounterVFATFrameWords - 1;
0433 
0434   LogDebug("RawDataUnpacker::processOptoRxFrameSampic")
0435       << "Framesize: " << frameSize << "\tframes: " << frameSize / (sizeofVFATPayload + 2);
0436 
0437   unsigned int nWords = (frameSize - 2) * 4 - 2;
0438 
0439   for (unsigned int i = 1; i * (sizeofVFATPayload + 2) < nWords; ++i) {
0440     // compile frame position
0441     // NOTE: DAQ group uses terms GOH and fiber in the other way
0442     unsigned int fiberIdx = (*(++VFATFrameWordPtr)) & 0xF;
0443     unsigned int gohIdx = (*VFATFrameWordPtr >> 4) & 0xF;
0444     TotemFramePosition fp(0, 0, optoRxId, gohIdx, fiberIdx);
0445     TotemT2FramePosition fp2a(0, 0, optoRxId, gohIdx, fiberIdx, 0);
0446     TotemT2FramePosition fp2b(0, 0, optoRxId, gohIdx, fiberIdx, 1);
0447 
0448     LogDebug("RawDataUnpacker::processOptoRxFrameSampic")
0449         << "OptoRx: " << optoRxId << " Goh: " << gohIdx << " Idx: " << fiberIdx;
0450 
0451     // prepare temporary VFAT frame
0452     VFATFrame frame(++VFATFrameWordPtr);
0453     VFATFrameWordPtr += sizeofVFATPayload;
0454 
0455     if (*(VFATFrameWordPtr) != 0xf00e) {
0456       edm::LogError("RawDataUnpacker::processOptoRxFrameSampic") << "Wrong trailer " << *VFATFrameWordPtr;
0457       continue;
0458     }
0459     // save frame to output
0460     frame.setPresenceFlags(1);
0461     if ((optoRxId >= FEDNumbering::MINTotemT2FEDID && optoRxId <= FEDNumbering::MAXTotemT2FEDID)) {
0462       frame.setPresenceFlags(15);  // check three VFAT signature digits, CRC present
0463       if (verbosity > 0)
0464         edm::LogWarning("Totem") << "T2 Frame Positions created: " << fp2a << "/" << fp2b << std::endl;
0465 
0466       fc->Insert(
0467           fp2a,
0468           frame);  //Fill twice with the mapping for both payloads packed into the same frame, will match only once for each
0469       fc->Insert(fp2b, frame);
0470     } else
0471       fc->Insert(fp, frame);
0472 
0473     LogDebug("RawDataUnpacker::processOptoRxFrameSampic") << "Trailer: " << std::hex << *VFATFrameWordPtr;
0474   }
0475 
0476   return 0;
0477 }