tdaq-develop-2025-02-12
FECommanderInterfaceImpl.cc
1 #include "otsdaq-components/FEInterfaces/FECommanderInterface.h"
2 // #include "otsdaq/Macros/CoutMacros.h"
3 #include "otsdaq/Macros/InterfacePluginMacros.h"
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <cstring> //for memcpy
8 #include <fstream>
9 #include <iostream>
10 #include <set>
11 #include <sstream>
12 #include <string>
13 
14 using namespace ots;
15 
16 //========================================================================================================================
17 ots::FECommanderInterface::FECommanderInterface(
18  const std::string& interfaceUID,
19  const ConfigurationTree& theXDAQContextConfigTree,
20  const std::string& interfaceConfigurationPath)
21  : Socket(theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
22  .getNode("HostIPAddress")
23  .getValue<std::string>(),
24  theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
25  .getNode("HostPort")
26  .getValue<unsigned int>())
27  , FEVInterface(interfaceUID, theXDAQContextConfigTree, interfaceConfigurationPath)
28  , interfaceSocket_(theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
29  .getNode("RemoteInterfaceIPAddress")
30  .getValue<std::string>(),
31  theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
32  .getNode("RemoteInterfacePort")
33  .getValue<unsigned int>())
34  , stateMachineName_(theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
35  .getNode("StateMachineName")
36  .getValue<std::string>())
37  , configurationAlias_(theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
38  .getNode("ConfigurationAlias")
39  .getValue<std::string>())
40  , onlyRunTransitions_(false)
41  , monitorRemoteAppStatus_(false)
42  , halted_(false)
43  , inRun_(false)
44 {
45  Socket::initialize();
46  universalAddressSize_ = 8;
47  universalDataSize_ = 8;
48 
49  try
50  {
51  onlyRunTransitions_ = theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
52  .getNode("OnlyRunTransitions")
53  .getValue<bool>();
54  }
55  catch(...) {;} //ignore missing setting
56 
57  __COUTV__(onlyRunTransitions_);
58 
59  try
60  {
61  monitorRemoteAppStatus_ = theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
62  .getNode("MonitorRemoteAppStatus")
63  .getValue<bool>();
64  }
65  catch(...) {;} //ignore missing setting
66 
67  __COUTV__(monitorRemoteAppStatus_);
68 
69  try
70  {
71  expectTransitionAck_ = theXDAQContextConfigTree.getNode(interfaceConfigurationPath)
72  .getNode("ExpectTransitionAck")
73  .getValue<bool>();
74  }
75  catch(...) {;} //ignore missing setting
76 
77  __COUTV__(expectTransitionAck_);
78 
79 
80 
81  if(monitorRemoteAppStatus_)
82  {
83  __COUT__ << "Enabling App Status checking..." << __E__;
84  std::thread([](FECommanderInterface* s) { FECommanderInterface::AppStatusWorkLoop(s); }, this).detach();
85  }
86  else
87  {
88  __COUT__ << "App Status checking is disabled." << __E__;
89 
90  // set all app status to "Not Monitored"
91  std::lock_guard<std::mutex> lock(remoteAppStatusMutex_);
92  remoteAppStatus_ = SupervisorInfo::APP_STATUS_NOT_MONITORED;
93  }
94 
95 } //end constructor()
96 
97 //========================================================================================================================
98 ots::FECommanderInterface::~FECommanderInterface(void)
99 {
100  __COUT__ << "Destructor" << __E__;
101 } //end destructor()
102 
103 //==============================================================================
106 void FECommanderInterface::AppStatusWorkLoop(FECommanderInterface* fePtr)
107 {
108  __COUT__ << "Started remote status checking loop..." << __E__;
109  std::string status;
110  bool verbose = true;
111  while(!fePtr->halted_)
112  {
113  sleep(1);
114 
115  try
116  {
117  status = fePtr->sendAndReceive(fePtr->interfaceSocket_, "GetRemoteAppStatus",
118  3 /* timeout seconds */, 0 /* timeout microseconds */, verbose);
119  }
120  catch(const std::exception& e)
121  {
122  __COUT_WARN__ << "No remote app status received. Trying to ignore." << __E__;
123  sleep(5);
124  continue;
125  }
126 
127  __COUTT__ << "Remote app status: " << status << __E__;
128 
129  std::lock_guard<std::mutex> lock(fePtr->remoteAppStatusMutex_);
130  fePtr->remoteAppStatus_ = "Remote:" + status;
131  } // end of infinite status checking loop
132  __COUT__ << "Exited remote status checking loop." << __E__;
133 } // end AppStatusWorkLoop()
134 
135 //==============================================================================
141 {
142  std::lock_guard<std::mutex> lock(remoteAppStatusMutex_);
143  return remoteAppStatus_;
144 } // end getStatusProgressString()
145 
146 //========================================================================================================================
147 void ots::FECommanderInterface::send(std::string buffer)
148 {
149  try
150  {
151  bool verbose = false;
152  __FE_COUT__ << "Sending: '" << buffer << "' " <<
153  (expectTransitionAck_?"and waiting for Ack":"") << std::endl;
154 
155  if(!expectTransitionAck_)
156  {
157  if(TransceiverSocket::send(interfaceSocket_, buffer, verbose) < 0)
158  {
159  __FE_SS__ << "Send failed to IP:Port " << interfaceSocket_.getIPAddress() << ":"
160  << interfaceSocket_.getPort() << __E__;
161  __FE_SS_THROW__;
162  }
163  }
164  else //expectTransitionAck_
165  {
166  std::string response = TransceiverSocket::sendAndReceive(interfaceSocket_, buffer,
167  5 /* timeout seconds */, 0 /* timeout microseconds */, verbose);
168 
169  if("Done" != response)
170  {
171  __FE_SS__ << "Send-and-Receive failed to remote IP:Port " << interfaceSocket_.getIPAddress() << ":"
172  << interfaceSocket_.getPort() << ". Here is response received from the remote target = \n'" << response <<
173  "\n'... - expecting 'Done.'" << __E__;
174  __FE_SS_THROW__;
175  }
176  }
177  }
178  catch(...)
179  {
180  __FE_SS__ << "Failed to send command '" << buffer << "' to remote state machine. ";
181  try
182  {
183  throw;
184  }
185  catch(const std::exception& e)
186  {
187  ss << "Here is the error: " << e.what() << __E__;
188  }
189  catch(...)
190  {
191  ss << "Unrecognized exception caught!" << __E__;
192  }
193 
194  __FE_SS_THROW__;
195  }
196 } //end send()
197 
198 //========================================================================================================================
199 void ots::FECommanderInterface::halt(void)
200 {
201  halted_ = true;
202  if(onlyRunTransitions_)
203  {
204  __FE_COUT__ << "Only executing run transitions - skipping Halt transition." << __E__;
205  return;
206  }
207  // MESSAGE = "PhysicsRuns0,Halt"
208 
209  __FE_COUTV__(inRun_);
210  if(inRun_)
211  send(stateMachineName_ + ",Abort");
212  else
213  send(stateMachineName_ + ",Halt");
214 } //end halt()
215 
216 //========================================================================================================================
217 void ots::FECommanderInterface::pause(void) { send(stateMachineName_ + ",Pause"); }
218 
219 //========================================================================================================================
220 void ots::FECommanderInterface::resume(void) { send(stateMachineName_ + ",Resume"); }
221 //========================================================================================================================
222 void ots::FECommanderInterface::start(std::string runNumber)
223 {
224  // MESSAGE = "PhysicsRuns0,Start, %i" % (int(run)) #"PhysicsRuns0,Start"
225  send(stateMachineName_ + ",Start," + runNumber);
226  inRun_ = true; //track to control Abort vs Halt
227 } //end start()
228 
229 //========================================================================================================================
230 void ots::FECommanderInterface::stop(void)
231 {
232  // MESSAGE = "PhysicsRuns0,Stop"
233  send(stateMachineName_ + ",Stop");
234  inRun_ = false; //track to control Abort vs Halt
235 } //end stop()
236 
237 //========================================================================================================================
238 void ots::FECommanderInterface::configure(void)
239 {
240 
241  if(onlyRunTransitions_)
242  {
243  __FE_COUT__ << "Only executing run transitions - skipping Configure transition." << __E__;
244  return;
245  }
246 
247  __FE_COUT__ << "Configure" << __E__;
248  // MESSAGE = "PhysicsRuns0,Configure,FQNETConfig"
249  send(stateMachineName_ + ",Configure," + configurationAlias_);
250 } //end configure()
virtual std::string getStatusProgressDetail(void) override
overriding VStateMachine::getStatusProgressDetail