otsdaq_prepmodernization  v2_04_01
FENIMPlusInterface_interface.cc
1 #include <stdint.h>
2 #include <iostream> // std::cout, std::dec, std::hex, std::oct
3 #include <set>
4 #include "otsdaq-core/Macros/CoutMacros.h"
5 #include "otsdaq-core/Macros/InterfacePluginMacros.h"
6 #include "otsdaq-core/MessageFacility/MessageFacility.h"
7 #include "otsdaq-prepmodernization/FEInterfaces/FENIMPlusInterface.h"
8 
9 using namespace ots;
10 
11 #undef __MF_SUBJECT__
12 #define __MF_SUBJECT__ "FE-FENIMPlusInterface"
13 
14 FENIMPlusInterface::FENIMPlusInterface(const std::string& interfaceUID,
15  const ConfigurationTree& theXDAQContextConfigTree,
16  const std::string& interfaceConfigurationPath)
17  : Socket(theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
18  .getNode("HostIPAddress")
19  .getValue<std::string>(),
20  theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
21  .getNode("HostPort")
22  .getValue<unsigned int>())
23  , FEOtsUDPTemplateInterface(
24  interfaceUID, theXDAQContextConfigTree, interfaceConfigurationPath)
25 {
26  // register FE Macro Functions
27  registerFEMacroFunction(
28  "GenerateTriggers", // feMacroName
29  static_cast<FEVInterface::frontEndMacroFunction_t>(
30  &FENIMPlusInterface::FEMacroGenerateTriggers),
31  std::vector<std::string>{"numberOfTriggers",
32  "signalHiDuration",
33  "signalLoDuration"}, // namesOfInputArgs
34  std::vector<std::string>{"triggersWereLaunched"}, // namesOfOutputArgs
35  1); // requiredUserPermissions
36 }
37 
38 //========================================================================================================================
39 FENIMPlusInterface::~FENIMPlusInterface(void) {}
40 
41 //========================================================================================================================
42 void FENIMPlusInterface::configure(void)
43 {
44  __CFG_COUT__ << "configure" << std::endl;
45 
46  std::string writeBuffer;
47  std::string readBuffer;
48  uint64_t readQuadWord;
49 
50  ConfigurationTree optionalLink =
51  theXDAQContextConfigTree_.getNode(theConfigurationPath_)
52  .getNode("LinkToOptionalParameters");
53  bool usingOptionalParams = !optionalLink.isDisconnected();
54 
56  // if clock reset is enabled reset clock
57  // MUST BE FIXED ADDING SOFT RESET
58  {
59  try
60  {
61  if((usingOptionalParams &&
62  optionalLink.getNode("EnableClockResetDuringConfigure").getValue<bool>()))
63  {
64  __CFG_COUT__ << "\"Soft\" Resetting NIM PLUS Ethernet!" << std::endl;
65 
66  OtsUDPFirmwareCore::softEthernetReset(writeBuffer);
67  OtsUDPHardware::write(writeBuffer);
68  OtsUDPFirmwareCore::clearEthernetReset(writeBuffer);
69  OtsUDPHardware::write(writeBuffer);
70  // sleep(1); //seconds
71  }
72  }
73  catch(...)
74  {
75  __CFG_COUT__ << "Could not find reset clock flag, so not resetting... "
76  << std::endl;
77  }
78  }
79 
80  FEOtsUDPTemplateInterface::configure(); // sets up destination IP/port
81 
82  // choose external or internal clock
83  __CFG_COUT__ << "Choosing external or internal clock..." << std::endl;
84  OtsUDPFirmwareCore::writeAdvanced(
85  writeBuffer,
86  0x3,
87  (usingOptionalParams
88  ? (optionalLink.getNode("UseExternalClock").getValue<bool>() ? 1 : 0)
89  : 0) |
90  (((usingOptionalParams
91  ? (optionalLink.getNode("ExternalClockSource").getValue<unsigned int>()
92  ? (optionalLink.getNode("ExternalClockSource")
93  .getValue<unsigned int>() -
94  1) /*subtract 1 to normal index*/
95  : 0 /*default to NW-FMC-PTA*/)
96  : 0) &
97  0x7)
98  << 4) // Choosing external clock source := 1-4 (front panel NIM-input A-D),
99  // 0 (NW-FMC-PTA clk source)
100 
101  ); // Choosing external := 1, internal := 0
102 
103  unsigned val =
104  (usingOptionalParams
105  ? (optionalLink.getNode("UseExternalClock").getValue<bool>() ? 1 : 0)
106  : 0) |
107  (((usingOptionalParams
108  ? (optionalLink.getNode("ExternalClockSource").getValue<unsigned int>()
109  ? (optionalLink.getNode("ExternalClockSource")
110  .getValue<unsigned int>() -
111  1) /*subtract 1 to normal index*/
112  : 0 /*default to NW-FMC-PTA*/)
113  : 0) &
114  0x7)
115  << 4);
116 
117  __CFG_COUT__ << "CHOOSING EXTERNAL CLOCK: " << usingOptionalParams << " : "
118  << optionalLink.getNode("UseExternalClock").getValue<bool>() << " : "
119  << optionalLink.getNode("ExternalClockSource").getValue<unsigned int>()
120  << std::hex << " : " << val << std::dec << std::endl;
121  ;
122  OtsUDPHardware::write(writeBuffer);
123  usleep(100000); // micro seconds
124 
125  { // debug read
126  // read NIM+ version (for debugging)
127  OtsUDPFirmwareCore::readAdvanced(writeBuffer,
128  0x5); // This can be removed when you want
129  OtsUDPHardware::read(writeBuffer,
130  readBuffer); // This can be removed when you want
131 
132  // read back clock lock loss status
133  OtsUDPFirmwareCore::readAdvanced(writeBuffer, 0x10);
134  OtsUDPHardware::read(writeBuffer, readQuadWord);
135  __CFG_COUT__ << "Clocks lock loss " << ((readQuadWord >> 24) & 0xF) << __E__;
136 
137  // if clock lock was lost at some point, reset DCMs here
138  // and check clock lock again
139  if(!((readQuadWord >> 24) & 0xF))
140  {
141  __CFG_COUT__ << "Re-locking clocks..." << std::endl;
142  // reset clock PLLs
143  OtsUDPFirmwareCore::writeAdvanced(
144  writeBuffer,
145  /*address*/ 0x999,
146  /*data*/ 0x7); // reset wiz0, wiz1, and nimDacClk
147  OtsUDPHardware::write(writeBuffer);
148  usleep(100000); // micro seconds
149  OtsUDPFirmwareCore::writeAdvanced(
150  writeBuffer, /*address*/ 0x999, /*data*/ 0); // unreset
151  OtsUDPHardware::write(writeBuffer);
152  usleep(100000); // micro seconds
153  OtsUDPFirmwareCore::writeAdvanced(
154  writeBuffer,
155  /*address*/ 0x999,
156  /*data*/ 0x8); // reset phase shift output clock
157  OtsUDPHardware::write(writeBuffer);
158  usleep(100000); // micro seconds
159  OtsUDPFirmwareCore::writeAdvanced(
160  writeBuffer, /*address*/ 0x999, /*data*/ 0); // unreset
161  OtsUDPHardware::write(writeBuffer);
162  usleep(100000); // micro seconds
163 
164  // read back clock lock loss status
165  OtsUDPFirmwareCore::readAdvanced(writeBuffer, 0x10);
166  OtsUDPHardware::read(writeBuffer, readQuadWord);
167  __CFG_COUT__ << "Clocks lock loss " << ((readQuadWord >> 24) & 0xF) << __E__;
168  }
169 
170  // read NIM+ version (for debugging)
171  OtsUDPFirmwareCore::readAdvanced(writeBuffer,
172  0x5); // This can be removed when you want
173  OtsUDPHardware::read(writeBuffer,
174  readBuffer); // This can be removed when you want
175  }
176 
177  // Run Configure Sequence Commands
178  // runSequenceOfCommands("LinkToConfigureSequence");
179 
180  // disable all 3 muxable trigger channels
181  // always do this to avoid stray output triggers during configure
182  if(1)
183  {
184  // addresses sig_norm and 2 veto channeling
185  // write 3 to disable and reset
186 
187  OtsUDPFirmwareCore::writeAdvanced(
188  writeBuffer, /*address*/ 0x4, /*data*/ 0x3); // disable sig norm
189  OtsUDPHardware::write(writeBuffer);
190 
191  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, 0x18016, 0x3); // disable cms1
192  OtsUDPHardware::write(writeBuffer);
193 
194  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, 0x18017, 0x3); // disable cms2
195  OtsUDPHardware::write(writeBuffer);
196 
197  OtsUDPFirmwareCore::writeAdvanced(
198  writeBuffer, 0x5, 0x0); // chA output mux to sig_norm
199  OtsUDPHardware::write(writeBuffer);
200 
201  OtsUDPFirmwareCore::writeAdvanced(
202  writeBuffer, 0x18013, 0x0); // chB output mux to sig_norm
203  OtsUDPHardware::write(writeBuffer);
204 
205  OtsUDPFirmwareCore::writeAdvanced(
206  writeBuffer, 0x18014, 0x0); // chC output mux to sig_norm
207  OtsUDPHardware::write(writeBuffer);
208 
209  OtsUDPFirmwareCore::writeAdvanced(
210  writeBuffer, 0x18015, 0x0); // chD output mux to sig_norm
211  OtsUDPHardware::write(writeBuffer);
212 
213  OtsUDPFirmwareCore::writeAdvanced(
214  writeBuffer, 0x1800C, 0xF); // setup output polarity
215  OtsUDPHardware::write(writeBuffer);
216 
217  sel_ctl_register_ = 0x0; // disable AND gate selection logic
218  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, 0x6, sel_ctl_register_);
219  OtsUDPHardware::write(writeBuffer);
220  }
221 
222  __CFG_COUT__ << "Initializing counter/sig-gen/acc-sync resets and enables." << __E__;
223  // Reset all the counters for configure
224  // Note: bit 6 which is acc_sync block reset)
225  // Note: bit 5 which is sig gen block reset)
226  nimEnables_.reset(); // set all bits to 0
227  nimResets_.set(); // set all bits to 1
228  nimResets_.reset(6); // do not reset acc sync block
229  OtsUDPFirmwareCore::writeAdvanced(
230  writeBuffer,
231  0x18000,
232  nimResets_.to_ulong()); // reset everything (counters and vetos/ps)
233  OtsUDPHardware::write(writeBuffer);
234  OtsUDPFirmwareCore::writeAdvanced(
235  writeBuffer, 0x18001, nimEnables_.to_ulong()); // disable everything
236  OtsUDPHardware::write(writeBuffer);
237 
238  nimResets_.reset(); // set all bits to 0
239  nimResets_.set(5); // hold sig gen in reset (only unreset if enabled)
240  OtsUDPFirmwareCore::writeAdvanced(
241  writeBuffer, 0x18000, nimResets_.to_ulong()); // unreset everything
242  OtsUDPHardware::write(writeBuffer);
243 
244  std::array<std::string, 4> channelNames(
245  {"ChannelA", "ChannelB", "ChannelC", "ChannelD"});
246  // set up DACs
247  bool doWriteDACs = false;
248  try
249  {
250  doWriteDACs =
251  usingOptionalParams &&
252  optionalLink.getNode("EnableDACSetupDuringConfigure").getValue<bool>();
253  }
254  catch(...)
255  {
256  __CFG_COUT__ << "Skipping DAC writing because enable field was not found in tree."
257  << std::endl;
258  }
259 
260  if(doWriteDACs) // works, but temporarily disabling
261  {
262  __CFG_COUT__ << "Setting up DACs" << std::endl;
263  const std::string dacValueField = "DACValue";
264  for(const auto& channelName : channelNames)
265  {
266  changeDACLevel(channelName,
267  optionalLink.getNode(dacValueField + channelName)
268  .getValue<unsigned short>());
269  }
270  }
271 
272  // setup sig_mod channels, the input delay and width stages and sig_log, and other
273  // pre-sig_norm things
274  try
275  {
276  unsigned char channelCount = 0;
277  bool invertPolarity;
278  //,selectRawInput;
279  // bool enableInput;
280  unsigned int logicInput;
281  uint64_t inputModMask;
282  unsigned int inputDelay;
283  unsigned int inputWidth;
284 
285  unsigned char inputPolarityMask = 0; // selectionRawInputMask = 0
286 
287  __CFG_COUT__ << "Setting up input channels..." << std::endl;
288  for(const auto& channelName : channelNames) // setup sig mod for each channel
289  {
290  // if(channelName != "ChannelD") { ++channelCount; continue;} //For Debugging
291  // just one channel
292 
293  // enableInput =
294  // theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode("EnableInput"
295  // + channelName).getValue<bool>();
296 
297  logicInput = theXDAQContextConfigTree_.getNode(theConfigurationPath_)
298  .getNode("LogicInput" + channelName)
299  .getValue<unsigned int>();
300  if(logicInput)
301  --logicInput; // handle non-default indexing
302  sel_ctl_register_ |= (logicInput & 0x3) << (channelCount * 2 + 8);
303  __CFG_COUT__ << "Logic input " << channelName << " : " << logicInput
304  << " => sel_ctl_register_= " << std::hex << sel_ctl_register_
305  << std::dec << std::endl;
306  if(usingOptionalParams)
307  {
308  inputDelay = optionalLink.getNode("DelayInput" + channelName)
309  .getValue<unsigned int>();
310  inputWidth = optionalLink.getNode("WidthInput" + channelName)
311  .getValue<unsigned int>();
312  inputModMask = (0xFFFFFFFFFFFFFFFF >> (64 - inputWidth)) << inputDelay;
313 
314  // selectRawInput = optionalLink.getNode("DoNotUseDelayAndWidthFor" +
315  // channelName).getValue<bool>();
316  }
317  else
318  {
319  inputModMask = 0x7; // b111 default value
320  // selectRawInput = false; //default to not raw input
321  }
322 
323  // selectionRawInputMask |= (selectRawInput << channelCount); //Note! Inverted
324  // relative to user input (default to sigmod as input, i.e. not raw input ys)
325 
326  invertPolarity = usingOptionalParams &&
327  optionalLink.getNode("InvertPolarityInput" + channelName)
328  .getValue<bool>();
329 
330  inputPolarityMask |= ((invertPolarity ? 1 : 0) << channelCount);
331 
332  __CFG_COUT__ << "Output word for " << channelName << " is "
333  << std::bitset<64>(inputModMask) << std::endl
334  << " with a delay of " << inputDelay << " and a width of "
335  << inputWidth << std::endl;
336 
337  OtsUDPFirmwareCore::writeAdvanced(writeBuffer,
338  /*address*/ ((channelCount + 1) << 8),
339  /*data*/ 0x3); // reset channel
340  OtsUDPHardware::write(writeBuffer);
341 
342  OtsUDPFirmwareCore::writeAdvanced(
343  writeBuffer,
344  ((channelCount + 1) << 8) | 0x2,
345  inputModMask); // set sig_mod width and delay
346  OtsUDPHardware::write(writeBuffer);
347 
348  // OtsUDPFirmwareCore::writeAdvanced(writeBuffer, ((channelCount+1) << 8) |
349  // 0x4, enableInput?0:1); //enable/disable channel
350  // OtsUDPHardware::write(writeBuffer);
351 
352  ++channelCount;
353  }
354  __CFG_COUT__ << "Input polarity mask is " << std::bitset<8>(inputPolarityMask)
355  << std::endl;
356  OtsUDPFirmwareCore::writeAdvanced(
357  writeBuffer,
358  /*address*/ 0x1800B,
359  /*data*/ inputPolarityMask); // setup input polarity
360  OtsUDPHardware::write(writeBuffer);
361 
362  // sel_ctl_register_ |= (selectionRawInputMask << 4);
363  __CFG_COUT__ << " sel_ctl_register_: " << std::bitset<16>(sel_ctl_register_)
364  << std::endl;
365  OtsUDPFirmwareCore::writeAdvanced(
366  writeBuffer,
367  /*address*/ 0x6,
368  /*data*/ sel_ctl_register_); // setup raw input selection muxes, assume the
369  // logic_control_register was 0 before this.
370  // (cleared at start of configure)
371  OtsUDPHardware::write(writeBuffer);
372 
373  __CFG_COUT__ << "Writing 40 MHz clock delay." << __E__;
374  OtsUDPFirmwareCore::writeAdvanced(
375  writeBuffer,
376  0x107,
377  (usingOptionalParams
378  ? optionalLink.getNode("40MHzClockDelay").getValue<unsigned int>()
379  : 0)); // chooses a 40MHz clock phase relative to the accelerator clock
380  // (in increments of ~3ns)
381  OtsUDPHardware::write(writeBuffer);
382 
383  __CFG_COUT__ << "Writing clock mask setup." << __E__;
384  OtsUDPFirmwareCore::writeAdvanced(
385  writeBuffer,
386  0x18008,
387  //(1<<8) | //disable sig_log masking with 40MHz clock block
388  (usingOptionalParams
389  ? optionalLink.getNode("ClockMaskSetup").getValue<unsigned int>()
390  : 0)); // chooses a section of 40MHz clock
391  OtsUDPHardware::write(writeBuffer);
392 
393  // 40Mhz Clock Stuff - Update to reflect firmware changes
394  nimResets_.set(6);
395  OtsUDPFirmwareCore::writeAdvanced(
396  writeBuffer,
397  0x18000,
398  nimResets_.to_ulong()); // resets section of 40MHz clock block
399  OtsUDPHardware::write(writeBuffer);
400 
401  nimResets_.reset(6);
402  OtsUDPFirmwareCore::writeAdvanced(
403  writeBuffer,
404  0x18000,
405  nimResets_.to_ulong()); // enables a section of 40MHz clock block
406  OtsUDPHardware::write(writeBuffer);
407 
408  __CFG_COUT__ << "Clock mask setup: " << std::hex
409  << optionalLink.getNode("ClockMaskSetup").getValue<unsigned int>()
410  << std::dec << std::endl;
411  }
412  catch(const std::runtime_error& e)
413  {
414  __CFG_COUT__ << "Failed input stage setup!\n" << e.what() << std::endl;
415  throw;
416  }
417 
418  // setup output stage
419  try
420  {
421  unsigned char channelCount = 0;
422  bool enableOutput;
423  unsigned int outputDelay;
424  unsigned int outputWidthMask; // max is 64 bit mask
425  uint64_t outputWidth;
426  uint64_t outputModMask;
427 
428  unsigned int outputMuxSelect;
429  unsigned int outputChannelSourceSelect;
430  unsigned int outputTimeVetoDuration, outputPrescaleCount;
431  bool outputBackpressureSelect;
432  unsigned char backpressureMask = 0;
433  unsigned int gateChannelVetoSel[3] = {0, 0, 0};
434 
435  __CFG_COUT__ << "Setting up output channels..." << std::endl;
436  // there are 3 output channels (alias: signorm, sigcms1, sigcms2)
437  std::array<std::string, 3> outChannelNames = {"Channel0", "Channel1", "Channel2"};
438  for(const auto& channelName : outChannelNames)
439  {
440  outputChannelSourceSelect =
441  theXDAQContextConfigTree_.getNode(theConfigurationPath_)
442  .getNode("TriggerInput" + channelName)
443  .getValue<unsigned int>(); // 0: sig_log or 1: sig_norm/ch0
444  __CFG_COUT__ << "TriggerInput for " << channelName << " is "
445  << outputChannelSourceSelect << std::endl;
446  if(outputChannelSourceSelect) // if non-default, subtract 1 so choice 1
447  // evaluates to 0, and so on..
448  --outputChannelSourceSelect;
449 
450  if(usingOptionalParams)
451  {
452  outputDelay = optionalLink.getNode("DelayTriggerOutput" + channelName)
453  .getValue<unsigned int>();
454  outputWidth = optionalLink.getNode("WidthTriggerOutput" + channelName)
455  .getValue<uint64_t>();
456 
457  if(outputWidth != 0)
458  {
459  if(outputWidth > 64)
460  outputWidthMask = 64;
461  else
462  {
463  outputWidthMask = outputWidth;
464  outputWidth = 0;
465  }
466  outputModMask = (0xFFFFFFFFFFFFFFFF >> (64 - outputWidthMask))
467  << outputDelay;
468  }
469  else // outputWidth == 0
470  outputModMask = 0; // disables output!
471 
472  outputTimeVetoDuration =
473  optionalLink.getNode("TimeVetoTriggerOutput" + channelName)
474  .getValue<unsigned int>(); // 0 ignores time veto, units of 3ns
475  // (NIM+X) or 6ns (NIM+)
476  outputPrescaleCount =
477  optionalLink.getNode("PrescaleTriggerOutput" + channelName)
478  .getValue<unsigned int>();
479  outputBackpressureSelect =
480  optionalLink.getNode("BackpressureTriggerOutput" + channelName)
481  .getValue<bool>();
482  gateChannelVetoSel[channelCount] =
483  optionalLink.getNode("VetoSourceTriggerOutput" + channelName)
484  .getValue<int>();
485  __CFG_COUT__ << "Raw gateChannelVetoSelect for " << channelName << " is "
486  << gateChannelVetoSel[channelCount] << std::endl;
487  // 0/1 := No Veto, 2-5 := Input_A-D
488  }
489  else // defaults
490  {
491  outputModMask = 0xFFF;
492  outputWidth = 0;
493  outputTimeVetoDuration = 0;
494  outputPrescaleCount = 0;
495  outputBackpressureSelect = false;
496  }
497 
498  if(gateChannelVetoSel[channelCount] <= 1)
499  gateChannelVetoSel[channelCount] = 4; // Ground on mux
500  else
501  gateChannelVetoSel[channelCount] -= 2; // 0-3 on mux is chA-D
502 
503  backpressureMask |= (outputBackpressureSelect ? 1 : 0) << channelCount;
504 
505  OtsUDPFirmwareCore::writeAdvanced(
506  writeBuffer,
507  channelCount == 0 ? 0x4 : (0x18016 + channelCount - 1),
508  0x33); // reset output channel block (bits 4/5 are reseting ch1/2)
509  OtsUDPHardware::write(writeBuffer);
510 
511  OtsUDPFirmwareCore::writeAdvanced(
512  writeBuffer,
513  channelCount == 0 ? 0x2 : (0x18002 + channelCount - 1),
514  outputModMask); // set output channel width/delay mask
515  OtsUDPHardware::write(writeBuffer);
516 
517  OtsUDPFirmwareCore::writeAdvanced(
518  writeBuffer,
519  0x106 + channelCount * 0x100,
520  outputWidth | (uint64_t(outputWidth ? 1 : 0 /*enable*/)
521  << 63)); // set output channel long width count
522  OtsUDPHardware::write(writeBuffer);
523 
524  __CFG_COUT__ << "Output word for " << channelName << " is "
525  << std::bitset<64>(outputModMask) << std::endl;
526  __CFG_COUT__ << "Output delay of " << outputDelay
527  << " and an extended width of " << outputWidth << std::endl;
528 
529  if(channelCount)
530  {
531  writeBuffer.resize(0);
532  OtsUDPFirmwareCore::writeAdvanced(
533  writeBuffer,
534  (0x18018 + channelCount - 1),
535  outputChannelSourceSelect); // select source (1 := signorm, 0 :=
536  // siglog)
537  OtsUDPHardware::write(writeBuffer);
538  __CFG_COUT__ << "Output src select is " << outputChannelSourceSelect
539  << " for " << channelName << std::endl;
540  }
541 
542  // time veto setup
543  writeBuffer.resize(0);
544  OtsUDPFirmwareCore::writeAdvanced(
545  writeBuffer,
546  channelCount == 0 ? 0x1801B : (0x18011 + channelCount - 1),
547  outputTimeVetoDuration);
548  OtsUDPHardware::write(writeBuffer);
549 
550  __CFG_COUT__ << "Veto count for " << channelName << " is "
551  << outputTimeVetoDuration << " writing to ch "
552  << (channelCount == 0 ? 0x1801B : (0x18011 + channelCount - 1))
553  << std::endl;
554 
555  // prescale veto setup
556  writeBuffer.resize(0);
557  OtsUDPFirmwareCore::writeAdvanced(
558  writeBuffer, 0x1801C + channelCount, 0); // Set to 0, then set to value
559  OtsUDPHardware::write(writeBuffer);
560  writeBuffer.resize(0);
561  OtsUDPFirmwareCore::writeAdvanced(
562  writeBuffer, 0x1801C + channelCount, outputPrescaleCount);
563  OtsUDPHardware::write(writeBuffer);
564 
565  __CFG_COUT__ << "Prescaler count for " << channelName << " is "
566  << outputPrescaleCount << " writing to ch "
567  << 0x1801C + channelCount << std::endl;
568 
569  ++channelCount;
570  }
571 
572  // backpressure select
573  // bit 0, 1, 2 mean apply backpressure to that output channel
574  // 2 external backpressure inputs
575  // bit 3 is 0/1 disable/enable for first input
576  // bit 4 is 0/1 disable/enable for second input
577  __CFG_COUT__ << "Backpressure Selecting..." << std::endl;
578  outputBackpressureSelect =
579  usingOptionalParams &&
580  optionalLink.getNode("EnableBackPressureNwFmcPta1").getValue<bool>();
581  backpressureMask |= outputBackpressureSelect << 3;
582  outputBackpressureSelect =
583  usingOptionalParams &&
584  optionalLink.getNode("EnableBackPressureNwFmcPta2").getValue<bool>();
585  backpressureMask |= outputBackpressureSelect << 4;
586  writeBuffer.resize(0);
587  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, 0x1801A, backpressureMask);
588  OtsUDPHardware::write(writeBuffer);
589 
590  // force output clk/trig bank to D by default
591  OtsUDPFirmwareCore::writeAdvanced(
592  writeBuffer, 0x200, (uint64_t)-1); // setup burst output mux select
593  OtsUDPHardware::write(writeBuffer);
594 
595  // and 4 output muxes (first is special)
596  __CFG_COUT__ << "Setting output muxes..." << std::endl;
597  unsigned int outputPolarityMask = 0;
598  bool outputInvertPolarity;
599  channelCount = 0;
600  for(const auto& channelName : channelNames)
601  {
602  outputMuxSelect = theXDAQContextConfigTree_.getNode(theConfigurationPath_)
603  .getNode("OutputMuxSelect" + channelName)
604  .getValue<unsigned int>();
605  if(outputMuxSelect)
606  --outputMuxSelect; // default is 0, the actual selection address for all
607  // other choices is 1 higher
608 
609  if(outputMuxSelect > 31)
610  {
611  __SS__;
612  throw std::runtime_error(ss.str() + "Invalid output mux select!");
613  }
614 
615  if(usingOptionalParams)
616  {
617  outputInvertPolarity =
618  usingOptionalParams &&
619  optionalLink.getNode("InvertPolarityOutput" + channelName)
620  .getValue<bool>();
621  outputPolarityMask |= ((outputInvertPolarity ? 1 : 0) << channelCount);
622  }
623  else
624  {
625  outputPolarityMask = 0xF;
626  }
627 
628  writeBuffer.resize(0);
629  OtsUDPFirmwareCore::writeAdvanced(
630  writeBuffer,
631  channelCount == 0 ? 0x5 : (0x18013 + channelCount - 1),
632  outputMuxSelect); // setup mux select
633  OtsUDPHardware::write(writeBuffer);
634  __CFG_COUT__ << "Mux value for output channel " << channelName << " is "
635  << outputMuxSelect << ", written to 0x" << std::hex
636  << (channelCount == 0 ? 0x5 : (0x18013 + channelCount - 1))
637  << std::dec << std::endl;
638 
639  ++channelCount;
640  }
641 
642  writeBuffer.resize(0);
643  OtsUDPFirmwareCore::writeAdvanced(
644  writeBuffer,
645  /*address*/ 0x1800C,
646  /*data*/ outputPolarityMask); // setup output polarity
647  OtsUDPHardware::write(writeBuffer);
648  __CFG_COUT__ << "Output polarity mask is " << std::bitset<8>(outputPolarityMask)
649  << std::endl;
650 
651  // setting up trigger/clk output banks A and B
652  if(usingOptionalParams)
653  {
654  // trigger/clock output banks are controlled by a single
655  // 64-bit register at address 0x200
656  //
657  // there are 12x 53MHz trigger channels
658  // and 6x 40MHz trigger channels
659  //
660  // ..each controlled by 2 bits to choose mux output channels 0-3
661  //
662  // this is a total of 18*2=36 control bits.. so 0 to 35 are used
663  //
664  // In the configuration, we organize by how the panel was assuembled
665  // which is two banks of 9 like so:
666  // * 0-5 are 53MHz
667  // * 6-8 are 40MHz
668 
669  uint64_t trigClkOutBankRegister = 0;
670  unsigned int bank = 0;
671 
672  std::array<std::string, 2> trigClkOutBankNames = {
673  "TriggerMuxSelectionsBankA", "TriggerMuxSelectionsBankB"};
674  for(auto& trigClkOutBankName : trigClkOutBankNames)
675  {
676  __COUTV__(trigClkOutBankName);
677 
678  ConfigurationTree::BitMap bankSelectionMap =
679  optionalLink.getNode(trigClkOutBankName).getValueAsBitMap();
680 
681  // 0-5 are 53MHz
682  // 6-8 are 40MHz
683 
684  unsigned int col = 0;
685  for(; col < 6; ++col)
686  trigClkOutBankRegister |=
687  (bankSelectionMap.get(0, col) & 0x3)
688  << ((bank * 6 + col) *
689  2); // put the two bit mux selection in the right place
690 
691  for(; col < 9; ++col)
692  trigClkOutBankRegister |=
693  (bankSelectionMap.get(0, col) & 0x3)
694  << ((12 + bank * 3 + col) *
695  2); // put the two bit mux selection in the right place
696 
697  ++bank;
698  }
699 
700  OtsUDPFirmwareCore::writeAdvanced(
701  writeBuffer,
702  0x200,
703  trigClkOutBankRegister); // setup burst output mux select
704  OtsUDPHardware::write(writeBuffer);
705  }
706 
707  // setup burst data blocks
708  {
709  __CFG_COUT__ << "Setting up Burst Data Blocks" << std::endl;
710 
711  unsigned int logicSampleDelay = 0;
712  unsigned int gateChannel = 0;
713  unsigned int gateChannelReg =
714  (gateChannelVetoSel[2] << 8) | (gateChannelVetoSel[1] << 4) |
715  (gateChannelVetoSel[0] << 0); // nibbles ... 3:= delta-time, 2:= out-ch2,
716  // 1:= out-ch1, 0 := out-ch0
717  __CFG_COUT__ << "Gate Ch Veto Selections - 2: " << gateChannelVetoSel[2]
718  << std::endl;
719  __CFG_COUT__ << "Gate Ch Veto Selections - 1: " << gateChannelVetoSel[1]
720  << std::endl;
721  __CFG_COUT__ << "Gate Ch Veto Selections - 0: " << gateChannelVetoSel[0]
722  << std::endl;
723  // value of 4 is no-gate
724  // 0-3 are input channels A-D depending on polarity
725 
726  if(usingOptionalParams)
727  {
728  outputMuxSelect =
729  optionalLink.getNode("BurstDataMuxSelect").getValue<unsigned int>();
730  logicSampleDelay = optionalLink.getNode("BurstDataLogicSampleDelay")
731  .getValue<unsigned int>();
732  gateChannel = optionalLink.getNode("BurstDataGateInputChannel")
733  .getValue<unsigned int>();
734  }
735  else
736  outputMuxSelect = 0;
737 
738  if(outputMuxSelect) // if non-default, subtract 1 so choice 1 evaluates to 0,
739  // and so on..
740  --outputMuxSelect;
741 
742  if(gateChannel >
743  1) // if non-default, subtract 1 so choice 1 evaluates to 0, and so on..
744  {
745  gateChannel -= 2; // to give range 0 to 3
746  gateChannelReg |= gateChannel << 12;
747  }
748  else // default is no gate
749  {
750  gateChannelReg |= 4 << 12;
751  }
752  __CFG_COUT__ << "Gate Ch Veto Selections - Burst: " << gateChannel
753  << std::endl;
754  std::bitset<16> gateChannelRegBitset(gateChannelReg);
755  __CFG_COUT__ << "Gate Ch Veto Register: " << gateChannelReg << std::endl;
756  __CFG_COUT__ << "Gate Ch Veto Register: " << gateChannelRegBitset.to_string()
757  << std::endl;
758 
759  OtsUDPFirmwareCore::writeAdvanced(
760  writeBuffer, 0x1800E, outputMuxSelect); // setup burst output mux select
761  OtsUDPHardware::write(writeBuffer);
762 
763  OtsUDPFirmwareCore::writeAdvanced(
764  writeBuffer,
765  0x18010,
766  logicSampleDelay); // setup burst logic sample delay
767  OtsUDPHardware::write(writeBuffer);
768 
769  OtsUDPFirmwareCore::writeAdvanced(
770  writeBuffer,
771  0x18004,
772  gateChannelReg); // setup burst block gate signal choice
773  OtsUDPHardware::write(writeBuffer);
774 
775  if(outputMuxSelect == 1)
776  { // enable timestamp counter if using the scope
777  OtsUDPFirmwareCore::writeAdvanced(
778  writeBuffer, 0x1800F, 0x2); // Enable Timestamp counter for scope
779  OtsUDPHardware::write(writeBuffer);
780  }
781  else
782  {
783  OtsUDPFirmwareCore::writeAdvanced(
784  writeBuffer, 0x1800F, 0); // Enable Timestamp counter for scope
785  OtsUDPHardware::write(writeBuffer);
786  }
787  }
788 
789  // selection logic setup
790  unsigned int coincidenceLogicWord =
791  theXDAQContextConfigTree_.getNode(theConfigurationPath_)
792  .getNode("CoincidenceLogicWord")
793  .getValue<unsigned int>();
794 
795  sel_ctl_register_ |= 1; // reset selection logic (i.e. bit-0 <= 1)
796  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, 0x6, sel_ctl_register_);
797  OtsUDPHardware::write(writeBuffer);
798  __CFG_COUT__ << " sel_ctl_register_ 1: " << std::bitset<16>(sel_ctl_register_)
799  << std::endl;
800 
801  sel_ctl_register_ &=
802  ~(3); // disable selection logic, take out of reset (i.e. bits 0 and 1 <= 0)
803  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, 0x6, sel_ctl_register_);
804  OtsUDPHardware::write(writeBuffer);
805  __CFG_COUT__ << " sel_ctl_register_ 2: " << std::bitset<16>(sel_ctl_register_)
806  << std::endl;
807 
808  OtsUDPFirmwareCore::writeAdvanced(
809  writeBuffer, 0x7, coincidenceLogicWord); // setup selection logic
810  OtsUDPHardware::write(writeBuffer);
811  __CFG_COUT__ << "Selection Logic word is bit: "
812  << std::bitset<16>(coincidenceLogicWord) << std::endl;
813  //__CFG_COUT__ << "Selection Logic word is int: " << coincidenceLogicWord <<
814  // std::endl;
815 
816  // NOTE: Consider commenting this out and NOT enabling sig_log during configure
817  // (wait until running)
818  sel_ctl_register_ |= 1 << 1; // renable selection logic (i.e. bit-1 <= 1)
819  OtsUDPFirmwareCore::writeAdvanced(
820  writeBuffer, 0x6, sel_ctl_register_); // re-enable selection logic
821  OtsUDPHardware::write(writeBuffer);
822  __CFG_COUT__ << " sel_ctl_register_: 3" << std::bitset<16>(sel_ctl_register_)
823  << std::endl;
824 
825  unsigned int sigGenCount =
826  optionalLink.getNode("SignalGeneratorPulseCount").getValue<unsigned int>();
827  unsigned int sigGenHighPer =
828  optionalLink.getNode("SignalGeneratorHighPeriod").getValue<unsigned int>();
829  unsigned int sigGenLowPer =
830  optionalLink.getNode("SignalGeneratorLowPeriod").getValue<unsigned int>();
831  bool sigGenPolarity =
832  optionalLink.getNode("SignalGeneratorInvertPolarity").getValue<bool>();
833  unsigned int sigGenPolarityMask = (sigGenPolarity ? 1 : 0);
834 
835  if(optionalLink.getNode("SignalGeneratorEnable").getValue<bool>())
836  {
837  nimResets_.set(5); // set bit 5 in resets to 1 to force a sig gen reset)
838  OtsUDPFirmwareCore::writeAdvanced(
839  writeBuffer, 0x18000, nimResets_.to_ulong()); // reset sig gen
840  OtsUDPHardware::write(writeBuffer);
841 
842  __CFG_COUT__ << "Resets all for sig gen!" << std::endl;
843 
844  // signal generator setup
845  writeBuffer.resize(0);
846  OtsUDPFirmwareCore::writeAdvanced(
847  writeBuffer, 0x18005, sigGenCount); // sig gen pulse count
848  OtsUDPHardware::write(writeBuffer);
849  writeBuffer.resize(0);
850  OtsUDPFirmwareCore::writeAdvanced(
851  writeBuffer, 0x18006, sigGenHighPer); // sig gen high per
852  OtsUDPHardware::write(writeBuffer);
853  writeBuffer.resize(0);
854  OtsUDPFirmwareCore::writeAdvanced(
855  writeBuffer, 0x18007, sigGenLowPer); // sig gen low per
856  OtsUDPHardware::write(writeBuffer);
857  writeBuffer.resize(0);
858  OtsUDPFirmwareCore::writeAdvanced(
859  writeBuffer, 0x1800D, sigGenPolarityMask); // sig gen polarity
860  OtsUDPHardware::write(writeBuffer);
861 
862  __CFG_COUT__ << "Configured signal generator with a count of " << sigGenCount
863  << " (0 is continuous output), a high period of "
864  << sigGenHighPer << ", a low period of " << sigGenLowPer
865  << ", and output inversion set to " << sigGenPolarity
866  << std::endl;
867 
868  nimResets_.reset(5); // reset bit 5 in resets to 0 to unreset sig gen
869  nimEnables_.set(5); // set bit 5 in enables to 1 to enable sig gen
870  }
871  else
872  {
873  nimResets_.set(
874  5); // set bit 5 in resets to 1 to make sure sig gen is held in reset
875  nimEnables_.reset(5); // set bit 5 in enables to 0 to disable sig gen
876  __CFG_COUT__ << "Signal Generator disabled" << std::endl;
877  }
878 
879  OtsUDPFirmwareCore::writeAdvanced(
880  writeBuffer,
881  0x18000,
882  nimResets_.to_ulong()); // set sig gen in or out of reset
883  OtsUDPHardware::write(writeBuffer);
884  __CFG_COUT__ << "Nim Resets (after sig gen setup) set to " << nimResets_
885  << std::endl;
886 
887  OtsUDPFirmwareCore::writeAdvanced(
888  writeBuffer, 0x18001, nimEnables_.to_ulong()); // enable or disable sig gen
889  OtsUDPHardware::write(writeBuffer);
890  __CFG_COUT__ << "Nim Enables (after sig gen setup) set to " << nimEnables_
891  << std::endl;
892  }
893  catch(const std::runtime_error& e)
894  {
895  __CFG_COUT__ << "Failed output stage setup!\n" << e.what() << std::endl;
896  throw;
897  }
898 
899  __CFG_COUT__ << "Checking sel_ctl_register_... Expect sel_ctl_register_ = 0x"
900  << std::hex << sel_ctl_register_ << std::dec << std::endl;
901 
902  // now that configure done, save sel_ctl_register_ for later
903  OtsUDPFirmwareCore::readAdvanced(writeBuffer, 10 /*address*/); // read back sig log
904 
905  // uint64_t readback;
906  // OtsUDPHardware::read(writeBuffer,readback);
907  // sel_ctl_register_ &= 0xffffffff00000000;
908  // sel_ctl_register_ += readback;
909  //__CFG_COUT__ << "receiveQuadWord all = 0x" << std::hex <<
910  // sel_ctl_register_ << std::dec << std::endl;
911 
912  // sel_ctl_register_ = ((sel_ctl_register_>>(5*8))&0x0FF);
913 
914  __CFG_COUT__ << "sel_ctl_register_ = 0x" << std::hex << sel_ctl_register_ << std::dec
915  << std::endl;
916 
917  // at this point sig_log should be active (for chipscope, and recognizing of trigger
918  // input active)
919 
920  __CFG_COUT__ << " sel_ctl_register_: " << std::bitset<16>(sel_ctl_register_)
921  << std::endl;
922 
923  __CFG_COUT__ << "Done with configuring." << std::endl;
924 } // end configure()
925 
926 //========================================================================================================================
927 void FENIMPlusInterface::halt(void)
928 {
929  __CFG_COUT__ << "\tHalt" << std::endl;
930  stop();
931 }
932 
933 //========================================================================================================================
934 void FENIMPlusInterface::pause(void)
935 {
936  __CFG_COUT__ << "\tPause" << std::endl;
937  stop();
938 }
939 
940 //========================================================================================================================
941 void FENIMPlusInterface::resume(void)
942 {
943  __CFG_COUT__ << "\tResume" << std::endl;
944  start("");
945 }
946 
947 //========================================================================================================================
948 void FENIMPlusInterface::start(std::string runNumber)
949 {
950  runNumber_ = runNumber;
951  __CFG_COUT__ << "\tStart " << runNumber_ << std::endl;
952  std::string writeBuffer;
953 
954  // Run Start Sequence Commands
955  // runSequenceOfCommands("LinkToStartSequence");
956 
957  __CFG_COUT__ << "Disabling sig_log" << std::endl;
958  OtsUDPFirmwareCore::writeAdvanced(
959  writeBuffer,
960  0x6,
961  (sel_ctl_register_) & (~(1 << 1))); // disable siglog block
962  OtsUDPHardware::write(writeBuffer);
963 
964  __CFG_COUT__ << "Resetting all counters (including sig log)" << std::endl;
965  // 0x18000 ==> counter resets
966  nimResets_.set(); // set all bits to 1
967  nimResets_.reset(6); // do not reset acc sync block
968  nimResets_.reset(5); // do not reset sig gen block
969  OtsUDPFirmwareCore::writeAdvanced(
970  writeBuffer, 0x18000, nimResets_.to_ulong()); // reset everything (counters, e.g.
971  // sig_log and sig_norm/cms1/cms2
972  // counters, and vetos/ps)
973  OtsUDPHardware::write(writeBuffer);
974 
975  nimResets_.reset(); // reset all bits to 0
976  OtsUDPFirmwareCore::writeAdvanced(
977  writeBuffer,
978  0x18000, // address,
979  nimResets_.to_ulong()); // unreset sig_log and sig_norm/cms1/cms2 counters
980  OtsUDPHardware::write(writeBuffer);
981 
982  ConfigurationTree optionalLink =
983  theXDAQContextConfigTree_.getNode(theConfigurationPath_)
984  .getNode("LinkToOptionalParameters");
985  bool usingOptionalParams = !optionalLink.isDisconnected();
986 
987  if(usingOptionalParams && optionalLink.getNode("EnableBurstData").getValue<bool>())
988  {
989  __CFG_COUT__ << "Enabling burst mode!" << __E__;
990  OtsUDPFirmwareCore::startBurst(writeBuffer);
991  OtsUDPHardware::write(writeBuffer);
992  }
993 
994  // enable nim plus burst data
995  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, /*address*/ 0x1801F, /*data*/ 0x6);
996  OtsUDPHardware::write(writeBuffer);
997  __CFG_COUT__ << "\tStart Done" << std::endl;
998 }
999 
1000 //========================================================================================================================
1001 void FENIMPlusInterface::stop(void)
1002 {
1003  std::string writeBuffer;
1004  // immediately stop triggers (by disabling sig log)
1005  OtsUDPFirmwareCore::writeAdvanced(
1006  writeBuffer,
1007  0x6 /*address*/,
1008  (sel_ctl_register_) & (~(1 << 1))); // disable siglog block
1009  OtsUDPHardware::write(writeBuffer);
1010 
1011  __CFG_COUT__ << "\tStop" << std::endl;
1012 
1013  // Run Stop Sequence Commands
1014  runSequenceOfCommands("LinkToStopSequence");
1015 
1016  // attempt to stop burst always
1017  OtsUDPFirmwareCore::stopBurst(writeBuffer);
1018  OtsUDPHardware::write(writeBuffer);
1019 
1020  uint64_t readQuadWord;
1021 
1022  ConfigurationTree optionalLink =
1023  theXDAQContextConfigTree_.getNode(theConfigurationPath_)
1024  .getNode("LinkToOptionalParameters");
1025  if(!optionalLink.isDisconnected())
1026  {
1027  std::string
1028  filename = // theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode(
1029  optionalLink.getNode("TriggerCountAtRunStopFilename").getValue<std::string>();
1030 
1031  if(filename != "DEFAULT" && filename != "")
1032  {
1033  std::string filename = optionalLink.getNode("TriggerCountAtRunStopFilename")
1034  .getValue<std::string>();
1035 
1036  if(filename != "DEFAULT" && filename != "")
1037  {
1038  filename += "_" + runNumber_ + ".cnt";
1039 
1040  __CFG_COUT__ << "Attempting to save counts to " << filename << __E__;
1041  FILE* fp =
1042  fopen( //("/data/TestBeam/2017_12_December/NimPlus/TriggerCount_" +
1043  // runNumber_ + ".cnt").c_str()
1044  filename.c_str(),
1045  "w");
1046  if(fp)
1047  {
1048  __CFG_COUT__ << "Saving counts to " << filename << __E__;
1049  // std::string readBuffer;
1050 
1051  uint32_t count;
1052  uint8_t tag;
1053 
1054  OtsUDPFirmwareCore::readAdvanced(writeBuffer, 0x102);
1055  OtsUDPHardware::read(writeBuffer, readQuadWord);
1056 
1057  count = (readQuadWord >> 32);
1058  tag = count >> 28; // top 4 bits
1059  count = (count & 0x0FFFFFFF); // only 28 bits
1060  __CFG_COUT__ << "sig_log count = " << count << __E__;
1061  fprintf(fp, "sig_log \t [tag=%d] %d 0x%4.4X\n", tag, count, count);
1062 
1063  count = (readQuadWord & 0x0FFFFFFFF);
1064  tag = count >> 28; // top 4 bits
1065  count = (count & 0x0FFFFFFF); // only 28 bits
1066  __CFG_COUT__ << "sig_norm(out0) count = " << count << __E__;
1067  fprintf(
1068  fp, "sig_norm(out0) \t [tag=%d] %d 0x%4.4X\n", tag, count, count);
1069 
1070  OtsUDPFirmwareCore::readAdvanced(writeBuffer, 0x100);
1071  OtsUDPHardware::read(writeBuffer, readQuadWord);
1072 
1073  count = (readQuadWord & 0x0FFFFFFFF);
1074  tag = count >> 28; // top 4 bits
1075  count = (count & 0x0FFFFFFF); // only 28 bits
1076  __CFG_COUT__ << "sig_cms1(out1) count = " << count << __E__;
1077  fprintf(
1078  fp, "sig_cms1(out1) \t [tag=%d] %d 0x%4.4X\n", tag, count, count);
1079 
1080  count = (readQuadWord >> 32);
1081  tag = count >> 28; // top 4 bits
1082  count = (count & 0x0FFFFFFF); // only 28 bits
1083  __CFG_COUT__ << "sig_cms2(out2) count = " << count << __E__;
1084  fprintf(
1085  fp, "sig_cms2(out2) \t [tag=%d] %d 0x%4.4X\n", tag, count, count);
1086 
1087  OtsUDPFirmwareCore::readAdvanced(writeBuffer, 0x105);
1088  OtsUDPHardware::read(writeBuffer, readQuadWord);
1089 
1090  count = (readQuadWord & 0x0FFFFFFFF);
1091  tag = count >> 28; // top 4 bits
1092  count = (count & 0x0FFFFFFF); // only 28 bits
1093  __CFG_COUT__ << "muxout-A count = " << count << __E__;
1094  fprintf(fp, "muxout-A \t [tag=%d] %d 0x%4.4X\n", tag, count, count);
1095 
1096  count = (readQuadWord >> 32);
1097  tag = count >> 28; // top 4 bits
1098  count = (count & 0x0FFFFFFF); // only 28 bits
1099  __CFG_COUT__ << "muxout-B count = " << count << __E__;
1100  fprintf(fp, "muxout-B \t [tag=%d] %d 0x%4.4X\n", tag, count, count);
1101 
1102  OtsUDPFirmwareCore::readAdvanced(writeBuffer, 0x106);
1103  OtsUDPHardware::read(writeBuffer, readQuadWord);
1104 
1105  count = (readQuadWord & 0x0FFFFFFFF);
1106  tag = count >> 28; // top 4 bits
1107  count = (count & 0x0FFFFFFF); // only 28 bits
1108  __CFG_COUT__ << "muxout-C count = " << count << __E__;
1109  fprintf(fp, "muxout-C \t [tag=%d] %d 0x%4.4X\n", tag, count, count);
1110 
1111  count = (readQuadWord >> 32);
1112  tag = count >> 28; // top 4 bits
1113  count = (count & 0x0FFFFFFF); // only 28 bits
1114  __CFG_COUT__ << "muxout-D count = " << count << __E__;
1115  fprintf(fp, "muxout-D \t [tag=%d] %d 0x%4.4X\n", tag, count, count);
1116 
1117  // check for clock loss
1118  OtsUDPFirmwareCore::readAdvanced(writeBuffer, 0x10);
1119  OtsUDPHardware::read(writeBuffer, readQuadWord);
1120 
1121  __CFG_COUT__ << "Clocks lock loss " << count << __E__;
1122 
1123  count = (((readQuadWord >> 24) & 0xF) >> 0) & 1;
1124  fprintf(
1125  fp, "DAC Clock-Lock-Loss \t %d 0x%4.4X\n", count, count);
1126  count = (((readQuadWord >> 24) & 0xF) >> 1) & 1;
1127  fprintf(
1128  fp, "Main Clock-Lock-Loss \t %d 0x%4.4X\n", count, count);
1129  count = (((readQuadWord >> 24) & 0xF) >> 2) & 1;
1130  fprintf(
1131  fp, "External Clock-Lock-Loss \t %d 0x%4.4X\n", count, count);
1132  count = (((readQuadWord >> 24) & 0xF) >> 3) & 1;
1133  fprintf(
1134  fp, "OutPhase Clock-Lock-Loss \t %d 0x%4.4X\n", count, count);
1135 
1136  fclose(fp);
1137  }
1138  }
1139  }
1140  }
1141 
1142  // there are 3 output channels (alias: signorm, sigcms1, sigcms2)
1143 
1144  writeBuffer.resize(0);
1145  OtsUDPFirmwareCore::writeAdvanced(
1146  writeBuffer, /*address*/ 0x4, /*data*/ 0x33); // only reset signorm 0x33);
1147  // //reset output channel blocks
1148  // synchronously
1149  OtsUDPHardware::write(writeBuffer);
1150 }
1151 
1152 //========================================================================================================================
1153 bool FENIMPlusInterface::running(void)
1154 {
1155  std::string writeBuffer;
1156 
1159  // long sleep so trigger numbers match
1160  // sleep(22);
1161  // sleep(1);
1162 
1163  __CFG_COUT__ << "Running" << std::endl;
1164  __CFG_COUT__ << " sel_ctl_register_: " << std::bitset<16>(sel_ctl_register_)
1165  << std::endl;
1166 
1167  // //example!
1168  // //play with array of 8 LEDs at address 0x1003
1169 
1170  ConfigurationTree optionalLink =
1171  theXDAQContextConfigTree_.getNode(theConfigurationPath_)
1172  .getNode("LinkToOptionalParameters");
1173  bool usingOptionalParams = !optionalLink.isDisconnected();
1174 
1175  // 0x0/0x8 to 0x4 to use edge detection
1176  try
1177  {
1178  unsigned int sleepSeconds = 0;
1179  if(usingOptionalParams)
1180  {
1181  try
1182  {
1183  sleepSeconds = optionalLink.getNode("SecondsDelayBeforeStartingTriggers")
1184  .getValue<unsigned int>();
1185  }
1186  catch(...)
1187  {
1188  __CFG_COUT__
1189  << "Ingore missing SecondsDelayBeforeStartingTriggers field..."
1190  << __E__;
1191  }
1192  }
1193 
1194  // if(!sleepSeconds) sleepSeconds = 22;
1195  __CFG_COUT__ << "Sleeping for " << sleepSeconds << " seconds..." << __E__;
1196  sleep(sleepSeconds);
1197 
1198  unsigned char channelCount = 0;
1199  bool enable40MHzMask;
1200  unsigned int gateChannelVetoSel;
1201 
1202  // there are 3 output channels (alias: signorm, sigcms1, sigcms2)
1203  std::array<std::string, 3> outChannelNames = {"Channel0", "Channel1", "Channel2"};
1204 
1205  __CFG_COUT__ << "Enabling output trigger channels!" << std::endl;
1206 
1207  // must do channel 0 last!! (synchronously enables all 3 channels)
1208  for(channelCount = 2; channelCount <= 2; --channelCount)
1209  {
1210  enable40MHzMask =
1211  usingOptionalParams && optionalLink
1212  .getNode("EnableClockMaskTriggerOutput" +
1213  outChannelNames[channelCount])
1214  .getValue<bool>();
1215  gateChannelVetoSel = usingOptionalParams
1216  ? optionalLink
1217  .getNode("VetoSourceTriggerOutput" +
1218  outChannelNames[channelCount])
1219  .getValue<int>()
1220  : 0;
1221 
1222  OtsUDPFirmwareCore::writeAdvanced(
1223  writeBuffer,
1224  channelCount == 0 ? 0x4 : (0x18016 + channelCount - 1),
1225  (enable40MHzMask ? 0x0 : 0x8) |
1226  (gateChannelVetoSel <= 1
1227  ? 0
1228  : (1 << 2))); // unreset output channel block
1229  OtsUDPHardware::write(writeBuffer);
1230  }
1231 
1232  __CFG_COUT__ << "Enabling siglog block!" << __E__;
1233  __CFG_COUT__ << " sel_ctl_register_: " << std::bitset<16>(sel_ctl_register_)
1234  << std::endl;
1235  OtsUDPFirmwareCore::writeAdvanced(
1236  writeBuffer,
1237  0x6,
1238  sel_ctl_register_); // enable sig mod block and
1239  // restore original register
1240  // value
1241  OtsUDPHardware::write(writeBuffer);
1242  }
1243  catch(const std::runtime_error& e)
1244  {
1245  __SS__ << "Failed start setup!\n" << e.what() << std::endl;
1246  __CFG_COUT_ERR__ << ss.str();
1247  throw std::runtime_error(ss.str());
1248  }
1249  return false;
1250 } // end running()
1251 
1253 // void FENIMPlusInterface::FEMacroGenerateTriggers(FEVInterface::frontEndMacroInArgs_t
1254 // argsIn, FEVInterface::frontEndMacroOutArgs_t argsOut)
1255 //{
1256 // __CFG_COUT__ << "FEMacroGenerateTriggers" << __E__;
1257 //
1258 // unsigned int numberOfTriggers =
1259 // FEVInterface::getFEMacroInputArgument<unsigned
1260 // int>(argsIn,"numberOfTriggers"); unsigned int clocksOfDelayBetweenTriggers =
1261 // FEVInterface::getFEMacroInputArgument<unsigned
1262 // int>(argsIn,"clocksOfDelayBetweenTriggers"); std::string& triggersWereLaunched =
1263 // FEVInterface::getFEMacroOutputArgument(argsOut,"triggersWereLaunched");
1264 //
1265 // unsigned int numberOfTriggersStr =
1266 // FEVInterface::getFEMacroInputArgument<std::string>(argsIn,"numberOfTriggers");
1267 //
1268 // __CFG_COUT__ << "numberOfTriggers " << numberOfTriggers << __E__;
1269 // __CFG_COUT__ << "numberOfTriggersStr " << numberOfTriggersStr << __E__;
1270 // __CFG_COUT__ << "clocksOfDelayBetweenTriggers " << clocksOfDelayBetweenTriggers <<
1271 //__E__;
1272 //
1273 //
1274 // //TODO launch triggers based on parameters...
1275 //
1276 //
1277 // __CFG_COUT__ << "triggersWereLaunched " << triggersWereLaunched << __E__;
1278 // triggersWereLaunched = "Done!";
1279 // __CFG_COUT__ << "triggersWereLaunched " << triggersWereLaunched << __E__;
1280 // FEVInterface::setFEMacroOutputArgument<unsigned int>(argsOut,"triggersWereLaunched",
1281 // 42.2f);
1282 // __CFG_COUT__ << "triggersWereLaunched " << triggersWereLaunched << __E__;
1283 //}
1284 
1285 //========================================================================================================================
1286 void FENIMPlusInterface::FEMacroGenerateTriggers(__ARGS__)
1287 {
1288  __CFG_COUT__ << "FEMacroGenerateTriggers" << __E__;
1289 
1290  unsigned int numberOfTriggers = __GET_ARG_IN__("numberOfTriggers", unsigned int);
1291  unsigned int signalHiDuration = __GET_ARG_IN__("signalHiDuration", unsigned int);
1292  unsigned int signalLoDuration = __GET_ARG_IN__("signalLoDuration", unsigned int);
1293  std::string& triggersWereLaunched =
1294  getFEMacroArgument(argsOut, "triggersWereLaunched");
1295  std::string numberOfTriggersStr = __GET_ARG_IN__("numberOfTriggers", std::string);
1296 
1297  __CFG_COUTV__(numberOfTriggers);
1298  __CFG_COUTV__(signalHiDuration);
1299  __CFG_COUTV__(signalLoDuration);
1300  __CFG_COUTV__(numberOfTriggersStr);
1301 
1302  // launch triggers based on parameters...
1303  {
1304  std::string writeBuffer;
1305 
1306  // clear bit 5 in 0x18001
1307  nimEnables_.reset(5);
1308  OtsUDPFirmwareCore::writeAdvanced(
1309  writeBuffer, 0x18001, nimEnables_.to_ulong()); // enable or disable sig gen
1310  OtsUDPHardware::write(writeBuffer);
1311  __CFG_COUT__ << "Nim Enables set to 0x" << std::hex << nimEnables_ << std::dec
1312  << std::endl;
1313 
1314  // 3 registers:
1315  // count 0x18005 (27:0)
1316  // hi_duration 0x18006 (27:0)
1317  // lo_duration 0x18007 (31:0)
1318 
1319  OtsUDPFirmwareCore::writeAdvanced(
1320  writeBuffer, 0x18005, nimEnables_.to_ulong()); // enable or disable sig gen
1321  OtsUDPHardware::write(writeBuffer);
1322  __CFG_COUT__ << "Nim Enables set to 0x" << std::hex << nimEnables_ << std::dec
1323  << std::endl;
1324 
1325  // Note: select input mux to sig gen
1326  // muxInputA 0x108 => 1
1327  // B, C, D are on same register shifted up by 3 bits.
1328 
1329  // set bit 5
1330  nimEnables_.set(5);
1331  OtsUDPFirmwareCore::writeAdvanced(
1332  writeBuffer, 0x18001, numberOfTriggers); // enable or disable sig gen
1333  OtsUDPHardware::write(writeBuffer);
1334  __CFG_COUT__ << "Nim Enables set to 0x" << std::hex << nimEnables_ << std::dec
1335  << std::endl;
1336  }
1337 
1338  __CFG_COUT__ << "triggersWereLaunched " << triggersWereLaunched << __E__;
1339  triggersWereLaunched = "Done!";
1340  __CFG_COUT__ << "triggersWereLaunched " << triggersWereLaunched << __E__;
1341  __SET_ARG_OUT__("triggersWereLaunched", 42.2f); //,unsigned int);
1342  __CFG_COUT__ << "triggersWereLaunched " << triggersWereLaunched << __E__;
1343  __SET_ARG_OUT__("triggersWereLaunched", 42.2f); //,float);
1344  __CFG_COUT__ << "triggersWereLaunched " << triggersWereLaunched << __E__;
1345 }
1346 
1347 //========================================================================================================================
1348 void FENIMPlusInterface::changeDACLevel(const std::string& channelName,
1349  unsigned int dacValue)
1350 {
1351  std::string writeBuffer;
1352  // 16 bit DAC value
1353  // - 15:12 channel := 2=A, 6=B, A=C, E=D
1354  // - 11:0 value := 0-3.3V
1355  std::map<std::string, unsigned int> channelNameToAddressMap;
1356  // channelNameToAddressMap["ChannelA"] = 0x6;
1357  // channelNameToAddressMap["ChannelB"] = 0xe;
1358  // channelNameToAddressMap["ChannelC"] = 0x2;
1359  // channelNameToAddressMap["ChannelD"] = 0xa;
1360 
1361  channelNameToAddressMap["ChannelA"] = 0x2;
1362  channelNameToAddressMap["ChannelB"] = 0x6;
1363  channelNameToAddressMap["ChannelC"] = 0x9;
1364  channelNameToAddressMap["ChannelD"] = 0xe;
1365  const std::string dacValueField = "DACValue";
1366  writeBuffer.resize(0);
1367  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, /*address*/ 0x1, /*data*/ 0x0);
1368  OtsUDPHardware::write(writeBuffer);
1369 
1370  // __CFG_COUT__ << "DAC NAME:-" << channelName
1371  // << "-has value: " << (int)dacValue
1372  // << std::hex << " hex: " << (unsigned int)dacValue
1373  // << " Writing: " << std::hex << (channelNameToAddressMap[channelName] <<
1374  // 12) | (dacValue & 0xFFF)
1375  // << " only register: " << channelNameToAddressMap[channelName]
1376  // << std::dec
1377  // << std::endl;
1378  writeBuffer.resize(0);
1379  OtsUDPFirmwareCore::writeAdvanced(
1380  writeBuffer,
1381  /*address*/ 0x0,
1382  /*data*/ (channelNameToAddressMap[channelName] << 12) | (dacValue & 0xFFF));
1383  OtsUDPHardware::write(writeBuffer);
1384 
1385  writeBuffer.resize(0);
1386  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, /*address*/ 0x1, /*data*/ 0x2);
1387  OtsUDPHardware::write(writeBuffer);
1388  writeBuffer.resize(0);
1389  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, /*address*/ 0x1, /*data*/ 0x0);
1390  OtsUDPHardware::write(writeBuffer);
1391  writeBuffer.resize(0);
1392  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, /*address*/ 0x1, /*data*/ 0x4);
1393  OtsUDPHardware::write(writeBuffer);
1394  writeBuffer.resize(0);
1395  OtsUDPFirmwareCore::writeAdvanced(writeBuffer, /*address*/ 0x1, /*data*/ 0x0);
1396  OtsUDPHardware::write(writeBuffer);
1397  // sleep(1); // give a little time to the slow DAC ASIC write
1398 }
1399 
1400 DEFINE_OTS_INTERFACE(FENIMPlusInterface)