SMACC2
Loading...
Searching...
No Matches
smacc_state_machine_info.cpp
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
23
24namespace smacc2
25{
27{
28 std::stringstream ss;
29
30 ss << "----------- PRINT STATE MACHINE STRUCTURE -------------------" << std::endl;
31 // Rebuild the state message list from scratch on every call.
32 stateMsgs.clear();
33 // Walk every registered state and describe it in a message and in the text summary.
34 for (auto & val : this->states)
35 {
36 smacc2_msgs::msg::SmaccState stateMsg;
37 auto state = val.second;
38 // Basic identity: index, demangled name and depth in the state hierarchy.
39 stateMsg.index = state->stateIndex_;
40
41 ss << "**** State: " << demangleSymbol(val.first.c_str()) << std::endl;
42
43 stateMsg.name = state->getDemangledFullName();
44 stateMsg.level = (int)state->getStateLevel();
45
46 ss << "Index: " << stateMsg.index << std::endl;
47 ss << "StateLevel: " << stateMsg.level << std::endl;
48
49 ss << " Childstates:" << std::endl;
50
51 // List the direct child states.
52 for (auto & child : state->children_)
53 {
54 auto childStateName = child->getDemangledFullName();
55 stateMsg.children_states.push_back(childStateName);
56
57 ss << " - " << childStateName << std::endl;
58 }
59
60 ss << " Transitions:" << std::endl;
61
62 // Convert each transition table row into a message and print its details.
63 for (auto & transition : state->transitions_)
64 {
65 smacc2_msgs::msg::SmaccTransition transitionMsg;
66
67 transitionInfoToMsg(transition, transitionMsg);
68
69 ss << " - Transition. " << std::endl;
70 ss << " - Index: " << transitionMsg.index << std::endl;
71 ss << " - Transition Name: " << transitionMsg.transition_name << std::endl;
72 ss << " - Transition Type: " << transitionMsg.transition_type << std::endl;
73 ss << " - Event Type :" << transitionMsg.event.event_type << std::endl;
74 ss << " - Event Source: " << transitionMsg.event.event_source << std::endl;
75 ss << " - Event ObjectTag: " << transitionMsg.event.event_object_tag << std::endl;
76 ss << " - Event Label: " << transitionMsg.event.label << std::endl;
77 ss << " - Destiny State: " << transitionMsg.destiny_state_name << std::endl;
78 ss << " - Owner State: " << transitionMsg.source_state_name << std::endl;
79 ss << " - Is History Node: " << std::to_string(transitionMsg.history_node) << std::endl;
80 ss << " - TransitionC++Type: " << transition.transitionTypeInfo->getFullName()
81 << std::endl;
82 ss << " - EventC++Type: " << transition.eventInfo->eventType->getFullName() << std::endl;
83
84 stateMsg.transitions.push_back(transitionMsg);
85 }
86
87 const std::type_info * statetid = state->tid_;
88
89 // Group the client behaviors statically configured for this state by orthogonal type.
90 std::map<const std::type_info *, std::vector<smacc2::ClientBehaviorInfoEntry *>>
91 smaccBehaviorInfoMappingByOrthogonalType;
92
93 ss << " Orthogonals:" << std::endl;
94 if (SmaccStateInfo::staticBehaviorInfo.count(statetid) > 0)
95 {
96 for (auto & bhinfo : SmaccStateInfo::staticBehaviorInfo[statetid])
97 {
98 if (smaccBehaviorInfoMappingByOrthogonalType.count(bhinfo.orthogonalType) == 0)
99 {
100 smaccBehaviorInfoMappingByOrthogonalType[bhinfo.orthogonalType] =
101 std::vector<smacc2::ClientBehaviorInfoEntry *>();
102 }
103
104 smaccBehaviorInfoMappingByOrthogonalType[bhinfo.orthogonalType].push_back(&bhinfo);
105 }
106 }
107
108 // Describe every runtime orthogonal with the behaviors and clients it holds for this state.
109 auto & runtimeOrthogonals = sm->getOrthogonals();
110
111 for (auto & orthogonal : runtimeOrthogonals)
112 {
113 smacc2_msgs::msg::SmaccOrthogonal orthogonalMsg;
114
115 const auto * orthogonaltid = &typeid(*(orthogonal.second));
116 orthogonalMsg.name = demangleSymbol(orthogonaltid->name());
117
118 ss << " - orthogonal: " << orthogonalMsg.name << std::endl;
119
120 // Client behaviors this state configures in this orthogonal.
121 if (smaccBehaviorInfoMappingByOrthogonalType[orthogonaltid].size() > 0)
122 {
123 auto & behaviors = smaccBehaviorInfoMappingByOrthogonalType[orthogonaltid];
124 for (auto & bhinfo : behaviors)
125 {
126 auto ClientBehaviorName = demangleSymbol(bhinfo->behaviorType->name());
127 orthogonalMsg.client_behavior_names.push_back(ClientBehaviorName);
128 ss << " - client behavior: " << ClientBehaviorName << std::endl;
129 }
130 }
131 else
132 {
133 ss << " - NO CLIENT BEHAVIORS -" << std::endl;
134 }
135
136 // Clients owned by the orthogonal for the whole state machine lifetime.
137 auto & clients = orthogonal.second->getClients();
138 if (clients.size() > 0)
139 {
140 for (auto & client : clients)
141 {
142 auto clientTid = client->getType();
143 auto clientName = clientTid->getNonTemplatedTypeName();
144 orthogonalMsg.client_names.push_back(clientName);
145 ss << " - client: " << clientName << std::endl;
146 }
147 }
148 else
149 {
150 ss << " - NO CLIENTS - " << std::endl;
151 }
152 stateMsg.orthogonals.push_back(orthogonalMsg);
153 }
154
155 // Event generators attached to this state.
156 ss << " State event generators:" << std::endl;
157 if (SmaccStateInfo::eventGeneratorsInfo.count(statetid) > 0)
158 {
159 int k = 0;
160 for (auto & eginfo : SmaccStateInfo::eventGeneratorsInfo[statetid])
161 {
162 smacc2_msgs::msg::SmaccEventGenerator eventGeneratorMsg;
163 eventGeneratorMsg.index = k++;
164 eventGeneratorMsg.type_name = eginfo->eventGeneratorType->getFullName();
165
166 ss << " - event generator: " << eventGeneratorMsg.type_name << std::endl;
167 if (eginfo->objectTagType != nullptr)
168 {
169 eventGeneratorMsg.object_tag = eginfo->objectTagType->getFullName();
170 ss << " - object tag: " << eventGeneratorMsg.object_tag << std::endl;
171 }
172 stateMsg.event_generators.push_back(eventGeneratorMsg);
173 }
174 }
175
176 // State reactors attached to this state, with the events each one listens to.
177 ss << " State reactors:" << std::endl;
178 if (SmaccStateInfo::stateReactorsInfo.count(statetid) > 0)
179 {
180 int k = 0;
181 for (auto & srinfo : SmaccStateInfo::stateReactorsInfo[statetid])
182 {
183 smacc2_msgs::msg::SmaccStateReactor stateReactorMsg;
184 stateReactorMsg.index = k++;
185 stateReactorMsg.type_name = srinfo->stateReactorType->getFullName();
186
187 ss << " - state reactor: " << stateReactorMsg.type_name << std::endl;
188 if (srinfo->objectTagType != nullptr)
189 {
190 stateReactorMsg.object_tag = srinfo->objectTagType->getFullName();
191 ss << " - object tag: " << stateReactorMsg.object_tag << std::endl;
192 }
193
194 // Record every source event that can trigger this reactor.
195 for (auto & tev : srinfo->sourceEventTypes)
196 {
197 // WE SHOULD CREATE A SMACC_EVENT_INFO TYPE, also using in typewalker transition
198 auto eventTypeName = tev->getEventTypeName();
199 smacc2_msgs::msg::SmaccEvent event;
200
201 ss << " - triggering event: " << tev->getEventTypeName() << std::endl;
202 event.event_type = eventTypeName;
203
204 event.event_source = tev->getEventSourceName();
205 ss << " - source type: " << event.event_source << std::endl;
206
207 event.event_object_tag = tev->getOrthogonalName();
208 ss << " - source object: " << event.event_object_tag << std::endl;
209
210 event.label = tev->label;
211 ss << " - event label: " << event.label << std::endl;
212
213 stateReactorMsg.event_sources.push_back(event);
214 }
215
216 stateMsg.state_reactors.push_back(stateReactorMsg);
217 }
218 }
219 else
220 {
221 ss << "- NO STATE REACTORS - " << std::endl;
222 }
223
224 ss << "----------------------------------------------------------" << std::endl;
225
226 // Emit the text summary at debug level and keep the message for the description topic.
227 auto resumeMsg = ss.str();
228 RCLCPP_DEBUG(getLogger(), "%s", resumeMsg.c_str());
229 stateMsgs.push_back(stateMsg);
230 }
231}
232} // namespace smacc2
const std::map< std::string, std::shared_ptr< smacc2::ISmaccOrthogonal > > & getOrthogonals() const
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
std::vector< smacc2_msgs::msg::SmaccState > stateMsgs
std::string demangleSymbol()
void transitionInfoToMsg(const SmaccTransitionInfo &transition, smacc2_msgs::msg::SmaccTransition &transitionMsg)