SMACC
Loading...
Searching...
No Matches
smacc_state_base.h
Go to the documentation of this file.
1/*****************************************************************************************************************
2 * ReelRobotix Inc. - Software License Agreement Copyright (c) 2018
3 * Authors: Pablo Inigo Blasco, Brett Aldrich
4 *
5 ******************************************************************************************************************/
6
7#pragma once
8#include <smacc/smacc_state.h>
12
13namespace smacc
14{
15 using namespace smacc::introspection;
16 using namespace smacc::default_events;
17
18 template <class MostDerived,
19 class Context,
20 class InnerInitial = mpl::list<>,
21 sc::history_mode historyMode = sc::has_deep_history>
23 MostDerived, Context, InnerInitial, historyMode>,
24 public ISmaccState
25 {
28
29 public:
30 typedef Context TContext;
31 typedef typename Context::inner_context_type context_type;
32 typedef typename context_type::state_iterator state_iterator;
33
34 typedef InnerInitial LastDeepState;
35
37 InnerInitial *smacc_inner_type;
38
41 {
42 my_context(typename base_type::context_ptr_type pContext) : pContext_(pContext)
43 {
44 }
45
46 typename base_type::context_ptr_type pContext_;
47 };
48
49 SmaccState() = delete;
50
51#define STATE_NAME (demangleSymbol(typeid(MostDerived).name()).c_str())
52 // Constructor that initializes the state ros node handle
54 {
55 static_assert(std::is_base_of<ISmaccState, Context>::value || std::is_base_of<ISmaccStateMachine, Context>::value, "The context class must be a SmaccState or a SmaccStateMachine");
56
57 static_assert(!std::is_same<MostDerived, Context>::value, "The context must be a different state or state machine than the current state");
58
59 ROS_WARN("[%s] creating ", STATE_NAME);
60 this->set_context(ctx.pContext_);
61
62 this->stateInfo_ = getStateInfo();
63
64 // storing a reference to the parent state
65 auto &ps = this->template context<Context>();
66 parentState_ = dynamic_cast<ISmaccState *>(&ps);
67 finishStateThrown = false;
68
70 ROS_DEBUG("[%s] Ros node handle namespace for this state: %s", STATE_NAME, contextNh.getNamespace().c_str());
71 if (contextNh.getNamespace() == "/")
72 {
73 auto nhname = smacc::utils::cleanShortTypeName(typeid(Context));
74 ROS_INFO("[%s] Creating ros NodeHandle for this state: %s", STATE_NAME, nhname.c_str());
75 contextNh = ros::NodeHandle(nhname);
76 }
77 }
78
79 virtual ~SmaccState()
80 {
81 }
82
84 {
85 auto smInfo = this->getStateMachine().getStateMachineInfo();
86
87 auto key = typeid(MostDerived).name();
88 if (smInfo.states.count(key))
89 {
90 return smInfo.states[key].get();
91 }
92 else
93 {
94 return nullptr;
95 }
96 }
97
98 std::string getFullName()
99 {
100 return demangleSymbol(typeid(MostDerived).name());
101 }
102
103 std::string getShortName()
104 {
105 return smacc::utils::cleanShortTypeName(typeid(MostDerived));
106 }
107
109 {
110 //auto* ctx = dynamic_cast<ISmaccState*>(this->template context<Context *>());
111
112 return parentState_;
113 }
114
115 // this function is called by boot statechart before the destructor call
116 void exit()
117 {
118 auto *derivedThis = static_cast<MostDerived *>(this);
119 this->getStateMachine().notifyOnStateExitting(derivedThis);
120 try
121 { // static_cast<MostDerived *>(this)->onExit();
122 standardOnExit(*derivedThis);
123 }
124 catch (...)
125 {
126 }
127 this->getStateMachine().notifyOnStateExited(derivedThis);
128 }
129
130 public:
131 // This method is static-polymorphic because of the curiously recurring template pattern. It
132 // calls to the most derived class onEntry method if declared on smacc state construction
134 {
135 }
136
137 // This method is static-polymorphic because of the curiously recurring template pattern. It
138 // calls to the most derived class onEntry method if declared on smacc state construction
139 void onEntry()
140 {
141 }
142
143 // this method is static-polimorphic because of the curiously recurreing pattern. It
144 // calls to the most derived class onExit method if declared on smacc state destruction
145 void onExit()
146 {
147 }
148
149 template <typename T>
150 bool getGlobalSMData(std::string name, T &ret)
151 {
152 return base_type::outermost_context().getGlobalSMData(name, ret);
153 }
154
155 // Store globally in this state machine. (By value parameter )
156 template <typename T>
157 void setGlobalSMData(std::string name, T value)
158 {
159 base_type::outermost_context().setGlobalSMData(name, value);
160 }
161
162 template <typename SmaccComponentType>
163 void requiresComponent(SmaccComponentType *&storage)
164 {
165 base_type::outermost_context().requiresComponent(storage);
166 }
167
169 {
170 return base_type::outermost_context();
171 }
172
173 template <typename TOrthogonal, typename TBehavior>
174 static void configure_orthogonal_runtime(std::function<void(TBehavior &bh, MostDerived &)> initializationFunction)
175 {
176 configure_orthogonal_internal<TOrthogonal, TBehavior>([=](ISmaccState *state) {
177 //auto bh = std::make_shared<TBehavior>(args...);
178 auto bh = state->configure<TOrthogonal, TBehavior>();
179 initializationFunction(*bh, *(static_cast<MostDerived *>(state)));
180 });
181 }
182
183 template <typename TOrthogonal, typename TBehavior>
184 static void configure_orthogonal_runtime(std::function<void(TBehavior &bh)> initializationFunction)
185 {
186 configure_orthogonal_internal<TOrthogonal, TBehavior>([=](ISmaccState *state) {
187 //auto bh = std::make_shared<TBehavior>(args...);
188 auto bh = state->configure<TOrthogonal, TBehavior>();
189 initializationFunction(*bh);
190 });
191 }
192
193 template <typename TOrthogonal, typename TBehavior, typename... Args>
194 static void configure_orthogonal(Args &&... args)
195 {
196 configure_orthogonal_internal<TOrthogonal, TBehavior>(
197 [=](ISmaccState *state) {
198 //auto bh = std::make_shared<TBehavior>(args...);
199 state->configure<TOrthogonal, TBehavior>(args...);
200 });
201 }
202
203 /*
204
205 template<typename TInputEventList>
206 void ISmaccState::state_reactor_initialize_inputEventList(smacc::introspection::StateReactorHandler* sr, TInputEventList *)
207 {
208 using boost::mpl::_1;
209 using wrappedList = typename boost::mpl::transform<TInputEventList, _1>::type;
210 AddTEventType<TInputEventList> op(sr);
211 boost::mpl::for_each<wrappedList>(op);
212 }
213
214 template <typename TStateReactor, typename TOutputEvent, typename TInputEventList, typename... TArgs... args>
215 std::shared_ptr<TStateReactor> ISmaccState::static_createStateReactor(TArgs... args)
216 {
217 auto srHandler = static_createStateReactor_aux(args...);
218
219 srHandler->addInputEvent<EvTopicMessage<CbLidarSensor, OrObstaclePerception>>();
220 srHandler->addInputEvent<EvTopicMessage<CbConditionTemperatureSensor, OrTemperatureSensor>>();
221
222 TInputEventList* mock;
223 state_reactor_initialize_inputEventList(mock,)
224
225 srHandler->setOutputEvent<TOutputEvent>();
226 }
227*/
228 template <typename TStateReactor, typename TOutputEvent, typename TInputEventList, typename... TArgs>
229 static std::shared_ptr<smacc::introspection::StateReactorHandler> static_createStateReactor(TArgs... args)
230 {
231 auto srh = std::make_shared<smacc::introspection::StateReactorHandler>();
232 auto srinfo = std::make_shared<SmaccStateReactorInfo>();
233
234 srinfo->stateReactorType = &typeid(TStateReactor);
235 srinfo->srh = srh;
236 srh->srInfo_ = srinfo;
237
238 const std::type_info *tindex = &(typeid(MostDerived)); // get identifier of the current state
239
240 if (!SmaccStateInfo::stateReactorsInfo.count(tindex))
241 SmaccStateInfo::stateReactorsInfo[tindex] = std::vector<std::shared_ptr<SmaccStateReactorInfo>>();
242
243 srinfo->factoryFunction = [&, srh, args...](ISmaccState *state) {
244 auto sr = state->createStateReactor<TStateReactor, TOutputEvent, TInputEventList, TArgs...>(args...);
245 srh->configureStateReactor(sr);
246 sr->initialize(state);
247 return sr;
248 };
249
250 SmaccStateInfo::stateReactorsInfo[tindex].push_back(srinfo);
251
252 return srh;
253 }
254
255 template <typename TEventGenerator, typename... TUArgs>
256 static std::shared_ptr<smacc::introspection::EventGeneratorHandler> static_createEventGenerator(TUArgs... args)
257 {
258 auto egh = std::make_shared<smacc::introspection::EventGeneratorHandler>();
259 auto eginfo = std::make_shared<SmaccEventGeneratorInfo>();
260 eginfo->eventGeneratorType = &typeid(TEventGenerator);
261 eginfo->egh = egh;
262 egh->egInfo_ = eginfo;
263
264 const std::type_info *tindex = &(typeid(MostDerived)); // get identifier of the current state
265
266 if (!SmaccStateInfo::eventGeneratorsInfo.count(tindex))
267 SmaccStateInfo::eventGeneratorsInfo[tindex] = std::vector<std::shared_ptr<SmaccEventGeneratorInfo>>();
268
269 eginfo->factoryFunction = [&, egh, args...](ISmaccState *state) {
270 auto eg = state->createEventGenerator<TEventGenerator>(args...);
271 egh->configureEventGenerator(eg);
272 eg->initialize(state);
273 eg->template onStateAllocation<MostDerived, TEventGenerator>();
274 return eg;
275 };
276
277 SmaccStateInfo::eventGeneratorsInfo[tindex].push_back(eginfo);
278 return egh;
279 }
280
281 template <typename TStateReactor, typename... TUArgs>
282 static std::shared_ptr<smacc::introspection::StateReactorHandler> static_createStateReactor_aux(TUArgs... args)
283 {
284 auto srh = std::make_shared<smacc::introspection::StateReactorHandler>();
285 auto srinfo = std::make_shared<SmaccStateReactorInfo>();
286
287 srinfo->stateReactorType = &typeid(TStateReactor);
288 srinfo->srh = srh;
289 srh->srInfo_ = srinfo;
290
291 const std::type_info *tindex = &(typeid(MostDerived)); // get identifier of the current state
292
293 if (!SmaccStateInfo::stateReactorsInfo.count(tindex))
294 SmaccStateInfo::stateReactorsInfo[tindex] = std::vector<std::shared_ptr<SmaccStateReactorInfo>>();
295
296 srinfo->factoryFunction = [&, srh, args...](ISmaccState *state) {
297 auto sr = state->createStateReactor<TStateReactor>(args...);
298 srh->configureStateReactor(sr);
299 sr->initialize(state);
300 return sr;
301 };
302
303 SmaccStateInfo::stateReactorsInfo[tindex].push_back(srinfo);
304
305 return srh;
306 }
307
308 void checkWhileLoopConditionAndThrowEvent(bool (MostDerived::*conditionFn)())
309 {
310 auto *thisobject = static_cast<MostDerived *>(this);
311 auto condition = boost::bind(conditionFn, thisobject);
312 bool conditionResult = condition();
313
314 //ROS_INFO("LOOP EVENT CONDITION: %d", conditionResult);
315 if (conditionResult)
316 {
317 this->postEvent<EvLoopContinue<MostDerived>>();
318 }
319 else
320 {
321 this->postEvent<EvLoopEnd<MostDerived>>();
322 }
323 ROS_INFO("[%s] POST THROW CONDITION", STATE_NAME);
324 }
325
327 {
328 this->postEvent<EvSequenceFinished<MostDerived>>();
329 }
330
332 // The following declarations should be private.
333 // They are only public because many compilers lack template friends.
335 // See base class for documentation
336 typedef typename base_type::outermost_context_base_type
338 typedef typename base_type::inner_context_ptr_type inner_context_ptr_type;
339 typedef typename base_type::context_ptr_type context_ptr_type;
340 typedef typename base_type::inner_initial_list inner_initial_list;
341
343 outermost_context_base_type &outermostContextBase)
344 {
345 deep_construct(&outermostContextBase, outermostContextBase);
346 }
347
348 // See base class for documentation
349 static void deep_construct(
350 const context_ptr_type &pContext,
351 outermost_context_base_type &outermostContextBase)
352 {
353 const inner_context_ptr_type pInnerContext(
354 shallow_construct(pContext, outermostContextBase));
355 base_type::template deep_construct_inner<inner_initial_list>(
356 pInnerContext, outermostContextBase);
357 }
358
360 const context_ptr_type &pContext,
361 outermost_context_base_type &outermostContextBase)
362 {
363 // allocating in memory
365 const inner_context_ptr_type pInnerContext(state);
366
367 ROS_INFO("[%s] State object created. Initializating...", STATE_NAME);
368 state->entryStateInternal();
369
370 outermostContextBase.add(pInnerContext);
371 return pInnerContext;
372 }
373
374 private:
375 template <typename TOrthogonal, typename TBehavior>
376 static void configure_orthogonal_internal(std::function<void(ISmaccState *state)> initializationFunction)
377 {
378 ROS_INFO("[%s] Runtime configure orthogonal %s -> %s", STATE_NAME, demangleSymbol(typeid(TOrthogonal).name()).c_str(), demangleSymbol(typeid(TBehavior).name()).c_str());
379
381 bhinfo.factoryFunction = initializationFunction;
382
383 bhinfo.behaviorType = &(typeid(TBehavior));
384 bhinfo.orthogonalType = &(typeid(TOrthogonal));
385
386 const std::type_info *tindex = &(typeid(MostDerived));
387 if (!SmaccStateInfo::staticBehaviorInfo.count(tindex))
388 SmaccStateInfo::staticBehaviorInfo[tindex] = std::vector<ClientBehaviorInfoEntry>();
389
390 SmaccStateInfo::staticBehaviorInfo[tindex].push_back(bhinfo);
391 }
392
394 {
395 this->getStateMachine().notifyOnStateEntryStart(static_cast<MostDerived *>(this));
396
397 // TODO: make this static to build the parameter tree at startup
398 this->nh = ros::NodeHandle(contextNh.getNamespace() + std::string("/") + smacc::utils::cleanShortTypeName(typeid(MostDerived)).c_str());
399
400 ROS_DEBUG("[%s] nodehandle namespace: %s", STATE_NAME, nh.getNamespace().c_str());
401
402 this->setParam("created", true);
403
404 // before dynamic runtimeConfigure, we execute the staticConfigure behavior configurations
405 {
406 ROS_INFO("[%s] -- STATIC STATE DESCRIPTION --", STATE_NAME);
407
408 for (const auto &stateReactorsVector : SmaccStateInfo::staticBehaviorInfo)
409 {
410 ROS_DEBUG("[%s] state info: %s", STATE_NAME, demangleSymbol(stateReactorsVector.first->name()).c_str());
411 for (auto &bhinfo : stateReactorsVector.second)
412 {
413 ROS_DEBUG("[%s] client behavior: %s", STATE_NAME, demangleSymbol(bhinfo.behaviorType->name()).c_str());
414 }
415 }
416
417 const std::type_info *tindex = &(typeid(MostDerived));
418 auto &staticDefinedBehaviors = SmaccStateInfo::staticBehaviorInfo[tindex];
419 auto &staticDefinedStateReactors = SmaccStateInfo::stateReactorsInfo[tindex];
420 auto &staticDefinedEventGenerators = SmaccStateInfo::eventGeneratorsInfo[tindex];
421
422 for(auto & ortho : this->getStateMachine().getOrthogonals())
423 {
424 ROS_INFO("[%s] Initializing orthogonal: %s", STATE_NAME, demangleSymbol(typeid(*ortho.second).name()).c_str());
425 ortho.second->initState(this);
426 }
427
428 for (auto &bhinfo : staticDefinedBehaviors)
429 {
430 ROS_INFO("[%s] Creating static client behavior: %s", STATE_NAME, demangleSymbol(bhinfo.behaviorType->name()).c_str());
431 bhinfo.factoryFunction(this);
432 }
433
434 for (auto &sr : staticDefinedStateReactors)
435 {
436 ROS_INFO("[%s] Creating static state reactor: %s", STATE_NAME, demangleSymbol(sr->stateReactorType->name()).c_str());
437 sr->factoryFunction(this);
438 }
439
440 for (auto &eg : staticDefinedEventGenerators)
441 {
442 ROS_INFO("[%s] Creating static event generator: %s", STATE_NAME, demangleSymbol(eg->eventGeneratorType->name()).c_str());
443 eg->factoryFunction(this);
444 }
445
446 ROS_INFO("[%s] ---- END STATIC DESCRIPTION", STATE_NAME);
447 }
448
449 ROS_INFO("[%s] State runtime configuration", STATE_NAME);
450
451 auto *derivedthis = static_cast<MostDerived *>(this);
452
453 // second the orthogonals are internally configured
454 this->getStateMachine().notifyOnRuntimeConfigured(derivedthis);
455
456 // first we runtime configure the state, where we create client behaviors
457 static_cast<MostDerived *>(this)->runtimeConfigure();
458
460
461 ROS_INFO("[%s] State OnEntry", STATE_NAME);
462
463 // finally we go to the derived state onEntry Function
464 static_cast<MostDerived *>(this)->onEntry();
465
466 // here orthogonals and client behaviors are entered OnEntry
467 this->getStateMachine().notifyOnStateEntryEnd(derivedthis);
468 }
469 };
470} // namespace smacc
void notifyOnRuntimeConfigurationFinished(StateType *state)
const SmaccStateMachineInfo & getStateMachineInfo()
void notifyOnStateExitting(StateType *state)
void notifyOnRuntimeConfigured(StateType *state)
const std::map< std::string, std::shared_ptr< smacc::ISmaccOrthogonal > > & getOrthogonals() const
void notifyOnStateEntryEnd(StateType *state)
void notifyOnStateExited(StateType *state)
void notifyOnStateEntryStart(StateType *state)
void setParam(std::string param_name, T param_val)
ros::NodeHandle nh
Definition: smacc_state.h:89
std::shared_ptr< TBehavior > configure(Args &&... args)
ISmaccState * parentState_
Definition: smacc_state.h:93
ros::NodeHandle contextNh
Definition: smacc_state.h:91
const smacc::introspection::SmaccStateInfo * stateInfo_
Definition: smacc_state.h:95
InnerInitial * smacc_inner_type
base_type::context_ptr_type context_ptr_type
context_type::state_iterator state_iterator
static void configure_orthogonal_internal(std::function< void(ISmaccState *state)> initializationFunction)
static inner_context_ptr_type shallow_construct(const context_ptr_type &pContext, outermost_context_base_type &outermostContextBase)
void requiresComponent(SmaccComponentType *&storage)
void throwSequenceFinishedEvent()
static std::shared_ptr< smacc::introspection::StateReactorHandler > static_createStateReactor(TArgs... args)
std::string getShortName()
const smacc::introspection::SmaccStateInfo * getStateInfo()
InnerInitial LastDeepState
base_type::inner_context_ptr_type inner_context_ptr_type
Context::inner_context_type context_type
sc::simple_state< MostDerived, Context, InnerInitial, historyMode > base_type
void checkWhileLoopConditionAndThrowEvent(bool(MostDerived::*conditionFn)())
static std::shared_ptr< smacc::introspection::EventGeneratorHandler > static_createEventGenerator(TUArgs... args)
std::string getFullName()
void setGlobalSMData(std::string name, T value)
static void configure_orthogonal(Args &&... args)
static void deep_construct(const context_ptr_type &pContext, outermost_context_base_type &outermostContextBase)
static std::shared_ptr< smacc::introspection::StateReactorHandler > static_createStateReactor_aux(TUArgs... args)
base_type::outermost_context_base_type outermost_context_base_type
virtual ISmaccState * getParentState()
base_type::inner_initial_list inner_initial_list
bool getGlobalSMData(std::string name, T &ret)
static void configure_orthogonal_runtime(std::function< void(TBehavior &bh, MostDerived &)> initializationFunction)
SmaccState(my_context ctx)
static void initial_deep_construct(outermost_context_base_type &outermostContextBase)
virtual ISmaccStateMachine & getStateMachine()
static void configure_orthogonal_runtime(std::function< void(TBehavior &bh)> initializationFunction)
static std::map< const std::type_info *, std::vector< std::shared_ptr< SmaccStateReactorInfo > > > stateReactorsInfo
static std::map< const std::type_info *, std::vector< ClientBehaviorInfoEntry > > staticBehaviorInfo
static std::map< const std::type_info *, std::vector< std::shared_ptr< SmaccEventGeneratorInfo > > > eventGeneratorsInfo
std::map< std::string, std::shared_ptr< SmaccStateInfo > > states
auto optionalNodeHandle(boost::intrusive_ptr< T > &obj) -> ros::NodeHandle
Definition: introspection.h:39
std::string demangleSymbol()
Definition: introspection.h:75
std::string cleanShortTypeName(const std::type_info &tinfo)
Definition: common.cpp:14
void standardOnExit(TState &st, std::true_type)
Definition: state_traits.h:62
#define STATE_NAME
base_type::context_ptr_type pContext_
my_context(typename base_type::context_ptr_type pContext)
std::function< void(smacc::ISmaccState *)> factoryFunction