CMS 3D CMS Logo

CMSSW_4_4_3_patch1/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
00143   {
00144     return ( (internalFEDChannelNum < validChannels_) &&
00145              feGood(internalFEDChannelNum/FEDCH_PER_FEUNIT) &&
00146              (this->readoutMode() == sistrip::READOUT_MODE_SCOPE || checkStatusBits(internalFEDChannelNum)) );
00147   }
00148 
00149   bool FEDBuffer::doChecks() const
00150   {
00151     //check that all channels were unpacked properly
00152     if (validChannels_ != FEDCH_PER_FED) return false;
00153     //do checks from base class
00154     if (!FEDBufferBase::doChecks()) return false;
00155     //check CRC
00156     if (!checkCRC()) return false;
00157     return true;
00158   }
00159 
00160   bool FEDBuffer::doCorruptBufferChecks() const
00161   {
00162     return ( checkCRC() &&
00163              checkChannelLengthsMatchBufferLength() &&
00164              checkChannelPacketCodes() &&
00165              //checkClusterLengths() &&
00166              checkFEUnitLengths() );
00167     //checkFEUnitAPVAddresses() );
00168   }
00169 
00170   bool FEDBuffer::checkAllChannelStatusBits() const
00171   {
00172     for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00173       //if FE unit is disabled then skip all channels on it
00174       if (!feGood(iCh/FEDCH_PER_FEUNIT)) {
00175         iCh += FEDCH_PER_FEUNIT;
00176         continue;
00177       }
00178       //channel is bad then return false
00179       if (!checkStatusBits(iCh)) return false;
00180     }
00181     //if no bad channels have been found then they are all fine
00182     return true;
00183   }
00184 
00185   bool FEDBuffer::checkChannelLengths() const
00186   {
00187     return (validChannels_ == FEDCH_PER_FED);
00188   }
00189 
00190   bool FEDBuffer::checkChannelLengthsMatchBufferLength() const
00191   {
00192     //check they fit into buffer
00193     if (!checkChannelLengths()) return false;
00194   
00195     //payload length from length of data buffer
00196     const size_t payloadLengthInWords = payloadLength_/8;
00197   
00198     //find channel length
00199     //find last enabled FE unit
00200     uint8_t lastEnabledFeUnit = 7;
00201     while ( !(fePresent(lastEnabledFeUnit) && feEnabled(lastEnabledFeUnit)) && lastEnabledFeUnit!=0 ) lastEnabledFeUnit--;
00202     //last channel is last channel on last enabled FE unit
00203     const FEDChannel& lastChannel = channels_[internalFEDChannelNum(lastEnabledFeUnit,FEDCH_PER_FEUNIT-1)];
00204     const size_t offsetLastChannel = lastChannel.offset();
00205     const size_t offsetEndOfChannelData = offsetLastChannel+lastChannel.length();
00206     const size_t channelDataLength = offsetEndOfChannelData;
00207     //channel length in words is length in bytes rounded up to nearest word
00208     size_t channelDataLengthInWords = channelDataLength/8;
00209     if (channelDataLength % 8) channelDataLengthInWords++;
00210   
00211     //check lengths match
00212     if (channelDataLengthInWords == payloadLengthInWords) {
00213       return true;
00214     } else {
00215       return false;
00216     }
00217   }
00218 
00219   bool FEDBuffer::checkChannelPacketCodes() const
00220   {
00221     const uint8_t correctPacketCode = getCorrectPacketCode();
00222     //if the readout mode if not one which has a packet code then this is set to zero. in this case return true
00223     if (!correctPacketCode) return true;
00224     for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00225       //if FE unit is disabled then skip all channels on it
00226       if (!feGood(iCh/FEDCH_PER_FEUNIT)) {
00227         iCh += FEDCH_PER_FEUNIT;
00228         continue;
00229       }
00230       //only check enabled, working channels
00231       if (channelGood(iCh)) {
00232         //if a channel is bad then return false
00233         if (channels_[iCh].packetCode() != correctPacketCode) return false;
00234       }
00235     }
00236     //if no bad channels were found the they are all ok
00237     return true;
00238   }
00239 
00240   bool FEDBuffer::checkFEUnitAPVAddresses() const
00241   {
00242     //get golden address
00243     const uint8_t goldenAddress = apveAddress();
00244     //don't check if the address is 00 since APVe is probably not connected
00245     if (goldenAddress == 0x00) return true;
00246     //check can only be done for full debug headers
00247     const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00248     if (!fdHeader) return true;
00249     //check all enabled FE units
00250     for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00251       if (!feGood(iFE)) continue;
00252       //if address is bad then return false
00253       if (fdHeader->feUnitMajorityAddress(iFE) != goldenAddress) return false;
00254     }
00255     //if no bad addresses were found then return true
00256     return true;
00257   }
00258 
00259   bool FEDBuffer::checkFEUnitLengths() const
00260   {
00261     //check can only be done for full debug headers
00262     const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00263     if (!fdHeader) return true;
00264     //check lengths for enabled FE units
00265     for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00266       if (!feGood(iFE)) continue;
00267       if (calculateFEUnitLength(iFE) != fdHeader->feUnitLength(iFE)) return false;
00268     }
00269     //if no errors were encountered then return true
00270     return true;
00271   }
00272   
00273   uint16_t FEDBuffer::calculateFEUnitLength(const uint8_t internalFEUnitNumber) const
00274   {
00275     //get length from channels
00276     uint16_t lengthFromChannels = 0;
00277     for (uint8_t iCh = 0; iCh < FEDCH_PER_FEUNIT; iCh++) {
00278       lengthFromChannels += channels_[internalFEDChannelNum(internalFEUnitNumber,iCh)].length();
00279     }
00280     return lengthFromChannels;
00281   }
00282   
00283   bool FEDBuffer::checkFEPayloadsPresent() const
00284   {
00285     for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00286       if (!fePresent(iFE)) return false;
00287     }
00288     return true;
00289   }
00290 
00291   std::string FEDBuffer::checkSummary() const
00292   {
00293     std::ostringstream summary;
00294     summary << FEDBufferBase::checkSummary();
00295     summary << "Check FE unit payloads are all present: " << (checkFEPayloadsPresent() ? "passed" : "FAILED" ) << std::endl;
00296     if (!checkFEPayloadsPresent()) {
00297       summary << "FE units missing payloads: ";
00298       for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00299         if (!fePresent(iFE)) summary << uint16_t(iFE) << " ";
00300       }
00301       summary << std::endl;
00302     }
00303     summary << "Check channel status bits: " << ( checkAllChannelStatusBits() ? "passed" : "FAILED" ) << std::endl;
00304     if (!checkAllChannelStatusBits()) {
00305       unsigned int badChannels = 0;
00306       if (headerType() == HEADER_TYPE_FULL_DEBUG) {
00307         const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00308         if (fdHeader) {
00309           for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00310             if (!feGood(iCh/FEDCH_PER_FEUNIT)) continue;
00311             if (!checkStatusBits(iCh)) {
00312               summary << uint16_t(iCh) << ": " << fdHeader->getChannelStatus(iCh) << std::endl;
00313               badChannels++;
00314             }
00315           }
00316         }
00317       } else {
00318         summary << "Channels with errors: ";
00319         for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00320           if (!feGood(iCh/FEDCH_PER_FEUNIT)) continue;
00321           if (!checkStatusBits(iCh)) {
00322             summary << uint16_t(iCh) << " ";
00323             badChannels++;
00324           }
00325         }
00326         summary << std::endl;
00327       } 
00328       summary << "Number of channels with bad status bits: " << badChannels << std::endl;
00329     }
00330     summary << "Check channel lengths match buffer length: " << ( checkChannelLengthsMatchBufferLength() ? "passed" : "FAILED" ) << std::endl;
00331     summary << "Check channel packet codes: " << ( checkChannelPacketCodes() ? "passed" : "FAILED" ) << std::endl;
00332     if (!checkChannelPacketCodes()) {
00333       summary << "Channels with bad packet codes: ";
00334       for (uint8_t iCh = 0; iCh < FEDCH_PER_FED; iCh++) {
00335         if (!feGood(iCh/FEDCH_PER_FEUNIT)) continue;
00336         if (channels_[iCh].packetCode() != getCorrectPacketCode())
00337           summary << uint16_t(iCh) << " ";
00338       }
00339     }
00340     summary << "Check FE unit lengths: " << ( checkFEUnitLengths() ? "passed" : "FAILED" ) << std::endl;
00341     if (!checkFEUnitLengths()) {
00342       const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00343       if (fdHeader) {
00344         summary << "Bad FE units:" << std::endl;
00345         for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00346           if (!feGood(iFE)) continue;
00347           uint16_t lengthFromChannels = calculateFEUnitLength(iFE);
00348           uint16_t lengthFromHeader = fdHeader->feUnitLength(iFE);
00349           if (lengthFromHeader != lengthFromChannels) {
00350             summary << "FE unit: " << uint16_t(iFE) 
00351                     << " length in header: " << lengthFromHeader 
00352                     << " length from channel lengths: " << lengthFromChannels << std::endl;
00353           }
00354         }
00355       }
00356     }
00357     summary << "Check FE unit APV addresses match APVe: " << ( checkFEUnitAPVAddresses() ? "passed" : "FAILED" ) << std::endl;
00358     if (!checkFEUnitAPVAddresses()) {
00359       const FEDFullDebugHeader* fdHeader = dynamic_cast<FEDFullDebugHeader*>(feHeader_.get());
00360       if (fdHeader) {
00361         const uint8_t goldenAddress = apveAddress();
00362         summary << "Address from APVe:" << uint16_t(goldenAddress) << std::endl;
00363         summary << "Bad FE units:" << std::endl;
00364         for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00365           if (!feGood(iFE)) continue;
00366           if (fdHeader->feUnitMajorityAddress(iFE) != goldenAddress) {
00367             summary << "FE unit: " << uint16_t(iFE)
00368                     << " majority address: " << uint16_t(fdHeader->feUnitMajorityAddress(iFE)) << std::endl;
00369           }
00370         }
00371       }
00372     }
00373     return summary.str();
00374   }
00375 
00376   uint8_t FEDBuffer::getCorrectPacketCode() const
00377   {
00378     switch(readoutMode()) {
00379     case READOUT_MODE_SCOPE:
00380       return PACKET_CODE_SCOPE;
00381       break;
00382     case READOUT_MODE_VIRGIN_RAW:
00383       return PACKET_CODE_VIRGIN_RAW;
00384       break;
00385     case READOUT_MODE_PROC_RAW:
00386       return PACKET_CODE_PROC_RAW;
00387       break;
00388     case READOUT_MODE_ZERO_SUPPRESSED:
00389       return PACKET_CODE_ZERO_SUPPRESSED;
00390       break;
00391     case READOUT_MODE_ZERO_SUPPRESSED_LITE:
00392     case READOUT_MODE_SPY:
00393     case READOUT_MODE_INVALID:
00394     default:
00395       return 0;
00396     }
00397   }
00398 
00399   uint8_t FEDBuffer::nFEUnitsPresent() const
00400   {
00401     uint8_t result = 0;
00402     for (uint8_t iFE = 0; iFE < FEUNITS_PER_FED; iFE++) {
00403       if (fePresent(iFE)) result++;
00404     }
00405     return result;
00406   }
00407   
00408   void FEDBuffer::print(std::ostream& os) const
00409   {
00410     FEDBufferBase::print(os);
00411     if (headerType() == HEADER_TYPE_FULL_DEBUG) {
00412       os << "FE units with data: " << uint16_t(nFEUnitsPresent()) << std::endl;
00413       os << "BE status register flags: ";
00414       dynamic_cast<const FEDFullDebugHeader*>(feHeader())->beStatusRegister().printFlags(os);
00415       os << std::endl;
00416     }
00417   }
00418 
00419 
00420 
00421 
00422   void FEDRawChannelUnpacker::throwBadChannelLength(const uint16_t length)
00423   {
00424     std::ostringstream ss;
00425     ss << "Channel length is invalid. Raw channels have 3 header bytes and 2 bytes per sample. "
00426        << "Channel length is " << uint16_t(length) << "."
00427        << std::endl;
00428     throw cms::Exception("FEDBuffer") << ss.str();
00429   }
00430 
00431 
00432 
00433 
00434   void FEDZSChannelUnpacker::throwBadChannelLength(const uint16_t length)
00435   {
00436     std::ostringstream ss;
00437     ss << "Channel length is longer than max allowed value. "
00438        << "Channel length is " << uint16_t(length) << "."
00439        << std::endl;
00440     throw cms::Exception("FEDBuffer") << ss.str();
00441   }
00442 
00443   void FEDZSChannelUnpacker::throwBadClusterLength()
00444   {
00445     std::ostringstream ss;
00446     ss << "Cluster does not fit into channel. "
00447        << "Cluster length is " << uint16_t(valuesLeftInCluster_) << "."
00448        << std::endl;
00449     throw cms::Exception("FEDBuffer") << ss.str();
00450   }
00451   
00452   void FEDZSChannelUnpacker::throwUnorderedData(const uint8_t currentStrip, const uint8_t firstStripOfNewCluster)
00453   {
00454     std::ostringstream ss;
00455     ss << "First strip of new cluster is not greater than last strip of previous cluster. "
00456        << "Last strip of previous cluster is " << uint16_t(currentStrip) << ". "
00457        << "First strip of new cluster is " << uint16_t(firstStripOfNewCluster) << "."
00458        << std::endl;
00459     throw cms::Exception("FEDBuffer") << ss.str();
00460   }
00461 
00462 }