//*-- AUTHOR Sergey Linev //*-- Modified : 17/04/2014 by I. Koenig //*---Adjusted for MDC clock TDC by JAM September 2024 //_HADES_CLASS_DESCRIPTION ///////////////////////////////////////////////////////////// // // HTrbCtdcUnpacker // // This is class to unpack and calibrate data of single FPGA TDC // It should be similar to functionality of hadaq::TdcProcessor from 'stream' framework // ///////////////////////////////////////////////////////////// #include "htrbctdcunpacker.h" #include "TString.h" #include "htrbctdciterator.h" #include "htrbctdcmessage.h" #include "hades.h" #include "hevent.h" #include "heventheader.h" HTrbCtdcUnpacker::HTrbCtdcUnpacker(vector& ids) : HTrb3Unpacker(ids), nCalSrc(0), fMinAddress(0), fMaxAddress(0), fUseTDCFromLookup(kFALSE) { fTDCs.clear(); fTDCsMap.clear(); } HTrbCtdcUnpacker::~HTrbCtdcUnpacker() { fTDCs.clear(); fTDCsMap.clear(); } void HTrbCtdcUnpacker::clearAll() { if (!isQuietMode()) fprintf(stderr, "JAM:HTrbCtdcUnpacker::clearAll is called!\n"); for (UInt_t ntds=0;ntdsgetCurrentEvent() == 0) return 0; if (gHades->getCurrentEvent()->getHeader() == 0) return 0; return gHades->getCurrentEvent()->getHeader()->getEventSeqNumber(); } Int_t HTrbCtdcUnpacker::addTDC(UInt_t trbaddr, size_t numchannels) { Int_t tdcindex=-1; TDC tdc(numchannels); tdc.fTdcId = trbaddr; tdcindex = fTDCs.size(); fTDCs.push_back(tdc); fTDCsMap[trbaddr] = tdcindex; if (getDebugFlag()>0) fprintf(stderr, "JAM:HTrbCtdcUnpacker::addTDC finds tdc address 0x%x for tdcindex %d after adding address 0x%x\n", fTDCs[tdcindex].getTrbAddr(), tdcindex, trbaddr); return tdcindex; } Bool_t HTrbCtdcUnpacker::scanTdcData(UInt_t trbaddr, UInt_t* data, UInt_t datalen) { HTrbCtdcIterator iter; iter.assign((UInt_t*) data, datalen, kFALSE); HTrbCtdcMessage& msg = iter.msg(); UInt_t cnt(0); while (iter.next()) { cnt++; // get existing TDC or add new one // simple caching to avoid repeating the same in each loop static Int_t tdc_index = -1; static UInt_t last_trbaddr = 0x0; if (last_trbaddr != trbaddr) { std::map::iterator it; it = fTDCsMap.find((UInt_t)trbaddr); if(it!=fTDCsMap.end()) { tdc_index = it->second; last_trbaddr = trbaddr; if (getDebugFlag()>0) fprintf(stderr, "HTrbCtdcUnpacker::scanTdcData finds tdcindex %d for trbnetaddress 0x%x .\n", tdc_index, trbaddr); } else { if((fMinAddress<=trbaddr) && (fMaxAddress>=trbaddr)) { if ( !fUseTDCFromLookup && fMinAddress!=0 && fMaxAddress!=0) { // here check that we have really an expected tdc and not a hub packet! In this case we add dynamically tdc_index = addTDC(trbaddr); cout << " Info: Added new trbnetaddress 0x"<1) fprintf(stderr, "HTrbCtdcUnpacker::scanTdcData finds tdc address 0x%x with subevtid 0x%x for tdcindex %d \n", tdc.getTrbAddr(), tdc.pSubEvtId, tdc_index); if (msg.isHeaderMsg()) { if (getDebugFlag()>0) fprintf(stderr, "HTrbCtdcUnpacker::scanTdcData finds header with reference time %e s \n",iter.getReferenceTime()) ; tdc.setReftime(iter.getReferenceTime()); // new header will contain updated reference time for all subsequent hits TODO: does this refert to differnt channel groups for format v1? continue; } ////////// JAM 24: we postpone possible calibrations from dabc eventbuilders for the moment, but prepare to get them later if(msg.isCalibMsg()) { tdc.fCalibr[0] = msg.getCalibFirst(); tdc.fCalibr[1] = msg.getCalibSecond(); tdc.fNcalibr = 0; if (getDebugFlag()>0) fprintf(stderr, "Evt:%d Subev:0x%04x TDC:0x%04x calibr v1 0x%04x v2 0x%04x\n", getEventSeqNumber(), (UInt_t) getSubEvtId(), (UInt_t) trbaddr, tdc.fCalibr[0] , tdc.fCalibr[1] ); continue; } if (msg.isHitMsg()) { UInt_t chid = iter.getHitChannel(); if(datalen>0) { tdc.fhasData = kTRUE; } if (chid >= tdc.numChannels()) { if (!isQuietMode()) fprintf(stderr, "Evt:%d Subev:0x%04x CTDC:0x%04x TDC Channel number problem %u\n", getEventSeqNumber(), (UInt_t) getSubEvtId(), (UInt_t) trbaddr, chid); continue; } // note: all times are in unit seconds here Double_t risingtm = iter.getMsgTimeLeading(); Double_t fallingtm = iter.getMsgTimeTrailing(); #ifdef CLOCKTDC_MAXTOT Double_t tot = iter.getMsgToT(); #ifdef CLOCKTDC_OVERFLOW_CORRECTION if(tot<0) { if (!isQuietMode()) fprintf(stderr, "Evt:%d Subev:0x%04x CTDC:0x%04x - correct negative tot %e s for channel %u by adding maxvalue %e s\n", getEventSeqNumber(), (UInt_t) getSubEvtId(), (UInt_t) trbaddr, tot, chid, CLOCKTDC_MAXVALUE_S); tot += CLOCKTDC_MAXVALUE_S; } #endif // additional check: when overflow correction is enabled, we should never come here if(tot>CLOCKTDC_MAXTOT || tot<0){ if (!isQuietMode()) fprintf(stderr, "Evt:%d Subev:0x%04x CTDC:0x%04x - exclude too high tot %e s for channel %u\n", getEventSeqNumber(), (UInt_t) getSubEvtId(), (UInt_t) trbaddr, tot, chid); continue; } #endif ChannelRec& rec = tdc.fCh[chid]; /// JAM 4-sep-2024 TODO: if we get any calibration corrections from eventbuilders later, we have to use them here before storing the hits //////// however, mechanism may be much different from trb3 tdc: need to correct risingtm and fallingtm instead of localtm here /////////////////////////////// // //JAM 2018: without hydra calibration parameter, use calibration info from DAQ: // // this code was also taken from hldprint and adjusted // if (fine<0x3ff) { // // JAM2019: redefinition of Hit1 in trb3 design, ignored intended format: // /* // if (msg.isHit1Msg()) { // // hit format without original raw data (future) // if (isrising) { // localtm -= fine*5e-12; // calibrated time, 5 ps/bin // } else { // localtm -= (fine & 0x1FF)*10e-12; // for falling edge 10 ps binning is used // if (fine & 0x200) localtm -= 0x800 * 5.0e-9; // in rare case time correction leads to epoch overflow // } // } else { // */ // if (tdc.fNcalibr<2) { // // JAM2018 TODO: encapsulate calibration function into TDC object // // // calibrated time, 5 ns correspond to value 0x3ffe or about 0.30521 ps/bin // double corr = tdc.fCalibr[tdc.fNcalibr++]*5.0e-9/0x3ffe; // if (!isrising) corr*=10.; // for falling edge correction 50 ns range is used // localtm -= corr; // } else { // //without calibration parameters use default simple fine time calibration: // localtm -=iter.getMsgTimeFine(); // } // //} // } /////////////// END tdc calibration correction example snipppet, use if (getDebugFlag()>0){ fprintf(stderr, "HTrbCtdcUnpacker::scanTdcData adds hit (address 0x%x, subev 0x%x, ch:%d) - t_rising=%E s, t_falling=%E s \n", tdc.getTrbAddr(), tdc.pSubEvtId, chid, risingtm, fallingtm); } rec.addHit(risingtm, fallingtm); // add to list of TDCs which have data (excluding REFCHAN) if(find(fFilledTDCs.begin(),fFilledTDCs.end(),tdc_index)==fFilledTDCs.end()) { fFilledTDCs.push_back(tdc_index); } continue; } // process other messages kinds // switch (msg.getKind()) { // case HTrbCtdcMessage::tdckind_Reserved: // break; // case HTrbCtdcMessage::tdckind_Header: { // UInt_t errbits = msg.getHeaderErr(); // if (errbits && !isQuietMode()) // fprintf(stderr, "Evt:%d Subev:0x%04x TDC:0x%04x found error bits: 0x%x\n", // getEventSeqNumber(), (UInt_t) getSubEvtId(), (UInt_t) trbaddr, errbits); // break; // } // case HTrbCtdcMessage::tdckind_Debug: // break; // case HTrbCtdcMessage::tdckind_Epoch: // break; // default: // if (!isQuietMode()) // fprintf(stderr, "Evt:%d Subev:0x%04x TDC:0x%04x Unknown bits 0x%x in header\n", // getEventSeqNumber(), (UInt_t) getSubEvtId(), (UInt_t) trbaddr, msg.getKind()); // break; // } } // iter return kTRUE; } Bool_t HTrbCtdcUnpacker::correctRefTime() { for (UInt_t i = 0; i < numActiveTDC(); ++i) { getActiveTDC(i)->correctRefTime(); } return kTRUE; } Bool_t HTrbCtdcUnpacker::reinit(void) { // Called in the beginning of each run, used here to initialize TDC unpacker // if TDCs processors are not yet created, use parameter to instantiate them Bool_t rc = kTRUE; // may get calibbration parameters here? return rc; } Bool_t HTrbCtdcUnpacker::decodeData(UInt_t trbaddr, UInt_t n, UInt_t * data) { return scanTdcData(trbaddr, data, n); }