1 #include "otsdaq-mu2e/FEInterfaces/CFOFrontEndInterface.h"
2 #include "otsdaq/Macros/InterfacePluginMacros.h"
11 #define __MF_SUBJECT__ "CFOFrontEndInterface"
15 const std::string& interfaceUID,
16 const ConfigurationTree& theXDAQContextConfigTree,
17 const std::string& interfaceConfigurationPath)
19 interfaceUID, theXDAQContextConfigTree, interfaceConfigurationPath)
21 __FE_COUT__ <<
"Constructing..." << __E__;
37 unsigned roc_mask = 0x1;
38 std::string expectedDesignVersion =
"";
39 auto mode = DTCLib::DTC_SimMode_NoCFO;
41 thisCFO_ =
new CFOLib::CFO_Registers(mode, dtc_, expectedDesignVersion);
43 __FE_COUT__ <<
"CFOFrontEndInterface instantiated with name: " << interfaceUID
44 <<
" talking to /dev/mu2e" << dtc_ << __E__;
48 CFOFrontEndInterface::~CFOFrontEndInterface(
void)
218 void CFOFrontEndInterface::readStatus(
void)
220 __FE_COUT__ <<
"firmware version (0x9004) = 0x" << std::hex << registerRead(0x9004)
222 __FE_COUT__ <<
"link enable (0x9114) = 0x" << std::hex << registerRead(0x9114)
224 __FE_COUT__ <<
"SERDES reset (0x9118) = 0x" << std::hex << registerRead(0x9118)
226 __FE_COUT__ <<
"SERDES unlock error (0x9124) = 0x" << std::hex << registerRead(0x9124)
228 __FE_COUT__ <<
"PLL locked (0x9128) = 0x" << std::hex << registerRead(0x9128)
230 __FE_COUT__ <<
"SERDES Rx status....(0x9134) = 0x" << std::hex << registerRead(0x9134)
232 __FE_COUT__ <<
"SERDES reset done...(0x9138) = 0x" << std::hex << registerRead(0x9138)
234 __FE_COUT__ <<
"SERDES Rx CDR lock..(0x9140) = 0x" << std::hex << registerRead(0x9140)
236 __FE_COUT__ <<
"SERDES ref clk freq.(0x9160) = 0x" << std::hex << registerRead(0x9160)
237 <<
" = " << std::dec << registerRead(0x9160) << __E__;
239 __FE_COUT__ << __E__;
244 int CFOFrontEndInterface::getLinkStatus()
246 int overall_link_status = registerRead(0x9140);
248 int link_status = (overall_link_status >> 0) & 0x1;
255 float CFOFrontEndInterface::MeasureLoopback(
int linkToLoopback)
257 const int maxNumberOfLoopbacks = 10000;
258 int numberOfLoopbacks =
259 getConfigurationManager()
260 ->getNode(
"/Mu2eGlobalsTable/SyncDemoConfig/NumberOfLoopbacks")
261 .getValue<
unsigned int>();
263 __FE_COUTV__(numberOfLoopbacks);
266 float numerator = 0.0;
267 float denominator = 0.0;
268 failed_loopback_ = 0;
270 int loopback_data[maxNumberOfLoopbacks] = {};
272 max_distribution_ = 0;
273 min_distribution_ = 99999;
275 for(
int n = 0; n < 10000; n++)
276 loopback_distribution_[n] = 0;
279 unsigned initial_9380 = registerRead(0x9380);
280 unsigned initial_9114 = registerRead(0x9114);
283 __FE_COUT__ <<
"LOOPBACK: CFO reset serdes RX " << __E__;
284 registerWrite(0x9118, 0x000000ff);
285 registerWrite(0x9118, 0x0);
288 __FE_COUT__ <<
"LOOPBACK: CFO status before loopback" << __E__;
294 for(
int n = 0; n <= numberOfLoopbacks; n++)
297 registerWrite(0x9380, 0x00000000);
300 registerWrite(0x9114, 0x00000000);
303 int dataToWrite = (0x00000101 << linkToLoopback);
304 registerWrite(0x9114, dataToWrite);
307 dataToWrite = (0x00000100 << linkToLoopback);
308 registerWrite(0x9380, dataToWrite);
311 dataToWrite = (0x00000101 << linkToLoopback);
312 registerWrite(0x9380, dataToWrite);
316 unsigned int delay = registerRead(0x9360);
321 if(delay < 10000 && n > 5)
325 numerator += (float)delay;
330 loopback_data[n] = delay;
332 loopback_distribution_[delay]++;
334 if(delay > max_distribution_)
336 max_distribution_ = delay;
341 if(delay < min_distribution_)
342 min_distribution_ = delay;
346 loopback_data[n] = -999;
363 __FE_COUT__ <<
"LOOPBACK: CFO status after loopback" << __E__;
367 registerWrite(0x9380, initial_9380);
368 registerWrite(0x9114, initial_9114);
374 average_loopback_ = -999.;
375 if(denominator > 0.5)
376 average_loopback_ = numerator / denominator;
380 for(
int n = 0; n < numberOfLoopbacks; n++)
382 if(loopback_data[n] > 0)
384 rms_loopback_ += (loopback_data[n] - average_loopback_) *
385 (loopback_data[n] - average_loopback_);
389 if(denominator > 0.5)
391 rms_loopback_ = sqrt(rms_loopback_ / denominator);
392 average_loopback_ *= 5;
396 __FE_COUT__ <<
"LOOPBACK: distribution: " << __E__;
402 for(
unsigned int n = (min_distribution_ - 5); n < (max_distribution_ + 5); n++)
404 __MCOUT_INFO__(
" delay [ " << n <<
" ] = " << loopback_distribution_[n] << __E__);
407 __MCOUT_INFO__(
" average = " << average_loopback_ <<
" ns, RMS = " << rms_loopback_
408 <<
" ns, failures = " << failed_loopback_ << __E__);
410 __FE_COUT__ << __E__;
412 __FE_COUT__ <<
"LOOPBACK: number of failed loopbacks = " << std::dec
413 << failed_loopback_ << __E__;
415 return average_loopback_;
420 void CFOFrontEndInterface::configure(
void)
422 __FE_COUTV__(getIterationIndex());
423 __FE_COUTV__(getSubIterationIndex());
430 const int number_of_system_configs =
433 int config_clock = configure_clock_;
434 const int reset_tx = 1;
436 const int number_of_dtc_config_steps = 7;
438 int number_of_total_config_steps =
439 number_of_system_configs * number_of_dtc_config_steps;
441 int config_step = getIterationIndex();
443 if(number_of_system_configs > 0)
445 if(config_step >= number_of_total_config_steps)
449 if((config_step % number_of_dtc_config_steps) == 0)
453 __FE_COUT__ <<
"CFO disable Event Start character output " << __E__;
454 registerWrite(0x9100, 0x0);
456 __FE_COUT__ <<
"CFO disable serdes transmit and receive " << __E__;
457 registerWrite(0x9114, 0x00000000);
459 __FE_COUT__ <<
"CFO turn off Event Windows" << __E__;
460 registerWrite(0x91a0, 0x00000000);
462 __FE_COUT__ <<
"CFO turn off 40MHz marker interval" << __E__;
463 registerWrite(0x9154, 0x00000000);
465 else if((config_step % number_of_dtc_config_steps) == 1)
469 if(config_clock == 1 && config_step < number_of_dtc_config_steps)
473 __MCOUT_INFO__(
"Step " << config_step <<
": CFO reset clock..." << __E__);
474 __FE_COUT__ <<
"CFO set crystal frequency to 156.25 MHz" << __E__;
476 registerWrite(0x9160, 0x09502F90);
479 registerWrite(0x9168, 0x55870100);
480 registerWrite(0x916c, 0x00000001);
490 int targetFrequency = 200000000;
492 auto oscillator = DTCLib::DTC_OscillatorType_SERDES;
498 __FE_COUT__ <<
"CFO set oscillator frequency to " << std::dec
499 << targetFrequency <<
" MHz" << __E__;
501 thisCFO_->SetNewOscillatorFrequency(targetFrequency);
510 __MCOUT_INFO__(
"Step " << config_step <<
": CFO do NOT reset clock..."
514 else if((config_step % number_of_dtc_config_steps) == 3)
519 __MCOUT_INFO__(
"Step " << config_step <<
": CFO reset TX..." << __E__);
521 __FE_COUT__ <<
"CFO reset serdes PLLs " << __E__;
522 registerWrite(0x9118, 0x0000ff00);
523 registerWrite(0x9118, 0x0);
526 __FE_COUT__ <<
"CFO reset serdes TX " << __E__;
527 registerWrite(0x9118, 0x00ff0000);
528 registerWrite(0x9118, 0x0);
533 __MCOUT_INFO__(
"Step " << config_step <<
"CFO do NOT reset TX..." << __E__);
536 else if((config_step % number_of_dtc_config_steps) == 6)
538 __MCOUT_INFO__(
"Step " << config_step
539 <<
": CFO enable Event start characters, SERDES Tx "
540 "and Rx, and event window interval"
543 __FE_COUT__ <<
"CFO reset serdes RX " << __E__;
544 registerWrite(0x9118, 0x000000ff);
545 registerWrite(0x9118, 0x0);
548 __FE_COUT__ <<
"CFO enable Event Start character output " << __E__;
549 registerWrite(0x9100, 0x5);
551 __FE_COUT__ <<
"CFO enable serdes transmit and receive " << __E__;
552 registerWrite(0x9114, 0x0000ffff);
554 __FE_COUT__ <<
"CFO set Event Window interval time" << __E__;
556 registerWrite(0x91a0, 0x1f40);
560 __FE_COUT__ <<
"CFO set 40MHz marker interval" << __E__;
561 registerWrite(0x9154, 0x0800);
565 __MCOUT_INFO__(
"--------------" << __E__);
566 __MCOUT_INFO__(
"CFO configured" << __E__);
568 if(getLinkStatus() == 1)
570 __MCOUT_INFO__(
"CFO links OK = 0x" << std::hex << registerRead(0x9140)
571 << std::dec << __E__);
573 if(number_of_system_configs < 0)
580 __MCOUT_INFO__(
"CFO links not OK = 0x" << std::hex << registerRead(0x9140)
581 << std::dec << __E__);
583 __FE_COUT__ << __E__;
587 indicateIterationWork();
592 void CFOFrontEndInterface::halt(
void)
594 __FE_COUT__ <<
"HALT: CFO status" << __E__;
599 void CFOFrontEndInterface::pause(
void)
601 __FE_COUT__ <<
"PAUSE: CFO status" << __E__;
606 void CFOFrontEndInterface::resume(
void)
608 __FE_COUT__ <<
"RESUME: CFO status" << __E__;
613 void CFOFrontEndInterface::start(std::string)
615 bool LoopbackLock =
true;
618 const int numberOfChains = 1;
619 int link[numberOfChains] = {0};
621 const int numberOfDTCsPerChain = 1;
623 const int numberOfROCsPerDTC = 1;
633 int numberOfMeasurements = numberOfChains * numberOfDTCsPerChain * numberOfROCsPerDTC;
635 int startIndex = getIterationIndex();
639 initial_9100_ = registerRead(0x9100);
640 initial_9114_ = registerRead(0x9114);
641 initial_91a0_ = registerRead(0x91a0);
642 initial_9154_ = registerRead(0x9154);
644 __FE_COUT__ <<
"CFO disable Event Start character output " << __E__;
645 registerWrite(0x9100, 0x0);
647 __FE_COUT__ <<
"CFO turn off Event Windows" << __E__;
648 registerWrite(0x91a0, 0x00000000);
650 __FE_COUT__ <<
"CFO turn off 40MHz marker interval" << __E__;
651 registerWrite(0x9154, 0x00000000);
653 __FE_COUT__ <<
"START: CFO status" << __E__;
656 for(
int nChain = 0; nChain < numberOfChains; nChain++)
658 for(
int nDTC = 0; nDTC < numberOfDTCsPerChain; nDTC++)
660 for(
int nROC = 0; nROC < numberOfROCsPerDTC; nROC++)
662 delay[nChain][nDTC][nROC] = -1;
663 delay_rms[nChain][nDTC][nROC] = -1;
664 delay_failed[nChain][nDTC][nROC] = -1;
669 indicateIterationWork();
673 if(startIndex > numberOfMeasurements)
675 __MCOUT_INFO__(
"-------------------------" << __E__);
676 __MCOUT_INFO__(
"FULL SYSTEM loopback DONE" << __E__);
678 for(
int nChain = 0; nChain < numberOfChains; nChain++)
680 for(
int nDTC = 0; nDTC < numberOfDTCsPerChain; nDTC++)
682 for(
int nROC = 0; nROC < numberOfROCsPerDTC; nROC++)
684 __MCOUT_INFO__(
"chain "
685 << nChain <<
" - DTC " << nDTC <<
" - ROC " << nROC
686 <<
" = " << std::dec << delay[nChain][nDTC][nROC]
687 <<
" ns +/- " << delay_rms[nChain][nDTC][nROC] <<
" ("
688 << delay_failed[nChain][nDTC][nROC] <<
")" << __E__);
693 float diff = delay[0][1][0] - delay[0][0][0];
695 __MCOUT_INFO__(
"DTC1_ROC0 - DTC0_ROC0 = " << diff << __E__);
696 __MCOUT_INFO__(
"-------------------------" << __E__);
698 __FE_COUT__ <<
"LOOPBACK: CFO reset serdes RX " << __E__;
699 registerWrite(0x9118, 0x000000ff);
700 registerWrite(0x9118, 0x0);
703 __FE_COUT__ <<
"CFO enable Event Start character output 0x" << std::hex << __E__;
704 registerWrite(0x9100, initial_9100_);
706 __FE_COUT__ <<
"CFO enable serdes transmit and receive 0x" << __E__;
707 registerWrite(0x9114, initial_9114_);
709 __FE_COUT__ <<
"CFO set Event Window interval time" << __E__;
710 registerWrite(0x91a0, initial_91a0_);
712 __FE_COUT__ <<
"CFO set 40MHz marker interval" << __E__;
713 registerWrite(0x9154, initial_9154_);
722 int activeROC = (startIndex - 1) % numberOfROCsPerDTC;
726 for(
int nDTC = 0; nDTC < numberOfDTCsPerChain; nDTC++)
732 if((startIndex - 1) >= (nDTC * numberOfROCsPerDTC) &&
733 (startIndex - 1) < ((nDTC + 1) * numberOfROCsPerDTC))
742 __MCOUT_INFO__(
" Looping back DTC" << activeDTC <<
" ROC" << activeROC << __E__);
746 while((chainIndex < numberOfChains))
749 MeasureLoopback(link[chainIndex]);
751 delay[chainIndex][activeDTC][activeROC] = average_loopback_;
752 delay_rms[chainIndex][activeDTC][activeROC] = rms_loopback_;
753 delay_failed[chainIndex][activeDTC][activeROC] = failed_loopback_;
755 __FE_COUT__ <<
"LOOPBACK: link " << link[chainIndex]
756 <<
" -> delay = " << delay[chainIndex][activeDTC][activeROC]
757 <<
" ns, rms = " << delay_rms[chainIndex][activeDTC][activeROC]
758 <<
" failed = " << delay_failed[chainIndex][activeDTC][activeROC]
765 indicateIterationWork();
770 void CFOFrontEndInterface::stop(
void)
772 int numberOfCAPTANPulses =
773 getConfigurationManager()
774 ->getNode(
"/Mu2eGlobalsTable/SyncDemoConfig/NumberOfCAPTANPulses")
775 .getValue<
unsigned int>();
777 __FE_COUTV__(numberOfCAPTANPulses);
779 if(numberOfCAPTANPulses == 0)
784 int loopbackIndex = getIterationIndex();
786 if(loopbackIndex > numberOfCAPTANPulses)
790 std::string filein1 =
"/home/mu2edaq/sync_demo/ots/DTC0_ROC0data.txt";
791 std::string filein2 =
"/home/mu2edaq/sync_demo/ots/DTC1_ROC0data.txt";
796 int iteration_source1[10000];
797 int timestamp_source1[10000];
806 in1 >> iteration_source1[nlines1] >> timestamp_source1[nlines1];
810 __FE_COUT__ <<
"iteration " << iteration_source1[nlines1] <<
" "
811 << timestamp_source1[nlines1] << __E__;
820 int iteration_source2[10000];
821 int timestamp_source2[10000];
830 in2 >> iteration_source2[nlines2] >> timestamp_source2[nlines2];
834 __FE_COUT__ <<
"iteration " << iteration_source2[nlines2] <<
" "
835 << timestamp_source2[nlines2] << __E__;
841 __FE_COUT__ <<
"Read in " << nlines1 <<
" lines from " << filein1 << __E__;
842 __FE_COUT__ <<
"Read in " << nlines2 <<
" lines from " << filein2 << __E__;
844 __FE_COUT__ << __E__;
848 int distribution[1001] = {};
850 int max_distribution = -1000;
851 int min_distribution = 1000;
855 int timestamp_diff[1000] = {};
857 float numerator = 0.;
858 float denominator = 0.;
860 for(
int i = 0; i < nlines1; i++)
862 if(timestamp_source1[i] == 65535 || timestamp_source2[i] == 65535 ||
863 timestamp_source1[i] == -999 || timestamp_source2[i] == -999)
865 timestamp_diff[i] = -999999;
870 (timestamp_source2[i] - timestamp_source1[i]) + offset;
872 if(timestamp_diff[i] >= 0 &&
873 timestamp_diff[i] < 1000)
875 numerator += (float)timestamp_diff[i];
878 distribution[timestamp_diff[i]]++;
880 if(timestamp_diff[i] > max_distribution)
882 max_distribution = timestamp_diff[i];
883 __COUT__ << i <<
" new max " << timestamp_source1[i] <<
" "
884 << timestamp_source2[i] <<
" " << timestamp_diff[i]
888 if(timestamp_diff[i] < min_distribution)
890 __COUT__ << i <<
" new min " << timestamp_source1[i] <<
" "
891 << timestamp_source2[i] <<
" " << timestamp_diff[i]
894 min_distribution = timestamp_diff[i];
899 timestamp_diff[i] = -999999;
903 float average = numerator / denominator;
907 for(
int n = 0; n < nlines1; n++)
909 if(timestamp_diff[n] != -999999)
911 rms += (timestamp_diff[n] - average) * (timestamp_diff[n] - average);
915 if(denominator > 0.0)
916 rms = sqrt(rms / denominator);
925 __MCOUT_INFO__(
"--------------------------------------------" << __E__);
926 __MCOUT_INFO__(
"--CAPTAN timestamp difference distribution--" << __E__);
927 for(
int n = (min_distribution - 5); n < (max_distribution + 5); n++)
929 int display = n - offset;
930 __MCOUT_INFO__(
" diff [ " << display <<
" ] = " << distribution[n] << __E__);
932 __MCOUT_INFO__(
"--------------------------------------------" << __E__);
934 __MCOUT_INFO__(
"Average = " << average <<
" ... RMS = " << rms << __E__);
939 indicateIterationWork();
944 bool CFOFrontEndInterface::running(
void)
946 while(WorkLoop::continueWorkLoop_)
CFOFrontEndInterface(const std::string &interfaceUID, const ConfigurationTree &theXDAQContextConfigTree, const std::string &interfaceConfigurationPath)