18#include <smacc_msgs/SmaccStatus.h>
21#include <boost/function_types/function_arity.hpp>
22#include <boost/function_types/function_type.hpp>
23#include <boost/function_types/parameter_types.hpp>
29 template <
typename TOrthogonal>
32 std::lock_guard<std::recursive_mutex> lock(
m_mutex_);
34 std::string orthogonalkey = demangledTypeName<TOrthogonal>();
41 ROS_DEBUG(
"Orthogonal %s resource is being required from some state, client or component. Found resource in cache.", orthogonalkey.c_str());
42 ret =
dynamic_cast<TOrthogonal *
>(it->second.get());
48 ss <<
"Orthogonal not found " << orthogonalkey.c_str() << std::endl;
49 ss <<
"The existing orthogonals are the following: " << std::endl;
52 ss <<
" - " << orthogonal.first << std::endl;
55 ROS_WARN_STREAM(ss.str());
62 template <
typename TOrthogonal>
66 std::string orthogonalkey = demangledTypeName<TOrthogonal>();
70 auto ret = std::make_shared<TOrthogonal>();
71 orthogonals_[orthogonalkey] = dynamic_pointer_cast<smacc::ISmaccOrthogonal>(ret);
73 ret->setStateMachine(
this);
75 ROS_INFO(
"%s Orthogonal is created", orthogonalkey.c_str());
79 ROS_WARN_STREAM(
"There were already one existing orthogonal of type "
80 << orthogonalkey.c_str() <<
". Skipping creation orthogonal request. ");
82 ss <<
"The existing orthogonals are the following: " << std::endl;
85 ss <<
" - " << orthogonal.first << std::endl;
87 ROS_WARN_STREAM(ss.str());
93 template <
typename SmaccComponentType>
96 ROS_DEBUG(
"component %s is required",
demangleSymbol(
typeid(SmaccComponentType).name()).c_str());
97 std::lock_guard<std::recursive_mutex> lock(
m_mutex_);
101 for (
auto &client : ortho.second->clients_)
104 storage = client->getComponent<SmaccComponentType>();
105 if (storage !=
nullptr)
112 ROS_WARN(
"component %s is required but it was not found in any orthogonal",
demangleSymbol(
typeid(SmaccComponentType).name()).c_str());
137 template <
typename EventType>
144 ROS_WARN_STREAM(
"CURRENT STATE SCOPED EVENT SKIPPED, state is exiting/transitioning " << demangleSymbol<EventType>());
155 ROS_DEBUG_STREAM(
"[PostEvent entry point] " << demangleSymbol<EventType>());
165 template <
typename EventType>
168 auto *ev =
new EventType();
172 template <
typename T>
175 std::lock_guard<std::recursive_mutex> lock(
m_mutex_);
177 bool success =
false;
192 ret = boost::any_cast<T>(v.second);
196 catch (boost::bad_any_cast &ex)
198 ROS_ERROR(
"bad any cast: %s", ex.what());
207 template <
typename T>
211 std::lock_guard<std::recursive_mutex> lock(
m_mutex_);
215 std::stringstream ss;
226 template <
typename StateField,
typename BehaviorType>
229 std::string stateFieldName =
demangleSymbol(
typeid(StateField).name());
230 std::string behaviorType =
demangleSymbol(
typeid(BehaviorType).name());
231 ROS_INFO(
"Mapping state field '%s' to stateReactor '%s'", stateFieldName.c_str(), behaviorType.c_str());
237 BehaviorType *behavior;
250 template <
typename TSmaccSignal,
typename TMemberFunctionPrototype,
typename TSmaccObjectType>
251 boost::signals2::connection
bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback,
252 TSmaccObjectType *
object, std::shared_ptr<CallbackCounterSemaphore> callbackCounter);
258 template <
typename TSmaccSignal,
typename TMemberFunctionPrototype,
typename TSmaccObjectType>
259 boost::signals2::connection
bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *
object, std::shared_ptr<CallbackCounterSemaphore> callbackCounter)
261 return signal.connect(
265 if(callbackCounter ==
nullptr)
267 (
object->*callback)();
269 else if (callbackCounter->acquire())
271 (
object->*callback)();
272 callbackCounter->release();
280 template <
typename TSmaccSignal,
typename TMemberFunctionPrototype,
typename TSmaccObjectType>
281 boost::signals2::connection
bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *
object, std::shared_ptr<CallbackCounterSemaphore> callbackCounter)
283 return signal.connect([=](
auto a1)
285 if(callbackCounter ==
nullptr)
287 (
object->*callback)(a1);
289 else if (callbackCounter->acquire())
291 (
object->*callback)(a1);
292 callbackCounter->release();
302 template <
typename TSmaccSignal,
typename TMemberFunctionPrototype,
typename TSmaccObjectType>
303 boost::signals2::connection
bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *
object, std::shared_ptr<CallbackCounterSemaphore> callbackCounter)
305 return signal.connect([=](
auto a1,
auto a2) {
306 if(callbackCounter ==
nullptr)
308 (
object->*callback)(a1,a2);
310 else if (callbackCounter->acquire())
312 (
object->*callback)(a1,a2);
313 callbackCounter->release();
323 template <
typename TSmaccSignal,
typename TMemberFunctionPrototype,
typename TSmaccObjectType>
324 boost::signals2::connection
bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *
object, std::shared_ptr<CallbackCounterSemaphore> callbackCounter)
326 return signal.connect([=](
auto a1,
auto a2,
auto a3) {
327 if(callbackCounter ==
nullptr)
329 (
object->*callback)(a1,a2,a3);
331 else if (callbackCounter->acquire())
333 (
object->*callback)(a1,a2,a3);
334 callbackCounter->release();
344 template <
typename TSmaccSignal,
typename TMemberFunctionPrototype,
typename TSmaccObjectType>
346 TMemberFunctionPrototype callback,
347 TSmaccObjectType *
object)
349 std::lock_guard<std::recursive_mutex> lock(
m_mutex_);
351 static_assert(std::is_base_of<ISmaccState, TSmaccObjectType>::value ||
352 std::is_base_of<ISmaccClient, TSmaccObjectType>::value ||
353 std::is_base_of<ISmaccClientBehavior, TSmaccObjectType>::value ||
354 std::is_base_of<StateReactor, TSmaccObjectType>::value ||
355 std::is_base_of<ISmaccComponent, TSmaccObjectType>::value,
356 "Only are accepted smacc types as subscribers for smacc signals");
358 typedef decltype(callback) ft;
361 boost::signals2::connection connection;
364 if (std::is_base_of<ISmaccComponent, TSmaccObjectType>::value ||
365 std::is_base_of<ISmaccClient, TSmaccObjectType>::value ||
366 std::is_base_of<ISmaccOrthogonal, TSmaccObjectType>::value ||
367 std::is_base_of<ISmaccStateMachine, TSmaccObjectType>::value)
369 connection = binder.
bindaux(signal, callback,
object,
nullptr);
371 else if (std::is_base_of<ISmaccState, TSmaccObjectType>::value ||
372 std::is_base_of<StateReactor, TSmaccObjectType>::value ||
373 std::is_base_of<ISmaccClientBehavior, TSmaccObjectType>::value)
375 ROS_INFO(
"[StateMachine] life-time constrained smacc signal subscription created. Subscriber is %s",
376 demangledTypeName<TSmaccObjectType>().c_str());
378 std::shared_ptr<CallbackCounterSemaphore> callbackCounterSemaphore;
385 callbackCounterSemaphore = std::make_shared<CallbackCounterSemaphore>(demangledTypeName<TSmaccObjectType>().c_str());
389 connection = binder.bindaux(signal, callback,
object, callbackCounterSemaphore);
390 callbackCounterSemaphore->addConnection(connection);
395 ROS_WARN(
"[StateMachine] connecting signal to an unknown object with life-time unknown behavior. It might provoke "
396 "an exception if the object is destroyed during the execution.");
398 connection = binder.bindaux(signal, callback,
object,
nullptr);
404 template <
typename T>
407 return nh_.getParam(param_name, param_storage);
411 template <
typename T>
414 return nh_.setParam(param_name, param_val);
418 template <
typename T>
421 return nh_.param(param_name, param_val, default_val);
424 template <
typename StateType>
427 std::lock_guard<std::recursive_mutex> lock(
m_mutex_);
429 ROS_DEBUG(
"[State Machne] Initializating a new state '%s' and updating current state. Getting state meta-information. number of orthogonals: %ld",
demangleSymbol(
typeid(StateType).name()).c_str(), this->
orthogonals_.size());
436 template <
typename StateType>
439 ROS_INFO(
"[%s] State OnEntry code finished",
demangleSymbol(
typeid(StateType).name()).c_str());
445 auto &orthogonal = pair.second;
448 orthogonal->onEntry();
450 catch (
const std::exception &e)
452 ROS_ERROR(
"[Orthogonal %s] Exception on Entry - continuing with next orthogonal. Exception info: %s",
453 pair.second->getName().c_str(), e.what());
457 for (
auto &sr : currentState->getStateReactors())
460 ROS_INFO(
"state reactor onEntry: %s", srname);
465 catch (
const std::exception &e)
467 ROS_ERROR(
"[State Reactor %s] Exception on Entry - continuing with next state reactor. Exception info: %s",
472 for (
auto &eg : currentState->getEventGenerators())
475 ROS_INFO(
"state reactor onEntry: %s", egname);
480 catch (
const std::exception &e)
482 ROS_ERROR(
"[Event generator %s] Exception on Entry - continuing with next state reactor. Exception info: %s",
488 std::lock_guard<std::recursive_mutex> lock(
m_mutex_);
494 template <
typename StateType>
500 auto &orthogonal = pair.second;
501 orthogonal->runtimeConfigure();
505 std::lock_guard<std::recursive_mutex> lock(
m_mutex_);
513 template <
typename StateType>
519 template <
typename StateType>
525 ROS_WARN_STREAM(
"exiting state: " << fullname);
528 ROS_INFO_STREAM(
"Notification State Exit: leaving state" << state);
531 auto &orthogonal = pair.second;
534 orthogonal->onExit();
536 catch (
const std::exception &e)
538 ROS_ERROR(
"[Orthogonal %s] Exception onExit - continuing with next orthogonal. Exception info: %s",
539 pair.second->getName().c_str(), e.what());
543 for (
auto &sr : state->getStateReactors())
546 ROS_INFO(
"state reactor OnExit: %s", srname);
551 catch (
const std::exception &e)
553 ROS_ERROR(
"[State Reactor %s] Exception on OnExit - continuing with next state reactor. Exception info: %s",
558 for (
auto &eg : state->getEventGenerators())
561 ROS_INFO(
"state reactor OnExit: %s", egname);
566 catch (
const std::exception &e)
568 ROS_ERROR(
"[State Reactor %s] Exception on OnExit - continuing with next state reactor. Exception info: %s",
574 template <
typename StateType>
582 ROS_WARN_STREAM(
"exiting state: " << fullname);
584 ROS_INFO_STREAM(
"Notification State Disposing: leaving state" << state);
587 auto &orthogonal = pair.second;
590 orthogonal->onDispose();
592 catch (
const std::exception &e)
594 ROS_ERROR(
"[Orthogonal %s] Exception onDispose - continuing with next orthogonal. Exception info: %s",
595 pair.second->getName().c_str(), e.what());
599 for (
auto &sr : state->getStateReactors())
602 ROS_INFO(
"state reactor disposing: %s", srname);
607 catch (
const std::exception &e)
609 ROS_ERROR(
"[State Reactor %s] Exception on OnDispose - continuing with next state reactor. Exception info: %s",
614 for (
auto &eg : state->getEventGenerators())
617 ROS_INFO(
"state reactor disposing: %s", egname);
622 catch (
const std::exception &e)
624 ROS_ERROR(
"[State Reactor %s] Exception on OnDispose - continuing with next state reactor. Exception info: %s",
633 ROS_WARN_STREAM(
"state exit: " << fullname);
639 template <
typename EventType>
642 ROS_DEBUG(
"PROPAGATING EVENT [%s] TO LUs [%s]: ", demangleSymbol<EventType>().c_str(), st->
getClassName().c_str());
655 template <
typename InitialStateType>
std::shared_ptr< SmaccStateMachineInfo > stateMachineInfo_
void notifyOnRuntimeConfigurationFinished(StateType *state)
bool param(std::string param_name, T ¶m_val, const T &default_val) const
TOrthogonal * getOrthogonal()
SignalDetector * signalDetector_
const SmaccStateMachineInfo & getStateMachineInfo()
void propagateEventToStateReactors(ISmaccState *st, EventType *ev)
std::vector< ISmaccState * > currentState_
std::recursive_mutex eventQueueMutex_
void lockStateMachine(std::string msg)
ISmaccState * getCurrentState() const
StateMachineInternalAction stateMachineCurrentAction
void notifyOnStateExitting(StateType *state)
void notifyOnRuntimeConfigured(StateType *state)
void notifyOnStateEntryEnd(StateType *state)
void setGlobalSMData(std::string name, T value)
uint64_t getCurrentStateCounter() const
void buildStateMachineInfo()
std::shared_ptr< SmaccStateInfo > currentStateInfo_
std::map< void *, std::shared_ptr< CallbackCounterSemaphore > > stateCallbackConnections
void requiresComponent(SmaccComponentType *&storage)
std::recursive_mutex m_mutex_
void notifyOnStateExited(StateType *state)
bool getParam(std::string param_name, T ¶m_storage)
std::map< std::string, std::shared_ptr< smacc::ISmaccOrthogonal > > orthogonals_
void updateStatusMessage()
std::map< std::string, std::pair< std::function< std::string()>, boost::any > > globalData_
boost::signals2::connection createSignalConnection(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *object)
void unlockStateMachine(std::string msg)
void disconnectSmaccSignalObject(void *object)
uint64_t stateSeqCounter_
bool getGlobalSMData(std::string name, T &ret)
void notifyOnStateEntryStart(StateType *state)
void checkStateMachineConsistence()
void setParam(std::string param_name, T param_val)
void postEvent(EventType *ev, EventLifeTime evlifetime=EventLifeTime::ABSOLUTE)
ISmaccState * getParentState()
virtual std::string getClassName()
std::vector< std::shared_ptr< StateReactor > > & getStateReactors()
void notifyStateConfigured(ISmaccState *currentState)
void postEvent(EventType *ev)
void notifyStateExited(ISmaccState *currentState)
std::string demangleSymbol()
boost::signals2::connection bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *object, std::shared_ptr< CallbackCounterSemaphore > callbackCounter)
boost::signals2::connection bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *object, std::shared_ptr< CallbackCounterSemaphore > callbackCounter)
boost::signals2::connection bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *object, std::shared_ptr< CallbackCounterSemaphore > callbackCounter)
boost::signals2::connection bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *object, std::shared_ptr< CallbackCounterSemaphore > callbackCounter)
boost::signals2::connection bindaux(TSmaccSignal &signal, TMemberFunctionPrototype callback, TSmaccObjectType *object, std::shared_ptr< CallbackCounterSemaphore > callbackCounter)