Skip to content
Snippets Groups Projects
Select Git revision
  • cmake_demangled
  • scandalizer protected
2 results

CodaDecoder.cxx

Blame
  • CodaDecoder.cxx 29.69 KiB
    ////////////////////////////////////////////////////////////////////
    //
    //   CodaDecoder
    //
    //    Object Oriented version of decoder
    //    Sept, 2014    R. Michaels
    //
    /////////////////////////////////////////////////////////////////////
    
    #include "CodaDecoder.h"
    #include "THaCrateMap.h"
    #include "THaBenchmark.h"
    #include "THaUsrstrutils.h"
    #include "TError.h"
    #include <iostream>
    
    using namespace std;
    
    namespace Decoder {
    
    //   static const Int_t MAX_EVTYPES = 200;
    //   static const Int_t MAX_PHYS_EVTYPES = 14;
    
    //_____________________________________________________________________________
    CodaDecoder::CodaDecoder() :
      nroc(0), irn(MAXROC,0), fbfound(MAXROC*MAXSLOT,false), psfact(MAX_PSFACT,-1),
      fdfirst(kTRUE), chkfbstat(1), evcnt_coda3(0)
    {
      fNeedInit=true;
      first_decode=kFALSE;
      fMultiBlockMode=kFALSE;
      fBlockIsDone=kFALSE;
      // Please leave these 3 lines for me to debug if I need to.  thanks, Bob
    #ifdef WANTDEBUG
      fDebugFile = new ofstream();
      fDebugFile->open("bobstuff.txt");
      *fDebugFile<< "Debug my stuff "<<endl<<endl;
    #endif
    }
    
    //_____________________________________________________________________________
    CodaDecoder::~CodaDecoder()
    {
    }
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::GetPrescaleFactor(Int_t trigger_type) const
    {
      // To get the prescale factors for trigger number "trigger_type"
      // (valid types are 1,2,3...)
      if ( (trigger_type > 0) && (trigger_type <= MAX_PSFACT)) {
        return psfact[trigger_type - 1];
      }
      if (fDebug > 0) {
        Warning( "CodaDecoder::GetPrescaleFactor", "Requested prescale factor for "
    	     "undefined trigger type %d", trigger_type );
      }
      return 0;
    }
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::LoadEvent(const UInt_t* evbuffer)
    {
      // Main engine for decoding, called by public LoadEvent() methods
    
      if (fDataVersion <= 0) {
         cout << "CODA version not set (="<<fDataVersion<<"). "
              << "Do SetCodaVersion(codaData->getCodaVersion()) first"<<endl;
         return HED_FATAL;
      }
      if (fDataVersion != 2 && fDataVersion != 3) {
         cout << "Unsupported CODA version = "<<fDataVersion<<"). Need 2 or 3."
              << "Cannot analyze these data. Twonk."<<endl;
         return HED_FATAL;
      }
    
      event_length = evbuffer[0]+1;  // in longwords (4 bytes)
      if( event_length < 0 ) { // FIXME: would be no issue if event_length was UInt_t
        cerr << "ERROR: CodaDecoder::LoadEvent: unsupported event length = "
             << evbuffer[0]+1 << endl;
        return HED_ERR;
      }
      event_num = 0;
      event_type = 0;
      if (fDebugFile) *fDebugFile << "CodaDecode:: Loading event  ... "<<endl;
      if (fDebugFile) *fDebugFile << "evbuffer ptr "<<hex<<evbuffer<<dec<<endl;
      assert( evbuffer );
      assert( fMap || fNeedInit );
      Int_t ret = HED_OK;
      buffer = evbuffer;
      if (first_decode || fNeedInit) {
         ret = init_cmap();
         if (fDebugFile) {
    	 *fDebugFile << endl << " CodaDecode:: Print of Crate Map"<<endl;
    	 fMap->print(*fDebugFile);
         } else {
          //      fMap->print();
         }
         if( ret != HED_OK ) return ret;
         ret = init_slotdata();
         if( ret != HED_OK ) return ret;
         FindUsedSlots();
         first_decode=kFALSE;
      }
      if( fDoBench ) fBench->Begin("clearEvent");
      for( Int_t i=0; i<fNSlotClear; i++ ) crateslot[fSlotClear[i]]->clearEvent();
      if( fDoBench ) fBench->Stop("clearEvent");
      if (fDataVersion == 2) {
        event_type = evbuffer[1]>>16;
        //if(event_type < 0) return HED_ERR; // can never happen 8-)
      } else {  // CODA version 3
        interpretCoda3(evbuffer);
      }
      if(fDebugFile) {
          *fDebugFile << "CodaDecode:: dumping "<<endl;
          dump(evbuffer);
      }
     
      if (event_type == PRESTART_EVTYPE ) {
        // Usually prestart is the first 'event'.  Call SetRunTime() to
        // re-initialize the crate map since we now know the run time.
        // This won't happen for split files (no prestart). For such files,
        // the user should call SetRunTime() explicitly.
        // For CODA3 these are set in interpretCoda3 above.
        if( fDataVersion == 2 ) {
          SetRunTime(static_cast<ULong64_t>(evbuffer[2]));
          run_num  = evbuffer[3];
          run_type = evbuffer[4];
          evt_time = fRunTime;
        }
      } else if( event_type == PRESCALE_EVTYPE || event_type == TS_PRESCALE_EVTYPE ) {
        ret = prescale_decode(evbuffer);
        if( ret != HED_OK )
          return ret;
      } else if (event_type == END_EVTYPE) {
        std::cout << " END_EVTYPE !!!!!\n";
      }
    
      if (event_type <= MAX_PHYS_EVTYPE) {
         if (fDataVersion == 3) {
             event_num = ++evcnt_coda3;
             FindRocsCoda3(evbuffer);
         } else {
             event_num = evbuffer[4];
             FindRocs(evbuffer);
         }
         recent_event = event_num;
    
         if (fdfirst && (fDebugFile!=0)) {
           fdfirst=kFALSE;
           CompareRocs();
         }
    
       // Decode each ROC
       // From this point onwards there is no diff between CODA 2.* and CODA 3.*
    
        for( Int_t i=0; i<nroc; i++ ) {
    
          Int_t iroc = irn[i];
          const RocDat_t* proc = rocdat+iroc;
          Int_t ipt = proc->pos + 1;
          Int_t iptmax = proc->pos + proc->len;
    
          if (fMap->isFastBus(iroc)) {  // checking that slots found = expected
    	  if (GetEvNum() > 200 && chkfbstat < 3) chkfbstat=2;
    	  if (chkfbstat == 1) ChkFbSlot(iroc, evbuffer, ipt, iptmax);
    	  if (chkfbstat == 2) {
    	      ChkFbSlots();
    	      chkfbstat = 3;
    	  }
          }
    
          Int_t status;
    
     // If at least one module is in a bank, must split the banks for this roc
    
          if (fMap->isBankStructure(iroc)) {
    	  if (fDebugFile) *fDebugFile << "\nCodaDecode::Calling bank_decode "<<i<<"   "<<iroc<<"  "<<ipt<<"  "<<iptmax<<endl;
    	  /*status =*/ bank_decode(iroc,evbuffer,ipt,iptmax);
          }
    
          if (fDebugFile) *fDebugFile << "\nCodaDecode::Calling roc_decode "<<i<<"   "<<evbuffer<<"  "<<iroc<<"  "<<ipt<<"  "<<iptmax<<endl;
    
          status = roc_decode(iroc,evbuffer, ipt, iptmax);
    
          // do something with status
          if (status == -1) break;
    
        }
      }
    
      return ret;
    }
    
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::interpretCoda3(const UInt_t* evbuffer)
    {
    
      event_type = 0;  
      bank_tag = ((evbuffer[1]&0xffff0000)>>16); 
      data_type = ((evbuffer[1]&0xff00)>>8);
      block_size =  evbuffer[1]&0xff;
    
      if((bank_tag >= 0xff00)> 0) {/* CODA Reserved bank type */
    
        switch (bank_tag) {
    
         case 0xffd1:
    
            event_type = PRESTART_EVTYPE;
            SetRunTime(static_cast<ULong64_t>(evbuffer[2]));
            run_num  = evbuffer[3];
            run_type = evbuffer[4];
            evt_time = fRunTime;
            if (fDebugFile) {
    	  *fDebugFile << "Prestart Event : run_num "<<run_num<<"  run type "<<run_type<<"   event_type "<<event_type<<"  run time "<<fRunTime<<endl;
            }
            break;
         case 0xffd2:
      	    event_type = GO_EVTYPE;
     	    break;
         case 0xffd4:
      	    event_type = END_EVTYPE;
    	    break;
         case 0xff50:
         case 0xff70:
      	    event_type=1;  // Physics event type
    	    break;
          default:
    	    cout << "CodaDecoder:: WARNING:  Undefined CODA 3 event type"<<endl;
        }
      }  else { /* User event type */
    
          event_type = bank_tag;  // need to check this.
    
          if(fDebugFile) *fDebugFile<<" User defined event type "<<event_type<<endl;
    
      }
    
      tbLen = 0;  
      if (event_type == 1) tbLen = trigBankDecode(&evbuffer[2], block_size);
       
      return HED_OK;
    }
             
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::trigBankDecode(const UInt_t* evbuffer, int blkSize) {
    
    // Decode the "Trigger Bank" which is a CODA3 structure that appears
    // near the top of the event buffer.  
    
      memset((void *)&tbank, 0, sizeof(TBOBJ));
    
      tbank.start = (uint32_t *)evbuffer;
      tbank.blksize = blkSize;
      tbank.len = evbuffer[0] + 1;
      tbank.tag = (evbuffer[1]&0xffff0000)>>16; 
      tbank.nrocs = (evbuffer[1]&0xff);
      tbank.evtNum = evbuffer[3];
    
      if((tbank.tag)&1)
        tbank.withTimeStamp = 1;
      if((tbank.tag)&2)
        tbank.withRunInfo = 1;
    
      if(tbank.withTimeStamp) {
        tbank.evTS = (uint64_t *)&evbuffer[5];
        if(tbank.withRunInfo) {
          tbank.evType = (uint16_t *)&evbuffer[5 + 2*blkSize + 3];
        }else{
          tbank.evType = (uint16_t *)&evbuffer[5 + 2*blkSize + 1];
        }
      }else{
        tbank.evTS = NULL;
        if(tbank.withRunInfo) {
          tbank.evType = (uint16_t *)&evbuffer[5 + 3];
        }else{
          tbank.evType = (uint16_t *)&evbuffer[5 + 1];
        }
      }
    
      return(tbank.len);
    
    }
    
    
    
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::LoadFromMultiBlock()
    {
      // LoadFromMultiBlock : This assumes the data are in multiblock mode.
    
      // For modules that are in multiblock mode, the next event is loaded.
      // For other modules not in multiblock mode (e.g. scalers) or other data (e.g. flags)
      // the data remain "stale" until the next block of events.
    
      if (!fMultiBlockMode) return HED_ERR;
      fBlockIsDone = kFALSE;
    
      for( Int_t i=0; i<fNSlotClear; i++ ) {
        if (crateslot[fSlotClear[i]]->GetModule()->IsMultiBlockMode()) crateslot[fSlotClear[i]]->clearEvent();
      }
    
      for( Int_t i=0; i<nroc; i++ ) {
    
          Int_t roc = irn[i];
          Int_t minslot = fMap->getMinSlot(roc);
          Int_t maxslot = fMap->getMaxSlot(roc);
          for (Int_t slot = minslot; slot <= maxslot; slot++) {
     // for CODA3, cross-check the block size (found in trigger bank and, separately, in modules)
            if(fDebugFile) *fDebugFile << "cross chk blk size "<<roc<<"  "<<slot<<"  "<<crateslot[idx(roc,slot)]->GetModule()->GetBlockSize()<<"   "<<block_size<<endl;;
            if (fDataVersion > 2 && (crateslot[idx(roc,slot)]->GetModule()->GetBlockSize() != block_size)) {
    	  cout << "ERROR::CodaDecoder:: inconsistent block size between trig. bank and module"<<endl;
    	}
    	if (fMap->slotUsed(roc,slot) && crateslot[idx(roc,slot)]->GetModule()->IsMultiBlockMode()) {
    	  crateslot[idx(roc,slot)]->LoadNextEvBuffer();
    	  if (crateslot[idx(roc,slot)]->BlockIsDone()) fBlockIsDone = kTRUE;
    	}
          }
      }
      return HED_OK;
    }
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::roc_decode( Int_t roc, const UInt_t* evbuffer,
    				  Int_t ipt, Int_t istop )
    {
      // Decode a Readout controller
      assert( evbuffer && fMap );
      if( fDoBench ) fBench->Begin("roc_decode");
      Int_t slot;
      Int_t Nslot = fMap->getNslot(roc);
      Int_t minslot = fMap->getMinSlot(roc);
      Int_t maxslot = fMap->getMaxSlot(roc);
      Int_t retval = HED_OK;
      Int_t nwords;
      synchmiss = false;
      synchextra = false;
      buffmode = false;
      const UInt_t* p      = evbuffer+ipt;    // Points to ROC ID word (1 before data)
      const UInt_t* pstop  =evbuffer+istop;   // Points to last word of data
      fBlockIsDone = kFALSE;
    
      Int_t firstslot, incrslot;
      Int_t n_slots_checked, n_slots_done;
    
      Bool_t slotdone;
    
    //  Int_t status = SD_ERR;
    
      n_slots_done = 0;
    
      if (istop > event_length) {
        cerr << "ERROR:: roc_decode:  stop point exceeds event length (?!)"<<endl;
        goto err;
      }
    
      if (fMap->isFastBus(roc)) {  // higher slot # appears first in multiblock mode
          firstslot=maxslot;       // the decoding order improves efficiency
          incrslot = -1;
      } else {
          firstslot=minslot;
          incrslot = 1;
      }
    
      if (fDebugFile) {
        *fDebugFile << "CodaDecode:: roc_decode:: roc#  "<<dec<<roc<<" nslot "<<Nslot<<endl;
        *fDebugFile << "CodaDecode:: roc_decode:: firstslot "<<dec<<firstslot<<"  incrslot "<<incrslot<<endl;
      }
    
      if (Nslot <= 0) goto err;
      fMap->setSlotDone();      // clears the "done" bits
    
      while ( p++ < pstop && n_slots_done < Nslot ) {
    
        if (fDebugFile) {
    	 *fDebugFile << "CodaDecode::roc_decode:: evbuff "<<(p-evbuffer)<<"  "<<hex<<*p<<dec<<endl;
    	 *fDebugFile << "CodaDecode::roc_decode:: n_slots_done "<<n_slots_done<<"  "<<firstslot<<endl;
        }
    
        LoadIfFlagData(p);
    
        n_slots_checked = 0;
        slot = firstslot;
        slotdone = kFALSE;
    // bank structure is decoded with bank_decode
        if (fMap->getBank(roc,slot) >= 0) {
          n_slots_done++;
          slotdone=kTRUE;
        }
    
        while(!slotdone && n_slots_checked < Nslot-n_slots_done && slot >= 0 && slot < MAXSLOT) {
    
    
          if (!fMap->slotUsed(roc,slot) || fMap->slotDone(slot)) {
    	 slot = slot + incrslot;
    	 continue;
          }
    
          ++n_slots_checked;
    
         if (fDebugFile) {
           *fDebugFile<< "roc_decode:: slot logic "<<roc<<"  "<<slot<<"  "<<firstslot<<"  "<<n_slots_checked<<"  "<<Nslot-n_slots_done<<endl;
         }
    
          nwords = crateslot[idx(roc,slot)]->LoadIfSlot(p, pstop);
    
          if (nwords > 0) {
    	   p = p + nwords - 1;
    	   fMap->setSlotDone(slot);
    	   n_slots_done++;
    	   if(fDebugFile) *fDebugFile << "CodaDecode::  slot "<<slot<<"  is DONE    "<<nwords<<endl;
    	   slotdone = kTRUE;
          }
    
          if (crateslot[idx(roc,slot)]->IsMultiBlockMode()) fMultiBlockMode = kTRUE;
          if (crateslot[idx(roc,slot)]->BlockIsDone()) fBlockIsDone = kTRUE;
    
          if (fDebugFile) {
    	  *fDebugFile<< "CodaDecode:: roc_decode:: after LoadIfSlot "<<p << "  "<<pstop<<"  "<<"  "<<hex<<*p<<"  "<<dec<<nwords<<endl;
          }
    
          slot = slot + incrslot;
    
        }
    
      } //end while(p++<pstop)
      goto exit;
    
     err:
      //  retval = (status == SD_ERR) ? HED_ERR : HED_WARN;
      retval = HED_ERR;
     exit:
      if( fDoBench ) fBench->Stop("roc_decode");
      return retval;
    }
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::bank_decode( Int_t roc, const UInt_t* evbuffer,
    				  Int_t ipt, Int_t istop )
    {
      // Split a roc into banks, if using bank structure
      // Then loop over slots and decode it from a bank if the slot
      // belongs to a bank.
      assert( evbuffer && fMap );
      if( fDoBench ) fBench->Begin("bank_decode");
      Int_t retval = HED_OK;
      if (!fMap->isBankStructure(roc)) return retval;
      fBlockIsDone = kFALSE;
    
      Int_t pos,len,bank,head;
    
      if (fDebugFile) *fDebugFile << "CodaDecode:: bank_decode  ... "<<roc<<"   "<<ipt<<"  "<<istop<<endl;
    
      pos = ipt+1;  // ipt points to ROC ID word
    
      while (pos < istop) {
        len = evbuffer[pos];
        head = evbuffer[pos+1];
        bank = (head>>16)&0xffff;
        if (fDebugFile) *fDebugFile << "bank 0x"<<hex<<bank<<"  head 0x"<<head<<"    len 0x"<<len<<dec<<endl;
    
        if (bank >= 0 && bank < MAXBANK) {
          bankdat[MAXBANK*roc+bank].pos=pos+2;
          bankdat[MAXBANK*roc+bank].len=len-1;
        }
    
        pos += len+1;
    
      }
    
      Int_t minslot = fMap->getMinSlot(roc);
      Int_t maxslot = fMap->getMaxSlot(roc);
    
      for (Int_t slot = minslot; slot <= maxslot; slot++) {
        if (!fMap->slotUsed(roc,slot)) continue;
        bank=fMap->getBank(roc,slot);
        if (bank < 0 || bank >= Decoder::MAXBANK) {
          cerr << "CodaDecoder::ERROR:  bank number out of range "<<endl;
          return 0;
        }
        pos = bankdat[MAXBANK*roc+bank].pos;
        len = bankdat[MAXBANK*roc+bank].len;
        if (fDebugFile) *fDebugFile << "CodaDecode:: loading bank "<<roc<<"  "<<slot<<"   "<<bank<<"  "<<pos<<"   "<<len<<endl;
        crateslot[idx(roc,slot)]->LoadBank(evbuffer,pos,len);
        if (crateslot[idx(roc,slot)]->IsMultiBlockMode()) fMultiBlockMode = kTRUE;
        if (crateslot[idx(roc,slot)]->BlockIsDone()) fBlockIsDone = kTRUE;
      }
    
      if( fDoBench ) fBench->Stop("bank_decode");
      return retval;
    }
    
    //_____________________________________________________________________________
     void CodaDecoder::FillBankData(UInt_t *rdat, Int_t roc, Int_t bank, Int_t offset, Int_t num) const
    {
      const int ldebug=0;
      Int_t pos,len,i,ilo,ihi,jk;
      jk =  MAXBANK*roc + bank;
    
      if (ldebug) cout << "Into FillBankData v1 "<<dec<<roc<<"  "<<bank<<"  "<<offset<<"  "<<num<<"   "<<jk<<endl;  
      if(fDebugFile) *fDebugFile << "Check FillBankData "<<roc<<"  "<<bank<<"   "<<jk<<endl;
    
     if (jk < 0 || jk >= MAXROC*MAXBANK) {
          cerr << "FillBankData::ERROR:  bankdat index out of range "<<endl;
          return;
      }  
      pos = bankdat[jk].pos;
      len = bankdat[jk].len;
      if (ldebug) cout << "FillBankData: pos "<<pos<<"  "<<len<<endl;
      if(fDebugFile) *fDebugFile << "FillBankData  pos, len "<<pos<<"   "<<len<<endl;
      if (offset > len-2) return;
      if (num > len) num = len;
      ilo = pos+offset;
      ihi = pos+offset+num;
      if (ihi >  GetEvLength()) ihi=GetEvLength();
      for (i=ilo; i<ihi; i++) rdat[i-ilo] = GetRawData(i);
     
      return;
    }
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::LoadIfFlagData(const UInt_t* evbuffer)
    {
      // Need to generalize this ...  too Hall A specific
      //
      // Looks for buffer mode and synch problems.  The latter are recoverable
      // but extremely rare, so I haven't bothered to write recovery a code yet,
      // but at least this warns you.
      assert( evbuffer );
      UInt_t word   = *evbuffer;
      UInt_t upword = word & 0xffff0000;
      if (fDebugFile) *fDebugFile << "CodaDecode:: TestBit on :  Flag data ? "<<hex<<word<<dec<<endl;
      if( word == 0xdc0000ff) synchmiss = true;
      if( upword == 0xdcfe0000) {
        synchextra = true;
        Int_t slot = (word&0xf800)>>11;
        Int_t nhit = (word&0x7ff);
        if(fDebug>0) {
          cout << "CodaDecoder: WARNING: Fastbus slot ";
          cout << slot << "  has extra hits "<<nhit<<endl;
        }
      }
      if( upword == 0xfabc0000) {
        Int_t datascan = *(evbuffer+3);
        if(fDebug>0 && (synchmiss || synchextra)) {
          cout << "CodaDecoder: WARNING: Synch problems !"<<endl;
          cout << "Data scan word 0x"<<hex<<datascan<<dec<<endl;
        }
      }
      if( upword == 0xfabb0000) buffmode = false;
      if((word&0xffffff00) == 0xfafbbf00) {
        buffmode = true;
        //    synchflag = word&0xff; // not used
      }
      return HED_OK;
    }
    
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::FindRocs(const UInt_t *evbuffer) {
    
    // The (old) decoding of CODA 2.* event buffer to find pointers and lengths of ROCs
    // ROC = ReadOut Controller, synonymous with "crate".
    
      assert( evbuffer && fMap );
    #ifdef FIXME
      if( fDoBench ) fBench->Begin("physics_decode");
    #endif
      Int_t status = HED_OK;
    
      // The following line is not meaningful for CODA3
      if( (evbuffer[1]&0xffff) != 0x10cc ) std::cout<<"Warning, header error"<<std::endl;
      if( event_type > MAX_PHYS_EVTYPE ) std::cout<<"Warning, Event type makes no sense"<<std::endl;
      memset(rocdat,0,MAXROC*sizeof(RocDat_t));
      // Set pos to start of first ROC data bank
      Int_t pos = evbuffer[2]+3;  // should be 7
      nroc = 0;
      while( pos+1 < event_length && nroc < MAXROC ) {
        Int_t len  = evbuffer[pos];
        Int_t iroc = (evbuffer[pos+1]&0xff0000)>>16;
        if( iroc>=MAXROC ) {
    #ifdef FIXME
          if(fDebug>0) {
    	cout << "ERROR in EvtTypeHandler::FindRocs "<<endl;
    	cout << "  illegal ROC number " <<dec<<iroc<<endl;
          }
          if( fDoBench ) fBench->Stop("physics_decode");
    #endif
          return HED_ERR;
        }
        // Save position and length of each found ROC data block
        rocdat[iroc].pos  = pos;
        rocdat[iroc].len  = len;
        irn[nroc++] = iroc;
        pos += len+1;
      }
    
      if (fDebugFile) {
        *fDebugFile << "CodaDecode:: num rocs "<<dec<<nroc<<endl;
        for (Int_t i=0; i < nroc; i++) {
          Int_t iroc=irn[i];
          *fDebugFile << "   CodaDecode::   roc  num "<<iroc<<"   pos "<<rocdat[iroc].pos<<"     len "<<rocdat[iroc].len<<endl;
        }
      }
    
      return status;
    
    }
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::FindRocsCoda3(const UInt_t *evbuffer) {
    
    // Find the pointers and lengths of ROCs in CODA3
    // ROC = ReadOut Controller, synonymous with "crate".
    // Earlier we had decoded the Trigger Bank in method trigBankDecode.
    // This determined tbLen and the tbank structure. 
    // For CODA3, the ROCs start after the Trigger Bank.
      
      Int_t pos = 2 + tbLen;
      nroc=0;
    
      while (pos < event_length) {
        Int_t len = (evbuffer[pos]+1);               /* total Length of ROC Bank */
        Int_t iroc = (evbuffer[pos+1]&0xffff0000)>>16;   /* ID of ROC */
        rocdat[iroc].len = len;
        rocdat[iroc].pos = pos;
        irn[nroc] = iroc;
        pos += len;
        nroc++;
      }
    
      /* Sanity check:  Check if number of ROCs matches */
      if(nroc != tbank.nrocs) {
          printf(" ****ERROR: Trigger and Physics Block sizes do not match (%d != %d)\n",nroc,tbank.nrocs);
    // If you are reading a data file orignally written with CODA 2 and then
    // processed (written out) with EVIO 4, it will segfault. Do as it says below.
          printf("This might indicate a file written with EVIO 4 that was a CODA 2 file\n");
          printf("Try  analyzer->SetCodaVersion(2)  in the analyzer script.\n");
    
      }
    
      if (fDebugFile) {  // debug   
    
        *fDebugFile << endl << "  FindRocsCoda3 :: Starting Event number = " << dec << tbank.evtNum;
        *fDebugFile << endl;
        *fDebugFile << "    Trigger Bank Len = "<<tbLen<<" words "<<endl;
        *fDebugFile << "    There are "<<nroc<<"  ROCs"<<endl;
        for(Int_t i=0;i<nroc;i++) {
          *fDebugFile << "     ROC ID = "<<irn[i]<<"  pos = "<<rocdat[irn[i]].pos
              <<"  Len = "<<rocdat[irn[i]].len<<endl;
        }
        *fDebugFile << "    Trigger BANK INFO,  TAG = "<<hex<<tbank.tag<<dec<<endl;
        *fDebugFile << "    start "<<hex<<tbank.start<<"      blksize "<<dec<<tbank.blksize
            <<"  len "<<tbank.len<<"   tag "<<tbank.tag<<"   nrocs "<<tbank.nrocs<<"   evtNum "<<tbank.evtNum;
        *fDebugFile << endl;
        *fDebugFile << "         Event #       Time Stamp       Event Type"<<endl;
        for(Int_t i=0; i<tbank.blksize; i++) {
           if(tbank.evTS != NULL) {
              *fDebugFile << "      "<<dec<<tbank.evtNum+i<<"   "<<tbank.evTS[i]<<"   "<<tbank.evType[i];
              *fDebugFile << endl;
           } else {
    	  *fDebugFile << "     "<<tbank.evtNum+i<<"(No Time Stamp)   "<<tbank.evType[i];
    	  *fDebugFile << endl;
           }
           *fDebugFile << endl<<endl;
        }
      }
    
      return 1;
    
    }
    
    //_____________________________________________________________________________
    // To initialize the THaSlotData member on first call to decoder
    int CodaDecoder::init_slotdata()
    {
      // Initialize all slots defined in the crate map as "used".
      //
      // This defeats the clever on-demand mechanism of the original decoder,
      // which would only allocate resources for a crate/slot if data for that
      // slot were actually encountered in the data stream. Now, resources
      // are allocated for everything, whether actually active or not.
      // The advantage is that one can configure the module objects associated
      // with each crate/slot. Of course, that could be done via database
      // parameters as well. Presumably the resource waste is minor on today's
      // computers, so fine.
      // Also note that all crateslots and modules will be deleted and recreated
      // right away every time this routine is called, even if there are no
      // changes to the map. This should be fixed.
    
      if(!fMap) return HED_ERR;
    
      for (Int_t iroc = 0; iroc<MAXROC; iroc++) {
        if( !fMap->crateUsed(iroc) ) continue;
        for (Int_t islot=0; islot < MAXSLOT; islot++) {
          if( !fMap->slotUsed(iroc,islot) ) continue;
          makeidx(iroc,islot);
          if (fDebugFile)
    	*fDebugFile << "CodaDecode::  crate, slot " << iroc << "  " << islot
    		    << "   Dev type  = " << crateslot[idx(iroc,islot)]->devType()
    		    << endl;
        }
      }
    
      if (fDebugFile) *fDebugFile << "CodaDecode:: fNSlotUsed "<<fNSlotUsed<<endl;
    
      // Update lists of used/clearable slots in case crate map changed
      return THaEvData::init_slotdata();
    }
    
    
    //_____________________________________________________________________________
    void CodaDecoder::dump(const UInt_t* evbuffer) const
    {
      if( !evbuffer ) return;
      if ( !fDebugFile ) return;
      *fDebugFile << "\n\n Raw Data Dump  " << endl;
      *fDebugFile << "\n Event number  " << dec << event_num;
      *fDebugFile << "  length " << event_length << "  type " << event_type << endl;
      Int_t ipt = 0;
      for (Int_t j=0; j<(event_length/5); j++) {
        *fDebugFile << dec << "\n evbuffer[" << ipt << "] = ";
        for (Int_t k=j; k<j+5; k++) {
          *fDebugFile << hex << evbuffer[ipt++] << " ";
        }
      }
      if (ipt < event_length) {
        *fDebugFile << dec << "\n evbuffer[" << ipt << "] = ";
        for (Int_t k=ipt; k<event_length; k++) {
          *fDebugFile << hex << evbuffer[ipt++] << " ";
        }
        *fDebugFile << endl;
      }
      *fDebugFile<<dec<<endl;
    }
    
    //_____________________________________________________________________________
    void CodaDecoder::CompareRocs()
    {
      if (!fMap || !fDebugFile) return;
      *fDebugFile<< "Comparing cratemap rocs with found rocs"<<endl;
      for (Int_t i=0; i<nroc; i++) {
        Int_t iroc = irn[i];
        if (!fMap->crateUsed(iroc)) {
    	  *fDebugFile << "ERROR  CompareRocs:: roc "<<iroc<<"  in data but not in map"<<endl;
        }
      }
      for (Int_t iroc1 = 0; iroc1<MAXROC; iroc1++) {
        if (  !fMap->crateUsed(iroc1)  ) continue;
        Int_t ifound=0;
        for( Int_t i=0; i<nroc; i++ ) {
          Int_t iroc2 = irn[i];
          if (iroc1 == iroc2) {
    	ifound=1;
    	break;
          }
        }
        if (!ifound) *fDebugFile << "ERROR: CompareRocs:  roc "<<iroc1<<" in cratemap but not found data"<<endl;
      }
    }
    
    //_____________________________________________________________________________
    void CodaDecoder::ChkFbSlot( Int_t roc, const UInt_t* evbuffer,
    				  Int_t ipt, Int_t istop )
    {
      const UInt_t* p      = evbuffer+ipt;    // Points to ROC ID word (1 before data)
      const UInt_t* pstop  =evbuffer+istop;   // Points to last word of data in roc
      while (p++ < pstop) {
        Int_t slot = (UInt_t(*p))>>27;  // A "self-reported" slot.
        Int_t index = MAXSLOT*roc + slot;
        if ((slot > 0) && (index >=0 && index < MAXROC*MAXSLOT)) fbfound[index]=true;
      }
    }
    
    //_____________________________________________________________________________
    void CodaDecoder::ChkFbSlots()
    {
      // This checks the fastbus slots to see if slots are appearing in both the
      // data and the cratemap.  If they appear in one but not the other, a warning
      // is issued, which usually means the cratemap is wrong.
      Int_t slotstat[MAXROC*MAXSLOT];
      for (Int_t iroc=0; iroc<MAXROC; iroc++) {
        if ( !fMap->isFastBus(iroc) ) continue;
        for (Int_t islot=0; islot<MAXSLOT; islot++) {
          Int_t index = MAXSLOT*iroc + islot;
          slotstat[index]=0;
          if (fbfound[index] && fMap->slotUsed(iroc, islot)) {
    	  if (fDebugFile) *fDebugFile << "FB slot in cratemap and in data.  (good!).  roc = "<<iroc<<"   slot = "<<islot<<endl;
    	  slotstat[index]=1;
          }
          if ( !fbfound[index] && fMap->slotUsed(iroc, islot)) {
    	if (fDebugFile) *fDebugFile << "FB slot NOT in data, but in cratemap  (bad!).  roc = "<<iroc<<"   slot = "<<islot<<endl;
    	slotstat[index]=2;
          }
          if ( fbfound[index] && !fMap->slotUsed(iroc, islot)) {
    	if (fDebugFile) *fDebugFile << "FB slot in data, but NOT in cratemap  (bad!).  roc = "<<iroc<<"   slot = "<<islot<<endl;
    	slotstat[index]=3;
          }
        }
      }
      // Why do we care? If the cratemap has info about additional hardware
      // that just wasn't read out by the DAQ, so what?
      // for (Int_t iroc=0; iroc<MAXROC; iroc++) {
      //   if ( !fMap->isFastBus(iroc) ) continue;
      //   for (Int_t islot=0; islot<MAXSLOT; islot++) {
      //     Int_t index = MAXSLOT*iroc + islot;
      //     if (slotstat[index]==2) cout << "Decoder:: WARNING:  Fastbus module in (roc,slot) = ("<<iroc<<","<<islot<<")  found in cratemap but NOT in data !"<<endl;
      //   }
      // }
      for (Int_t iroc=0; iroc<MAXROC; iroc++) {
        if ( !fMap->isFastBus(iroc) ) continue;
        for (Int_t islot=0; islot<MAXSLOT; islot++) {
          Int_t index = MAXSLOT*iroc + islot;
          if (slotstat[index]==3) cout << "Decoder:: WARNING:  Fastbus module in (roc,slot) = ("<<iroc<<","<<islot<<")  found in data but NOT in cratemap !"<<endl;
        }
      }
    }
    
    
    //_____________________________________________________________________________
    void CodaDecoder::SetRunTime( ULong64_t tloc )
    {
      // Set run time and re-initialize crate map (and possibly other
      // database parameters for the new time.
    
      if( fRunTime == tloc )
        return;
      fRunTime = tloc;
      fNeedInit = true;  // force re-init
    }
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::prescale_decode(const UInt_t* evbuffer)
    {
      // Decodes prescale factors from either
      // TS_PRESCALE_EVTYPE(default) = PS factors
      // read from Trig. Super. registors (since 11/03)
      //   - or -
      // PRESCALE_EVTYPE = PS factors from traditional
      //     "prescale.dat" file.
    
      assert( evbuffer );
      assert( event_type == TS_PRESCALE_EVTYPE ||
    	  event_type == PRESCALE_EVTYPE );
      const Int_t HEAD_OFF1 = 2;
      const Int_t HEAD_OFF2 = 4;
      static const char* const pstr[] = { "ps1", "ps2", "ps3", "ps4",
    				      "ps5", "ps6", "ps7", "ps8",
    				      "ps9", "ps10", "ps11", "ps12" };
      // TS registers -->
      if( event_type == TS_PRESCALE_EVTYPE) {
        // this is more authoritative
        for (Int_t j = 0; j < 8; j++) {
          Int_t k = j + HEAD_OFF1;
          Int_t ps = 0;
          if (k < event_length) {
    	ps = evbuffer[k];
    	if (psfact[j]!=0 && ps != psfact[j]) {
    	  Warning("prescale_decode","Mismatch in prescale factor: "
    		  "Trig %d  oldps %d   TS_PRESCALE %d. Setting to TS_PRESCALE",
    		  j+1,psfact[j],ps);
    	}
          }
          psfact[j]=ps;
          if (fDebug > 1)
    	cout << "%% TS psfact "<<dec<<j<<"  "<<psfact[j]<<endl;
        }
      }
      // "prescale.dat" -->
      else if( event_type == PRESCALE_EVTYPE ) {
        if( event_length <= HEAD_OFF2 )
          return HED_ERR;  //oops, event too short?
        THaUsrstrutils sut;
        sut.string_from_evbuffer(evbuffer+HEAD_OFF2, event_length-HEAD_OFF2);
        for(Int_t trig=0; trig<MAX_PSFACT; trig++) {
          Int_t ps =  sut.getint(pstr[trig]);
          Int_t psmax = 65536; // 2^16 for trig > 3
          if (trig < 4) psmax = 16777216;  // 2^24 for 1st 4 trigs
          if (trig > 7) ps = 1;  // cannot prescale trig 9-12
          ps = ps % psmax;
          if (psfact[trig]==-1) // not read before
    	psfact[trig] = ps;
          else if (ps != psfact[trig]) {
    	Warning("prescale_decode","Mismatch in prescale factor: "
    		"Trig %d  oldps %d   prescale.dat %d, Keeping old value",
    		trig+1,psfact[trig],ps);
          }
          if (fDebug > 1)
    	cout << "** psfact[ "<<trig+1<< " ] = "<<psfact[trig]<<endl;
        }
      }
      // Ok in any case
      return HED_OK;
    }
    
    //_____________________________________________________________________________
    Int_t CodaDecoder::SetCodaVersion( Int_t version )
    {
      if (version != 2 && version != 3) {
        cout << "ERROR::CodaDecoder::SetCodaVersion version " << version;
        cout << "  must be 2 or 3 only." << endl;
        cout << "Not setting CODA version ! " << endl;
        return -1;
      }
      return (fDataVersion = version);
    }
    
    //_____________________________________________________________________________
    
    } // namespace Decoder
    
    ClassImp(Decoder::CodaDecoder)