SMACC2
Loading...
Searching...
No Matches
smacc_state_machine_info.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
22
23#include <map>
24#include <memory>
25#include <string>
26#include <vector>
27
28#include <smacc2/common.hpp>
30
31// smacc_msgs
32#include <smacc2_msgs/msg/smacc_event_generator.hpp>
33#include <smacc2_msgs/msg/smacc_orthogonal.hpp>
34#include <smacc2_msgs/msg/smacc_state.hpp>
35#include <smacc2_msgs/msg/smacc_state_reactor.hpp>
36#include <smacc2_msgs/msg/smacc_transition.hpp>
37
38namespace smacc2
39{
40namespace introspection
41{
42extern rclcpp::Node::SharedPtr globalNh_;
43
44class SmaccStateMachineInfo : public std::enable_shared_from_this<SmaccStateMachineInfo>
45{
46public:
47 explicit SmaccStateMachineInfo(rclcpp::Node::SharedPtr nh) : nh_(nh) {}
48
49 std::map<std::string, std::shared_ptr<SmaccStateInfo>> states;
50
51 std::vector<smacc2_msgs::msg::SmaccState> stateMsgs;
52
53 template <typename InitialStateType>
55
56 template <typename StateType>
57 std::shared_ptr<SmaccStateInfo> createState(std::shared_ptr<SmaccStateInfo> parentState);
58
59 template <typename StateType>
61 {
62 auto typeNameStr = typeid(StateType).name();
63
64 return states.count(typeNameStr) > 0;
65 }
66
67 template <typename StateType>
68 std::shared_ptr<SmaccStateInfo> getState()
69 {
70 if (this->containsState<StateType>())
71 {
72 return states[typeid(StateType).name()];
73 }
74 return nullptr;
75 }
76
77 inline rclcpp::Node::SharedPtr getNode() { return nh_; }
78
79 inline rclcpp::Logger getLogger() { return nh_->get_logger(); }
80
81 template <typename StateType>
82 void addState(std::shared_ptr<StateType> & state);
84
85private:
86 rclcpp::Node::SharedPtr nh_;
87};
88
89//---------------------------------------------
91{
92 std::shared_ptr<SmaccStateInfo> & parentState_;
93 explicit AddSubState(std::shared_ptr<SmaccStateInfo> & parentState) : parentState_(parentState) {}
94
95 template <typename T>
96 void operator()(T);
97};
98
99//---------------------------------------------
101{
102 std::shared_ptr<SmaccStateInfo> & currentState_;
103
104 explicit AddTransition(std::shared_ptr<SmaccStateInfo> & currentState)
105 : currentState_(currentState)
106 {
107 }
108
109 template <
110 template <typename, typename, typename> typename TTransition, typename TevSource,
111 template <typename> typename EvType, typename Tag, typename DestinyState>
112 void operator()(TTransition<EvType<TevSource>, DestinyState, Tag>);
113
114 template <
115 template <typename, typename> typename TTransition, typename TevSource,
116 template <typename> typename EvType, typename DestinyState>
117 void operator()(TTransition<EvType<TevSource>, DestinyState>);
118
119 template <typename T>
120 void operator()(T);
121};
122
123//---------------------------------------------
124template <typename InitialStateType>
126{
127 static void walkStates(std::shared_ptr<SmaccStateInfo> & currentState, bool rootInitialNode);
128};
129
130//---------------------------------------------
131template <typename T>
133{
134 using type_t = typename T::type;
135 //auto childState = this->parentState_->createChildState<type_t>()
137}
138
139//--------------------------------------------
140template <typename T>
141typename disable_if<boost::mpl::is_sequence<T>>::type processSubState(
142 std::shared_ptr<SmaccStateInfo> & parentState)
143{
144 WalkStatesExecutor<T>::walkStates(parentState, false);
145}
146
147//---------------------------------------------
148template <typename T>
149typename enable_if<boost::mpl::is_sequence<T>>::type processSubState(
150 std::shared_ptr<SmaccStateInfo> & parentState)
151{
152 using boost::mpl::_1;
153 using wrappedList = typename boost::mpl::transform<T, add_type_wrapper<_1>>::type;
154 boost::mpl::for_each<wrappedList>(AddSubState(parentState));
155}
156
157//--------------------------------------------
158/*Iterate on All Transitions*/
159template <typename T>
160typename enable_if<boost::mpl::is_sequence<T>>::type processTransitions(
161 std::shared_ptr<SmaccStateInfo> & sourceState)
162{
163 RCLCPP_INFO(
164 globalNh_->get_logger(), "State %s Walker has transition list",
165 sourceState->fullStateName.c_str());
166 using boost::mpl::_1;
167 using wrappedList = typename boost::mpl::transform<T, add_type_wrapper<_1>>::type;
168 RCLCPP_INFO(
169 globalNh_->get_logger(), "[DIAG] About to call boost::mpl::for_each for state %s",
170 sourceState->fullStateName.c_str());
171 boost::mpl::for_each<wrappedList>(AddTransition(sourceState));
172 RCLCPP_INFO(
173 globalNh_->get_logger(), "[DIAG] Completed boost::mpl::for_each for state %s",
174 sourceState->fullStateName.c_str());
175}
176
177template <typename Ev, typename Dst, typename Tag>
179 smacc2::Transition<Ev, boost::statechart::deep_history<Dst>, Tag> *,
180 std::shared_ptr<SmaccStateInfo> & sourceState)
181{
182 RCLCPP_INFO(
183 globalNh_->get_logger(), "[DIAG] processTransition [deep_history] START for state %s",
184 sourceState->toShortName().c_str());
185 auto transitionTypeInfo = TypeInfo::getTypeInfoFromType<
187 RCLCPP_INFO(
188 globalNh_->get_logger(), "[DIAG] processTransition [deep_history] got TypeInfo for state %s",
189 sourceState->toShortName().c_str());
190 smacc2::Transition<Ev, Dst, Tag> * mock = nullptr;
191 processTransitionAux(mock, sourceState, true, transitionTypeInfo);
192}
193
194template <typename Ev, typename Dst, typename Tag>
196 smacc2::Transition<Ev, Dst, Tag> * t, std::shared_ptr<SmaccStateInfo> & sourceState)
197{
198 RCLCPP_INFO(
199 globalNh_->get_logger(), "[DIAG] processTransition START for state %s",
200 sourceState->toShortName().c_str());
202 RCLCPP_INFO(
203 globalNh_->get_logger(), "[DIAG] processTransition got TypeInfo for state %s",
204 sourceState->toShortName().c_str());
205 RCLCPP_INFO(
206 globalNh_->get_logger(), "State %s Walker transition: %s", sourceState->toShortName().c_str(),
207 demangleSymbol(typeid(Ev).name()).c_str());
208 processTransitionAux(t, sourceState, false, transitionTypeInfo);
209}
210
211template <typename Ev, typename Dst, typename Tag>
213 smacc2::Transition<Ev, Dst, Tag> *, std::shared_ptr<SmaccStateInfo> & sourceState, bool history,
214 TypeInfo::Ptr & transitionTypeInfo)
215{
216 RCLCPP_INFO(
217 globalNh_->get_logger(), "State %s Walker transition: %s", sourceState->toShortName().c_str(),
218 demangleSymbol(typeid(Ev).name()).c_str());
219 std::string transitionTag;
220 std::string transitionType;
221
222 if (typeid(Tag) != typeid(default_transition_name))
223 {
224 transitionTag = demangleSymbol<Tag>();
225 transitionType = getTransitionType<Tag>();
226 RCLCPP_DEBUG_STREAM(globalNh_->get_logger(), "TRANSITION TYPE:" << transitionType);
227 }
228 else
229 {
230 transitionTag = "";
231 automaticTransitionTag<Ev>(transitionTag);
232 automaticTransitionType<Ev>(transitionType);
233 }
234
235 RCLCPP_INFO_STREAM(globalNh_->get_logger(), "Transition tag: " << transitionTag);
236
237 if (!sourceState->stateMachine_->containsState<Dst>())
238 {
239 auto realparentState = sourceState->stateMachine_->getState<typename Dst::TContext>();
240 auto siblingnode = sourceState->stateMachine_->createState<Dst>(realparentState);
241
242 // auto siblingnode = sourceState->stateMachine_->createState<Dst>(sourceState->parentState_);
243 WalkStatesExecutor<Dst>::walkStates(siblingnode, true);
244 sourceState->declareTransition<Ev>(
245 siblingnode, transitionTag, transitionType, history, transitionTypeInfo);
246 }
247 else
248 {
249 // auto realparentState = sourceState->stateMachine_->getState<typename Dst::TContext>();
250 // auto siblingnode = sourceState->stateMachine_->createState<Dst>(realparentState);
251
252 auto siblingnode = sourceState->stateMachine_->getState<Dst>();
253 sourceState->declareTransition<Ev>(
254 siblingnode, transitionTag, transitionType, history, transitionTypeInfo);
255 }
256}
257
258//---------------------------------------------
259template <typename EvType>
261 std::shared_ptr<SmaccStateInfo> & dstState, std::string transitionTag, std::string transitionType,
262 bool history, TypeInfo::Ptr transitionTypeInfo)
263{
264 auto evtype = demangledTypeName<EvType>();
265
266 SmaccTransitionInfo transitionInfo;
267 transitionInfo.index = transitions_.size();
268 transitionInfo.sourceState = shared_from_this();
269 transitionInfo.destinyState = dstState;
270 transitionInfo.transitionTypeInfo = transitionTypeInfo;
271
272 if (transitionTag != "")
273 transitionInfo.transitionTag = transitionTag;
274 else
275 transitionInfo.transitionTag = "Transition_" + std::to_string(transitionInfo.index);
276
277 transitionInfo.transitionType = transitionType;
278 transitionInfo.historyNode = history;
279
280 transitionInfo.eventInfo =
281 std::make_shared<SmaccEventInfo>(transitionTypeInfo->templateParameters.front());
282
283 EventLabel<EvType>(transitionInfo.eventInfo->label);
284 // RCLCPP_DEBUG_STREAM(getLogger(), "LABEL: " << transitionInfo.eventInfo->label);
285
286 transitions_.push_back(transitionInfo);
287}
288//---------------------------------------------
289
290//------------------ staticConfigure -----------------------------
291
292// SFINAE test
293template <typename T>
295{
296private:
297 typedef char YesType[1];
298 typedef char NoType[2];
299
300 template <typename C>
301 static YesType & test(decltype(&C::staticConfigure));
302 template <typename C>
303 static NoType & test(...);
304
305public:
306 enum
307 {
308 value = sizeof(test<T>(0)) == sizeof(YesType)
309 };
310};
311
312// template <typename TevSource, template <typename> typename EvType>
313// void SmaccStateInfo::declareTransition(std::shared_ptr<SmaccStateInfo> &dstState, std::string transitionTag, std::string transitionType, bool history)
314// {
315// auto evtype = demangledTypeName<EvType<TevSource>>();
316
317// SmaccTransitionInfo transitionInfo;
318// transitionInfo.index = transitions_.size();
319// transitionInfo.sourceState = shared_from_this();
320// transitionInfo.destinyState = dstState;
321
322// if (transitionTag != "")
323// transitionInfo.transitionTag = transitionTag;
324// else
325// transitionInfo.transitionTag = "Transition_" + std::to_string(transitionInfo.index);
326
327// transitionInfo.transitionType = transitionType;
328
329// transitionInfo.eventInfo = std::make_shared<SmaccEventInfo>(TypeInfo::getTypeInfoFromString(demangleSymbol(typeid(EvType<TevSource>).name())));
330
331// EventLabel<EvType<TevSource>>(transitionInfo.eventInfo->label);
332// RCLCPP_ERROR_STREAM(getLogger(),"LABEL: " << transitionInfo.eventInfo->label);
333
334// transitions_.push_back(transitionInfo);
335// }
336
337//---------------------------------------------
338template <typename Ev, typename Dst>
340 statechart::transition<Ev, Dst> *, std::shared_ptr<SmaccStateInfo> & sourceState)
341{
342 // RCLCPP_INFO_STREAM(getLogger(),"GOTCHA");
343}
344
345template <typename Ev>
347 statechart::custom_reaction<Ev> *, std::shared_ptr<SmaccStateInfo> & sourceState)
348{
349 // RCLCPP_INFO_STREAM(getLogger(),"GOTCHA");
350}
351
352//---------------------------------------------
353// only reached if it is a leaf transition in the mpl::list
354
355template <typename T>
356typename disable_if<boost::mpl::is_sequence<T>>::type processTransitions(
357 std::shared_ptr<SmaccStateInfo> & sourceState)
358{
359 RCLCPP_INFO(
360 globalNh_->get_logger(), "[DIAG] processTransitions [single/leaf] called for state %s",
361 sourceState->fullStateName.c_str());
362 T * dummy = nullptr;
363 processTransition(dummy, sourceState);
364 RCLCPP_INFO(
365 globalNh_->get_logger(), "[DIAG] processTransitions [single/leaf] completed for state %s",
366 sourceState->fullStateName.c_str());
367}
368
369template <typename T>
370typename std::enable_if<HasOnDefinition<T>::value, void>::type CallOnDefinition()
371{
372 /* something when T has toString ... */
373 RCLCPP_INFO_STREAM(
374 globalNh_->get_logger(), "EXECUTING ONDEFINITION: " << demangleSymbol(typeid(T).name()));
375 T::staticConfigure();
376}
377
378template <typename T>
379typename std::enable_if<!HasOnDefinition<T>::value, void>::type CallOnDefinition()
380{
381 RCLCPP_INFO_STREAM(
382 globalNh_->get_logger(),
383 "static OnDefinition: dont exist for " << demangleSymbol(typeid(T).name()));
384 /* something when T has toString ... */
385}
386
387/*
388// only reached if it is a leaf transition in the mpl::list
389template <template <typename,typename,typename> typename TTransition, typename TevSource,
390template <typename> typename EvType, typename Tag, typename DestinyState >
391typename disable_if<boost::mpl::is_sequence<TTransition<EvType<TevSource>,DestinyState, Tag>>>::type
392processTransitions(std::shared_ptr<SmaccStateInfo> &sourceState)
393{
394 RCLCPP_INFO(getLogger(),"DETECTED COMPLEX TRANSITION **************");
395 // RCLCPP_INFO_STREAM(getLogger(),"state transition from: " << sourceState->demangledStateName
396 << " of type: " << demangledTypeName<T>());
397 TTransition<EvType<TevSource>,DestinyState, Tag> *dummy;
398 processTransition(dummy, sourceState);
399}
400
401template <template <typename,typename> typename TTransition, typename TevSource,
402template <typename> typename EvType, typename DestinyState >
403typename disable_if<boost::mpl::is_sequence<TTransition<EvType<TevSource>,DestinyState>>>::type
404processTransitions(std::shared_ptr<SmaccStateInfo> &sourceState)
405{
406 RCLCPP_INFO(getLogger(),"DETECTED COMPLEX TRANSITION **************");
407 // RCLCPP_INFO_STREAM(getLogger(),"state transition from: " << sourceState->demangledStateName
408 << " of type: " << demangledTypeName<T>());
409 TTransition<EvType<TevSource>,DestinyState> *dummy;
410 processTransition(dummy, sourceState);
411}
412*/
413
414//--------------------------------------------
415
416template <
417 template <typename, typename, typename> typename TTransition, typename TevSource,
418 template <typename> typename EvType, typename Tag, typename DestinyState>
419void AddTransition::operator()(TTransition<EvType<TevSource>, DestinyState, Tag>)
420{
421 RCLCPP_INFO(
422 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [3-param] called for state %s",
423 currentState_->fullStateName.c_str());
425 RCLCPP_INFO(
426 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [3-param] completed for state %s",
427 currentState_->fullStateName.c_str());
428}
429
430//--------------------------------------------
431
432template <
433 template <typename, typename> typename TTransition, typename TevSource,
434 template <typename> typename EvType, typename DestinyState>
435void AddTransition::operator()(TTransition<EvType<TevSource>, DestinyState>)
436{
437 RCLCPP_INFO(
438 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [2-param] called for state %s",
439 currentState_->fullStateName.c_str());
441 RCLCPP_INFO(
442 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [2-param] completed for state %s",
443 currentState_->fullStateName.c_str());
444}
445
446template <typename TTrans>
448{
449 RCLCPP_INFO(
450 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [generic] called for state %s",
451 currentState_->fullStateName.c_str());
452 using type_t = typename TTrans::type;
454 RCLCPP_INFO(
455 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [generic] completed for state %s",
456 currentState_->fullStateName.c_str());
457}
458
459/*
460void CallOnDefinition(...)
461{
462
463}*/
464
465//-----------------------------------------------------------------------------------
466template <typename InitialStateType>
468 std::shared_ptr<SmaccStateInfo> & parentState, bool rootInitialNode)
469{
470 //rclcpp::Duration(1).sleep();
471 auto currentname = demangledTypeName<InitialStateType>();
472
473 std::shared_ptr<SmaccStateInfo> targetState;
474
475 if (!rootInitialNode)
476 {
477 if (parentState->stateMachine_->containsState<InitialStateType>())
478 {
479 // it already exist: break;
480 return;
481 }
482
483 targetState = parentState->createChildState<InitialStateType>();
484 }
485 else
486 {
487 targetState = parentState;
488 }
489
491
492 typedef
493 typename std::remove_pointer<decltype(InitialStateType::smacc_inner_type)>::type InnerType;
494 processSubState<InnerType>(targetState);
495
496 // -------------------- REACTIONS --------------------
497 typedef typename InitialStateType::reactions reactions;
498 // RCLCPP_INFO_STREAM(getLogger(),"state machine initial state reactions: "
499 // << demangledTypeName<reactions>());
500
502}
503
504//------------------------------------------------
505
506template <typename InitialStateType>
508{
509 auto initialState = this->createState<InitialStateType>(nullptr);
511}
512
513template <typename StateType>
514std::shared_ptr<SmaccStateInfo> SmaccStateMachineInfo::createState(
515 std::shared_ptr<SmaccStateInfo> parent)
516{
517 auto thisptr = this->shared_from_this();
518 auto * statetid = &(typeid(StateType));
519
520 auto demangledName = demangledTypeName<StateType>();
521 RCLCPP_INFO_STREAM(getLogger(), "Creating State Info: " << demangledName);
522
523 auto state = std::make_shared<SmaccStateInfo>(statetid, parent, thisptr);
524 state->demangledStateName = demangledName;
525 state->fullStateName = typeid(StateType).name();
526 state->stateIndex_ = states.size();
527
528 if (parent != nullptr)
529 {
530 parent->children_.push_back(state);
531 }
532
533 this->addState(state);
534
535 return state;
536}
537
538template <typename StateType>
539void SmaccStateMachineInfo::addState(std::shared_ptr<StateType> & state)
540{
541 states[state->fullStateName] = state;
542}
543
544template <typename StateType>
545std::shared_ptr<SmaccStateInfo> SmaccStateInfo::createChildState()
546{
547 auto realparentState = this->stateMachine_->getState<typename StateType::TContext>();
548
549 auto childState = this->stateMachine_->createState<StateType>(realparentState);
550
551 RCLCPP_WARN_STREAM(
552 getLogger(), "Real parent state> " << demangleSymbol<typename StateType::TContext>());
553
554 /*auto contextInfo = TypeInfo::getTypeInfoFromType<InitialStateType>();
555 auto parentState2= getState<InitialStateType::TContext>();
556 parentState2->createChildState<InitialStateType>();*/
557
558 // this->stateMachine_->addState(childState);
559 // stateMachineInfo.addState(stateMachineInfo)
560 // stateNames.push_back(currentname);
561 // RCLCPP_INFO(getLogger(),"------------");
562 // RCLCPP_INFO_STREAM(getLogger(),"** STATE state: "<< this->demangledStateName);
563
564 return childState;
565}
566} // namespace introspection
567} // namespace smacc2
static YesType & test(decltype(&C::staticConfigure))
std::shared_ptr< SmaccStateInfo > createChildState()
void declareTransition(std::shared_ptr< SmaccStateInfo > &dstState, std::string transitionTag, std::string transitionType, bool history, TypeInfo::Ptr transitionTypeInfo)
std::vector< SmaccTransitionInfo > transitions_
std::shared_ptr< SmaccStateMachineInfo > stateMachine_
void addState(std::shared_ptr< StateType > &state)
std::shared_ptr< SmaccStateInfo > createState(std::shared_ptr< SmaccStateInfo > parentState)
std::map< std::string, std::shared_ptr< SmaccStateInfo > > states
std::vector< smacc2_msgs::msg::SmaccState > stateMsgs
static TypeInfo::Ptr getTypeInfoFromType()
std::shared_ptr< TypeInfo > Ptr
std::enable_if< HasAutomaticTransitionType< T >::value, void >::type automaticTransitionType(std::string &transition_type)
disable_if< boost::mpl::is_sequence< T > >::type processSubState(std::shared_ptr< SmaccStateInfo > &parentState)
rclcpp::Node::SharedPtr globalNh_
std::enable_if< HasEventLabel< T >::value, void >::type EventLabel(std::string &label)
void processTransition(smacc2::Transition< Ev, boost::statechart::deep_history< Dst >, Tag > *, std::shared_ptr< SmaccStateInfo > &sourceState)
static std::string getTransitionType()
std::string demangleSymbol()
enable_if< boost::mpl::is_sequence< T > >::type processTransitions(std::shared_ptr< SmaccStateInfo > &sourceState)
void processTransitionAux(smacc2::Transition< Ev, Dst, Tag > *, std::shared_ptr< SmaccStateInfo > &sourceState, bool history, TypeInfo::Ptr &transitionTypeInfo)
std::enable_if< HasOnDefinition< T >::value, void >::type CallOnDefinition()
std::enable_if< HasAutomaticTransitionTag< T >::value, void >::type automaticTransitionTag(std::string &transition_name)
std::string demangledTypeName()
std::shared_ptr< SmaccStateInfo > & parentState_
AddSubState(std::shared_ptr< SmaccStateInfo > &parentState)
AddTransition(std::shared_ptr< SmaccStateInfo > &currentState)
void operator()(TTransition< EvType< TevSource >, DestinyState, Tag >)
std::shared_ptr< SmaccStateInfo > & currentState_
std::shared_ptr< const SmaccStateInfo > destinyState
std::shared_ptr< SmaccEventInfo > eventInfo
std::shared_ptr< const SmaccStateInfo > sourceState
smacc2::introspection::TypeInfo::Ptr transitionTypeInfo
static void walkStates(std::shared_ptr< SmaccStateInfo > &currentState, bool rootInitialNode)