otsdaq_mu2e  v2_04_02
CFOFrontEndInterface_interface.cc
1 #include "otsdaq-mu2e/FEInterfaces/CFOFrontEndInterface.h"
2 #include "otsdaq/Macros/InterfacePluginMacros.h"
3 //#include "otsdaq/DAQHardware/FrontEndHardwareTemplate.h"
4 //#include "otsdaq/DAQHardware/FrontEndFirmwareTemplate.h"
5 
6 //#include "mu2e_driver/mu2e_mmap_ioctl.h" // m_ioc_cmd_t
7 
8 using namespace ots;
9 
10 #undef __MF_SUBJECT__
11 #define __MF_SUBJECT__ "CFOFrontEndInterface"
12 
13 //===========================================================================================
15  const std::string& interfaceUID,
16  const ConfigurationTree& theXDAQContextConfigTree,
17  const std::string& interfaceConfigurationPath)
19  interfaceUID, theXDAQContextConfigTree, interfaceConfigurationPath)
20 {
21  __FE_COUT__ << "Constructing..." << __E__;
22 
23  // theFrontEndHardware_ = new FrontEndHardwareTemplate();
30  //
31  // dtc_ = getSelfNode().getNode("DeviceIndex").getValue<unsigned int>();
32  // snprintf(devfile_, 11, "/dev/" MU2E_DEV_FILE, dtc_);
33  // fd_ = open(devfile_, O_RDONLY);
34  //
35  // __FE_COUT__ << "Device file descriptor opened!" << __E__;
36 
37  unsigned roc_mask = 0x1;
38  std::string expectedDesignVersion = "";
39  auto mode = DTCLib::DTC_SimMode_NoCFO;
40 
41  thisCFO_ = new CFOLib::CFO_Registers(mode, dtc_, expectedDesignVersion);
42 
43  __FE_COUT__ << "CFOFrontEndInterface instantiated with name: " << interfaceUID
44  << " talking to /dev/mu2e" << dtc_ << __E__;
45 } // end constructor()
46 
47 //===========================================================================================
48 CFOFrontEndInterface::~CFOFrontEndInterface(void)
49 {
50  delete thisCFO_;
51  // delete theFrontEndHardware_;
52  // delete theFrontEndFirmware_;
53 }
54 //
63 // void DTCFrontEndInterface::universalRead(char* address, char* returnValue)
64 //{
65 // // __FE_COUT__ << "DTC READ" << __E__;
66 //
67 // if(emulatorMode_)
68 // {
69 // __FE_COUT__ << "Emulator read " << __E__;
70 // for(unsigned int i = 0; i < universalDataSize_; ++i)
71 // returnValue[i] = 0xF0 | i;
72 // return;
73 // }
74 //
75 // (*((dtc_address_t*)returnValue)) = registerRead(*((dtc_address_t*)address));
76 //
77 // // __COUTV__(reg_access_.val);
78 //
79 //} //end universalRead()
80 //
84 // dtc_data_t DTCFrontEndInterface::registerRead(const dtc_address_t address)
85 //{
86 // reg_access_.access_type = 0; // 0 = read, 1 = write
87 // reg_access_.reg_offset = address;
88 // // __COUTV__(reg_access.reg_offset);
89 //
90 // if(ioctl(fd_, M_IOC_REG_ACCESS, &reg_access_))
91 // {
92 // __SS__ << "ERROR: DTC register read - Does file exist? -> /dev/mu2e" << dtc_
93 // << __E__;
94 // __SS_THROW__;
95 // }
96 //
97 // return reg_access_.val;
98 //
99 //} // end registerRead()
100 //
107 // void CFOFrontEndInterface::universalWrite(char* address, char* writeValue)
108 //{
109 // // __FE_COUT__ << "CFO WRITE" << __E__;
110 //
111 // reg_access_.access_type = 1; // 0 = read, 1 = write
112 //
113 // reg_access_.reg_offset = *((int*)address);
114 // // __COUTV__(reg_access.reg_offset);
115 //
116 // reg_access_.val = *((int*)writeValue);
117 // // __COUTV__(reg_access.val);
118 //
119 // if(ioctl(fd_, M_IOC_REG_ACCESS, &reg_access_))
120 // __FE_COUT_ERR__ << "ERROR: CFO universal write - Does file exist? /dev/mu2e"
121 // << dtc_ << __E__;
122 //
123 // return;
124 //}
125 //
129 // int CFOFrontEndInterface::registerWrite(int address, int dataToWrite)
130 //{
131 // uint8_t* addrs = new uint8_t[universalAddressSize_]; // create address buffer
132 // // of interface size
133 // uint8_t* data =
134 // new uint8_t[universalDataSize_]; // create data buffer of interface size
135 //
136 // uint8_t macroAddrs[20] = {}; // assume we'll never have 20 bytes in an address
137 // uint8_t macroData[20] =
138 // {}; // assume we'll never have 20 bytes read out from a register
139 //
140 // // fill byte-by-byte
141 // for(unsigned int i = 0; i < universalAddressSize_; i++)
142 // macroAddrs[i] = 0xff & (address >> i * 8);
143 //
144 // // 0-pad
145 // for(unsigned int i = 0; i < universalAddressSize_; ++i)
146 // addrs[i] = (i < 2) ? macroAddrs[i] : 0;
147 //
148 // // fill byte-by-byte
149 // for(unsigned int i = 0; i < universalDataSize_; i++)
150 // macroData[i] = 0xff & (dataToWrite >> i * 8);
151 //
152 // // 0-pad
153 // for(unsigned int i = 0; i < universalDataSize_; ++i)
154 // data[i] = (i < 4) ? macroData[i] : 0;
155 //
156 // universalWrite((char*)addrs, (char*)data);
157 //
158 // // usleep(100);
159 //
160 // int readbackValue = registerRead(address);
161 //
162 // int i = 0;
163 //
164 // ////this is a I2C register, it clears bit0 when transaction finishes
165 // if((address == 0x916c) && ((dataToWrite & 0x1) == 1))
166 // {
167 // // wait for I2C to clear...
168 // while((readbackValue & 0x1) != 0)
169 // {
170 // i++;
171 // readbackValue = registerRead(address);
172 // usleep(100);
173 // if((i % 10) == 0)
174 // __FE_COUT__ << "CFO I2C waited " << i << " times..." << __E__;
175 // }
176 // // if (i > 0) __FE_COUT__ << "CFO I2C waited " << i << " times..." <<
177 // // __E__;
178 // }
179 //
180 // // lowest 8-bits are the I2C read value. But we aren't reading anything back
181 // // for the moment...
182 // if(address == 0x9168)
183 // {
184 // if((readbackValue & 0xffffff00) != (dataToWrite & 0xffffff00))
185 // {
186 // __FE_COUT_ERR__ << "CFO: write value 0x" << std::hex << dataToWrite
187 // << " to register 0x" << std::hex << address
188 // << "... read back 0x" << std::hex << readbackValue << __E__;
189 // }
190 // }
191 //
192 // // lowest order bit clears itself
193 // if((address == 0x9380) && ((dataToWrite & 0x1) == 1))
194 // {
195 // if((readbackValue & 0xfffffffe) != (dataToWrite & 0xfffffffe))
196 // {
197 // __FE_COUT_ERR__ << "CFO: write value 0x" << std::hex << dataToWrite
198 // << " to register 0x" << std::hex << address
199 // << "... read back 0x" << std::hex << readbackValue << __E__;
200 // }
201 // }
202 //
203 // if(readbackValue != dataToWrite && address != 0x9168 && address != 0x916c &&
204 // address != 0x9380)
205 // {
206 // __FE_COUT_ERR__ << "CFO: write value 0x" << std::hex << dataToWrite
207 // << " to register 0x" << std::hex << address << "... read back 0x"
208 // << std::hex << readbackValue << __E__;
209 // }
210 //
211 // delete[] addrs; // free the memory
212 // delete[] data; // free the memory
213 //
214 // return readbackValue;
215 //}
216 
217 //=====================================================================================
218 void CFOFrontEndInterface::readStatus(void)
219 {
220  __FE_COUT__ << "firmware version (0x9004) = 0x" << std::hex << registerRead(0x9004)
221  << __E__;
222  __FE_COUT__ << "link enable (0x9114) = 0x" << std::hex << registerRead(0x9114)
223  << __E__;
224  __FE_COUT__ << "SERDES reset (0x9118) = 0x" << std::hex << registerRead(0x9118)
225  << __E__;
226  __FE_COUT__ << "SERDES unlock error (0x9124) = 0x" << std::hex << registerRead(0x9124)
227  << __E__;
228  __FE_COUT__ << "PLL locked (0x9128) = 0x" << std::hex << registerRead(0x9128)
229  << __E__;
230  __FE_COUT__ << "SERDES Rx status....(0x9134) = 0x" << std::hex << registerRead(0x9134)
231  << __E__;
232  __FE_COUT__ << "SERDES reset done...(0x9138) = 0x" << std::hex << registerRead(0x9138)
233  << __E__;
234  __FE_COUT__ << "SERDES Rx CDR lock..(0x9140) = 0x" << std::hex << registerRead(0x9140)
235  << __E__;
236  __FE_COUT__ << "SERDES ref clk freq.(0x9160) = 0x" << std::hex << registerRead(0x9160)
237  << " = " << std::dec << registerRead(0x9160) << __E__;
238 
239  __FE_COUT__ << __E__;
240 }
241 
242 //=====================================================================================
243 //
244 int CFOFrontEndInterface::getLinkStatus()
245 {
246  int overall_link_status = registerRead(0x9140);
247 
248  int link_status = (overall_link_status >> 0) & 0x1;
249 
250  return link_status;
251 }
252 
253 //=====================================================================================
254 //
255 float CFOFrontEndInterface::MeasureLoopback(int linkToLoopback)
256 {
257  const int maxNumberOfLoopbacks = 10000;
258  int numberOfLoopbacks =
259  getConfigurationManager()
260  ->getNode("/Mu2eGlobalsTable/SyncDemoConfig/NumberOfLoopbacks")
261  .getValue<unsigned int>();
262 
263  __FE_COUTV__(numberOfLoopbacks);
264 
265  // prepare histograms
266  float numerator = 0.0;
267  float denominator = 0.0;
268  failed_loopback_ = 0;
269 
270  int loopback_data[maxNumberOfLoopbacks] = {};
271 
272  max_distribution_ = 0; // maximum value of the histogram
273  min_distribution_ = 99999; // minimum value of the histogram
274 
275  for(int n = 0; n < 10000; n++)
276  loopback_distribution_[n] = 0; // zero out the histogram
277 
278  // get initial states
279  unsigned initial_9380 = registerRead(0x9380);
280  unsigned initial_9114 = registerRead(0x9114);
281 
282  // clean up after the DTC has done all of its resetting...
283  __FE_COUT__ << "LOOPBACK: CFO reset serdes RX " << __E__;
284  registerWrite(0x9118, 0x000000ff);
285  registerWrite(0x9118, 0x0);
286  sleep(1);
287 
288  __FE_COUT__ << "LOOPBACK: CFO status before loopback" << __E__;
289  readStatus();
290 
291  // __FE_COUT__ << "LOOPBACK: BEFORE max_distribution_: " <<
292  // max_distribution_ << __E__;
293 
294  for(int n = 0; n <= numberOfLoopbacks; n++)
295  {
296  //----------take out of delay measurement mode
297  registerWrite(0x9380, 0x00000000);
298 
299  //-------- Disable tx and rx data
300  registerWrite(0x9114, 0x00000000);
301 
302  //--- enable tx and rx for link linkToLoopback
303  int dataToWrite = (0x00000101 << linkToLoopback);
304  registerWrite(0x9114, dataToWrite);
305 
306  //----- Put linkToLoopback in delay measurement mode
307  dataToWrite = (0x00000100 << linkToLoopback);
308  registerWrite(0x9380, dataToWrite);
309 
310  //------ begin delay measurement
311  dataToWrite = (0x00000101 << linkToLoopback);
312  registerWrite(0x9380, dataToWrite);
313  usleep(5);
314 
315  //--------read delay value
316  unsigned int delay = registerRead(0x9360);
317 
318  //__MCOUT_INFO__("LOOPBACK iteration " << std::dec << n << " gives " << delay <<
319  //__E__);
320 
321  if(delay < 10000 && n > 5)
322  { // skip the first events since the ROC is
323  // resetting its alignment
324 
325  numerator += (float)delay;
326  denominator += 1.0;
327  // __FE_COUT__ << "LOOPBACK iteration " << std::dec << n <<
328  // " gives " << delay << __E__;
329 
330  loopback_data[n] = delay;
331 
332  loopback_distribution_[delay]++;
333 
334  if(delay > max_distribution_)
335  {
336  max_distribution_ = delay;
337  // __FE_COUT__ << "LOOPBACK: new max_distribution_: " <<
338  // max_distribution_ << __E__;
339  }
340 
341  if(delay < min_distribution_)
342  min_distribution_ = delay;
343  }
344  else
345  {
346  loopback_data[n] = -999;
347 
348  if(n > 5)
349  { // skip the first events since the ROC is resetting its alignment
350  failed_loopback_++;
351  }
352  }
353 
354  //----------clear delay measurement mode
355  // registerWrite(0x9380,0x00000000);
356 
357  //-------- Disable tx and rx data
358  // registerWrite(0x9114,0x00000000);
359 
360  usleep(5);
361  }
362 
363  __FE_COUT__ << "LOOPBACK: CFO status after loopback" << __E__;
364  readStatus();
365 
366  // return back to initial state
367  registerWrite(0x9380, initial_9380);
368  registerWrite(0x9114, initial_9114);
369 
370  // ---------------------------
371  // do a little bit of analysis
372  // ---------------------------
373 
374  average_loopback_ = -999.;
375  if(denominator > 0.5)
376  average_loopback_ = numerator / denominator;
377 
378  rms_loopback_ = 0.;
379 
380  for(int n = 0; n < numberOfLoopbacks; n++)
381  {
382  if(loopback_data[n] > 0)
383  {
384  rms_loopback_ += (loopback_data[n] - average_loopback_) *
385  (loopback_data[n] - average_loopback_);
386  }
387  }
388 
389  if(denominator > 0.5)
390  {
391  rms_loopback_ = sqrt(rms_loopback_ / denominator);
392  average_loopback_ *= 5; // convert from 5ns bins (200MHz) to 1ns bins
393  rms_loopback_ *= 5; // convert from 5ns bins (200MHz) to 1ns bins
394  }
395 
396  __FE_COUT__ << "LOOPBACK: distribution: " << __E__;
397  // __FE_COUT__ << "LOOPBACK: min_distribution_: " << min_distribution_ <<
398  //__E__;
399  // __FE_COUT__ << "LOOPBACK: max_distribution_: " << max_distribution_ <<
400  //__E__;
401 
402  for(unsigned int n = (min_distribution_ - 5); n < (max_distribution_ + 5); n++)
403  {
404  __MCOUT_INFO__(" delay [ " << n << " ] = " << loopback_distribution_[n] << __E__);
405  }
406 
407  __MCOUT_INFO__(" average = " << average_loopback_ << " ns, RMS = " << rms_loopback_
408  << " ns, failures = " << failed_loopback_ << __E__);
409 
410  __FE_COUT__ << __E__;
411 
412  __FE_COUT__ << "LOOPBACK: number of failed loopbacks = " << std::dec
413  << failed_loopback_ << __E__;
414 
415  return average_loopback_;
416 
417 } // end MeasureLoopback()
418 
419 //===============================================================================================
420 void CFOFrontEndInterface::configure(void)
421 {
422  __FE_COUTV__(getIterationIndex());
423  __FE_COUTV__(getSubIterationIndex());
424 
425  // NOTE: otsdaq/xdaq has a soap reply timeout for state transitions.
426  // Therefore, break up configuration into several steps so as to reply before
427  // the time out As well, there is a specific order in which to configure the
428  // links in the chain of CFO->DTC0->DTC1->...DTCN
429 
430  const int number_of_system_configs =
431  2; // if < 0, keep trying until links are OK.
432  // If > 0, go through configuration steps this many times
433  int config_clock = configure_clock_; // 1 = yes, 0 = no
434  const int reset_tx = 1; // 1 = yes, 0 = no
435 
436  const int number_of_dtc_config_steps = 7;
437 
438  int number_of_total_config_steps =
439  number_of_system_configs * number_of_dtc_config_steps;
440 
441  int config_step = getIterationIndex();
442 
443  if(number_of_system_configs > 0)
444  {
445  if(config_step >= number_of_total_config_steps) // done - exit system config
446  return;
447  }
448 
449  if((config_step % number_of_dtc_config_steps) == 0)
450  {
451  // disable outputs
452 
453  __FE_COUT__ << "CFO disable Event Start character output " << __E__;
454  registerWrite(0x9100, 0x0);
455 
456  __FE_COUT__ << "CFO disable serdes transmit and receive " << __E__;
457  registerWrite(0x9114, 0x00000000);
458 
459  __FE_COUT__ << "CFO turn off Event Windows" << __E__;
460  registerWrite(0x91a0, 0x00000000);
461 
462  __FE_COUT__ << "CFO turn off 40MHz marker interval" << __E__;
463  registerWrite(0x9154, 0x00000000);
464  }
465  else if((config_step % number_of_dtc_config_steps) == 1)
466  {
467  // reset clocks
468 
469  if(config_clock == 1 && config_step < number_of_dtc_config_steps)
470  {
471  // only configure the clock/crystal the first loop through...
472 
473  __MCOUT_INFO__("Step " << config_step << ": CFO reset clock..." << __E__);
474  __FE_COUT__ << "CFO set crystal frequency to 156.25 MHz" << __E__;
475 
476  registerWrite(0x9160, 0x09502F90);
477 
478  // set RST_REG bit
479  registerWrite(0x9168, 0x55870100);
480  registerWrite(0x916c, 0x00000001);
481 
482  sleep(5);
483 
484  //-----begin code snippet pulled from: mu2eUtil program_clock -C 0 -F
485  // 200000000 ---
486  // C=0 = main board SERDES clock
487  // C=1 = DDR clock
488  // C=2 = Timing board SERDES clock
489 
490  int targetFrequency = 200000000;
491 
492  auto oscillator = DTCLib::DTC_OscillatorType_SERDES; //-C 0 = CFO (main
493  // board SERDES clock)
494  // auto oscillator = DTCLib::DTC_OscillatorType_DDR; //-C 1 (DDR clock)
495  // auto oscillator = DTCLib::DTC_OscillatorType_Timing; //-C 2 = DTC (with
496  // timing card)
497 
498  __FE_COUT__ << "CFO set oscillator frequency to " << std::dec
499  << targetFrequency << " MHz" << __E__;
500 
501  thisCFO_->SetNewOscillatorFrequency(targetFrequency);
502 
503  //-----end code snippet pulled from: mu2eUtil program_clock -C 0 -F
504  // 200000000
505 
506  sleep(5);
507  }
508  else
509  {
510  __MCOUT_INFO__("Step " << config_step << ": CFO do NOT reset clock..."
511  << __E__);
512  }
513  }
514  else if((config_step % number_of_dtc_config_steps) == 3)
515  {
516  // after DTC jitter attenuator OK, config CFO SERDES PLLs and TX
517  if(reset_tx == 1)
518  {
519  __MCOUT_INFO__("Step " << config_step << ": CFO reset TX..." << __E__);
520 
521  __FE_COUT__ << "CFO reset serdes PLLs " << __E__;
522  registerWrite(0x9118, 0x0000ff00);
523  registerWrite(0x9118, 0x0);
524  sleep(3);
525 
526  __FE_COUT__ << "CFO reset serdes TX " << __E__;
527  registerWrite(0x9118, 0x00ff0000);
528  registerWrite(0x9118, 0x0);
529  sleep(3);
530  }
531  else
532  {
533  __MCOUT_INFO__("Step " << config_step << "CFO do NOT reset TX..." << __E__);
534  }
535  }
536  else if((config_step % number_of_dtc_config_steps) == 6)
537  {
538  __MCOUT_INFO__("Step " << config_step
539  << ": CFO enable Event start characters, SERDES Tx "
540  "and Rx, and event window interval"
541  << __E__);
542 
543  __FE_COUT__ << "CFO reset serdes RX " << __E__;
544  registerWrite(0x9118, 0x000000ff);
545  registerWrite(0x9118, 0x0);
546  sleep(3);
547 
548  __FE_COUT__ << "CFO enable Event Start character output " << __E__;
549  registerWrite(0x9100, 0x5);
550 
551  __FE_COUT__ << "CFO enable serdes transmit and receive " << __E__;
552  registerWrite(0x9114, 0x0000ffff);
553 
554  __FE_COUT__ << "CFO set Event Window interval time" << __E__;
555  // registerWrite(0x91a0,0x154); //1.7us
556  registerWrite(0x91a0, 0x1f40); // 40us
557  // registerWrite(0x91a0,0x00000000); // for NO markers, write these
558  // values
559 
560  __FE_COUT__ << "CFO set 40MHz marker interval" << __E__;
561  registerWrite(0x9154, 0x0800);
562  // registerWrite(0x9154,0x00000000); // for NO markers, write these
563  // values
564 
565  __MCOUT_INFO__("--------------" << __E__);
566  __MCOUT_INFO__("CFO configured" << __E__);
567 
568  if(getLinkStatus() == 1)
569  {
570  __MCOUT_INFO__("CFO links OK = 0x" << std::hex << registerRead(0x9140)
571  << std::dec << __E__);
572 
573  if(number_of_system_configs < 0)
574  {
575  return; // links OK, kick out
576  }
577  }
578  else
579  {
580  __MCOUT_INFO__("CFO links not OK = 0x" << std::hex << registerRead(0x9140)
581  << std::dec << __E__);
582  }
583  __FE_COUT__ << __E__;
584  }
585 
586  readStatus(); // spit out link status at every step
587  indicateIterationWork(); // I still need to be touched
588  return;
589 }
590 
591 //==============================================================================
592 void CFOFrontEndInterface::halt(void)
593 {
594  __FE_COUT__ << "HALT: CFO status" << __E__;
595  readStatus();
596 }
597 
598 //==============================================================================
599 void CFOFrontEndInterface::pause(void)
600 {
601  __FE_COUT__ << "PAUSE: CFO status" << __E__;
602  readStatus();
603 }
604 
605 //==============================================================================
606 void CFOFrontEndInterface::resume(void)
607 {
608  __FE_COUT__ << "RESUME: CFO status" << __E__;
609  readStatus();
610 }
611 
612 //==============================================================================
613 void CFOFrontEndInterface::start(std::string) // runNumber)
614 {
615  bool LoopbackLock = true;
616  int loopbackROC = 0;
617 
618  const int numberOfChains = 1;
619  int link[numberOfChains] = {0};
620 
621  const int numberOfDTCsPerChain = 1; // assume 0, then 1
622 
623  const int numberOfROCsPerDTC = 1; // assume 0, then 1
624 
625  // To do loopbacks on all CFOs, first have to setup all DTCs, then the CFO
626  // (this method) work per iteration. Loop back done on all chains (in this
627  // method), assuming the following order: i DTC0 DTC1 ... DTCN 0 ROC0 none ...
628  // none 1 ROC1 none ... none 2 none ROC0 ... none 3 none ROC1 ... none
629  // ...
630  // N-1 none none ... ROC0
631  // N none none ... ROC1
632 
633  int numberOfMeasurements = numberOfChains * numberOfDTCsPerChain * numberOfROCsPerDTC;
634 
635  int startIndex = getIterationIndex();
636 
637  if(startIndex == 0) // setup
638  {
639  initial_9100_ = registerRead(0x9100);
640  initial_9114_ = registerRead(0x9114);
641  initial_91a0_ = registerRead(0x91a0);
642  initial_9154_ = registerRead(0x9154);
643 
644  __FE_COUT__ << "CFO disable Event Start character output " << __E__;
645  registerWrite(0x9100, 0x0);
646 
647  __FE_COUT__ << "CFO turn off Event Windows" << __E__;
648  registerWrite(0x91a0, 0x00000000);
649 
650  __FE_COUT__ << "CFO turn off 40MHz marker interval" << __E__;
651  registerWrite(0x9154, 0x00000000);
652 
653  __FE_COUT__ << "START: CFO status" << __E__;
654  readStatus();
655 
656  for(int nChain = 0; nChain < numberOfChains; nChain++)
657  {
658  for(int nDTC = 0; nDTC < numberOfDTCsPerChain; nDTC++)
659  {
660  for(int nROC = 0; nROC < numberOfROCsPerDTC; nROC++)
661  {
662  delay[nChain][nDTC][nROC] = -1;
663  delay_rms[nChain][nDTC][nROC] = -1;
664  delay_failed[nChain][nDTC][nROC] = -1;
665  }
666  }
667  }
668 
669  indicateIterationWork(); // I still need to be touched
670  return;
671  }
672 
673  if(startIndex > numberOfMeasurements) // finish
674  {
675  __MCOUT_INFO__("-------------------------" << __E__);
676  __MCOUT_INFO__("FULL SYSTEM loopback DONE" << __E__);
677 
678  for(int nChain = 0; nChain < numberOfChains; nChain++)
679  {
680  for(int nDTC = 0; nDTC < numberOfDTCsPerChain; nDTC++)
681  {
682  for(int nROC = 0; nROC < numberOfROCsPerDTC; nROC++)
683  {
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__);
689  }
690  }
691  }
692 
693  float diff = delay[0][1][0] - delay[0][0][0];
694 
695  __MCOUT_INFO__("DTC1_ROC0 - DTC0_ROC0 = " << diff << __E__);
696  __MCOUT_INFO__("-------------------------" << __E__);
697 
698  __FE_COUT__ << "LOOPBACK: CFO reset serdes RX " << __E__;
699  registerWrite(0x9118, 0x000000ff);
700  registerWrite(0x9118, 0x0);
701  usleep(50);
702 
703  __FE_COUT__ << "CFO enable Event Start character output 0x" << std::hex << __E__;
704  registerWrite(0x9100, initial_9100_);
705 
706  __FE_COUT__ << "CFO enable serdes transmit and receive 0x" << __E__;
707  registerWrite(0x9114, initial_9114_);
708 
709  __FE_COUT__ << "CFO set Event Window interval time" << __E__;
710  registerWrite(0x91a0, initial_91a0_); // 40us
711 
712  __FE_COUT__ << "CFO set 40MHz marker interval" << __E__;
713  registerWrite(0x9154, initial_9154_);
714 
715  readStatus();
716  return;
717  }
718 
719  //=========== Perform loopback=============
720 
721  // where are we in the procedure?
722  int activeROC = (startIndex - 1) % numberOfROCsPerDTC;
723 
724  int activeDTC = -1;
725 
726  for(int nDTC = 0; nDTC < numberOfDTCsPerChain; nDTC++)
727  {
728  // __FE_COUT__ << "loopback index = " << startIndex
729  // << " nDTC = " << nDTC
730  // << " numberOfDTCsPerChain = " << numberOfDTCsPerChain
731  // << __E__;
732  if((startIndex - 1) >= (nDTC * numberOfROCsPerDTC) &&
733  (startIndex - 1) < ((nDTC + 1) * numberOfROCsPerDTC))
734  {
735  // __FE_COUT__ << "ACTIVE DTC " << nDTC <<
736  //__E__;
737  activeDTC = nDTC;
738  }
739  }
740 
741  // __MOUT__ << "loopback index = " << startIndex;
742  __MCOUT_INFO__(" Looping back DTC" << activeDTC << " ROC" << activeROC << __E__);
743 
744  int chainIndex = 0;
745 
746  while((chainIndex < numberOfChains))
747  {
748  //__MCOUT__( "LOOPBACK: on DTC " << link[chainIndex] <<__E__);
749  MeasureLoopback(link[chainIndex]);
750 
751  delay[chainIndex][activeDTC][activeROC] = average_loopback_;
752  delay_rms[chainIndex][activeDTC][activeROC] = rms_loopback_;
753  delay_failed[chainIndex][activeDTC][activeROC] = failed_loopback_;
754 
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]
759  << __E__;
760 
761  chainIndex++;
762 
763  } // (chainIndex < numberOfChains)
764 
765  indicateIterationWork(); // I still need to be touched
766  return;
767 }
768 
769 //==============================================================================
770 void CFOFrontEndInterface::stop(void)
771 {
772  int numberOfCAPTANPulses =
773  getConfigurationManager()
774  ->getNode("/Mu2eGlobalsTable/SyncDemoConfig/NumberOfCAPTANPulses")
775  .getValue<unsigned int>();
776 
777  __FE_COUTV__(numberOfCAPTANPulses);
778 
779  if(numberOfCAPTANPulses == 0)
780  {
781  return;
782  }
783 
784  int loopbackIndex = getIterationIndex();
785 
786  if(loopbackIndex > numberOfCAPTANPulses)
787  {
788  //---- begin read in data
789 
790  std::string filein1 = "/home/mu2edaq/sync_demo/ots/DTC0_ROC0data.txt";
791  std::string filein2 = "/home/mu2edaq/sync_demo/ots/DTC1_ROC0data.txt";
792 
793  // file 1
794  std::ifstream in1;
795 
796  int iteration_source1[10000];
797  int timestamp_source1[10000];
798 
799  in1.open(filein1);
800 
801  // std::cout << filein1 << std::endl;
802 
803  int nlines1 = 0;
804  while(1)
805  {
806  in1 >> iteration_source1[nlines1] >> timestamp_source1[nlines1];
807  if(!in1.good())
808  break;
809  if(nlines1 < 10)
810  __FE_COUT__ << "iteration " << iteration_source1[nlines1] << " "
811  << timestamp_source1[nlines1] << __E__;
812  nlines1++;
813  }
814 
815  in1.close();
816 
817  // file 2
818  std::ifstream in2;
819 
820  int iteration_source2[10000];
821  int timestamp_source2[10000];
822 
823  in2.open(filein2);
824 
825  // std::cout << filein1 << std::endl;
826 
827  int nlines2 = 0;
828  while(1)
829  {
830  in2 >> iteration_source2[nlines2] >> timestamp_source2[nlines2];
831  if(!in2.good())
832  break;
833  if(nlines2 < 10)
834  __FE_COUT__ << "iteration " << iteration_source2[nlines2] << " "
835  << timestamp_source2[nlines2] << __E__;
836  nlines2++;
837  }
838 
839  in2.close();
840 
841  __FE_COUT__ << "Read in " << nlines1 << " lines from " << filein1 << __E__;
842  __FE_COUT__ << "Read in " << nlines2 << " lines from " << filein2 << __E__;
843 
844  __FE_COUT__ << __E__;
845 
846  //__MCOUT_INFO__("iter file1 file2 diff" << __E__);
847 
848  int distribution[1001] = {};
849 
850  int max_distribution = -1000;
851  int min_distribution = 1000;
852 
853  int offset = 500;
854 
855  int timestamp_diff[1000] = {};
856 
857  float numerator = 0.;
858  float denominator = 0.;
859 
860  for(int i = 0; i < nlines1; i++)
861  {
862  if(timestamp_source1[i] == 65535 || timestamp_source2[i] == 65535 ||
863  timestamp_source1[i] == -999 || timestamp_source2[i] == -999)
864  {
865  timestamp_diff[i] = -999999;
866  }
867  else
868  {
869  timestamp_diff[i] =
870  (timestamp_source2[i] - timestamp_source1[i]) + offset;
871 
872  if(timestamp_diff[i] >= 0 &&
873  timestamp_diff[i] < 1000) // crossed from one event window to another
874  {
875  numerator += (float)timestamp_diff[i];
876  denominator += 1.0;
877 
878  distribution[timestamp_diff[i]]++;
879 
880  if(timestamp_diff[i] > max_distribution)
881  {
882  max_distribution = timestamp_diff[i];
883  __COUT__ << i << " new max " << timestamp_source1[i] << " "
884  << timestamp_source2[i] << " " << timestamp_diff[i]
885  << __E__;
886  }
887 
888  if(timestamp_diff[i] < min_distribution)
889  {
890  __COUT__ << i << " new min " << timestamp_source1[i] << " "
891  << timestamp_source2[i] << " " << timestamp_diff[i]
892  << __E__;
893 
894  min_distribution = timestamp_diff[i];
895  }
896  }
897  else
898  {
899  timestamp_diff[i] = -999999;
900  }
901  }
902  }
903  float average = numerator / denominator;
904 
905  float rms = 0.;
906 
907  for(int n = 0; n < nlines1; n++)
908  {
909  if(timestamp_diff[n] != -999999)
910  {
911  rms += (timestamp_diff[n] - average) * (timestamp_diff[n] - average);
912  }
913  }
914 
915  if(denominator > 0.0)
916  rms = sqrt(rms / denominator);
917 
918  average -= offset;
919 
920  // __FE_COUT__ << "LOOPBACK: min_distribution_: " << min_distribution_ <<
921  // __E__;
922  // __FE_COUT__ << "LOOPBACK: max_distribution_: " << max_distribution_ <<
923  // __E__;
924 
925  __MCOUT_INFO__("--------------------------------------------" << __E__);
926  __MCOUT_INFO__("--CAPTAN timestamp difference distribution--" << __E__);
927  for(int n = (min_distribution - 5); n < (max_distribution + 5); n++)
928  {
929  int display = n - offset;
930  __MCOUT_INFO__(" diff [ " << display << " ] = " << distribution[n] << __E__);
931  }
932  __MCOUT_INFO__("--------------------------------------------" << __E__);
933 
934  __MCOUT_INFO__("Average = " << average << " ... RMS = " << rms << __E__);
935 
936  return;
937  }
938 
939  indicateIterationWork();
940  return;
941 }
942 
943 //==============================================================================
944 bool CFOFrontEndInterface::running(void)
945 {
946  while(WorkLoop::continueWorkLoop_)
947  {
948  break;
949  }
950 
951  return false;
952 }
953 
954 DEFINE_OTS_INTERFACE(CFOFrontEndInterface)
CFOFrontEndInterface(const std::string &interfaceUID, const ConfigurationTree &theXDAQContextConfigTree, const std::string &interfaceConfigurationPath)