00001 /**********************************************************\ 00002 * File: MQwF1TDC.C * 00003 * * 00004 * Author: P. M. King, Rakitha Beminiwattha, * 00005 * J. H. Lee * 00006 * Time-stamp: <2010-04-12 12:12> * 00007 \**********************************************************/ 00008 00009 #include "MQwF1TDC.h" 00010 #include "QwColor.h" 00011 #include "QwLog.h" 00012 00013 #include <math.h> 00014 00015 00016 const UInt_t MQwF1TDC::kF1Mask_SlotNumber = 0xf8000000; 00017 const UInt_t MQwF1TDC::kF1Mask_ResolutionLockFlag = 0x04000000; 00018 const UInt_t MQwF1TDC::kF1Mask_OutputFIFOFlag = 0x02000000; 00019 const UInt_t MQwF1TDC::kF1Mask_HitFIFOFlag = 0x01000000; 00020 00021 const UInt_t MQwF1TDC::kF1Mask_HeaderFlag = 0x00800000; 00022 00023 const UInt_t MQwF1TDC::kF1Mask_FakeDataFlag = 0x00400000; 00024 const UInt_t MQwF1TDC::kF1Mask_ChannelNumber = 0x003f0000; 00025 const UInt_t MQwF1TDC::kF1Mask_ChipAddress = 0x00380000; 00026 const UInt_t MQwF1TDC::kF1Mask_ChannelAddress = 0x00070000; 00027 00028 const UInt_t MQwF1TDC::kF1Mask_Dataword = 0x0000ffff; 00029 00030 const UInt_t MQwF1TDC::kF1Mask_HeaderTrigFIFOFlag = 0x00400000; 00031 const UInt_t MQwF1TDC::kF1Mask_HeaderEventNumber = 0x003f0000; 00032 const UInt_t MQwF1TDC::kF1Mask_HeaderTriggerTime = 0x0000ff80; 00033 const UInt_t MQwF1TDC::kF1Mask_HeaderXorSetupFlag = 0x00000040; 00034 const UInt_t MQwF1TDC::kF1Mask_HeaderChannelNumber = 0x0000003f; 00035 const UInt_t MQwF1TDC::kF1Mask_HeaderChipAddress = 0x00000038; 00036 const UInt_t MQwF1TDC::kF1Mask_HeaderChannelAddress = 0x00000007; 00037 00038 00039 00040 MQwF1TDC::MQwF1TDC() 00041 { 00042 fF1ROCNumber = 0; 00043 fF1SlotNumber = 0; 00044 00045 fF1HeaderFlag = kFALSE; 00046 00047 fF1HitFIFOFlag = kFALSE; 00048 fF1OutputFIFOFlag = kFALSE; 00049 fF1ResolutionLockFlag = kFALSE; 00050 00051 fF1FakeDataFlag = kFALSE; 00052 fF1ChannelNumber = 0; 00053 fF1Dataword = 0; 00054 00055 00056 fF1HeaderTrigFIFOFlag = kFALSE; 00057 fF1HeaderEventNumber = 0; 00058 fF1HeaderTriggerTime = 0; 00059 fF1HeaderXorSetupFlag = kFALSE; 00060 00061 fF1MaxChannelsPerModule = 64; 00062 00063 // This initial fF1MaxChannelsPerModule 64 00064 // is used to "resize" a vector in RegisterSlotNumber() function 00065 // in each Subsystem, before one can access the real F1TDC 00066 // configuration from CODA buffer. And it is a constant value (64) 00067 // and is totally independent upon the real F1TDC configuration. 00068 // The real maximum channel number can be access via F1TDContainer 00069 // class of each subsystem. 00070 00071 // However, Qweak uses only the Normal Resolution configuration. 00072 // Thus, it is always 64 channels we uses. 00073 // If someone wants to use the High Resolution Mode of F1TDC, 00074 // it would be better to change this number to 32 by hand. 00075 // Friday, September 3 13:50:49 EDT 2010, jhlee 00076 00077 fF1OverFlowEntryFlag = kFALSE; 00078 fF1ValidDataSlotFlag = kFALSE; 00079 } 00080 00081 MQwF1TDC::~MQwF1TDC() { } 00082 00083 00084 void MQwF1TDC::DecodeTDCWord(UInt_t &word, const UInt_t roc_id) 00085 { 00086 00087 fF1ROCNumber = roc_id; 00088 fF1SlotNumber = (word & kF1Mask_SlotNumber)>>27; 00089 00090 if( fF1SlotNumber>=1 && fF1SlotNumber<=21 ) fF1ValidDataSlotFlag = kTRUE; 00091 else fF1ValidDataSlotFlag = kFALSE; 00092 00093 00094 fF1HeaderFlag = ((word & kF1Mask_HeaderFlag)==0); 00095 // TRUE if the mask bit IS NOT set 00096 00097 // These three flags should be TRUE if their mask bit IS set 00098 fF1HitFIFOFlag = ((word & kF1Mask_HitFIFOFlag )!=0); 00099 fF1OutputFIFOFlag = ((word & kF1Mask_OutputFIFOFlag )!=0); 00100 fF1ResolutionLockFlag = ((word & kF1Mask_ResolutionLockFlag)!=0); 00101 00102 if (fF1HeaderFlag){ 00103 // This is a header word. 00104 fF1Dataword = 0; 00105 fF1HeaderTrigFIFOFlag = ((word & kF1Mask_HeaderTrigFIFOFlag)!=0); 00106 fF1HeaderEventNumber = ( word & kF1Mask_HeaderEventNumber )>>16; 00107 fF1HeaderTriggerTime = ( word & kF1Mask_HeaderTriggerTime )>>7; 00108 fF1HeaderXorSetupFlag = ((word & kF1Mask_HeaderXorSetupFlag)!=0); 00109 fF1ChannelNumber = ( word & kF1Mask_HeaderChannelNumber ); 00110 fF1ChipAddress = ( word & kF1Mask_HeaderChipAddress)>>3; 00111 fF1ChannelAddress = ( word & kF1Mask_HeaderChannelAddress); 00112 } 00113 else { 00114 // This is a data word. 00115 fF1FakeDataFlag = ((word & kF1Mask_FakeDataFlag)!=0); // This flag should be TRUE if their mask bit IS set 00116 fF1ChannelNumber = ( word & kF1Mask_ChannelNumber )>>16; 00117 fF1ChipAddress = ( word & kF1Mask_ChipAddress )>>19; 00118 fF1ChannelAddress = ( word & kF1Mask_ChannelAddress )>>16; 00119 fF1Dataword = ( word & kF1Mask_Dataword ); 00120 00121 if(fF1Dataword == 65535) fF1OverFlowEntryFlag = kTRUE; 00122 else fF1OverFlowEntryFlag = kFALSE; 00123 // skip to record overflow dataword entry (65535, 0xFFFF) 00124 fF1HeaderEventNumber = 0; 00125 fF1HeaderTriggerTime = 0; 00126 // std::cout << "fake flag " << fF1FakeDataFlag 00127 // << " channel: " << fF1ChannelNumber 00128 // << " raw time: " << fF1Dataword 00129 // << std::endl; 00130 } 00131 return; 00132 } 00133 00134 std::ostream& operator<< (std::ostream& os, const MQwF1TDC &f1tdc) 00135 { 00136 if(f1tdc.fF1HeaderFlag) { 00137 os << "<<<< Header:"; 00138 } 00139 else { 00140 os << ">>>> DATA :"; 00141 } 00142 00143 os << " Ch" << std::setw(3) << f1tdc.fF1ChannelNumber; 00144 os << "[" << f1tdc.fF1ChipAddress; 00145 os << "," << f1tdc.fF1ChannelAddress; 00146 os << "]"; 00147 00148 if(f1tdc.fF1HeaderFlag) { 00149 os << " Xor " << f1tdc.fF1HeaderXorSetupFlag 00150 << " tOF " << f1tdc.fF1HeaderTrigFIFOFlag; 00151 } 00152 else { 00153 os << " - DATA " 00154 << f1tdc.fF1FakeDataFlag 00155 << " - "; 00156 } 00157 00158 os << "(hitOF,outOF,resLK)(" 00159 << f1tdc.fF1HitFIFOFlag 00160 << f1tdc.fF1OutputFIFOFlag 00161 << f1tdc.fF1ResolutionLockFlag 00162 << ")"; 00163 os << " ROC" << std::setw(2) << f1tdc.fF1ROCNumber; 00164 00165 Int_t slot = 0; 00166 slot = f1tdc.fF1SlotNumber; 00167 00168 os << " Slot" << std::setw(2) << slot; 00169 00170 if(f1tdc.fF1HeaderFlag) { 00171 os << " EvtN" << std::setw(2) << f1tdc.fF1HeaderEventNumber; 00172 os << " TriT" << std::setw(4) << f1tdc.fF1HeaderTriggerTime; 00173 } 00174 else { 00175 os << " RawT " << std::setw(10) << f1tdc.fF1Dataword; 00176 } 00177 00178 if(slot == 0) { 00179 os << ": a filler word"; 00180 } 00181 if( (not f1tdc.fF1HeaderFlag) and (f1tdc.fF1FakeDataFlag) ){ 00182 os << ": --> fake data"; 00183 } 00184 00185 // os << std::endl; 00186 return os; 00187 } 00188 00189 00190 00191 void MQwF1TDC::Print(Bool_t flag) 00192 { 00193 if (! this) return; // do nothing if this is a null object 00194 00195 if(flag) { 00196 std::cout << *this << std::endl; 00197 } 00198 return; 00199 } 00200 00201 00202 void MQwF1TDC::PrintTDCHeader(Bool_t flag) 00203 { 00204 if (! this) return; // do nothing if this is a null object 00205 00206 if(flag) { 00207 std::cout << *this << std::endl; 00208 } 00209 return; 00210 } 00211 00212 00213 void MQwF1TDC::PrintTDCData(Bool_t flag) 00214 { 00215 if (! this) return; // do nothing if this is a null object 00216 00217 if(flag) { 00218 std::cout << *this << std::endl; 00219 } 00220 return; 00221 } 00222 00223 00224 // Double_t MQwF1TDC::SubtractReference(Double_t rawtime, Double_t reftime) 00225 // { 00226 // // Note that this produces the opposite sign of the corrected time 00227 // // as compared to the UInt_t version from revision 423 shown above. 00228 // // 00229 // // For Region 3, according to the UInt_t version from revision 423, 00230 // // the internal parameters should be: 00231 // // fMinDiff = -30000 00232 // // fMaxDiff = 30000 00233 // // fOffset = 64495 00234 // // fTimeShift = 8929 00235 // // 00236 // Double_t real_time = rawtime - reftime; 00237 00238 // if( real_time < fMinDiff ) { 00239 // real_time += fOffset; 00240 // } 00241 // else if( real_time > fMaxDiff) { 00242 // real_time -= fOffset; 00243 // } 00244 // real_time = real_time + fTimeShift; 00245 // return real_time; 00246 // } 00247 00248 00249 00250 // Double_t MQwF1TDC::ActualTimeDifference(Double_t raw_time, Double_t ref_time) 00251 // { 00252 00253 // Double_t trigger_window = 12896.0; 00254 // Double_t time_offset = 65341.0; 00255 00256 // Double_t time_condition = 0.0; 00257 // Double_t local_time_difference = 0.0; 00258 // Double_t actual_time_difference = 0.0; 00259 00260 // local_time_difference = raw_time - ref_time; 00261 00262 // if(local_time_difference == 0.0) { 00263 // // raw_time is the same as ref_time 00264 // actual_time_difference = local_time_difference; 00265 // } 00266 // else { 00267 // time_condition = fabs(local_time_difference); 00268 // // maximum value is trigger_window -1, 00269 // // thus 12896-1 = 12895 - 0 = 12985 00270 // if(time_condition < trigger_window) { 00271 // // there is no ROLLEVENT within trigger window 00272 // actual_time_difference = local_time_difference; 00273 // } 00274 // else { 00275 // // there is an ROLLOVER event within trigger window 00276 // if (local_time_difference > 0.0) { 00277 // // ref_time is in after ROLLOVER event 00278 // actual_time_difference = local_time_difference - time_offset; 00279 // } 00280 // else { 00281 // // we already excluded local_time_diffrence == 0 case. 00282 // // ref_time is in before ROLLOVER event 00283 // actual_time_difference = local_time_difference + time_offset; 00284 // } 00285 00286 // } 00287 // } 00288 // return actual_time_difference; 00289 // } 00290 00291 00292 00293 void MQwF1TDC::PrintResolutionLockStatus(const UInt_t roc_id) 00294 { 00295 if (not fF1ResolutionLockFlag) { 00296 QwWarning << "F1TDC board RESOULTION LOCK FAIL at Ch " 00297 << GetTDCChannelNumber() << " ROC " << roc_id 00298 << " Slot " << GetTDCSlotNumber() << QwLog::endl; 00299 } 00300 return; 00301 } 00302 00303 00304 00305 void MQwF1TDC::PrintHitFIFOStatus(const UInt_t roc_id) 00306 { 00307 if (fF1HitFIFOFlag) { 00308 QwWarning << "F1TDC board HIT FIFO FULL at Ch " 00309 << GetTDCChannelNumber() << " ROC " << roc_id 00310 << " Slot " << GetTDCSlotNumber() << QwLog::endl; 00311 } 00312 return; 00313 } 00314 00315 00316 00317 void MQwF1TDC::PrintOutputFIFOStatus(const UInt_t roc_id) 00318 { 00319 if (fF1OutputFIFOFlag) { 00320 QwWarning << "F1TDC board OUTPUT FIFO FULL at Ch " 00321 << GetTDCChannelNumber() << " ROC " << roc_id 00322 << " Slot " << GetTDCSlotNumber() << QwLog::endl; 00323 } 00324 return; 00325 } 00326 00327 00328 Bool_t MQwF1TDC::IsValidDataword() const 00329 { 00330 // fF1ValidDataSlotFlag = TRUE, 00331 // fF1ResolutionFlag = TRUE, 00332 // fF1HeaderFlag = FALSE, 00333 // fF1OverFlowEntry = FALSE, 00334 // fF1FakeDataWord = FALSE, then it is a valid data word. 00335 if( fF1ValidDataSlotFlag && fF1ResolutionLockFlag && !fF1HeaderFlag && !fF1OverFlowEntryFlag && !fF1FakeDataFlag) 00336 // if( fF1ValidDataSlotFlag && fF1ResolutionLockFlag && !fF1HeaderFlag) 00337 return kTRUE; 00338 else 00339 return kFALSE; 00340 } 00341 00342 00343 // Bool_t MQwF1TDC::CheckDataIntegrity(const UInt_t roc_id, UInt_t *buffer, UInt_t num_words) 00344 // { 00345 // UInt_t reference_trig_time = 0; 00346 // UInt_t reference_event_num = 0; 00347 00348 // const Int_t valid_trigger_time_offset = 1; 00349 00350 // Bool_t event_ok_flag = kFALSE; 00351 // Bool_t trig_time_ok_flag = kFALSE; 00352 // Bool_t data_integrity_flag = kFALSE; 00353 00354 // Bool_t temp_print_flag = false; 00355 00356 // for (UInt_t i=0; i<num_words ; i++) { 00357 00358 // DecodeTDCWord(buffer[i], roc_id); 00359 00360 00361 // // We use the multiblock data transfer for F1TDC, thus 00362 // // we must get the event number and the trigger time from the first buffer 00363 // // (buffer[0]), and these valuse can be used to check "data" integrity 00364 // // over all F1TDCs 00365 // if ( i==0 ) {//; 00366 // if ( IsHeaderword() ) {//;; 00367 // reference_event_num = GetTDCEventNumber(); 00368 // reference_trig_time = GetTDCTriggerTime(); 00369 // PrintTDCHeader(temp_print_flag); 00370 // }//;; 00371 // else {//;; 00372 // QwWarning << QwColor(Qw::kRed) 00373 // << "The first word of F1TDC must be header word. " 00374 // << "Something wrong into this CODA stream.\n"; 00375 // QwWarning << QwLog::endl; 00376 // return false; 00377 // }//;; 00378 // }//; 00379 // else {//; 00380 // if ( IsHeaderword() ) {//;; 00381 // // Check date integrity, if it is fail, we skip this whole buffer to do further process 00382 // event_ok_flag = ( reference_event_num == GetTDCHeaderEventNumber() ); 00383 // trig_time_ok_flag = abs( reference_trig_time - GetTDCHeaderTriggerTime() ) <= valid_trigger_time_offset; 00384 // PrintTDCHeader(temp_print_flag); 00385 00386 // // If SEU exists, Xor Setup Register bit is changing from 1 to 0, I think. 00387 // // Thus, it sets the trigger time 0 and the event number 0. 00388 // // For example, 00389 // // Ch 8 Xor 0 tOF 0(hitOF,outOF,resLK)(001) ROC 9 Slot 10 EvtN 0 TriT 0 00390 // // And it is the source of the trigger time and the event number differences 00391 // // within the same ROC. In the CheckDataIntegrity routine, I decided 00392 // // to skip such a event. 00393 // // Sunday, August 8 03:42:48 EDT 2010, jhlee 00394 00395 // if (IsHeaderXorSetup()) {//;;; 00396 // // Trigger Time difference of up to 1 count among the chips is acceptable 00397 // // For the Trigger Time, this assumes that an external SYNC_RESET signal has 00398 // // been successfully applied at the start of the run 00399 // if (not trig_time_ok_flag) { 00400 // if(temp_print_flag){ 00401 // QwWarning << QwColor(Qw::kBlue) 00402 // << "There is the no SYNC_RESET on the F1TDC board at" 00403 // << " Ch " << fF1ChannelNumber 00404 // << " ROC " << fF1ROCNumber 00405 // << " Slot " << fF1SlotNumber <<"\n"; 00406 // QwWarning << QwColor(Qw::kBlue) 00407 // << "This event is excluded from the ROOT data stream.\n"; 00408 // QwWarning << QwColor(Qw::kRed) 00409 // << "Please, send an email to (a) Qweak DAQ expert(s) if you have time.\n"; 00410 // QwWarning << QwLog::endl; 00411 // } 00412 // } 00413 // // Any difference in the Event Number among the chips indicates a serious error 00414 // // that requires a reset of the board. 00415 00416 // if (not event_ok_flag) { 00417 // if(temp_print_flag){ 00418 // QwWarning << QwColor(Qw::kRed) 00419 // << "There is the Event Number Mismatch issue on the F1TDC board at" 00420 // << " ROC " << fF1ROCNumber 00421 // << " Slot " << fF1SlotNumber << "\n"; 00422 // QwWarning << QwColor(Qw::kRed) 00423 // << "This event is excluded from the ROOT data stream.\n"; 00424 // QwWarning << QwColor(Qw::kRed) 00425 // << "Please, send an email to (a) Qweak DAQ expert(s) if you have time.\n"; 00426 // QwWarning << QwLog::endl; 00427 // } 00428 // } 00429 00430 // data_integrity_flag = (event_ok_flag) && (trig_time_ok_flag) && IsNotHeaderTrigFIFO() ; 00431 00432 // if (not data_integrity_flag) return data_integrity_flag; //false 00433 // // we stop check data, because all other next buffers 00434 // // is useless and we don't need to check them in order to save some time. 00435 // } //;;; 00436 // else {//;;; 00437 00438 // if (temp_print_flag) { 00439 00440 // // I don't include the SEU in the CheckDataIntegrity. 00441 // // At this moment, I have no idea how I handle during data processes. 00442 // // Sunday, August 8 04:02:17 EDT 2010, jhlee 00443 00444 // QwWarning << QwColor(Qw::kRed) 00445 // << "There is the Single Event Upset (SEU) on the F1TDC board at" 00446 // << " ROC " << fF1ROCNumber 00447 // << " Slot " << fF1SlotNumber << "\n"; 00448 // QwWarning << QwColor(Qw::kRed) 00449 // << "Please, send an email to (a) Qweak DAQ expert(s) if you have time.\n"; 00450 // QwWarning << QwLog::endl; 00451 // } 00452 // }//;;; 00453 // }//;; 00454 // else { //;; // dataword 00455 // if(!fF1OverFlowEntryFlag) PrintTDCData(temp_print_flag); 00456 // }//;; 00457 // }//; 00458 // }//for (UInt_t i=0; i<num_words ; i++) { 00459 00460 00461 // return (data_integrity_flag); 00462 00463 // } 00464