Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-08-08 03:11:32

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;
0075 
0076   if (optoRxId >= FEDNumbering::MINTotemRPTimingVerticalFEDID &&
0077       optoRxId <= FEDNumbering::MAXTotemRPTimingVerticalFEDID) {
0078     processOptoRxFrameSampic(buf, frameSize, fedInfo, fc);
0079     return 0;
0080   }
0081 
0082   // parallel or serial transmission?
0083   switch (fov) {
0084     case 1:
0085       return processOptoRxFrameSerial(buf, frameSize, fc);
0086     case 2:
0087     case 3:
0088       return processOptoRxFrameParallel(buf, frameSize, fedInfo, fc);
0089     default:
0090       break;
0091   }
0092 
0093   if (verbosity)
0094     LogWarning("Totem") << "Error in RawDataUnpacker::processOptoRxFrame > "
0095                         << "Unknown FOV = " << fov << endl;
0096 
0097   return 0;
0098 }
0099 
0100 int RawDataUnpacker::processOptoRxFrameSerial(const word *buf,
0101                                               unsigned int frameSize,
0102                                               SimpleVFATFrameCollection *fc) const {
0103   // get OptoRx metadata
0104   unsigned int optoRxId = (buf[0] >> 8) & 0xFFF;
0105 
0106   // get number of subframes
0107   unsigned int subFrames = (frameSize - 2) / 194;
0108 
0109   // process all sub-frames
0110   unsigned int errorCounter = 0;
0111   for (unsigned int r = 0; r < subFrames; ++r) {
0112     for (unsigned int c = 0; c < 4; ++c) {
0113       unsigned int head = (buf[1 + 194 * r] >> (16 * c)) & 0xFFFF;
0114       unsigned int foot = (buf[194 + 194 * r] >> (16 * c)) & 0xFFFF;
0115 
0116       LogDebug("Totem") << "r = " << r << ", c = " << c << ": "
0117                         << "S = " << (head & 0x1) << ", BOF = " << (head >> 12) << ", EOF = " << (foot >> 12)
0118                         << ", ID = " << ((head >> 8) & 0xF) << ", ID' = " << ((foot >> 8) & 0xF);
0119 
0120       // stop if this GOH is NOT active
0121       if ((head & 0x1) == 0)
0122         continue;
0123 
0124       LogDebug("Totem") << "Header active (" << head << " -> " << (head & 0x1) << ").";
0125 
0126       // check structure
0127       if (head >> 12 != 0x4 || foot >> 12 != 0xB || ((head >> 8) & 0xF) != ((foot >> 8) & 0xF)) {
0128         std::ostringstream oss;
0129         if (head >> 12 != 0x4)
0130           oss << "\n\tHeader is not 0x4 as expected (0x" << std::hex << head << ").";
0131         if (foot >> 12 != 0xB)
0132           oss << "\n\tFooter is not 0xB as expected (0x" << std::hex << foot << ").";
0133         if (((head >> 8) & 0xF) != ((foot >> 8) & 0xF))
0134           oss << "\n\tIncompatible GOH IDs in header (0x" << std::hex << ((head >> 8) & 0xF) << ") and footer (0x"
0135               << std::hex << ((foot >> 8) & 0xF) << ").";
0136 
0137         if (verbosity)
0138           LogWarning("Totem") << "Error in RawDataUnpacker::processOptoRxFrame > "
0139                               << "Wrong payload structure (in GOH block row " << r << " and column " << c
0140                               << ") in OptoRx frame ID " << optoRxId << ". GOH block omitted." << oss.str() << endl;
0141 
0142         errorCounter++;
0143         continue;
0144       }
0145 
0146       // allocate memory for VFAT frames
0147       unsigned int goh = (head >> 8) & 0xF;
0148       vector<VFATFrame::word *> dataPtrs;
0149       for (unsigned int fi = 0; fi < 16; fi++) {
0150         TotemFramePosition fp(0, 0, optoRxId, goh, fi);
0151         dataPtrs.push_back(fc->InsertEmptyFrame(fp)->getData());
0152       }
0153 
0154       LogDebug("Totem").log([&](auto &l) {
0155         l << "transposing GOH block at prefix: " << (optoRxId * 192 + goh * 16) << ", dataPtrs = ";
0156         for (auto p : dataPtrs) {
0157           l << p << " ";
0158         }
0159       });
0160       // deserialization
0161       for (int i = 0; i < 192; i++) {
0162         int iword = 11 - i / 16;  // number of current word (11...0)
0163         int ibit = 15 - i % 16;   // number of current bit (15...0)
0164         unsigned int w = (buf[i + 2 + 194 * r] >> (16 * c)) & 0xFFFF;
0165 
0166         // Fill the current bit of the current word of all VFAT frames
0167         for (int idx = 0; idx < 16; idx++) {
0168           if (w & (1 << idx))
0169             dataPtrs[idx][iword] |= (1 << ibit);
0170         }
0171       }
0172     }
0173   }
0174 
0175   return errorCounter;
0176 }
0177 
0178 int RawDataUnpacker::processOptoRxFrameParallel(const word *buf,
0179                                                 unsigned int frameSize,
0180                                                 TotemFEDInfo &fedInfo,
0181                                                 SimpleVFATFrameCollection *fc) const {
0182   // get OptoRx metadata
0183   unsigned long long head = buf[0];
0184   unsigned int optoRxId = (head >> 8) & 0xFFF;
0185 
0186   // recast data as buffer or 16bit words, skip header
0187   const uint16_t *payload = (const uint16_t *)(buf + 1);
0188 
0189   // read in OrbitCounter block
0190   const uint32_t *ocPtr = (const uint32_t *)payload;
0191   fedInfo.setOrbitCounter(*ocPtr);
0192   payload += 2;
0193 
0194   // size in 16bit words, without header, footer and orbit counter block
0195   unsigned int nWords = (frameSize - 2) * 4 - 2;
0196 
0197   // process all VFAT data
0198   for (unsigned int offset = 0; offset < nWords;) {
0199     unsigned int wordsProcessed = processVFATDataParallel(payload + offset, nWords, optoRxId, fc);
0200     offset += wordsProcessed;
0201   }
0202 
0203   return 0;
0204 }
0205 
0206 int RawDataUnpacker::processVFATDataParallel(const uint16_t *buf,
0207                                              unsigned int maxWords,
0208                                              unsigned int optoRxId,
0209                                              SimpleVFATFrameCollection *fc) const {
0210   // start counting processed words
0211   unsigned int wordsProcessed = 1;
0212 
0213   // padding word? skip it
0214   if (buf[0] == 0xFFFF)
0215     return wordsProcessed;
0216 
0217   // check header flag
0218   unsigned int hFlag = (buf[0] >> 8) & 0xFF;
0219   if (hFlag != vmCluster && hFlag != vmRaw && hFlag != vmDiamondCompact) {
0220     if (verbosity)
0221       LogWarning("Totem") << "Error in RawDataUnpacker::processVFATDataParallel > "
0222                           << "Unknown header flag " << hFlag << ". Skipping this word." << endl;
0223     return wordsProcessed;
0224   }
0225 
0226   // compile frame position
0227   // NOTE: DAQ group uses terms GOH and fiber in the other way
0228   unsigned int gohIdx = (buf[0] >> 4) & 0xF;
0229   unsigned int fiberIdx = (buf[0] >> 0) & 0xF;
0230   TotemFramePosition fp(0, 0, optoRxId, gohIdx, fiberIdx);
0231 
0232   // prepare temporary VFAT frame
0233   VFATFrame f;
0234   VFATFrame::word *fd = f.getData();
0235 
0236   // copy footprint, BC, EC, Flags, ID, if they exist
0237   uint8_t presenceFlags = 0;
0238 
0239   if (((buf[wordsProcessed] >> 12) & 0xF) == 0xA)  // BC
0240   {
0241     presenceFlags |= 0x1;
0242     fd[11] = buf[wordsProcessed];
0243     wordsProcessed++;
0244   }
0245 
0246   if (((buf[wordsProcessed] >> 12) & 0xF) == 0xC)  // EC, flags
0247   {
0248     presenceFlags |= 0x2;
0249     fd[10] = buf[wordsProcessed];
0250     wordsProcessed++;
0251   }
0252 
0253   if (((buf[wordsProcessed] >> 12) & 0xF) == 0xE)  // ID
0254   {
0255     presenceFlags |= 0x4;
0256     fd[9] = buf[wordsProcessed];
0257     wordsProcessed++;
0258   }
0259 
0260   // save offset where channel data start
0261   unsigned int dataOffset = wordsProcessed;
0262 
0263   // find trailer
0264   switch (hFlag) {
0265     case vmCluster: {
0266       unsigned int nCl = 0;
0267       while ((buf[wordsProcessed + nCl] >> 12) != 0xF && (wordsProcessed + nCl < maxWords))
0268         nCl++;
0269       wordsProcessed += nCl;
0270     } break;
0271     case vmRaw:
0272       wordsProcessed += 9;
0273       break;
0274     case vmDiamondCompact: {
0275       wordsProcessed--;
0276       while ((buf[wordsProcessed] & 0xFFF0) != 0xF000 && (wordsProcessed < maxWords))
0277         wordsProcessed++;
0278     } break;
0279   }
0280 
0281   // process trailer
0282   unsigned int tSig = buf[wordsProcessed] >> 12;
0283   unsigned int tErrFlags = (buf[wordsProcessed] >> 8) & 0xF;
0284   unsigned int tSize = buf[wordsProcessed] & 0xFF;
0285 
0286   f.setDAQErrorFlags(tErrFlags);
0287 
0288   // consistency checks
0289   bool skipFrame = false;
0290   stringstream ess;
0291 
0292   if (tSig != 0xF) {
0293     if (verbosity)
0294       ess << "    Wrong trailer signature (" << tSig << ")." << endl;
0295     skipFrame = true;
0296   }
0297 
0298   if (tErrFlags != 0) {
0299     if (verbosity)
0300       ess << "    Error flags not zero (" << tErrFlags << ")." << endl;
0301     skipFrame = true;
0302   }
0303 
0304   wordsProcessed++;
0305 
0306   if (tSize != wordsProcessed) {
0307     if (verbosity)
0308       ess << "    Trailer size (" << tSize << ") does not match with words processed (" << wordsProcessed << ")."
0309           << endl;
0310     skipFrame = true;
0311   }
0312 
0313   if (skipFrame) {
0314     if (verbosity)
0315       LogWarning("Totem") << "Error in RawDataUnpacker::processVFATDataParallel > Frame at " << fp
0316                           << " has the following problems and will be skipped.\n"
0317                           << endl
0318                           << ess.rdbuf();
0319 
0320     return wordsProcessed;
0321   }
0322 
0323   // get channel data - cluster mode
0324   if (hFlag == vmCluster) {
0325     for (unsigned int nCl = 0; (buf[dataOffset + nCl] >> 12) != 0xF && (dataOffset + nCl < maxWords); ++nCl) {
0326       const uint16_t &w = buf[dataOffset + nCl];
0327       unsigned int upperBlock = w >> 8;
0328       unsigned int clSize = upperBlock & 0x7F;
0329       unsigned int clPos = (w >> 0) & 0xFF;
0330 
0331       // special case: upperBlock=0xD0 => numberOfClusters
0332       if (upperBlock == 0xD0) {
0333         presenceFlags |= 0x10;
0334         f.setNumberOfClusters(clPos);
0335         continue;
0336       }
0337 
0338       // special case: size=0 means chip full
0339       if (clSize == 0)
0340         clSize = 128;
0341 
0342       // activate channels
0343       //  convention - range <pos, pos-size+1>
0344       signed int chMax = clPos;
0345       signed int chMin = clPos - clSize + 1;
0346       if (chMax < 0 || chMax > 127 || chMin < 0 || chMin > 127 || chMin > chMax) {
0347         if (verbosity)
0348           LogWarning("Totem") << "Error in RawDataUnpacker::processVFATDataParallel > "
0349                               << "Invalid cluster (pos=" << clPos << ", size=" << clSize << ", min=" << chMin
0350                               << ", max=" << chMax << ") at " << fp << ". Skipping this cluster." << endl;
0351         continue;
0352       }
0353 
0354       for (signed int ch = chMin; ch <= chMax; ch++) {
0355         unsigned int wi = ch / 16;
0356         unsigned int bi = ch % 16;
0357         fd[wi + 1] |= (1 << bi);
0358       }
0359     }
0360   }
0361 
0362   // get channel data and CRC - raw mode
0363   if (hFlag == vmRaw) {
0364     for (unsigned int i = 0; i < 8; i++)
0365       fd[8 - i] = buf[dataOffset + i];
0366 
0367     // copy CRC
0368     presenceFlags |= 0x8;
0369     fd[0] = buf[dataOffset + 8];
0370   }
0371 
0372   // get channel data for diamond compact mode
0373   if (hFlag == vmDiamondCompact) {
0374     for (unsigned int i = 1; (buf[i + 1] & 0xFFF0) != 0xF000 && (i + 1 < maxWords); i++) {
0375       if ((buf[i] & 0xF000) == VFAT_HEADER_OF_EC) {
0376         // Event Counter word is found
0377         fd[10] = buf[i];
0378         continue;
0379       }
0380       switch (buf[i] & 0xF800) {
0381         case VFAT_DIAMOND_HEADER_OF_WORD_2:
0382           // word 2 of the diamond VFAT frame is found
0383           fd[1] = buf[i + 1];
0384           fd[2] = buf[i];
0385           break;
0386         case VFAT_DIAMOND_HEADER_OF_WORD_3:
0387           // word 3 of the diamond VFAT frame is found
0388           fd[3] = buf[i];
0389           fd[4] = buf[i - 1];
0390           break;
0391         case VFAT_DIAMOND_HEADER_OF_WORD_5:
0392           // word 5 of the diamond VFAT frame is found
0393           fd[5] = buf[i];
0394           fd[6] = buf[i - 1];
0395           break;
0396         case VFAT_DIAMOND_HEADER_OF_WORD_7:
0397           // word 7 of the diamond VFAT frame is found
0398           fd[7] = buf[i];
0399           fd[8] = buf[i - 1];
0400           break;
0401         default:
0402           break;
0403       }
0404       presenceFlags |= 0x8;
0405     }
0406   }
0407 
0408   // save frame to output
0409   f.setPresenceFlags(presenceFlags);
0410   fc->Insert(fp, f);
0411 
0412   return wordsProcessed;
0413 }
0414 
0415 int RawDataUnpacker::processOptoRxFrameSampic(const word *buf,
0416                                               unsigned int frameSize,
0417                                               TotemFEDInfo &fedInfo,
0418                                               SimpleVFATFrameCollection *fc) const {
0419   unsigned int optoRxId = (buf[0] >> 8) & 0xFFF;
0420 
0421   LogDebug("RawDataUnpacker::processOptoRxFrameSampic")
0422       << "Processing sampic frame: OptoRx " << optoRxId << "   framesize: " << frameSize;
0423 
0424   unsigned int orbitCounterVFATFrameWords = 6;
0425   unsigned int sizeofVFATPayload = 12;
0426 
0427   const VFATFrame::word *VFATFrameWordPtr = (const VFATFrame::word *)buf;
0428   VFATFrameWordPtr += orbitCounterVFATFrameWords - 1;
0429 
0430   LogDebug("RawDataUnpacker::processOptoRxFrameSampic")
0431       << "Framesize: " << frameSize << "\tframes: " << frameSize / (sizeofVFATPayload + 2);
0432 
0433   unsigned int nWords = (frameSize - 2) * 4 - 2;
0434 
0435   for (unsigned int i = 1; i * (sizeofVFATPayload + 2) < nWords; ++i) {
0436     // compile frame position
0437     // NOTE: DAQ group uses terms GOH and fiber in the other way
0438     unsigned int fiberIdx = (*(++VFATFrameWordPtr)) & 0xF;
0439     unsigned int gohIdx = (*VFATFrameWordPtr >> 4) & 0xF;
0440     TotemFramePosition fp(0, 0, optoRxId, gohIdx, fiberIdx);
0441 
0442     LogDebug("RawDataUnpacker::processOptoRxFrameSampic")
0443         << "OptoRx: " << optoRxId << " Goh: " << gohIdx << " Idx: " << fiberIdx;
0444 
0445     // prepare temporary VFAT frame
0446     VFATFrame frame(++VFATFrameWordPtr);
0447     VFATFrameWordPtr += sizeofVFATPayload;
0448 
0449     if (*(VFATFrameWordPtr) != 0xf00e) {
0450       edm::LogError("RawDataUnpacker::processOptoRxFrameSampic") << "Wrong trailer " << *VFATFrameWordPtr;
0451       continue;
0452     }
0453     // save frame to output
0454     frame.setPresenceFlags(1);
0455     fc->Insert(fp, frame);
0456 
0457     LogDebug("RawDataUnpacker::processOptoRxFrameSampic") << "Trailer: " << std::hex << *VFATFrameWordPtr;
0458   }
0459 
0460   return 0;
0461 }