SMACC2
Loading...
Searching...
No Matches
smacc_state_machine_info.hpp
Go to the documentation of this file.
1// Copyright 2025 Robosoft 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;
136}
137
138//--------------------------------------------
139template <typename T>
140typename disable_if<boost::mpl::is_sequence<T>>::type processSubState(
141 std::shared_ptr<SmaccStateInfo> & parentState)
142{
143 WalkStatesExecutor<T>::walkStates(parentState, false);
144}
145
146//---------------------------------------------
147template <typename T>
148typename enable_if<boost::mpl::is_sequence<T>>::type processSubState(
149 std::shared_ptr<SmaccStateInfo> & parentState)
150{
151 using boost::mpl::_1;
152 using wrappedList = typename boost::mpl::transform<T, add_type_wrapper<_1>>::type;
153 boost::mpl::for_each<wrappedList>(AddSubState(parentState));
154}
155
156//--------------------------------------------
157/*Iterate on All Transitions*/
158template <typename T>
159typename enable_if<boost::mpl::is_sequence<T>>::type processTransitions(
160 std::shared_ptr<SmaccStateInfo> & sourceState)
161{
162 RCLCPP_INFO(
163 globalNh_->get_logger(), "State %s Walker has transition list",
164 sourceState->fullStateName.c_str());
165 using boost::mpl::_1;
166 using wrappedList = typename boost::mpl::transform<T, add_type_wrapper<_1>>::type;
167 RCLCPP_INFO(
168 globalNh_->get_logger(), "[DIAG] About to call boost::mpl::for_each for state %s",
169 sourceState->fullStateName.c_str());
170 boost::mpl::for_each<wrappedList>(AddTransition(sourceState));
171 RCLCPP_INFO(
172 globalNh_->get_logger(), "[DIAG] Completed boost::mpl::for_each for state %s",
173 sourceState->fullStateName.c_str());
174}
175
176template <typename Ev, typename Dst, typename Tag>
178 smacc2::Transition<Ev, boost::statechart::deep_history<Dst>, Tag> *,
179 std::shared_ptr<SmaccStateInfo> & sourceState)
180{
181 RCLCPP_INFO(
182 globalNh_->get_logger(), "[DIAG] processTransition [deep_history] START for state %s",
183 sourceState->toShortName().c_str());
184 auto transitionTypeInfo = TypeInfo::getTypeInfoFromType<
186 RCLCPP_INFO(
187 globalNh_->get_logger(), "[DIAG] processTransition [deep_history] got TypeInfo for state %s",
188 sourceState->toShortName().c_str());
189 smacc2::Transition<Ev, Dst, Tag> * mock = nullptr;
190 processTransitionAux(mock, sourceState, true, transitionTypeInfo);
191}
192
193template <typename Ev, typename Dst, typename Tag>
195 smacc2::Transition<Ev, Dst, Tag> * t, std::shared_ptr<SmaccStateInfo> & sourceState)
196{
197 RCLCPP_INFO(
198 globalNh_->get_logger(), "[DIAG] processTransition START for state %s",
199 sourceState->toShortName().c_str());
201 RCLCPP_INFO(
202 globalNh_->get_logger(), "[DIAG] processTransition got TypeInfo for state %s",
203 sourceState->toShortName().c_str());
204 RCLCPP_INFO(
205 globalNh_->get_logger(), "State %s Walker transition: %s", sourceState->toShortName().c_str(),
206 demangleSymbol(typeid(Ev).name()).c_str());
207 processTransitionAux(t, sourceState, false, transitionTypeInfo);
208}
209
210template <typename Ev, typename Dst, typename Tag>
212 smacc2::Transition<Ev, Dst, Tag> *, std::shared_ptr<SmaccStateInfo> & sourceState, bool history,
213 TypeInfo::Ptr & transitionTypeInfo)
214{
215 RCLCPP_INFO(
216 globalNh_->get_logger(), "State %s Walker transition: %s", sourceState->toShortName().c_str(),
217 demangleSymbol(typeid(Ev).name()).c_str());
218 std::string transitionTag;
219 std::string transitionType;
220
221 if (typeid(Tag) != typeid(default_transition_name))
222 {
223 transitionTag = demangleSymbol<Tag>();
224 transitionType = getTransitionType<Tag>();
225 RCLCPP_DEBUG_STREAM(globalNh_->get_logger(), "TRANSITION TYPE:" << transitionType);
226 }
227 else
228 {
229 transitionTag = "";
230 automaticTransitionTag<Ev>(transitionTag);
231 automaticTransitionType<Ev>(transitionType);
232 }
233
234 RCLCPP_INFO_STREAM(globalNh_->get_logger(), "Transition tag: " << transitionTag);
235
236 if (!sourceState->stateMachine_->containsState<Dst>())
237 {
238 auto realparentState = sourceState->stateMachine_->getState<typename Dst::TContext>();
239 auto siblingnode = sourceState->stateMachine_->createState<Dst>(realparentState);
240
241 WalkStatesExecutor<Dst>::walkStates(siblingnode, true);
242 sourceState->declareTransition<Ev>(
243 siblingnode, transitionTag, transitionType, history, transitionTypeInfo);
244 }
245 else
246 {
247 auto siblingnode = sourceState->stateMachine_->getState<Dst>();
248 sourceState->declareTransition<Ev>(
249 siblingnode, transitionTag, transitionType, history, transitionTypeInfo);
250 }
251}
252
253//---------------------------------------------
254template <typename EvType>
256 std::shared_ptr<SmaccStateInfo> & dstState, std::string transitionTag, std::string transitionType,
257 bool history, TypeInfo::Ptr transitionTypeInfo)
258{
259 auto evtype = demangledTypeName<EvType>();
260
261 SmaccTransitionInfo transitionInfo;
262 transitionInfo.index = transitions_.size();
263 transitionInfo.sourceState = shared_from_this();
264 transitionInfo.destinyState = dstState;
265 transitionInfo.transitionTypeInfo = transitionTypeInfo;
266
267 if (transitionTag != "")
268 transitionInfo.transitionTag = transitionTag;
269 else
270 transitionInfo.transitionTag = "Transition_" + std::to_string(transitionInfo.index);
271
272 transitionInfo.transitionType = transitionType;
273 transitionInfo.historyNode = history;
274
275 transitionInfo.eventInfo =
276 std::make_shared<SmaccEventInfo>(transitionTypeInfo->templateParameters.front());
277
278 EventLabel<EvType>(transitionInfo.eventInfo->label);
279 // RCLCPP_DEBUG_STREAM(getLogger(), "LABEL: " << transitionInfo.eventInfo->label);
280
281 transitions_.push_back(transitionInfo);
282}
283//---------------------------------------------
284
285//------------------ staticConfigure -----------------------------
286
287// SFINAE test
288template <typename T>
290{
291private:
292 typedef char YesType[1];
293 typedef char NoType[2];
294
295 template <typename C>
296 static YesType & test(decltype(&C::staticConfigure));
297 template <typename C>
298 static NoType & test(...);
299
300public:
301 enum
302 {
303 value = sizeof(test<T>(0)) == sizeof(YesType)
304 };
305};
306
307//---------------------------------------------
308template <typename Ev, typename Dst>
310 statechart::transition<Ev, Dst> *, std::shared_ptr<SmaccStateInfo> & sourceState)
311{
312}
313
314template <typename Ev>
316 statechart::custom_reaction<Ev> *, std::shared_ptr<SmaccStateInfo> & sourceState)
317{
318}
319
320//---------------------------------------------
321// only reached if it is a leaf transition in the mpl::list
322
323template <typename T>
324typename disable_if<boost::mpl::is_sequence<T>>::type processTransitions(
325 std::shared_ptr<SmaccStateInfo> & sourceState)
326{
327 RCLCPP_INFO(
328 globalNh_->get_logger(), "[DIAG] processTransitions [single/leaf] called for state %s",
329 sourceState->fullStateName.c_str());
330 T * dummy = nullptr;
331 processTransition(dummy, sourceState);
332 RCLCPP_INFO(
333 globalNh_->get_logger(), "[DIAG] processTransitions [single/leaf] completed for state %s",
334 sourceState->fullStateName.c_str());
335}
336
337template <typename T>
338typename std::enable_if<HasOnDefinition<T>::value, void>::type CallOnDefinition()
339{
340 /* something when T has toString ... */
341 RCLCPP_INFO_STREAM(
342 globalNh_->get_logger(), "EXECUTING ONDEFINITION: " << demangleSymbol(typeid(T).name()));
343 T::staticConfigure();
344}
345
346template <typename T>
347typename std::enable_if<!HasOnDefinition<T>::value, void>::type CallOnDefinition()
348{
349 RCLCPP_INFO_STREAM(
350 globalNh_->get_logger(),
351 "static OnDefinition: dont exist for " << demangleSymbol(typeid(T).name()));
352 /* something when T has toString ... */
353}
354
355//--------------------------------------------
356
357template <
358 template <typename, typename, typename> typename TTransition, typename TevSource,
359 template <typename> typename EvType, typename Tag, typename DestinyState>
360void AddTransition::operator()(TTransition<EvType<TevSource>, DestinyState, Tag>)
361{
362 RCLCPP_INFO(
363 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [3-param] called for state %s",
364 currentState_->fullStateName.c_str());
366 RCLCPP_INFO(
367 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [3-param] completed for state %s",
368 currentState_->fullStateName.c_str());
369}
370
371//--------------------------------------------
372
373template <
374 template <typename, typename> typename TTransition, typename TevSource,
375 template <typename> typename EvType, typename DestinyState>
376void AddTransition::operator()(TTransition<EvType<TevSource>, DestinyState>)
377{
378 RCLCPP_INFO(
379 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [2-param] called for state %s",
380 currentState_->fullStateName.c_str());
382 RCLCPP_INFO(
383 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [2-param] completed for state %s",
384 currentState_->fullStateName.c_str());
385}
386
387template <typename TTrans>
389{
390 RCLCPP_INFO(
391 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [generic] called for state %s",
392 currentState_->fullStateName.c_str());
393 using type_t = typename TTrans::type;
395 RCLCPP_INFO(
396 globalNh_->get_logger(), "[DIAG] AddTransition::operator() [generic] completed for state %s",
397 currentState_->fullStateName.c_str());
398}
399
400//-----------------------------------------------------------------------------------
401template <typename InitialStateType>
403 std::shared_ptr<SmaccStateInfo> & parentState, bool rootInitialNode)
404{
405 auto currentname = demangledTypeName<InitialStateType>();
406
407 std::shared_ptr<SmaccStateInfo> targetState;
408
409 if (!rootInitialNode)
410 {
411 if (parentState->stateMachine_->containsState<InitialStateType>())
412 {
413 return;
414 }
415
416 targetState = parentState->createChildState<InitialStateType>();
417 }
418 else
419 {
420 targetState = parentState;
421 }
422
424
425 typedef
426 typename std::remove_pointer<decltype(InitialStateType::smacc_inner_type)>::type InnerType;
427 processSubState<InnerType>(targetState);
428
429 // -------------------- REACTIONS --------------------
430 typedef typename InitialStateType::reactions reactions;
431
433}
434
435//------------------------------------------------
436
437template <typename InitialStateType>
439{
440 auto initialState = this->createState<InitialStateType>(nullptr);
442}
443
444template <typename StateType>
445std::shared_ptr<SmaccStateInfo> SmaccStateMachineInfo::createState(
446 std::shared_ptr<SmaccStateInfo> parent)
447{
448 auto thisptr = this->shared_from_this();
449 auto * statetid = &(typeid(StateType));
450
451 auto demangledName = demangledTypeName<StateType>();
452 RCLCPP_INFO_STREAM(getLogger(), "Creating State Info: " << demangledName);
453
454 auto state = std::make_shared<SmaccStateInfo>(statetid, parent, thisptr);
455 state->demangledStateName = demangledName;
456 state->fullStateName = typeid(StateType).name();
457 state->stateIndex_ = states.size();
458
459 if (parent != nullptr)
460 {
461 parent->children_.push_back(state);
462 }
463
464 this->addState(state);
465
466 return state;
467}
468
469template <typename StateType>
470void SmaccStateMachineInfo::addState(std::shared_ptr<StateType> & state)
471{
472 states[state->fullStateName] = state;
473}
474
475template <typename StateType>
476std::shared_ptr<SmaccStateInfo> SmaccStateInfo::createChildState()
477{
478 auto realparentState = this->stateMachine_->getState<typename StateType::TContext>();
479
480 auto childState = this->stateMachine_->createState<StateType>(realparentState);
481
482 RCLCPP_WARN_STREAM(
483 getLogger(), "Real parent state> " << demangleSymbol<typename StateType::TContext>());
484
485 return childState;
486}
487} // namespace introspection
488} // 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)