RobotUnitModuleBase.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * ArmarX is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * ArmarX is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * @package RobotAPI::ArmarXObjects::RobotUnit
17  * @author Raphael Grimm ( raphael dot grimm at kit dot edu )
18  * @date 2018
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
23 #include "RobotUnitModuleBase.h"
24 
25 #include <sstream>
26 
27 #include <VirtualRobot/Robot.h>
28 
32 
33 #include "RobotUnitModules.h"
34 
35 namespace armarx
36 {
37  std::string
39  {
40  switch (s)
41  {
43  return "RobotUnitState::InitializingComponent";
45  return "RobotUnitState::InitializingDevices";
47  return "RobotUnitState::InitializingUnits";
49  return "RobotUnitState::InitializingControlThread";
51  return "RobotUnitState::Running";
53  return "RobotUnitState::Exiting";
54  }
55  throw std::invalid_argument{"Unknown state " + to_string(static_cast<std::size_t>(s)) +
56  "\nStacktrace\n" + LogSender::CreateBackTrace()};
57  }
58 } // namespace armarx
59 
61 {
62  // //////////////////////////////////////////////////////////////////////////// //
63  // /////////////////////////// call for each module /////////////////////////// //
64  // //////////////////////////////////////////////////////////////////////////// //
65 #define cast_to_and_call(Type, fn, rethrow) \
66  ARMARX_TRACE; \
67  try \
68  { \
69  dynamic_cast<Type*>(this)->Type::fn; \
70  } \
71  catch (Ice::Exception & e) \
72  { \
73  ARMARX_ERROR << "exception in " << #Type "::" #fn << "!\nwhat:\n" \
74  << e.what() << "\n\tid : " << e.ice_id() << "\n\tfile : " << e.ice_file() \
75  << "\n\tline : " << e.ice_line() << "\n\tstack: " << e.ice_stackTrace(); \
76  if (rethrow) \
77  { \
78  throw; \
79  } \
80  } \
81  catch (std::exception & e) \
82  { \
83  ARMARX_ERROR << "exception in " << #Type "::" #fn << "!\nwhat:\n" << e.what(); \
84  if (rethrow) \
85  { \
86  throw; \
87  } \
88  } \
89  catch (...) \
90  { \
91  ARMARX_ERROR << "exception in " << #Type "::" #fn << "!"; \
92  if (rethrow) \
93  { \
94  throw; \
95  } \
96  }
97 
98 #define for_each_module_apply(r, data, elem) data(elem)
99 #define for_each_module(macro) \
100  BOOST_PP_SEQ_FOR_EACH(for_each_module_apply, macro, BOOST_PP_VARIADIC_TO_SEQ(RobotUnitModules))
101 
102 #define check_base(Type) \
103  static_assert(std::is_base_of<ModuleBase, Type>::value, \
104  "The RobotUnitModule '" #Type "' has to derived ModuleBase");
106 #undef check_base
107 
109  {
110 #define check_deriving(Type) \
111  ARMARX_CHECK_NOT_NULL(dynamic_cast<const Type*>(this)) \
112  << "This class does not derive from " << GetTypeString<Type>();
114 #undef check_deriving
115  }
116 
117  // //////////////////////////////////////////////////////////////////////////// //
118  // ManagedIceObject life cycle
119  void
121  {
122  ARMARX_TRACE;
124  auto guard = getGuard();
126  ARMARX_IMPORTANT << "Starting initialization of RobotUnitModule '" << getName();
127  cast_to_and_call(::armarx::RobotUnitModule::RobotData, _initVirtualRobot(), true);
128 
129 #define call_module_hook(Type) \
130  cast_to_and_call(::armarx::RobotUnitModule::Type, _preOnInitRobotUnit(), true)
132 #undef call_module_hook
133 
134  onInitRobotUnit();
135 
136 #define call_module_hook(Type) \
137  cast_to_and_call(::armarx::RobotUnitModule::Type, _postOnInitRobotUnit(), true)
139 #undef call_module_hook
140 
142  }
143 
144  void
146  {
147  ARMARX_TRACE;
149 
150 #define call_module_hook(Type) \
151  cast_to_and_call(::armarx::RobotUnitModule::Type, _preOnConnectRobotUnit(), true)
153 #undef call_module_hook
154 
156 
157 #define call_module_hook(Type) \
158  cast_to_and_call(::armarx::RobotUnitModule::Type, _postOnConnectRobotUnit(), true)
160 #undef call_module_hook
161  }
162 
163  void
165  {
166  ARMARX_TRACE;
168 
169 #define call_module_hook(Type) \
170  cast_to_and_call(::armarx::RobotUnitModule::Type, _preOnDisconnectRobotUnit(), true)
172 #undef call_module_hook
173 
175 
176 #define call_module_hook(Type) \
177  cast_to_and_call(::armarx::RobotUnitModule::Type, _postOnDisconnectRobotUnit(), true)
179 #undef call_module_hook
180  }
181 
182  void
184  {
185  ARMARX_TRACE;
187  auto guard = getGuard();
188 
189  finishRunning();
190 
191 #define call_module_hook(Type) \
192  cast_to_and_call(::armarx::RobotUnitModule::Type, _preOnExitRobotUnit(), false)
194 #undef call_module_hook
195 
196  onExitRobotUnit();
197 
198 #define call_module_hook(Type) \
199  cast_to_and_call(::armarx::RobotUnitModule::Type, _postOnExitRobotUnit(), false)
201 #undef call_module_hook
202  }
203 
204  // //////////////////////////////////////////////////////////////////////////// //
205  // other ManagedIceObject / Component methods
206  void
207  ModuleBase::componentPropertiesUpdated(const std::set<std::string>& changedProperties)
208  {
209 #define call_module_hook(Type) \
210  cast_to_and_call( \
211  ::armarx::RobotUnitModule::Type, _componentPropertiesUpdated(changedProperties), true)
213 #undef call_module_hook
214  }
215 
216  void
218  {
219 #define call_module_hook(Type) \
220  cast_to_and_call(::armarx::RobotUnitModule::Type, _icePropertiesInitialized(), true)
222 #undef call_module_hook
223  }
224 
225  // //////////////////////////////////////////////////////////////////////////// //
226  // RobotUnit life cycle
227  void
229  {
230  ARMARX_TRACE;
232  auto guard = getGuard();
234 
235 #define call_module_hook(Type) \
236  cast_to_and_call(::armarx::RobotUnitModule::Type, _preFinishComponentInitialization(), true)
238 #undef call_module_hook
239 
240  setRobotUnitState(RobotUnitState::InitializingDevices);
241 
242 #define call_module_hook(Type) \
243  cast_to_and_call(::armarx::RobotUnitModule::Type, _postFinishComponentInitialization(), true)
245 #undef call_module_hook
246  }
247 
248  void
250  {
251  ARMARX_TRACE;
253  auto guard = getGuard();
255 
256 #define call_module_hook(Type) \
257  cast_to_and_call(::armarx::RobotUnitModule::Type, _preFinishDeviceInitialization(), true)
259 #undef call_module_hook
260 
261  setRobotUnitState(RobotUnitState::InitializingUnits);
262 
263 #define call_module_hook(Type) \
264  cast_to_and_call(::armarx::RobotUnitModule::Type, _postFinishDeviceInitialization(), true)
266 #undef call_module_hook
267  }
268 
269  void
271  {
272  ARMARX_TRACE;
274  auto guard = getGuard();
276 
277 #define call_module_hook(Type) \
278  cast_to_and_call(::armarx::RobotUnitModule::Type, _preFinishUnitInitialization(), true)
280 #undef call_module_hook
281 
283 
284 #define call_module_hook(Type) \
285  cast_to_and_call(::armarx::RobotUnitModule::Type, _postFinishUnitInitialization(), true)
287 #undef call_module_hook
288  }
289 
290  void
292  {
293  ARMARX_TRACE;
295  auto guard = getGuard();
297 
298 #define call_module_hook(Type) \
299  cast_to_and_call(::armarx::RobotUnitModule::Type, _preFinishControlThreadInitialization(), true)
301 #undef call_module_hook
302 
303  setRobotUnitState(RobotUnitState::Running);
304 
305 #define call_module_hook(Type) \
306  cast_to_and_call( \
307  ::armarx::RobotUnitModule::Type, _postFinishControlThreadInitialization(), true)
309 #undef call_module_hook
310  }
311 
312  void
314  {
315  ARMARX_TRACE;
317  shutDown();
318  GuardType guard{dataMutex}; //DO NOT USE getGuard here!
320  {
321  ARMARX_ERROR << "called finishRunning when state was "
323  }
324 
325 #define call_module_hook(Type) \
326  cast_to_and_call(::armarx::RobotUnitModule::Type, _preFinishRunning(), false)
328 #undef call_module_hook
329 
330  setRobotUnitState(RobotUnitState::Exiting);
332 
333 #define call_module_hook(Type) \
334  cast_to_and_call(::armarx::RobotUnitModule::Type, _postFinishRunning(), false)
336 #undef call_module_hook
337  }
338 
339 #undef for_each_module_apply
340 #undef for_each_module
341 #undef cast_to_and_call
342  // //////////////////////////////////////////////////////////////////////////// //
343  // ////////////////////////////////// other /////////////////////////////////// //
344  // //////////////////////////////////////////////////////////////////////////// //
345 
346  const std::set<RobotUnitState> ModuleBase::DevicesReadyStates{
350 
351  void
352  ModuleBase::setRobotUnitState(RobotUnitState to)
353  {
354  ARMARX_TRACE;
355  auto guard = getGuard();
356 
357  const auto transitionErrorMessage = [=, this](RobotUnitState expectedFrom)
358  {
359  return "Can't switch to state " + to_string(to) + " from " + to_string(state) +
360  "! The expected source state is " + to_string(expectedFrom) + ".";
361  };
362  const auto transitionErrorThrow = [=, this](RobotUnitState expectedFrom)
363  {
364  if (state != expectedFrom)
365  {
366  const auto msg = transitionErrorMessage(expectedFrom);
367  ARMARX_ERROR << msg;
368  throw std::invalid_argument{msg};
369  }
370  };
371 
372  switch (to)
373  {
375  throw std::invalid_argument{
376  "Can't switch to state RobotUnitState::InitializingComponent"};
378  transitionErrorThrow(RobotUnitState::InitializingComponent);
379  break;
381  transitionErrorThrow(RobotUnitState::InitializingDevices);
382  break;
384  transitionErrorThrow(RobotUnitState::InitializingUnits);
385  break;
387  transitionErrorThrow(RobotUnitState::InitializingControlThread);
388  break;
390  if (state != RobotUnitState::Running)
391  {
392  ARMARX_ERROR << transitionErrorMessage(RobotUnitState::Running);
393  }
394  break;
395  default:
396  throw std::invalid_argument{"setRobotUnitState: Unknown target state " +
397  to_string(static_cast<std::size_t>(to)) +
398  "\nStacktrace\n" + LogSender::CreateBackTrace()};
399  }
400  ARMARX_INFO << "switching state from " << to_string(state) << " to " << to_string(to);
401  state = to;
402  }
403 
404  bool
406  {
407  return DevicesReadyStates.count(state);
408  }
409 
410  bool
412  {
414  std::this_thread::get_id() == _module<ControlThread>().getControlThreadId();
415  }
416 
417  void
418  ModuleBase::throwIfInControlThread(const std::string& fnc) const
419  {
420  ARMARX_TRACE;
421  if (inControlThread())
422  {
423  std::stringstream str;
424  str << "Called function '" << fnc << "' in the Control Thread\nStack trace:\n"
426  ARMARX_ERROR << str.str();
427  throw LogicError{str.str()};
428  }
429  }
430 
433  {
434  ARMARX_TRACE;
435  if (inControlThread())
436  {
437  throw LogicError{"Attempted to lock mutex in Control Thread\nStack trace:\n" +
439  }
440  GuardType guard{dataMutex, std::defer_lock};
441  if (guard.try_lock())
442  {
443  return guard;
444  }
445  while (!guard.try_lock_for(std::chrono::microseconds{100}))
446  {
447  if (isShuttingDown())
448  {
449  throw LogicError{"Attempting to lock mutex during shutdown\nStacktrace\n" +
451  }
452  }
453 
454  return guard;
455  }
456 
457  void
458  ModuleBase::throwIfStateIsNot(const std::set<RobotUnitState>& stateSet,
459  const std::string& fnc,
460  bool onlyWarn) const
461  {
462  ARMARX_TRACE;
463  if (!stateSet.count(state))
464  {
465  std::stringstream ss;
466  ss << fnc << ": Can't be called if state is not in {";
467  bool fst = true;
468  for (RobotUnitState st : stateSet)
469  {
470  if (!fst)
471  {
472  ss << ", ";
473  }
474  ss << st;
475  fst = false;
476  }
477  ss << "} (current state " << getRobotUnitState() << ")\n"
478  << "Stacktrace:\n"
480  ARMARX_ERROR << ss.str();
481  if (!onlyWarn)
482  {
483  throw LogicError{ss.str()};
484  }
485  }
486  }
487 
488  void
489  ModuleBase::throwIfStateIsNot(RobotUnitState s, const std::string& fnc, bool onlyWarn) const
490  {
491  throwIfStateIsNot(std::set<RobotUnitState>{s}, fnc, onlyWarn);
492  }
493 
494  void
495  ModuleBase::throwIfStateIs(const std::set<RobotUnitState>& stateSet,
496  const std::string& fnc,
497  bool onlyWarn) const
498  {
499  ARMARX_TRACE;
500  if (stateSet.count(state))
501  {
502  std::stringstream ss;
503  ss << fnc << ": Can't be called if state is in {";
504  bool fst = true;
505  for (RobotUnitState st : stateSet)
506  {
507  if (!fst)
508  {
509  ss << ", ";
510  }
511  ss << st;
512  fst = false;
513  }
514  ss << "} (current state " << getRobotUnitState() << ")\n"
515  << "Stacktrace:\n"
517  ARMARX_ERROR << ss.str();
518  if (!onlyWarn)
519  {
520  throw LogicError{ss.str()};
521  }
522  }
523  }
524 
525  void
526  ModuleBase::throwIfStateIs(RobotUnitState s, const std::string& fnc, bool onlyWarn) const
527  {
528  throwIfStateIs(std::set<RobotUnitState>{s}, fnc, onlyWarn);
529  }
530 
531  void
532  ModuleBase::throwIfDevicesNotReady(const std::string& fnc) const
533  {
534  throwIfStateIsNot(DevicesReadyStates, fnc);
535  }
536 
537  std::atomic<ModuleBase*> ModuleBase::Instance_{nullptr};
538 
540  {
541  ARMARX_TRACE;
542  if (Instance_ && this != Instance_)
543  {
544  ARMARX_FATAL << "This class is a Singleton. It was already instantiated. (Instance = "
545  << Instance_ << ", this = " << this << ")";
546  std::terminate();
547  }
548  Instance_ = this;
549  }
550 
551 } // namespace armarx::RobotUnitModule
armarx::RobotUnitModule::ModuleBase::isShuttingDown
bool isShuttingDown() const
Returns whether the RobotUnit is shutting down.
Definition: RobotUnitModuleBase.h:647
armarx::RobotUnitModule::ModuleBase::onConnectRobotUnit
virtual void onConnectRobotUnit()
called in onConnectComponent
Definition: RobotUnitModuleBase.h:681
str
std::string str(const T &t)
Definition: UserAssistedSegmenterGuiWidgetController.cpp:43
armarx::RobotUnitModule::ModuleBase::onExitComponent
void onExitComponent() final override
Definition: RobotUnitModuleBase.cpp:183
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:190
RobotUnitModules.h
RobotUnitModuleBase.h
trace.h
armarx::RobotUnitModule::ModuleBase::throwIfStateIs
void throwIfStateIs(const std::set< RobotUnitState > &stateSet, const std::string &fnc, bool onlyWarn=false) const
Throws an exception if the current state is in.
Definition: RobotUnitModuleBase.cpp:495
call_module_hook
#define call_module_hook(Type)
cast_to_and_call
#define cast_to_and_call(Type, fn, rethrow)
Definition: RobotUnitModuleBase.cpp:65
armarx::RobotUnitModule::ModuleBase::getRobotUnitState
RobotUnitState getRobotUnitState() const
Returns the RobotUnit's State.
Definition: RobotUnitModuleBase.ipp:29
armarx::RobotUnitModule::ModuleBase::onInitRobotUnit
virtual void onInitRobotUnit()
called in onInitComponent
Definition: RobotUnitModuleBase.h:671
ARMARX_FATAL
#define ARMARX_FATAL
Definition: Logging.h:199
armarx::RobotUnitModule::ModuleBase::checkDerivedClasses
void checkDerivedClasses() const
Checks whether the implementing class derives all modules.
armarx::RobotUnitModule::ModuleBase::finishUnitInitialization
virtual void finishUnitInitialization()
Transition RobotUnitState::InitializingUnits -> RobotUnitState::WaitingForRTThreadInitialization.
Definition: RobotUnitModuleBase.cpp:270
armarx::RobotUnitState::InitializingUnits
@ InitializingUnits
armarx::RobotUnitModule::for_each_module
for_each_module(check_base) void ModuleBase
Definition: RobotUnitModuleBase.cpp:105
armarx::RobotUnitModule::ModuleBase::ModuleBase
ModuleBase()
Ctor.
Definition: RobotUnitModuleBase.cpp:539
ARMARX_TRACE
#define ARMARX_TRACE
Definition: trace.h:77
armarx::RobotUnitModule::ModuleBase::inControlThread
bool inControlThread() const
Returns whether the current thread is the ControlThread.
Definition: RobotUnitModuleBase.cpp:411
armarx::RobotUnitModule::ModuleBase::shutDown
void shutDown()
Requests the RobotUnit to shut down.
Definition: RobotUnitModuleBase.h:657
armarx::RobotUnitState::Running
@ Running
armarx::RobotUnitModule::ModuleBase::onDisconnectComponent
void onDisconnectComponent() final override
Definition: RobotUnitModuleBase.cpp:164
armarx::RobotUnitModule::ModuleBase::componentPropertiesUpdated
void componentPropertiesUpdated(const std::set< std::string > &changedProperties) override
Definition: RobotUnitModuleBase.cpp:207
boost::process::posix::terminate
void terminate(const Process &p)
Definition: terminate.hpp:22
armarx::RobotUnitModule::ModuleBase::finishControlThreadInitialization
virtual void finishControlThreadInitialization()
Transition RobotUnitState::InitializingControlThread -> RobotUnitState::Running.
Definition: RobotUnitModuleBase.cpp:291
armarx::RobotUnitModule::ModuleBase::getGuard
GuardType getGuard() const
Returns a guard to the RobotUnits mutex.
Definition: RobotUnitModuleBase.cpp:432
armarx::LogSender::CreateBackTrace
static std::string CreateBackTrace(int linesToSkip=1)
Definition: LogSender.cpp:516
check_base
#define check_base(Type)
Definition: RobotUnitModuleBase.cpp:102
armarx::RobotUnitModule::ModuleBase::onExitRobotUnit
virtual void onExitRobotUnit()
called in onExitComponent before calling finishRunning
Definition: RobotUnitModuleBase.h:702
armarx::RobotUnitModule::ModuleBase::onDisconnectRobotUnit
virtual void onDisconnectRobotUnit()
called in onDisconnecComponent
Definition: RobotUnitModuleBase.h:691
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
armarx::RobotUnitModule::ModuleBase::finishRunning
virtual void finishRunning()
Transition RobotUnitState::Running -> RobotUnitState::Exiting.
Definition: RobotUnitModuleBase.cpp:313
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
armarx::RobotUnitModule::ModuleBase::joinControlThread
virtual void joinControlThread()=0
Implementations have to join their ControlThread in this hook. (used by RobotUnit::finishRunning())
armarx::RobotUnitState::InitializingControlThread
@ InitializingControlThread
ExpressionException.h
check_deriving
#define check_deriving(Type)
Preprocessor.h
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
armarx::RobotUnitModule::ModuleBase::areDevicesReady
bool areDevicesReady() const
Returns whether Devices are ready.
Definition: RobotUnitModuleBase.cpp:405
armarx::RobotUnitState::InitializingDevices
@ InitializingDevices
armarx::RobotUnitModule::ModuleBase::icePropertiesInitialized
void icePropertiesInitialized() override
Definition: RobotUnitModuleBase.cpp:217
armarx::RobotUnitModule::ModuleBase::GuardType
std::unique_lock< MutexType > GuardType
Definition: RobotUnitModuleBase.h:226
armarx::RobotUnitState::InitializingComponent
@ InitializingComponent
armarx::RobotUnitModule::ModuleBase::throwIfInControlThread
void throwIfInControlThread(const std::string &fnc) const
Throws if the current thread is the ControlThread.
Definition: RobotUnitModuleBase.cpp:418
armarx::RobotUnitState
RobotUnitState
The current state of the multi step initialization of a RobotUnit.
Definition: RobotUnitModuleBase.h:74
armarx::RobotUnitModule::ModuleBase::throwIfDevicesNotReady
void throwIfDevicesNotReady(const std::string &fnc) const
Throws if the Devices are not ready.
Definition: RobotUnitModuleBase.cpp:532
armarx::ManagedIceObject::getName
std::string getName() const
Retrieve name of object.
Definition: ManagedIceObject.cpp:108
armarx::RobotUnitModule::ModuleBase::throwIfStateIsNot
void throwIfStateIsNot(const std::set< RobotUnitState > &stateSet, const std::string &fnc, bool onlyWarn=false) const
Throws an exception if the current state is not in.
Definition: RobotUnitModuleBase.cpp:458
armarx::RobotUnitModule
Definition: ControlDevice.h:34
armarx::RobotUnitModule::ModuleBase::finishComponentInitialization
virtual void finishComponentInitialization()
Transition RobotUnitState::InitializingComponent -> RobotUnitState::InitializingDevices.
Definition: RobotUnitModuleBase.cpp:228
armarx::RobotUnitModule::ModuleBase::onInitComponent
void onInitComponent() final override
armarx::RobotUnitModule::RobotData
This Module holds all high-level data about the robot.
Definition: RobotUnitModuleRobotData.h:52
armarx::RobotUnitModule::ModuleBase::finishDeviceInitialization
virtual void finishDeviceInitialization()
Transition RobotUnitState::InitializingDevices -> RobotUnitState::InitializingUnits.
Definition: RobotUnitModuleBase.cpp:249
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx::RobotUnitState::Exiting
@ Exiting
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::RobotUnitModule::ModuleBase::onConnectComponent
void onConnectComponent() final override
Definition: RobotUnitModuleBase.cpp:145