otsdaq_components  v2_05_02_indev
FEOtsUDPProducerTemplateInterface_interface.cc
1 #include <iostream>
2 #include <set>
3 #include "otsdaq-components/FEInterfaces/FEOtsUDPProducerTemplateInterface.h"
4 #include "otsdaq/Macros/CoutMacros.h"
5 #include "otsdaq/Macros/InterfacePluginMacros.h"
6 #include "otsdaq/MessageFacility/MessageFacility.h"
7 
8 using namespace ots;
9 
10 //==============================================================================
11 FEOtsUDPProducerTemplateInterface::FEOtsUDPProducerTemplateInterface(
12  const std::string& interfaceUID,
13  const ConfigurationTree& theXDAQContextConfigTree,
14  const std::string& interfaceConfigurationPath)
15  : Socket(theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
16  .getNode("HostIPAddress")
17  .getValue<std::string>(),
18  theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
19  .getNode("HostPort")
20  .getValue<unsigned int>())
21  //, WorkLoop (interfaceUID + "-workloop")
22  , FEProducerVInterface(
23  interfaceUID, theXDAQContextConfigTree, interfaceConfigurationPath)
24  //, DataProducer ("supervisorID","bufferID","processorID",100/*bufferSize*/)
25  , OtsUDPHardware(theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
26  .getNode("InterfaceIPAddress")
27  .getValue<std::string>(),
28  theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
29  .getNode("InterfacePort")
30  .getValue<unsigned int>())
31  , OtsUDPFirmwareDataGen(theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
32  .getNode("FirmwareVersion")
33  .getValue<unsigned int>())
34 {
35  // registration of FEMacro 'varTest2' generated, Oct-11-2018 02:28:57, by 'admin'
36  // using MacroMaker.
37  FEVInterface::registerFEMacroFunction(
38  "varTest2", // feMacroName
39  static_cast<FEVInterface::frontEndMacroFunction_t>(
40  &FEOtsUDPProducerTemplateInterface::varTest2), // feMacroFunction
41  std::vector<std::string>{"myOtherArg"}, // namesOfInputArgs
42  std::vector<std::string>{"myArg", "outArg1"}, // namesOfOutputArgs
43  1); // requiredUserPermissions
44 
45  // registration of FEMacro 'varTest' generated, Oct-11-2018 11:36:28, by 'admin' using
46  // MacroMaker.
47  FEVInterface::registerFEMacroFunction(
48  "varTest", // feMacroName
49  static_cast<FEVInterface::frontEndMacroFunction_t>(
50  &FEOtsUDPProducerTemplateInterface::varTest), // feMacroFunction
51  std::vector<std::string>{"myOtherArg"}, // namesOfInputArgs
52  std::vector<std::string>{"myArg", "outArg1"}, // namesOfOutputArgs
53  1); // requiredUserPermissions
54 
55  universalAddressSize_ = 8;
56  universalDataSize_ = 8;
57 }
58 
59 //==============================================================================
60 FEOtsUDPProducerTemplateInterface::~FEOtsUDPProducerTemplateInterface(void) {}
61 
62 //==============================================================================
63 void FEOtsUDPProducerTemplateInterface::configure(void)
64 {
65  // unsigned int i = VStateMachine::getIterationIndex();
66  // unsigned int j = VStateMachine::getSubIterationIndex();
67  // if(i == 0 && j < 5)
68  // VStateMachine::indicateSubIterationWork();
69  // else if(i < 10)
70  // VStateMachine::indicateIterationWork();
71  //
72  // __FE_COUTV__(VStateMachine::getSubIterationIndex());
73  // __FE_COUTV__(VStateMachine::getSubIterationWork());
74  // __FE_COUTV__(VStateMachine::getIterationIndex());
75  // __FE_COUTV__(VStateMachine::getIterationWork());
76  //
77  // __FE_COUTV__(i);
78  // __FE_COUTV__(getInterfaceUID());
79  // switch(i)
80  // {
81  // case 1:
82  // if(getInterfaceUID() == "ExampleInterface0")
83  // {
84  // FEVInterface::sendToFrontEnd("ExampleInterface1","Hello1");
85  // FEVInterface::sendToFrontEnd("ExampleInterface1",4.3f);
86  // FEVInterface::sendToFrontEnd("ExampleInterface1",4);
87  // FEVInterface::sendToFrontEnd("ExampleInterface2","Hello2");
88  // FEVInterface::sendToFrontEnd("ExampleInterface2",4.6f);
89  // FEVInterface::sendToFrontEnd("ExampleInterface2",6);
90  // }
91  // break;
92  // case 2:
93  // if(getInterfaceUID() != "ExampleInterface0")
94  // {
95  // std::string a = FEVInterface::receiveFromFrontEnd("ExampleInterface0");
96  // double b = FEVInterface::receiveFromFrontEnd<double>("ExampleInterface0");
97  // unsigned short c =
98  // FEVInterface::receiveFromFrontEnd<unsigned
99  // short>("ExampleInterface0");
100  // __FE_COUTV__(a);
101  // __FE_COUTV__(b);
102  // __FE_COUTV__(c);
103  // }
104  // break;
105  // case 3:
106  // if(getInterfaceUID() == "ExampleInterface0")
107  // {
108  // std::vector<frontEndMacroArg_t> argsIn;
109  // __SET_ARG_IN__("myOtherArg",(unsigned int)5);
110  //
111  // std::vector<frontEndMacroArg_t> argsOut;
112  //
113  // __FE_COUTV__(StringMacros::vectorToString(argsIn));
114  //
115  // FEVInterface::runFrontEndMacro("ExampleInterface2","varTest2",
116  // argsIn,argsOut);
117  //
118  // __FE_COUTV__(StringMacros::vectorToString(argsOut));
119  // __FE_COUTV__(FEVInterface::getFEMacroArgument(
120  // argsOut,"outArg1"));
121  //
122  // {
123  // std::string a = FEVInterface::getFEMacroArgument(
124  // argsOut,"myArg");
125  // double b = getFEMacroArgumentValue<double>(
126  // argsOut,"outArg1");
127  // unsigned short c = getFEMacroArgumentValue<unsigned short>(
128  // argsOut,"outArg1");
129  // __FE_COUTV__(a);
130  // __FE_COUTV__(b);
131  // __FE_COUTV__(c);
132  // }
133  //
134  //
135  //
136  // FEVInterface::runFrontEndMacro("ExampleInterface1","varTest",
137  // argsIn,argsOut);
138  // __FE_COUTV__(StringMacros::vectorToString(argsOut));
139  //
140  // {
141  // std::string a = __GET_ARG_OUT__("myArg",std::string);
142  // double b = __GET_ARG_OUT__("outArg1",double);
143  // unsigned short c = __GET_ARG_OUT__("outArg1",unsigned short);
144  // __FE_COUTV__(a);
145  // __FE_COUTV__(b);
146  // __FE_COUTV__(c);
147  // }
148  // }
149  //
150  // break;
151  // default:;
152  // }
153  //
154  //
155  // return;
156 
157  __FE_COUT__ << "configure" << __E__;
158  __FE_COUT__ << "Clearing receive socket buffer: " << OtsUDPHardware::clearReadSocket()
159  << " packets cleared." << __E__;
160 
161  std::string sendBuffer;
162  std::string recvBuffer;
163  uint64_t readQuadWord;
164 
165  __FE_COUT__
166  << "Configuration Path Table: "
167  << theXDAQContextConfigTree_.getNode(theConfigurationPath_).getTableName() << "-v"
168  << theXDAQContextConfigTree_.getNode(theConfigurationPath_).getTableVersion()
169  << __E__;
170 
171  __FE_COUT__ << "Interface name: "
172  << theXDAQContextConfigTree_.getNode(theConfigurationPath_) << __E__;
173 
174  __FE_COUT__ << "Configured Firmware Version: "
175  << theXDAQContextConfigTree_.getNode(theConfigurationPath_)
176  .getNode("FirmwareVersion")
177  .getValue<unsigned int>()
178  << __E__;
179 
180  __FE_COUT__ << "Setting Destination IP: "
181  << theXDAQContextConfigTree_.getNode(theConfigurationPath_)
182  .getNode("StreamToIPAddress")
183  .getValue<std::string>()
184  << __E__;
185  __FE_COUT__ << "And Destination Port: "
186  << theXDAQContextConfigTree_.getNode(theConfigurationPath_)
187  .getNode("StreamToPort")
188  .getValue<unsigned int>()
189  << __E__;
190 
191  OtsUDPFirmwareCore::setDataDestination(
192  sendBuffer,
193  theXDAQContextConfigTree_.getNode(theConfigurationPath_)
194  .getNode("StreamToIPAddress")
195  .getValue<std::string>(),
196  theXDAQContextConfigTree_.getNode(theConfigurationPath_)
197  .getNode("StreamToPort")
198  .getValue<uint64_t>());
199  OtsUDPHardware::write(sendBuffer);
200 
201  __FE_COUT__ << "Reading back burst dest MAC/IP/Port: " << __E__;
202 
203  OtsUDPFirmwareCore::readDataDestinationMAC(sendBuffer);
204  OtsUDPHardware::read(sendBuffer, readQuadWord);
205 
206  OtsUDPFirmwareCore::readDataDestinationIP(sendBuffer);
207  OtsUDPHardware::read(sendBuffer, readQuadWord);
208 
209  OtsUDPFirmwareCore::readDataDestinationPort(sendBuffer);
210  OtsUDPHardware::read(sendBuffer, readQuadWord);
211 
212  OtsUDPFirmwareCore::readControlDestinationPort(sendBuffer);
213  OtsUDPHardware::read(sendBuffer, readQuadWord);
214 
215  // Run Configure Sequence Commands
216  FEVInterface::runSequenceOfCommands("LinkToConfigureSequence");
217 
218  __FE_COUT__ << "Done with ots Template configuring." << __E__;
219 }
220 
221 //==============================================================================
222 // void FEOtsUDPProducerTemplateInterface::configureDetector(const DACStream&
223 // theDACStream)
224 //{
225 // __FE_COUT__ << "\tconfigureDetector" << __E__;
226 //}
227 
228 //==============================================================================
229 void FEOtsUDPProducerTemplateInterface::halt(void)
230 {
231  __FE_COUT__ << "\tHalt" << __E__;
232  stop();
233 }
234 
235 //==============================================================================
236 void FEOtsUDPProducerTemplateInterface::pause(void)
237 {
238  __FE_COUT__ << "\tPause" << __E__;
239  stop();
240 }
241 
242 //==============================================================================
243 void FEOtsUDPProducerTemplateInterface::resume(void)
244 {
245  __FE_COUT__ << "\tResume" << __E__;
246  start("");
247 }
248 
249 //==============================================================================
250 void FEOtsUDPProducerTemplateInterface::start(std::string) // runNumber)
251 {
252  __FE_COUT__ << "\tStart" << __E__;
253 
254  // unsigned int i = VStateMachine::getIterationIndex();
255  // unsigned int j = VStateMachine::getSubIterationIndex();
256  // if(i == 0 && j < 5)
257  // VStateMachine::indicateSubIterationWork();
258  // else if(i < 10)
259  // VStateMachine::indicateIterationWork();
260  //
261  //
262  // __FE_COUTV__(VStateMachine::getSubIterationIndex());
263  // __FE_COUTV__(VStateMachine::getSubIterationWork());
264  // __FE_COUTV__(VStateMachine::getIterationIndex());
265  // __FE_COUTV__(VStateMachine::getIterationWork());
266  //
267  //
268  // return;
269 
270  // Run Start Sequence Commands
271  FEVInterface::runSequenceOfCommands("LinkToStartSequence");
272 
273  std::string sendBuffer;
274  OtsUDPFirmwareCore::startBurst(sendBuffer);
275  OtsUDPHardware::write(sendBuffer);
276 }
277 
278 //==============================================================================
279 void FEOtsUDPProducerTemplateInterface::stop(void)
280 {
281  __FE_COUT__ << "\tStop" << __E__;
282 
283  // Run Stop Sequence Commands
284 
285  FEVInterface::runSequenceOfCommands("LinkToStopSequence");
286 
287  std::string sendBuffer;
288  OtsUDPFirmwareCore::stopBurst(sendBuffer);
289  OtsUDPHardware::write(sendBuffer);
290 }
291 
292 //==============================================================================
293 bool FEOtsUDPProducerTemplateInterface::running(void)
294 {
295  __FE_COUT__ << "\tRunning" << __E__;
296 
297  //__SS__ << "?" << __E__; //test exceptions during running
298  //__SS_THROW__;
299 
300  int state = -1;
301  while (WorkLoop::continueWorkLoop_)
302  {
303  // while running
304  // play with the LEDs at address 0x1003
305 
306  ++state;
307  if (state < 8)
308  sleep(1);
309  else
310  {
311  // if(1 || getInterfaceUID() == "ExampleInterface1")
312  // {
313  // throw __OTS_SOFT_EXCEPTION__("Soft error here");
314  // }
315  // else
316  break;
317  }
318 
319  {
320  if (DataProducerBase::attachToEmptySubBuffer(dataP_, headerP_) < 0)
321  {
322  __CFG_COUT__ << "There are no available buffers! Retrying...after "
323  "waiting 10 milliseconds!"
324  << std::endl;
325  usleep(10000);
326  return true;
327  }
328 
329  if (1) // test data buffers
330  {
331  // sleep(1);
332  unsigned long long value = 0xB57321; // this is 8-bytes
333  std::string& buffer = *dataP_;
334  buffer.resize(8); // NOTE: this is inexpensive according to
335  // Lorenzo/documentation in C++11 (only increases size
336  // once and doesn't decrease size)
337  memcpy(
338  (void*)&buffer[0] /*dest*/, (void*)&value /*src*/, 8 /*numOfBytes*/);
339 
340  // size() and length() are equivalent
341  __CFG_COUT__ << "Writing to buffer " << buffer.size() << " bytes!"
342  << __E__;
343  __CFG_COUT__ << "Writing to buffer length " << buffer.length()
344  << " bytes!" << __E__;
345 
346  __CFG_COUT__ << "Buffer Data: "
347  << BinaryStringMacros::binaryNumberToHexString(buffer)
348  << __E__;
349 
350  __CFG_COUTV__(DataProcessor::theCircularBuffer_);
351 
352  __CFG_COUT__ << __E__;
353 
354  __CFG_COUT__ << __E__;
355 
356  DataProducerBase::setWrittenSubBuffer<
357  std::string,
358  std::map<std::string, std::string> >();
359  __CFG_COUT__ << __E__;
360  __CFG_COUTV__(DataProcessor::theCircularBuffer_);
361  }
362  }
363  if (0)
364  {
365  unsigned long long value = 0xA54321; // this is 8-bytes
366  std::string buffer;
367  buffer.resize(8); // NOTE: this is inexpensive according to
368  // Lorenzo/documentation in C++11 (only increases size once
369  // and doesn't decrease size)
370  memcpy((void*)&buffer[0] /*dest*/, (void*)&value /*src*/, 8 /*numOfBytes*/);
371 
372  // size() and length() are equivalent
373  __FE_COUT__ << "Writing to buffer " << buffer.size() << " bytes!" << __E__;
374  __FE_COUT__ << "Writing to buffer length " << buffer.length() << " bytes!"
375  << __E__;
376 
377  __FE_COUT__ << "Buffer Data: "
378  << BinaryStringMacros::binaryNumberToHexString(buffer) << __E__;
379 
380  FEProducerVInterface::copyToNextBuffer(buffer);
381  }
382  }
383 
384  // //example!
385  // //play with array of 8 LEDs at address 0x1003
386 
387  //
388  // bool flashLEDsWhileRunning = false;
389  // if(flashLEDsWhileRunning)
390  // {
391  // std::string writeBuffer;
392  // int state = -1;
393  // while(WorkLoop::continueWorkLoop_)
394  // {
395  // //while running
396  // //play with the LEDs at address 0x1003
397  //
398  // ++state;
399  // if(state < 8)
400  // {
401  // writeBuffer.resize(0);
402  // OtsUDPFirmwareCore::write(writeBuffer, 0x1003,1<<state);
403  // OtsUDPHardware::write(writeBuffer);
404  // }
405  // else if(state%2 == 1 && state < 11)
406  // {
407  // writeBuffer.resize(0);
408  // OtsUDPFirmwareCore::write(writeBuffer, 0x1003, 0xFF);
409  // OtsUDPHardware::write(writeBuffer);
410  // }
411  // else if(state%2 == 0 && state < 11)
412  // {
413  // writeBuffer.resize(0);
414  // OtsUDPFirmwareCore::write(writeBuffer, 0x1003,0);
415  // OtsUDPHardware::write(writeBuffer);
416  // }
417  // else
418  // state = -1;
419  //
420  // sleep(1);
421  // }
422  // }
423 
424  return false;
425 }
426 
427 //==============================================================================
428 // NOTE: buffer for address must be at least size universalAddressSize_
429 // NOTE: buffer for returnValue must be max UDP size to handle return possibility
430 void ots::FEOtsUDPProducerTemplateInterface::universalRead(char* address,
431  char* returnValue)
432 {
433  __FE_COUT__ << "address size " << universalAddressSize_ << __E__;
434 
435  __FE_COUT__ << "Request: ";
436  for (unsigned int i = 0; i < universalAddressSize_; ++i)
437  printf("%2.2X", (unsigned char)address[i]);
438  std::cout << __E__;
439 
440  std::string readBuffer, sendBuffer;
441  OtsUDPFirmwareCore::readAdvanced(sendBuffer, address, 1 /*size*/);
442 
443  OtsUDPHardware::read(sendBuffer, readBuffer); // data reply
444 
445  __FE_COUT__ << "Result SIZE: " << readBuffer.size() << __E__;
446  std::memcpy(returnValue, readBuffer.substr(2).c_str(), universalDataSize_);
447 } // end universalRead()
448 
449 //==============================================================================
450 // NOTE: buffer for address must be at least size universalAddressSize_
451 // NOTE: buffer for writeValue must be at least size universalDataSize_
452 void ots::FEOtsUDPProducerTemplateInterface::universalWrite(char* address,
453  char* writeValue)
454 {
455  __FE_COUT__ << "address size " << universalAddressSize_ << __E__;
456  __FE_COUT__ << "data size " << universalDataSize_ << __E__;
457  __FE_COUT__ << "Sending: ";
458  for (unsigned int i = 0; i < universalAddressSize_; ++i)
459  printf("%2.2X", (unsigned char)address[i]);
460  std::cout << __E__;
461 
462  std::string sendBuffer;
463  OtsUDPFirmwareCore::writeAdvanced(sendBuffer, address, writeValue, 1 /*size*/);
464  OtsUDPHardware::write(sendBuffer); // data request
465 } // end universalWrite()
466 
467 //==============================================================================
468 // varTest
469 // FEMacro 'varTest' generated, Oct-11-2018 11:36:28, by 'admin' using MacroMaker.
470 // Macro Notes: This is a great test!
471 void FEOtsUDPProducerTemplateInterface::varTest(__ARGS__)
472 {
473  __FE_COUT__ << "# of input args = " << argsIn.size() << __E__;
474  __FE_COUT__ << "# of output args = " << argsOut.size() << __E__;
475  for (auto& argIn : argsIn)
476  __FE_COUT__ << argIn.first << ": " << argIn.second << __E__;
477 
478  // macro commands section
479  {
480  char* address = new char[universalAddressSize_] {
481  0}; //create address buffer of interface size and init to all 0
482  char* data = new char[universalDataSize_] {
483  0}; //create data buffer of interface size and init to all 0
484  uint64_t macroAddress; // create macro address buffer (size 8 bytes)
485  //uint64_t macroData; // create macro address buffer (size 8 bytes)
486  std::map<std::string /*arg name*/, uint64_t /*arg val*/>
487  macroArgs; // create map from arg name to 64-bit number
488 
489  // command-#0: Read(0x1002 /*address*/,myArg /*data*/);
490  macroAddress = 0x1002;
491  memcpy(address, &macroAddress, 8); // copy macro address to buffer
492  universalRead(address, data);
493  memcpy(&macroArgs["myArg"], data, 8); // copy buffer to argument map
494  __SET_ARG_OUT__("myArg", macroArgs["myArg"]); // update output argument result
495 
496  // command-#1: Read(0x1001 /*address*/,data);
497  macroAddress = 0x1001;
498  memcpy(address, &macroAddress, 8); // copy macro address to buffer
499  universalRead(address, data);
500  memcpy(&macroArgs["outArg1"], data, 8); // copy buffer to argument map
501  __SET_ARG_OUT__("outArg1", macroArgs["outArg1"]); // update output argument
502  // result
503 
504  // command-#2: Write(0x1002 /*address*/,myOtherArg /*data*/);
505  macroAddress = 0x1002;
506  memcpy(address, &macroAddress, 8); // copy macro address to buffer
507  macroArgs["myOtherArg"] = __GET_ARG_IN__(
508  "myOtherArg",
509  uint64_t); // initialize from input arguments //get macro data argument
510  memcpy(data, &macroArgs["myOtherArg"], 8); // copy macro data argument to buffer
511  universalWrite(address, data);
512 
513  // command-#3: Write(0x1001 /*address*/,myArg /*data*/);
514  macroAddress = 0x1001;
515  memcpy(address,
516  &macroAddress,
517  8); // copy macro address to buffer //get macro data argument
518  memcpy(data, &macroArgs["myArg"], 8); // copy macro data argument to buffer
519  universalWrite(address, data);
520 
521  // command-#4: delay(4);
522  __FE_COUT__ << "Sleeping for... " << 4 << " milliseconds " << __E__;
523  usleep(4 * 1000 /* microseconds */);
524 
525  delete[] address; // free the memory
526  delete[] data; // free the memory
527  }
528 
529  for (auto& argOut : argsOut)
530  __FE_COUT__ << argOut.first << ": " << argOut.second << __E__;
531 
532 } // end varTest()
533 
534 //==============================================================================
535 // varTest2
536 // FEMacro 'varTest2' generated, Oct-11-2018 02:28:57, by 'admin' using MacroMaker.
537 // Macro Notes: [Modified 14:28 10/11/2018] This is a great test!
538 void FEOtsUDPProducerTemplateInterface::varTest2(__ARGS__)
539 {
540  __FE_COUT__ << "# of input args = " << argsIn.size() << __E__;
541  __FE_COUT__ << "# of output args = " << argsOut.size() << __E__;
542  for (auto& argIn : argsIn)
543  __FE_COUT__ << argIn.first << ": " << argIn.second << __E__;
544 
545  // macro commands section
546  {
547  char* address = new char[universalAddressSize_] {
548  0}; //create address buffer of interface size and init to all 0
549  char* data = new char[universalDataSize_] {
550  0}; //create data buffer of interface size and init to all 0
551  uint64_t macroAddress; // create macro address buffer (size 8 bytes)
552  //uint64_t macroData; // create macro address buffer (size 8 bytes)
553  std::map<std::string /*arg name*/, uint64_t /*arg val*/>
554  macroArgs; // create map from arg name to 64-bit number
555 
556  // command-#0: Read(0x1002 /*address*/,myArg /*data*/);
557  macroAddress = 0x1002;
558  memcpy(address, &macroAddress, 8); // copy macro address to buffer
559  universalRead(address, data);
560  memcpy(&macroArgs["myArg"], data, 8); // copy buffer to argument map
561  __SET_ARG_OUT__("myArg", macroArgs["myArg"]); // update output argument result
562 
563  // command-#1: Read(0x1001 /*address*/,data);
564  macroAddress = 0x1001;
565  memcpy(address, &macroAddress, 8); // copy macro address to buffer
566  universalRead(address, data);
567  memcpy(&macroArgs["outArg1"], data, 8); // copy buffer to argument map
568  __SET_ARG_OUT__("outArg1", macroArgs["outArg1"]); // update output argument
569  // result
570 
571  // command-#2: Write(0x1002 /*address*/,myOtherArg /*data*/);
572  macroAddress = 0x1002;
573  memcpy(address, &macroAddress, 8); // copy macro address to buffer
574  macroArgs["myOtherArg"] = __GET_ARG_IN__(
575  "myOtherArg",
576  uint64_t); // initialize from input arguments //get macro data argument
577  memcpy(data, &macroArgs["myOtherArg"], 8); // copy macro data argument to buffer
578  universalWrite(address, data);
579 
580  // command-#3: Write(0x1001 /*address*/,myArg /*data*/);
581  macroAddress = 0x1001;
582  memcpy(address,
583  &macroAddress,
584  8); // copy macro address to buffer //get macro data argument
585  memcpy(data, &macroArgs["myArg"], 8); // copy macro data argument to buffer
586  universalWrite(address, data);
587 
588  // command-#4: delay(4);
589  __FE_COUT__ << "Sleeping for... " << 4 << " milliseconds " << __E__;
590  usleep(4 * 1000 /* microseconds */);
591 
592  delete[] address; // free the memory
593  delete[] data; // free the memory
594  }
595 
596  for (auto& argOut : argsOut)
597  __FE_COUT__ << argOut.first << ": " << argOut.second << __E__;
598 
599 } // end varTest2()
600 
601 DEFINE_OTS_INTERFACE(FEOtsUDPProducerTemplateInterface)