SMACC2
smacc_state_base.hpp
Go to the documentation of this file.
1// Copyright 2021 RobosoftAI Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*****************************************************************************************************************
16 *
17 * Authors: Pablo Inigo Blasco, Brett Aldrich
18 *
19 ******************************************************************************************************************/
20
21#pragma once
28
29#define STATE_NAME (demangleSymbol(typeid(MostDerived).name()).c_str())
30
31namespace smacc2
32{
33using namespace smacc2::introspection;
34using namespace smacc2::default_events;
35
36template <
37 class MostDerived, class Context, class InnerInitial = mpl::list<>,
38 sc::history_mode historyMode = sc::has_deep_history>
39class SmaccState : public sc::simple_state<MostDerived, Context, InnerInitial, historyMode>,
40 public ISmaccState
41{
42 typedef sc::simple_state<MostDerived, Context, InnerInitial, historyMode> base_type;
43
44public:
45 typedef Context TContext;
46 typedef typename Context::inner_context_type context_type;
47 typedef typename context_type::state_iterator state_iterator;
48
49 typedef InnerInitial LastDeepState;
50
52 InnerInitial * smacc_inner_type;
53
56 {
57 my_context(typename base_type::context_ptr_type pContext) : pContext_(pContext) {}
58
59 typename base_type::context_ptr_type pContext_;
60 };
61
62 SmaccState() = delete;
63
64 // Constructor that initializes the state ros node handle
66 {
67 static_assert(
68 std::is_base_of<ISmaccState, Context>::value ||
69 std::is_base_of<ISmaccStateMachine, Context>::value,
70 "The context class must be a SmaccState or a SmaccStateMachine");
71 static_assert(
72 !std::is_same<MostDerived, Context>::value,
73 "The context must be a different state or state machine "
74 "than the current state");
75
76 logger_.reset(new rclcpp::Logger(
77 rclcpp::get_logger(smacc2::utils::cleanShortTypeName(typeid(MostDerived)))));
78
79 RCLCPP_INFO(getLogger(), "[%s] creating state ", STATE_NAME);
80 this->set_context(ctx.pContext_);
81
82 node_ = this->getStateMachine().getNode();
83
84 this->stateInfo_ = getStateInfo();
85
86 // storing a reference to the parent state
87 auto & ps = this->template context<Context>();
88 parentState_ = dynamic_cast<ISmaccState *>(&ps);
89 finishStateThrown = false;
90 }
91
92 virtual ~SmaccState() {}
93
95 {
96 auto smInfo = this->getStateMachine().getStateMachineInfo();
97
98 auto key = typeid(MostDerived).name();
99 if (smInfo.states.count(key))
100 {
101 return smInfo.states[key].get();
102 }
103 else
104 {
105 return nullptr;
106 }
107 }
108
109 std::string getName() override { return getShortName(); }
110
111 std::string getFullName() { return demangleSymbol(typeid(MostDerived).name()); }
112
113 std::string getShortName() { return smacc2::utils::cleanShortTypeName(typeid(MostDerived)); }
114
116 {
117 // auto* ctx = dynamic_cast<ISmaccState*>(this->template context<Context *>());
118
119 return parentState_;
120 }
121
122 // this function is called by boot statechart before the destructor call
123 void exit()
124 {
125 auto * derivedThis = static_cast<MostDerived *>(this);
126 this->getStateMachine().notifyOnStateExitting(derivedThis);
127 {
128 std::lock_guard<std::recursive_mutex> lock(this->getStateMachine().getMutex());
130 try
131 {
133 // static_cast<MostDerived *>(this)->onExit();
134 standardOnExit(*derivedThis);
136 }
137 catch (...)
138 {
139 }
140 this->getStateMachine().notifyOnStateExited(derivedThis);
141 }
142 }
143
144public:
145 // This method is static-polymorphic because of the curiously recurring template pattern. It
146 // calls to the most derived class onEntry method if declared on smacc state construction
148
149 // This method is static-polymorphic because of the curiously recurring template pattern. It
150 // calls to the most derived class onEntry method if declared on smacc state construction
151 void onEntry() {}
152
153 // this method is static-polimorphic because of the curiously recurreing pattern. It
154 // calls to the most derived class onExit method if declared on smacc state destruction
155 void onExit() {}
156
157 template <typename T>
158 bool getGlobalSMData(std::string name, T & ret)
159 {
160 return base_type::outermost_context().getGlobalSMData(name, ret);
161 }
162
163 // Store globally in this state machine. (By value parameter )
164 template <typename T>
165 void setGlobalSMData(std::string name, T value)
166 {
167 base_type::outermost_context().setGlobalSMData(name, value);
168 }
169
170 template <typename SmaccComponentType>
171 void requiresComponent(SmaccComponentType *& storage)
172 {
173 base_type::outermost_context().requiresComponent(storage);
174 }
175
176 virtual ISmaccStateMachine & getStateMachine() { return base_type::outermost_context(); }
177
178 template <typename TOrthogonal, typename TBehavior>
180 std::function<void(TBehavior & bh, MostDerived &)> initializationFunction)
181 {
182 configure_orthogonal_internal<TOrthogonal, TBehavior>([=](ISmaccState * state) {
183 // auto bh = std::make_shared<TBehavior>(args...);
184 auto bh = state->configure<TOrthogonal, TBehavior>();
185 initializationFunction(*bh, *(static_cast<MostDerived *>(state)));
186 });
187 }
188
189 template <typename TOrthogonal, typename TBehavior>
191 std::function<void(TBehavior & bh)> initializationFunction)
192 {
193 configure_orthogonal_internal<TOrthogonal, TBehavior>([=](ISmaccState * state) {
194 // auto bh = std::make_shared<TBehavior>(args...);
195 auto bh = state->configure<TOrthogonal, TBehavior>();
196 initializationFunction(*bh);
197 });
198 }
199
200 template <typename TOrthogonal, typename TBehavior, typename... Args>
201 static void configure_orthogonal(Args &&... args)
202 {
203 configure_orthogonal_internal<TOrthogonal, TBehavior>([=](ISmaccState * state) {
204 // auto bh = std::make_shared<TBehavior>(args...);
205 state->configure<TOrthogonal, TBehavior>(args...);
206 });
207 }
208
209 template <
210 typename TStateReactor, typename TOutputEvent, typename TInputEventList, typename... TArgs>
211 static std::shared_ptr<smacc2::introspection::StateReactorHandler> static_createStateReactor(
212 TArgs... args)
213 {
214 auto srh = std::make_shared<smacc2::introspection::StateReactorHandler>(globalNh_);
215 auto srinfo = std::make_shared<SmaccStateReactorInfo>();
216
217 srinfo->stateReactorType = TypeInfo::getTypeInfoFromType<TStateReactor>();
218 srinfo->outputEventType = TypeInfo::getTypeInfoFromType<TOutputEvent>();
219
220 if (srinfo->outputEventType->templateParameters.size() == 2)
221 {
222 srinfo->objectTagType = srinfo->outputEventType->templateParameters[1];
223 }
224 else if (srinfo->outputEventType->templateParameters.size() == 1)
225 {
226 srinfo->objectTagType = TypeInfo::getTypeInfoFromType<state_reactors::EmptyObjectTag>();
227 }
228 else
229 {
230 assert(
231 false &&
232 "state reactor output events should have one or two parameters (SourceType, ObjectTag)");
233 }
234
235 // iterate statically on all event sources
236 using boost::mpl::_1;
237 using wrappedList = typename boost::mpl::transform<TInputEventList, _1>::type;
239 boost::mpl::for_each<wrappedList>(op);
240
241 srinfo->srh = srh;
242 srh->srInfo_ = srinfo;
243
244 const std::type_info * tindex = &(typeid(MostDerived)); // get identifier of the current state
245
246 if (!SmaccStateInfo::stateReactorsInfo.count(tindex))
248 std::vector<std::shared_ptr<SmaccStateReactorInfo>>();
249
250 srinfo->factoryFunction = [&, srh, args...](ISmaccState * state) {
251 auto sr =
252 state->createStateReactor<TStateReactor, TOutputEvent, TInputEventList, TArgs...>(args...);
253 srh->configureStateReactor(sr);
254 sr->initialize(state);
255 return sr;
256 };
257
258 SmaccStateInfo::stateReactorsInfo[tindex].push_back(srinfo);
259
260 return srh;
261 }
262
263 template <typename TEventGenerator, typename... TUArgs>
264 static std::shared_ptr<smacc2::introspection::EventGeneratorHandler> static_createEventGenerator(
265 TUArgs... args)
266 {
267 auto egh = std::make_shared<smacc2::introspection::EventGeneratorHandler>();
268 auto eginfo = std::make_shared<SmaccEventGeneratorInfo>();
269 eginfo->eventGeneratorType = TypeInfo::getTypeInfoFromType<TEventGenerator>();
270
271 eginfo->egh = egh;
272 egh->egInfo_ = eginfo;
273
274 const std::type_info * tindex = &(typeid(MostDerived)); // get identifier of the current state
275
276 if (!SmaccStateInfo::eventGeneratorsInfo.count(tindex))
278 std::vector<std::shared_ptr<SmaccEventGeneratorInfo>>();
279
280 eginfo->factoryFunction = [&, egh, args...](ISmaccState * state) {
281 auto eg = state->createEventGenerator<TEventGenerator>(args...);
282 egh->configureEventGenerator(eg);
283 eg->initialize(state);
284 eg->template onStateAllocation<MostDerived, TEventGenerator>();
285 return eg;
286 };
287
288 SmaccStateInfo::eventGeneratorsInfo[tindex].push_back(eginfo);
289 return egh;
290 }
291
292 template <typename TStateReactor, typename... TUArgs>
293 static std::shared_ptr<smacc2::introspection::StateReactorHandler> static_createStateReactor_aux(
294 TUArgs... args)
295 {
296 auto srh = std::make_shared<smacc2::introspection::StateReactorHandler>(globalNh_);
297 auto srinfo = std::make_shared<SmaccStateReactorInfo>();
298
299 srinfo->stateReactorType = TypeInfo::getTypeInfoFromType<TStateReactor>();
300 srinfo->srh = srh;
301 srh->srInfo_ = srinfo;
302
303 const std::type_info * tindex = &(typeid(MostDerived)); // get identifier of the current state
304
305 if (!SmaccStateInfo::stateReactorsInfo.count(tindex))
307 std::vector<std::shared_ptr<SmaccStateReactorInfo>>();
308
309 srinfo->factoryFunction = [&, srh, args...](ISmaccState * state) {
310 auto sr = state->createStateReactor<TStateReactor>(args...);
311 srh->configureStateReactor(sr);
312 sr->initialize(state);
313 return sr;
314 };
315
316 SmaccStateInfo::stateReactorsInfo[tindex].push_back(srinfo);
317
318 return srh;
319 }
320
321 void checkWhileLoopConditionAndThrowEvent(bool (MostDerived::*conditionFn)())
322 {
323 auto * thisobject = static_cast<MostDerived *>(this);
324 auto condition = boost::bind(conditionFn, thisobject);
325 bool conditionResult = condition();
326
327 // RCLCPP_INFO("LOOP EVENT CONDITION: %d", conditionResult);
328 if (conditionResult)
329 {
330 this->postEvent<EvLoopContinue<MostDerived>>();
331 }
332 else
333 {
334 this->postEvent<EvLoopEnd<MostDerived>>();
335 }
336 RCLCPP_INFO(getLogger(), "[%s] POST THROW CONDITION", STATE_NAME);
337 }
338
339 void throwSequenceFinishedEvent() { this->postEvent<EvSequenceFinished<MostDerived>>(); }
340
342 // The following declarations should be private.
343 // They are only public because many compilers lack template friends.
345 // See base class for documentation
346 typedef typename base_type::outermost_context_base_type outermost_context_base_type;
347 typedef typename base_type::inner_context_ptr_type inner_context_ptr_type;
348 typedef typename base_type::context_ptr_type context_ptr_type;
349 typedef typename base_type::inner_initial_list inner_initial_list;
350
351 static void initial_deep_construct(outermost_context_base_type & outermostContextBase)
352 {
353 deep_construct(&outermostContextBase, outermostContextBase);
354 }
355
356 // See base class for documentation
357 static void deep_construct(
358 const context_ptr_type & pContext, outermost_context_base_type & outermostContextBase)
359 {
360 const inner_context_ptr_type pInnerContext(shallow_construct(pContext, outermostContextBase));
361 base_type::template deep_construct_inner<inner_initial_list>(
362 pInnerContext, outermostContextBase);
363 }
364
366 const context_ptr_type & pContext, outermost_context_base_type & outermostContextBase)
367 {
368 // allocating in memory
369 auto state = new MostDerived(
371 const inner_context_ptr_type pInnerContext(state);
372
374 state->entryStateInternal();
376
377 outermostContextBase.add(pInnerContext);
378 return pInnerContext;
379 }
380
381private:
382 template <typename TOrthogonal, typename TBehavior>
384 std::function<void(ISmaccState * state)> initializationFunction)
385 {
387 bhinfo.factoryFunction = initializationFunction;
388
389 bhinfo.behaviorType = &(typeid(TBehavior));
390 bhinfo.orthogonalType = &(typeid(TOrthogonal));
391
392 const std::type_info * tindex = &(typeid(MostDerived));
393 if (!SmaccStateInfo::staticBehaviorInfo.count(tindex))
394 SmaccStateInfo::staticBehaviorInfo[tindex] = std::vector<ClientBehaviorInfoEntry>();
395
396 SmaccStateInfo::staticBehaviorInfo[tindex].push_back(bhinfo);
397 RCLCPP_INFO_STREAM(
398 rclcpp::get_logger("static"), "[states walking] State "
400 << "client behavior count: "
401 << SmaccStateInfo::staticBehaviorInfo[tindex].size());
402 }
403
405 {
406 // finally we go to the derived state onEntry Function
407
408 RCLCPP_INFO(getLogger(), "[%s] State object created. Initializating...", STATE_NAME);
409 this->getStateMachine().notifyOnStateEntryStart(static_cast<MostDerived *>(this));
410
411 RCLCPP_INFO_STREAM(
412 getLogger(), "[" << smacc2::utils::cleanShortTypeName(typeid(MostDerived)).c_str()
413 << "] creating ros subnode");
414
415 // before dynamic runtimeConfigure, we execute the staticConfigure behavior configurations
416 {
417 RCLCPP_INFO(getLogger(), "[%s] -- STATIC STATE DESCRIPTION --", STATE_NAME);
418
419 for (const auto & stateReactorsVector : SmaccStateInfo::staticBehaviorInfo)
420 {
421 RCLCPP_DEBUG(
422 getLogger(), "[%s] state reactor info: %s", STATE_NAME,
423 demangleSymbol(stateReactorsVector.first->name()).c_str());
424 for (auto & srinfo : stateReactorsVector.second)
425 {
426 RCLCPP_DEBUG(
427 getLogger(), "[%s] state reactor: %s", STATE_NAME,
428 demangleSymbol(srinfo.behaviorType->name()).c_str());
429 }
430 }
431
432 const std::type_info * tindex = &(typeid(MostDerived));
433 auto & staticDefinedBehaviors = SmaccStateInfo::staticBehaviorInfo[tindex];
434 auto & staticDefinedStateReactors = SmaccStateInfo::stateReactorsInfo[tindex];
435 auto & staticDefinedEventGenerators = SmaccStateInfo::eventGeneratorsInfo[tindex];
436
437 RCLCPP_DEBUG_STREAM(
438 getLogger(), "finding static client behaviors. State Database: "
439 << SmaccStateInfo::staticBehaviorInfo.size() << ". Current state "
440 << cleanShortTypeName(*tindex)
441 << " cbs: " << SmaccStateInfo::staticBehaviorInfo[tindex].size());
442 for (auto & bhinfo : staticDefinedBehaviors)
443 {
444 RCLCPP_INFO(
445 getLogger(), "[%s] Creating static client behavior: %s", STATE_NAME,
446 demangleSymbol(bhinfo.behaviorType->name()).c_str());
447 bhinfo.factoryFunction(this);
448 }
449
450 for (auto & sr : staticDefinedStateReactors)
451 {
452 RCLCPP_INFO(
453 getLogger(), "[%s] Creating static state reactor: %s", STATE_NAME,
454 sr->stateReactorType->getFullName().c_str());
455 sr->factoryFunction(this);
456 }
457
458 for (auto & eg : staticDefinedEventGenerators)
459 {
460 RCLCPP_INFO(
461 getLogger(), "[%s] Creating static event generator: %s", STATE_NAME,
462 eg->eventGeneratorType->getFullName().c_str());
463 eg->factoryFunction(this);
464 }
465
466 RCLCPP_INFO(getLogger(), "[%s] ---- END STATIC DESCRIPTION", STATE_NAME);
467 }
468
469 RCLCPP_INFO(getLogger(), "[%s] State runtime configuration", STATE_NAME);
470
471 auto * derivedthis = static_cast<MostDerived *>(this);
472
473 // second the orthogonals are internally configured
474 this->getStateMachine().notifyOnRuntimeConfigured(derivedthis);
475
477 // first we runtime configure the state, where we create client behaviors
478 static_cast<MostDerived *>(this)->runtimeConfigure();
480
482
483 RCLCPP_INFO(getLogger(), "[%s] State OnEntry", STATE_NAME);
484
485 static_cast<MostDerived *>(this)->onEntry();
486
487 // here orthogonals and client behaviors are entered OnEntry
488 this->getStateMachine().notifyOnStateEntryEnd(derivedthis);
489 }
490};
491} // namespace smacc2
rclcpp::Node::SharedPtr getNode()
void notifyOnStateExitting(StateType *state)
void notifyOnRuntimeConfigurationFinished(StateType *state)
void notifyOnStateExited(StateType *state)
void notifyOnStateEntryEnd(StateType *state)
const SmaccStateMachineInfo & getStateMachineInfo()
void notifyOnRuntimeConfigured(StateType *state)
void notifyOnStateEntryStart(StateType *state)
std::shared_ptr< rclcpp::Logger > logger_
Definition: smacc_state.hpp:98
rclcpp::Logger getLogger()
Definition: smacc_state.hpp:36
std::shared_ptr< TBehavior > configure(Args &&... args)
rclcpp::Node::SharedPtr node_
Definition: smacc_state.hpp:97
ISmaccState * parentState_
const smacc2::introspection::SmaccStateInfo * stateInfo_
sc::simple_state< MostDerived, Context, InnerInitial, historyMode > base_type
static inner_context_ptr_type shallow_construct(const context_ptr_type &pContext, outermost_context_base_type &outermostContextBase)
static std::shared_ptr< smacc2::introspection::StateReactorHandler > static_createStateReactor(TArgs... args)
base_type::context_ptr_type context_ptr_type
static void initial_deep_construct(outermost_context_base_type &outermostContextBase)
InnerInitial * smacc_inner_type
base_type::inner_context_ptr_type inner_context_ptr_type
void checkWhileLoopConditionAndThrowEvent(bool(MostDerived::*conditionFn)())
static void configure_orthogonal_internal(std::function< void(ISmaccState *state)> initializationFunction)
base_type::inner_initial_list inner_initial_list
static std::shared_ptr< smacc2::introspection::EventGeneratorHandler > static_createEventGenerator(TUArgs... args)
virtual ISmaccStateMachine & getStateMachine()
static std::shared_ptr< smacc2::introspection::StateReactorHandler > static_createStateReactor_aux(TUArgs... args)
const smacc2::introspection::SmaccStateInfo * getStateInfo()
bool getGlobalSMData(std::string name, T &ret)
std::string getFullName()
static void deep_construct(const context_ptr_type &pContext, outermost_context_base_type &outermostContextBase)
base_type::outermost_context_base_type outermost_context_base_type
InnerInitial LastDeepState
virtual ISmaccState * getParentState()
SmaccState(my_context ctx)
context_type::state_iterator state_iterator
std::string getName() override
void setGlobalSMData(std::string name, T value)
Context::inner_context_type context_type
static void configure_orthogonal_runtime(std::function< void(TBehavior &bh)> initializationFunction)
void requiresComponent(SmaccComponentType *&storage)
std::string getShortName()
static void configure_orthogonal_runtime(std::function< void(TBehavior &bh, MostDerived &)> initializationFunction)
static void configure_orthogonal(Args &&... args)
static std::map< const std::type_info *, std::vector< std::shared_ptr< SmaccStateReactorInfo > > > stateReactorsInfo
static std::map< const std::type_info *, std::vector< std::shared_ptr< SmaccEventGeneratorInfo > > > eventGeneratorsInfo
static std::map< const std::type_info *, std::vector< ClientBehaviorInfoEntry > > staticBehaviorInfo
std::map< std::string, std::shared_ptr< SmaccStateInfo > > states
rclcpp::Node::SharedPtr globalNh_
Definition: reflection.cpp:28
std::string demangleSymbol(const std::string &name)
std::string cleanShortTypeName(const std::type_info &tinfo)
Definition: common.cpp:28
void standardOnExit(TState &st, std::true_type)
#define STATE_NAME
void TRACEPOINT(spinOnce)
my_context(typename base_type::context_ptr_type pContext)
base_type::context_ptr_type pContext_
std::function< void(smacc2::ISmaccState *)> factoryFunction
smacc2_state_onExit_end
smacc2_state_onRuntimeConfigure_start
smacc2_state_onEntry_end
smacc2_state_onRuntimeConfigure_end
smacc2_state_onEntry_start
smacc2_state_onExit_start