SMACC2
Loading...
Searching...
No Matches
smacc_signal_detector.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#pragma once
21
22#include <atomic>
23#include <boost/thread.hpp>
24#include <smacc2/common.hpp>
25#include <smacc2_msgs/msg/smacc_status.hpp>
26
27namespace smacc2
28{
34
35// Mostly define the state machine ros thread and receive events state machine components (clients, state elements)
36// This class also contains the event queue of the state machine
38{
39public:
41 SmaccFifoScheduler * scheduler,
43
44 void initialize(ISmaccStateMachine * stateMachine);
45
46 void setProcessorHandle(SmaccFifoScheduler::processor_handle processorHandle);
47
48 // Runs the polling loop into a thread...
49 void runThread();
50
51 // Waits for the polling thread to end...
52 void join();
53
54 void stop();
55
56 void terminateScheduler();
57
58 void pollingLoop();
59
60 template <typename EventType>
61 void postEvent(EventType * ev)
62 {
63 boost::intrusive_ptr<EventType> weakPtrEvent = ev;
64 this->scheduler_->queue_event(processorHandle_, weakPtrEvent);
65 }
66
67 rclcpp::Node::SharedPtr getNode();
68 inline rclcpp::Logger getLogger() { return getNode()->get_logger(); }
69
70 void notifyStateConfigured(ISmaccState * currentState);
71
72 void notifyStateExited(ISmaccState * currentState);
73
74 // Called after state machine ROS initialization is complete (initializeROS)
75 // This signals that orthogonals, clients, and ROS objects are ready
77
78private:
79 void pollOnce();
80
82
83 std::vector<ISmaccUpdatable *> updatableClients_;
84
85 std::vector<std::vector<ISmaccUpdatable *>> updatableStateElements_;
86 std::atomic<int64_t> lastState_;
87
89
90 void findUpdatableStateElements(ISmaccState * currentState);
91
92 // Loop frequency of the signal detector (to check answers from actionservers)
94
95 std::atomic<bool> end_;
96
97 std::atomic<bool> initialized_;
98
99 // Flag set after initializeROS() completes - indicates ROS objects are ready
100 std::atomic<bool> rosInitialized_;
101
102 rclcpp::Publisher<smacc2_msgs::msg::SmaccStatus>::SharedPtr statusPub_;
103
104 // ---- boost statechart related ----
105
107
108 SmaccFifoScheduler::processor_handle processorHandle_;
109
111
113};
114
115void onSigQuit(int sig);
116
117// Signal handler for graceful shutdown (SIGINT/SIGTERM)
118void onSignalShutdown(int sig);
119
120// Singleton class managing SMACC execution lifecycle
121// Replaces global g_signal_detector for signal handler access
123{
124public:
125 // Get singleton instance
126 static SmExecution & getInstance();
127
128 // Delete copy and move constructors/operators
129 SmExecution(const SmExecution &) = delete;
130 SmExecution & operator=(const SmExecution &) = delete;
133
134 boost::thread * schedulerThread;
135 boost::thread * signalDetectorLoop;
138 SmaccFifoScheduler::processor_handle sm;
139
140private:
141 // Private constructor for singleton
142 SmExecution();
143};
144
145// Main entry point for any SMACC state machine
146// It instantiates and starts the specified state machine type
147// it uses two threads: a new thread and the current one.
148// The created thread is for the state machine process
149// it locks the current thread to handle events of the state machine
150template <typename StateMachineType>
152{
153 // Register signal handlers for graceful shutdown
154 ::signal(SIGINT, onSignalShutdown);
155 ::signal(SIGTERM, onSignalShutdown);
156 ::signal(SIGQUIT, onSigQuit);
157
158 // Get singleton instance
159 SmExecution & smExecution = SmExecution::getInstance();
160
161 // create the asynchronous state machine scheduler
162 SmaccFifoScheduler scheduler1(true);
163
164 // create the signalDetector component
165 SignalDetector signalDetector(&scheduler1, executionModel);
166
167 // Store in singleton for signal handler access
168 smExecution.signalDetector = &signalDetector;
169 smExecution.scheduler1 = &scheduler1;
170
171 // create the asynchronous state machine processor
172 SmaccFifoScheduler::processor_handle sm =
173 scheduler1.create_processor<StateMachineType>(&signalDetector);
174
175 // initialize the asynchronous state machine processor
176 signalDetector.setProcessorHandle(sm);
177 smExecution.sm = sm;
178
179 scheduler1.initiate_processor(sm);
180
181 //create a thread for the asynchronous state machine processor execution
182 boost::thread schedulerThread(boost::bind(&sc::fifo_scheduler<>::operator(), &scheduler1, 0));
183 smExecution.schedulerThread = &schedulerThread;
184
185 // use the main thread for the signal detector component (waiting actionclient requests)
186 signalDetector.pollingLoop();
187
188 // After polling loop exits (due to shutdown), terminate the scheduler from main thread
189 // This is safe to call here (not from signal handler) as we're in the main thread context
190 RCLCPP_INFO(rclcpp::get_logger("SMACC"), "Polling loop exited. Terminating scheduler...");
191 signalDetector.terminateScheduler();
192
193 // Wait for scheduler thread to finish
194 RCLCPP_INFO(rclcpp::get_logger("SMACC"), "Waiting for scheduler thread to join...");
195 schedulerThread.join();
196 RCLCPP_INFO(rclcpp::get_logger("SMACC"), "Scheduler thread terminated. Shutdown complete.");
197
198 // Clear singleton references
199 smExecution.signalDetector = nullptr;
200 smExecution.scheduler1 = nullptr;
201 smExecution.schedulerThread = nullptr;
202}
203
204template <typename StateMachineType>
206{
207 // Register signal handlers for graceful shutdown
208 ::signal(SIGINT, onSignalShutdown);
209 ::signal(SIGTERM, onSignalShutdown);
210 ::signal(SIGQUIT, onSigQuit);
211
212 // Get singleton instance
213 SmExecution & smExecution = SmExecution::getInstance();
214
215 // create the asynchronous state machine scheduler
216 smExecution.scheduler1 = new SmaccFifoScheduler(true);
217
218 // create the signalDetector component
219 smExecution.signalDetector = new SignalDetector(smExecution.scheduler1);
220
221 // create the asynchronous state machine processor
222 smExecution.sm =
223 smExecution.scheduler1->create_processor<StateMachineType>(smExecution.signalDetector);
224
225 // initialize the asynchronous state machine processor
226 smExecution.signalDetector->setProcessorHandle(smExecution.sm);
227
228 smExecution.scheduler1->initiate_processor(smExecution.sm);
229
230 //create a thread for the asynchronous state machine processor execution
231 smExecution.schedulerThread =
232 new boost::thread(boost::bind(&sc::fifo_scheduler<>::operator(), smExecution.scheduler1, NULL));
233 smExecution.signalDetectorLoop =
234 new boost::thread(boost::bind(&SignalDetector::pollingLoop, smExecution.signalDetector));
235
236 return smExecution;
237}
238
239} // namespace smacc2
SmaccFifoScheduler * scheduler_
void notifyStateExited(ISmaccState *currentState)
void initialize(ISmaccStateMachine *stateMachine)
std::vector< std::vector< ISmaccUpdatable * > > updatableStateElements_
std::atomic< bool > rosInitialized_
rclcpp::Node::SharedPtr getNode()
SmaccFifoScheduler::processor_handle processorHandle_
SignalDetector(SmaccFifoScheduler *scheduler, ExecutionModel executionModel=ExecutionModel::SINGLE_THREAD_SPINNER)
std::atomic< int64_t > lastState_
std::vector< ISmaccUpdatable * > updatableClients_
void setProcessorHandle(SmaccFifoScheduler::processor_handle processorHandle)
rclcpp::Publisher< smacc2_msgs::msg::SmaccStatus >::SharedPtr statusPub_
void findUpdatableStateElements(ISmaccState *currentState)
ISmaccStateMachine * smaccStateMachine_
void notifyStateConfigured(ISmaccState *currentState)
std::atomic< bool > initialized_
SmaccFifoScheduler::processor_handle sm
static SmExecution & getInstance()
SmaccFifoScheduler * scheduler1
SmExecution & operator=(const SmExecution &)=delete
SmExecution & operator=(SmExecution &&)=delete
SmExecution(const SmExecution &)=delete
SmExecution(SmExecution &&)=delete
void onSigQuit(int sig)
void onSignalShutdown(int sig)
SmExecution & run_async()
void run(ExecutionModel executionModel=ExecutionModel::SINGLE_THREAD_SPINNER)
boost::statechart::fifo_scheduler< SmaccFifoWorker, SmaccAllocator > SmaccFifoScheduler