CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_8_patch3/src/EventFilter/SiStripRawToDigi/src/SiStripFEDBuffer.cc

Go to the documentation of this file.
00001 #include <iomanip>
00002 #include <ostream>
00003 #include <sstream>
00004 #include <cstring>
00005 
00006 #include "EventFilter/SiStripRawToDigi/interface/SiStripFEDBuffer.h"
00007 
00008 #include "DataFormats/SiStripCommon/interface/SiStripFedKey.h"
00009 
00010 namespace sistrip {
00011 
00012   FEDBuffer::FEDBuffer(const uint8_t* fedBuffer, const size_t fedBufferSize, const bool allowBadBuffer)
00013     : FEDBufferBase(fedBuffer,fedBufferSize,allowBadBuffer,false)
00014   {
00015     channels_.reserve(FEDCH_PER_FED);
00016     //build the correct type of FE header object
00017     if ( (headerType() != HEADER_TYPE_INVALID) && (headerType() != HEADER_TYPE_NONE) ) {
00018       feHeader_ = FEDFEHeader::newFEHeader(headerType(),getPointerToDataAfterTrackerSpecialHeader());
00019       payloadPointer_ = getPointerToDataAfterTrackerSpecialHeader()+feHeader_->lengthInBytes();
00020     } else {
00021       feHeader_ = std::auto_ptr<FEDFEHeader>();
00022       payloadPointer_ = getPointerToDataAfterTrackerSpecialHeader();
00023       if (!allowBadBuffer) {
00024         std::ostringstream ss;
00025         ss << "Header type is invalid. "
00026            << "Header type nibble is ";
00027         uint8_t headerNibble = trackerSpecialHeader().headerTypeNibble();
00028         printHex(&headerNibble,1,ss);
00029         ss << ". ";
00030         throw cms::Exception("FEDBuffer") << ss.str();
00031       }
00032     }
00033     if (readoutMode() == READOUT_MODE_SPY) {
00034       throw cms::Exception("FEDBuffer") << "Unpacking of spy channel data with FEDBuffer is not supported" << std::endl;
00035     }
00036     payloadLength_ = getPointerToByteAfterEndOfPayload()-payloadPointer_;
00037     //check if FE units are present in data
00038     //in Full Debug mode, use the lengths from the header
00039     const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00040     if (fdHeader) {
00041       for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00042         if (fdHeader->fePresent(iFE)) fePresent_[iFE] = true;
00043         else fePresent_[iFE] = false;
00044       }
00045     }
00046     //in APV error mode, use the FE present byte in the FED status register
00047     // a value of '1' means a FE unit's data is missing (in old firmware versions it is always 0)
00048     else {
00049       for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00050       if (fedStatusRegister().feDataMissingFlag(iFE)) fePresent_[iFE] = false;
00051       else fePresent_[iFE] = true;
00052       }
00053     }
00054     //try to find channels
00055     validChannels_ = 0;
00056     try {
00057       findChannels();
00058     } catch (const cms::Exception& e) {
00059       //if there was a problem either rethrow the exception or just mark channel pointers NULL
00060       if (!allowBadBuffer) throw;
00061       else {
00062         channels_.insert(channels_.end(),size_t(FEDCH_PER_FED-validChannels_),FEDChannel(payloadPointer_,0,0));
00063       }
00064     }
00065   }
00066 
00067   FEDBuffer::~FEDBuffer()
00068   {
00069   }
00070 
00071   void FEDBuffer::findChannels()
00072   {
00073     //set min length to 2 for ZSLite, 7 for ZS and 3 for raw
00074     uint16_t minLength;
00075     switch (readoutMode()) {
00076       case READOUT_MODE_ZERO_SUPPRESSED:
00077         minLength = 7;
00078         break;
00079       case READOUT_MODE_ZERO_SUPPRESSED_LITE:
00080         minLength = 2;
00081         break;
00082       default:
00083         minLength = 3;
00084         break;
00085     }
00086     size_t offsetBeginningOfChannel = 0;
00087     for (size_t i = 0; i < FEDCH_PER_FED; i++) {
00088       //if FE unit is not enabled then skip rest of FE unit adding NULL pointers
00089       if ( !(fePresent(i/FEDCH_PER_FEUNIT) && feEnabled(i/FEDCH_PER_FEUNIT)) ) {
00090         channels_.insert(channels_.end(),size_t(FEDCH_PER_FEUNIT),FEDChannel(payloadPointer_,0,0));
00091         i += FEDCH_PER_FEUNIT-1;
00092         validChannels_ += FEDCH_PER_FEUNIT;
00093         continue;
00094       }
00095       //if FE unit is enabled
00096       //check that channel length bytes fit into buffer
00097       if (offsetBeginningOfChannel+1 >= payloadLength_) {
00098         std::ostringstream ss;
00099         SiStripFedKey key(0,i/FEDCH_PER_FEUNIT,i%FEDCH_PER_FEUNIT);
00100         ss << "Channel " << uint16_t(i) << " (FE unit " << key.feUnit() << " channel " << key.feChan() << " according to external numbering scheme)" 
00101            << " does not fit into buffer. "
00102            << "Channel starts at " << uint16_t(offsetBeginningOfChannel) << " in payload. "
00103            << "Payload length is " << uint16_t(payloadLength_) << ". ";
00104         throw cms::Exception("FEDBuffer") << ss.str();
00105       }
00106       channels_.push_back(FEDChannel(payloadPointer_,offsetBeginningOfChannel));
00107       //get length and check that whole channel fits into buffer
00108       uint16_t channelLength = channels_.back().length();
00109       //check that the channel length is long enough to contain the header
00110       if (channelLength < minLength) {
00111         SiStripFedKey key(0,i/FEDCH_PER_FEUNIT,i%FEDCH_PER_FEUNIT);
00112         std::ostringstream ss;
00113         ss << "Channel " << uint16_t(i) << " (FE unit " << key.feUnit() << " channel " << key.feChan() << " according to external numbering scheme)"
00114            << " is too short. "
00115            << "Channel starts at " << uint16_t(offsetBeginningOfChannel) << " in payload. "
00116            << "Channel length is " << uint16_t(channelLength) << ". "
00117            << "Min length is " << uint16_t(minLength) << ". ";
00118         throw cms::Exception("FEDBuffer") << ss.str();
00119       }
00120       if (offsetBeginningOfChannel+channelLength > payloadLength_) {
00121         SiStripFedKey key(0,i/FEDCH_PER_FEUNIT,i%FEDCH_PER_FEUNIT);
00122         std::ostringstream ss;
00123         ss << "Channel " << uint16_t(i) << " (FE unit " << key.feUnit() << " channel " << key.feChan() << " according to external numbering scheme)" 
00124            << "Channel starts at " << uint16_t(offsetBeginningOfChannel) << " in payload. "
00125            << "Channel length is " << uint16_t(channelLength) << ". "
00126            << "Payload length is " << uint16_t(payloadLength_) << ". ";
00127         throw cms::Exception("FEDBuffer") << ss.str();
00128       }
00129       validChannels_++;
00130       const size_t offsetEndOfChannel = offsetBeginningOfChannel+channelLength;
00131       //add padding if necessary and calculate offset for begining of next channel
00132       if (!( (i+1) % FEDCH_PER_FEUNIT )) {
00133         uint8_t numPaddingBytes = 8 - (offsetEndOfChannel % 8);
00134         if (numPaddingBytes == 8) numPaddingBytes = 0;
00135         offsetBeginningOfChannel = offsetEndOfChannel + numPaddingBytes;
00136       } else {
00137         offsetBeginningOfChannel = offsetEndOfChannel;
00138       }
00139     }
00140   }
00141   
00142   bool FEDBuffer::channelGood(const uint8_t internalFEDChannelNum, const bool doAPVeCheck) const
00143   {
00144     return ( (internalFEDChannelNum < validChannels_) &&
00145              ( (doAPVeCheck && feGood(internalFEDChannelNum/FEDCH_PER_FEUNIT)) || 
00146                (!doAPVeCheck && feGoodWithoutAPVEmulatorCheck(internalFEDChannelNum/FEDCH_PER_FEUNIT)) 
00147                ) &&
00148              (this->readoutMode() == sistrip::READOUT_MODE_SCOPE || checkStatusBits(internalFEDChannelNum)) );
00149   }
00150 
00151   bool FEDBuffer::doChecks() const
00152   {
00153     //check that all channels were unpacked properly
00154     if (validChannels_ != FEDCH_PER_FED) return false;
00155     //do checks from base class
00156     if (!FEDBufferBase::doChecks()) return false;
00157     //check CRC
00158     if (!checkCRC()) return false;
00159     return true;
00160   }
00161 
00162   bool FEDBuffer::doCorruptBufferChecks() const
00163   {
00164     return ( checkCRC() &&
00165              checkChannelLengthsMatchBufferLength() &&
00166              checkChannelPacketCodes() &&
00167              //checkClusterLengths() &&
00168              checkFEUnitLengths() );
00169     //checkFEUnitAPVAddresses() );
00170   }
00171 
00172   bool FEDBuffer::checkAllChannelStatusBits() const
00173   {
00174     for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00175       //if FE unit is disabled then skip all channels on it
00176       if (!feGood(iCh/FEDCH_PER_FEUNIT)) {
00177         iCh += FEDCH_PER_FEUNIT;
00178         continue;
00179       }
00180       //channel is bad then return false
00181       if (!checkStatusBits(iCh)) return false;
00182     }
00183     //if no bad channels have been found then they are all fine
00184     return true;
00185   }
00186 
00187   bool FEDBuffer::checkChannelLengths() const
00188   {
00189     return (validChannels_ == FEDCH_PER_FED);
00190   }
00191 
00192   bool FEDBuffer::checkChannelLengthsMatchBufferLength() const
00193   {
00194     //check they fit into buffer
00195     if (!checkChannelLengths()) return false;
00196   
00197     //payload length from length of data buffer
00198     const size_t payloadLengthInWords = payloadLength_/8;
00199   
00200     //find channel length
00201     //find last enabled FE unit
00202     uint8_t lastEnabledFeUnit = 7;
00203     while ( !(fePresent(lastEnabledFeUnit) && feEnabled(lastEnabledFeUnit)) && lastEnabledFeUnit!=0 ) lastEnabledFeUnit--;
00204     //last channel is last channel on last enabled FE unit
00205     const FEDChannel& lastChannel = channels_[internalFEDChannelNum(lastEnabledFeUnit,FEDCH_PER_FEUNIT-1)];
00206     const size_t offsetLastChannel = lastChannel.offset();
00207     const size_t offsetEndOfChannelData = offsetLastChannel+lastChannel.length();
00208     const size_t channelDataLength = offsetEndOfChannelData;
00209     //channel length in words is length in bytes rounded up to nearest word
00210     size_t channelDataLengthInWords = channelDataLength/8;
00211     if (channelDataLength % 8) channelDataLengthInWords++;
00212   
00213     //check lengths match
00214     if (channelDataLengthInWords == payloadLengthInWords) {
00215       return true;
00216     } else {
00217       return false;
00218     }
00219   }
00220 
00221   bool FEDBuffer::checkChannelPacketCodes() const
00222   {
00223     const uint8_t correctPacketCode = getCorrectPacketCode();
00224     //if the readout mode if not one which has a packet code then this is set to zero. in this case return true
00225     if (!correctPacketCode) return true;
00226     for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00227       //if FE unit is disabled then skip all channels on it
00228       if (!feGood(iCh/FEDCH_PER_FEUNIT)) {
00229         iCh += FEDCH_PER_FEUNIT;
00230         continue;
00231       }
00232       //only check enabled, working channels
00233       if (channelGood(iCh)) {
00234         //if a channel is bad then return false
00235         if (channels_[iCh].packetCode() != correctPacketCode) return false;
00236       }
00237     }
00238     //if no bad channels were found the they are all ok
00239     return true;
00240   }
00241 
00242   bool FEDBuffer::checkFEUnitAPVAddresses() const
00243   {
00244     //get golden address
00245     const uint8_t goldenAddress = apveAddress();
00246     //don't check if the address is 00 since APVe is probably not connected
00247     if (goldenAddress == 0x00) return true;
00248     //check can only be done for full debug headers
00249     const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00250     if (!fdHeader) return true;
00251     //check all enabled FE units
00252     for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00253       if (!feGood(iFE)) continue;
00254       //if address is bad then return false
00255       if (fdHeader->feUnitMajorityAddress(iFE) != goldenAddress) return false;
00256     }
00257     //if no bad addresses were found then return true
00258     return true;
00259   }
00260 
00261   bool FEDBuffer::checkFEUnitLengths() const
00262   {
00263     //check can only be done for full debug headers
00264     const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00265     if (!fdHeader) return true;
00266     //check lengths for enabled FE units
00267     for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00268       if (!feGood(iFE)) continue;
00269       if (calculateFEUnitLength(iFE) != fdHeader->feUnitLength(iFE)) return false;
00270     }
00271     //if no errors were encountered then return true
00272     return true;
00273   }
00274   
00275   uint16_t FEDBuffer::calculateFEUnitLength(const uint8_t internalFEUnitNumber) const
00276   {
00277     //get length from channels
00278     uint16_t lengthFromChannels = 0;
00279     for (uint8_t iCh = 0; iCh < FEDCH_PER_FEUNIT; iCh++) {
00280       lengthFromChannels += channels_[internalFEDChannelNum(internalFEUnitNumber,iCh)].length();
00281     }
00282     return lengthFromChannels;
00283   }
00284   
00285   bool FEDBuffer::checkFEPayloadsPresent() const
00286   {
00287     for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00288       if (!fePresent(iFE)) return false;
00289     }
00290     return true;
00291   }
00292 
00293   std::string FEDBuffer::checkSummary() const
00294   {
00295     std::ostringstream summary;
00296     summary << FEDBufferBase::checkSummary();
00297     summary << "Check FE unit payloads are all present: " << (checkFEPayloadsPresent() ? "passed" : "FAILED" ) << std::endl;
00298     if (!checkFEPayloadsPresent()) {
00299       summary << "FE units missing payloads: ";
00300       for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00301         if (!fePresent(iFE)) summary << uint16_t(iFE) << " ";
00302       }
00303       summary << std::endl;
00304     }
00305     summary << "Check channel status bits: " << ( checkAllChannelStatusBits() ? "passed" : "FAILED" ) << std::endl;
00306     if (!checkAllChannelStatusBits()) {
00307       unsigned int badChannels = 0;
00308       if (headerType() == HEADER_TYPE_FULL_DEBUG) {
00309         const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00310         if (fdHeader) {
00311           for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00312             if (!feGood(iCh/FEDCH_PER_FEUNIT)) continue;
00313             if (!checkStatusBits(iCh)) {
00314               summary << uint16_t(iCh) << ": " << fdHeader->getChannelStatus(iCh) << std::endl;
00315               badChannels++;
00316             }
00317           }
00318         }
00319       } else {
00320         summary << "Channels with errors: ";
00321         for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00322           if (!feGood(iCh/FEDCH_PER_FEUNIT)) continue;
00323           if (!checkStatusBits(iCh)) {
00324             summary << uint16_t(iCh) << " ";
00325             badChannels++;
00326           }
00327         }
00328         summary << std::endl;
00329       } 
00330       summary << "Number of channels with bad status bits: " << badChannels << std::endl;
00331     }
00332     summary << "Check channel lengths match buffer length: " << ( checkChannelLengthsMatchBufferLength() ? "passed" : "FAILED" ) << std::endl;
00333     summary << "Check channel packet codes: " << ( checkChannelPacketCodes() ? "passed" : "FAILED" ) << std::endl;
00334     if (!checkChannelPacketCodes()) {
00335       summary << "Channels with bad packet codes: ";
00336       for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00337         if (!feGood(iCh/FEDCH_PER_FEUNIT)) continue;
00338         if (channels_[iCh].packetCode() != getCorrectPacketCode())
00339           summary << uint16_t(iCh) << " ";
00340       }
00341     }
00342     summary << "Check FE unit lengths: " << ( checkFEUnitLengths() ? "passed" : "FAILED" ) << std::endl;
00343     if (!checkFEUnitLengths()) {
00344       const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00345       if (fdHeader) {
00346         summary << "Bad FE units:" << std::endl;
00347         for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00348           if (!feGood(iFE)) continue;
00349           uint16_t lengthFromChannels = calculateFEUnitLength(iFE);
00350           uint16_t lengthFromHeader = fdHeader->feUnitLength(iFE);
00351           if (lengthFromHeader != lengthFromChannels) {
00352             summary << "FE unit: " << uint16_t(iFE) 
00353                     << " length in header: " << lengthFromHeader 
00354                     << " length from channel lengths: " << lengthFromChannels << std::endl;
00355           }
00356         }
00357       }
00358     }
00359     summary << "Check FE unit APV addresses match APVe: " << ( checkFEUnitAPVAddresses() ? "passed" : "FAILED" ) << std::endl;
00360     if (!checkFEUnitAPVAddresses()) {
00361       const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00362       if (fdHeader) {
00363         const uint8_t goldenAddress = apveAddress();
00364         summary << "Address from APVe:" << uint16_t(goldenAddress) << std::endl;
00365         summary << "Bad FE units:" << std::endl;
00366         for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00367           if (!feGood(iFE)) continue;
00368           if (fdHeader->feUnitMajorityAddress(iFE) != goldenAddress) {
00369             summary << "FE unit: " << uint16_t(iFE)
00370                     << " majority address: " << uint16_t(fdHeader->feUnitMajorityAddress(iFE)) << std::endl;
00371           }
00372         }
00373       }
00374     }
00375     return summary.str();
00376   }
00377 
00378   uint8_t FEDBuffer::getCorrectPacketCode() const
00379   {
00380     switch(readoutMode()) {
00381     case READOUT_MODE_SCOPE:
00382       return PACKET_CODE_SCOPE;
00383       break;
00384     case READOUT_MODE_VIRGIN_RAW:
00385       return PACKET_CODE_VIRGIN_RAW;
00386       break;
00387     case READOUT_MODE_PROC_RAW:
00388       return PACKET_CODE_PROC_RAW;
00389       break;
00390     case READOUT_MODE_ZERO_SUPPRESSED:
00391       return PACKET_CODE_ZERO_SUPPRESSED;
00392       break;
00393     case READOUT_MODE_ZERO_SUPPRESSED_LITE:
00394     case READOUT_MODE_SPY:
00395     case READOUT_MODE_INVALID:
00396     default:
00397       return 0;
00398     }
00399   }
00400 
00401   uint8_t FEDBuffer::nFEUnitsPresent() const
00402   {
00403     uint8_t result = 0;
00404     for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00405       if (fePresent(iFE)) result++;
00406     }
00407     return result;
00408   }
00409   
00410   void FEDBuffer::print(std::ostream& os) const
00411   {
00412     FEDBufferBase::print(os);
00413     if (headerType() == HEADER_TYPE_FULL_DEBUG) {
00414       os << "FE units with data: " << uint16_t(nFEUnitsPresent()) << std::endl;
00415       os << "BE status register flags: ";
00416       dynamic_cast<const FEDFullDebugHeader*>(feHeader())->beStatusRegister().printFlags(os);
00417       os << std::endl;
00418     }
00419   }
00420 
00421 
00422 
00423 
00424   void FEDRawChannelUnpacker::throwBadChannelLength(const uint16_t length)
00425   {
00426     std::ostringstream ss;
00427     ss << "Channel length is invalid. Raw channels have 3 header bytes and 2 bytes per sample. "
00428        << "Channel length is " << uint16_t(length) << "."
00429        << std::endl;
00430     throw cms::Exception("FEDBuffer") << ss.str();
00431   }
00432 
00433 
00434 
00435 
00436   void FEDZSChannelUnpacker::throwBadChannelLength(const uint16_t length)
00437   {
00438     std::ostringstream ss;
00439     ss << "Channel length is longer than max allowed value. "
00440        << "Channel length is " << uint16_t(length) << "."
00441        << std::endl;
00442     throw cms::Exception("FEDBuffer") << ss.str();
00443   }
00444 
00445   void FEDZSChannelUnpacker::throwBadClusterLength()
00446   {
00447     std::ostringstream ss;
00448     ss << "Cluster does not fit into channel. "
00449        << "Cluster length is " << uint16_t(valuesLeftInCluster_) << "."
00450        << std::endl;
00451     throw cms::Exception("FEDBuffer") << ss.str();
00452   }
00453   
00454   void FEDZSChannelUnpacker::throwUnorderedData(const uint8_t currentStrip, const uint8_t firstStripOfNewCluster)
00455   {
00456     std::ostringstream ss;
00457     ss << "First strip of new cluster is not greater than last strip of previous cluster. "
00458        << "Last strip of previous cluster is " << uint16_t(currentStrip) << ". "
00459        << "First strip of new cluster is " << uint16_t(firstStripOfNewCluster) << "."
00460        << std::endl;
00461     throw cms::Exception("FEDBuffer") << ss.str();
00462   }
00463 
00464 }