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