scanner_state_machine.h
Go to the documentation of this file.
1 // Copyright (c) 2020-2021 Pilz GmbH & Co. KG
2 //
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU Lesser General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public License
14 // along with this program. If not, see <https://www.gnu.org/licenses/>.
15 #ifndef PSEN_SCAN_V2_STANDALONE_SCANNER_PROTOCOL_DEF_H
16 #define PSEN_SCAN_V2_STANDALONE_SCANNER_PROTOCOL_DEF_H
17 
18 #include <functional>
19 #include <string>
20 #include <memory>
21 #include <mutex>
22 #include <chrono>
23 #include <stdexcept>
24 #include <vector>
25 #include <boost/optional.hpp>
26 
27 #define BOOST_MSM_CONSTRUCTOR_ARG_SIZE 12 // see https://www.boost.org/doc/libs/1_66_0/libs/msm/doc/HTML/ch03s05.html
28 
29 // back-end
30 #include <boost/msm/back/state_machine.hpp>
31 // front-end
32 #include <boost/msm/front/state_machine_def.hpp>
33 
34 #include <boost/msm/back/tools.hpp>
35 #include <boost/msm/back/metafunctions.hpp>
36 
38 
43 
46 
49 
56 
58 {
62 namespace protocol_layer
63 {
64 namespace msm = boost::msm;
65 namespace mpl = boost::mpl;
66 
68 
69 // clang-format off
70 #define STATE(state_name)\
71  class state_name : public msm::front::state<>\
72 {\
73  public:\
74  template <class Event, class FSM>\
75  void on_entry(Event const&, FSM& fsm);\
76  \
77  template <class Event, class FSM>\
78  void on_exit(Event const&, FSM& fsm);\
79 }
80 // clang-format on
81 
82 static constexpr std::chrono::milliseconds WATCHDOG_TIMEOUT{ 1000 };
83 static constexpr uint32_t DEFAULT_NUM_MSG_PER_ROUND{ 6 };
84 
85 using ScannerStartedCallback = std::function<void()>;
86 using ScannerStoppedCallback = std::function<void()>;
87 using StartErrorCallback = std::function<void(const std::string&)>;
88 using StopErrorCallback = std::function<void(const std::string&)>;
89 using TimeoutCallback = std::function<void()>;
90 using InformUserAboutLaserScanCallback = std::function<void(const LaserScan&)>;
91 
101 {
102 public:
103  virtual ~IWatchdogFactory() = default;
104 
105 public:
106  virtual std::unique_ptr<util::Watchdog> create(const util::Watchdog::Timeout& timeout,
107  const TimeoutCallback& timeout_callback) = 0;
108 };
109 
120 {
121 public:
122  WatchdogFactory() = default;
123  std::unique_ptr<util::Watchdog> create(const util::Watchdog::Timeout& timeout,
124  const TimeoutCallback& timeout_callback) override;
125 };
126 
127 // front-end: define the FSM structure
145 class ScannerProtocolDef : public msm::front::state_machine_def<ScannerProtocolDef>
146 {
147 public:
149  const communication_layer::NewMessageCallback& control_msg_callback,
150  const communication_layer::ErrorCallback& control_error_callback,
151  const communication_layer::ErrorCallback& start_error_callback,
152  const communication_layer::ErrorCallback& stop_error_callback,
153  const communication_layer::NewMessageCallback& data_msg_callback,
154  const communication_layer::ErrorCallback& data_error_callback,
155  const ScannerStartedCallback& scanner_started_callback,
156  const ScannerStoppedCallback& scanner_stopped_callback,
157  const InformUserAboutLaserScanCallback& laser_scan_callback,
158  const TimeoutCallback& start_timeout_callback,
159  const TimeoutCallback& monitoring_frame_timeout_callback);
160 
161 public: // States
162  STATE(Idle);
163  STATE(WaitForStartReply);
164  STATE(WaitForMonitoringFrame);
165  STATE(WaitForStopReply);
166  STATE(Stopped);
167  STATE(Error);
168 
169 public: // Action methods
170  template <class T>
171  void sendStartRequest(const T& event);
172  void handleStartRequestTimeout(const scanner_events::StartTimeout& event);
173  template <class T>
174  void sendStopRequest(const T& event);
175  void handleMonitoringFrame(const scanner_events::RawMonitoringFrameReceived& event);
176  void handleMonitoringFrameTimeout(const scanner_events::MonitoringFrameTimeout& event);
177  void notifyUserAboutStart(scanner_events::RawReplyReceived const& reply_event);
178  void notifyUserAboutUnknownStartReply(scanner_events::RawReplyReceived const& reply_event);
179  void notifyUserAboutRefusedStartReply(scanner_events::RawReplyReceived const& reply_event);
180  void notifyUserAboutStop(scanner_events::RawReplyReceived const& reply_event);
181  void notifyUserAboutUnknownStopReply(scanner_events::RawReplyReceived const& reply_event);
182  void notifyUserAboutRefusedStopReply(scanner_events::RawReplyReceived const& reply_event);
183 
184 public: // Guards
185  bool isAcceptedStopReply(scanner_events::RawReplyReceived const& reply_event);
186  bool isUnknownStopReply(scanner_events::RawReplyReceived const& reply_event);
187  bool isRefusedStopReply(scanner_events::RawReplyReceived const& reply_event);
188  bool isAcceptedStartReply(scanner_events::RawReplyReceived const& reply_event);
189  bool isUnknownStartReply(scanner_events::RawReplyReceived const& reply_event);
190  bool isRefusedStartReply(scanner_events::RawReplyReceived const& reply_event);
191 
192 public: // Replaces the default exception/no-transition responses
193  template <class FSM, class Event>
194  void exception_caught(Event const& event, FSM& fsm, std::exception& exception); // NOLINT
195 
196  template <class FSM, class Event>
197  void no_transition(Event const& event, FSM& /*unused*/, int state); // NOLINT
198 
199  template <class FSM>
200  void
201  no_transition(const scanner_events::RawMonitoringFrameReceived& /*unused*/, FSM& /*unused*/, int state); // NOLINT
202 
203 public: // Definition of state machine via table
204  typedef Idle initial_state;
206 
207  // clang-format off
211  struct transition_table : mpl::vector< // NOLINT
212  // Start Event Next Action Guard
213  // +------------------------------+----------------------------+---------------------------+--------------------------------------+-------------------------+
214  a_row < Idle, e::StartRequest, WaitForStartReply, &m::sendStartRequest >,
215  a_row < Idle, e::StopRequest, WaitForStopReply, &m::sendStopRequest >,
216  row < WaitForStartReply, e::RawReplyReceived, WaitForMonitoringFrame, &m::notifyUserAboutStart, &m::isAcceptedStartReply >,
217  row < WaitForStartReply, e::RawReplyReceived, Error, &m::notifyUserAboutRefusedStartReply, &m::isRefusedStartReply >,
218  row < WaitForStartReply, e::RawReplyReceived, Error, &m::notifyUserAboutUnknownStartReply, &m::isUnknownStartReply >,
219  a_irow < WaitForStartReply, e::StartTimeout, &m::handleStartRequestTimeout >,
220  a_irow < WaitForMonitoringFrame, e::RawMonitoringFrameReceived, &m::handleMonitoringFrame >,
221  a_irow < WaitForMonitoringFrame, e::MonitoringFrameTimeout, &m::handleMonitoringFrameTimeout >,
222  a_row < WaitForStartReply, e::StopRequest, WaitForStopReply, &m::sendStopRequest >,
223  a_row < WaitForMonitoringFrame, e::StopRequest, WaitForStopReply, &m::sendStopRequest >,
224  _irow < WaitForStopReply, e::RawMonitoringFrameReceived >,
225  row < WaitForStopReply, e::RawReplyReceived, Stopped, &m::notifyUserAboutStop, &m::isAcceptedStopReply >,
226  row < WaitForStopReply, e::RawReplyReceived, Error, &m::notifyUserAboutRefusedStopReply, &m::isRefusedStopReply >,
227  row < WaitForStopReply, e::RawReplyReceived, Error, &m::notifyUserAboutUnknownStopReply, &m::isUnknownStopReply >,
228  _irow < Stopped, e::RawMonitoringFrameReceived >
229  // +------------------------------+----------------------------+--------------------------+---------------------------------------+-------------------------+
230  > {};
231  // clang-format on
232 
233 private:
234  // LCOV_EXCL_START
240  class InternalScannerReplyError : public std::runtime_error
241  {
242  public:
243  InternalScannerReplyError(const std::string& error_msg);
244  };
245  // LCOV_EXCL_STOP
246  bool isStartReply(data_conversion_layer::scanner_reply::Message const& msg);
247  bool isStopReply(data_conversion_layer::scanner_reply::Message const& msg);
248  bool isAcceptedReply(data_conversion_layer::scanner_reply::Message const& msg);
249  bool isUnknownReply(data_conversion_layer::scanner_reply::Message const& msg);
250  bool isRefusedReply(data_conversion_layer::scanner_reply::Message const& msg);
251 
252  void checkForInternalErrors(const data_conversion_layer::scanner_reply::Message& msg);
253  void checkForDiagnosticErrors(const data_conversion_layer::monitoring_frame::Message& msg);
258  void checkForChangedActiveZoneset(const data_conversion_layer::monitoring_frame::Message& msg);
259 
264  void informUserAboutTheScanData(const data_conversion_layer::monitoring_frame::MessageStamped& stamped_msg);
269  void
270  sendMessageWithMeasurements(const std::vector<data_conversion_layer::monitoring_frame::MessageStamped>& stamped_msg);
275  bool
276  framesContainMeasurements(const std::vector<data_conversion_layer::monitoring_frame::MessageStamped>& stamped_msg);
277 
278 private:
280 
281  std::unique_ptr<util::Watchdog> start_reply_watchdog_{};
282 
283  std::unique_ptr<util::Watchdog> monitoring_frame_watchdog_{};
285  boost::optional<data_conversion_layer::monitoring_frame::Message> zoneset_reference_msg_;
286 
287  // Udp Clients
290 
291  // Callbacks
297 
298  // Timeout Handler
299  const std::function<void()> start_timeout_callback_;
300  const std::function<void()> monitoring_frame_timeout_callback_;
301 
302  // Factories
303  WatchdogFactory watchdog_factory_{};
304 };
305 
306 // Pick a back-end
312 using ScannerStateMachine = msm::back::state_machine<ScannerProtocolDef>;
313 
314 } // namespace protocol_layer
315 } // namespace psen_scan_v2_standalone
316 
318 
319 #endif // PSEN_SCAN_V2_STANDALONE_SCANNER_PROTOCOL_DEF_H
Error
Helper for asynchronously sending and receiving data via UDP.
Definition: udp_client.h:74
Watchdog factory implementation for scanner interaction timeouts.
std::function< void(const std::string &)> ErrorCallback
Definition: udp_client.h:50
Higher level data type representing a single monitoring frame.
std::function< void(const data_conversion_layer::RawDataConstPtr &, const std::size_t &, const int64_t &timestamp)> NewMessageCallback
Definition: udp_client.h:49
msm::back::state_machine< ScannerProtocolDef > ScannerStateMachine
State machine handling all events according to the scanner protocol and error handling specification...
const std::chrono::high_resolution_clock::duration Timeout
Definition: watchdog.h:42
config
std::function< void(const LaserScan &)> InformUserAboutLaserScanCallback
std::function< void(const std::string &)> StopErrorCallback
Table describing the state machine which is specified in the scanner protocol.
Contains the events needed to define and implement the scanner protocol.
Exception thrown when something goes wrong with the scanner reply.
Higher level data type storing the configuration details of the scanner like scanner IP...
Wrapping class for a Message and its corresponding timestamp.
const InformUserAboutLaserScanCallback inform_user_about_laser_scan_callback_
Root namespace in which the software components to communicate with the scanner (firmware-version: 2)...
Definition: udp_client.h:41
Received Start- or Stop-Reply message from scanner device.
Interface to create event timeout callbacks.
Timeout while waiting for scanner device to start.
static constexpr std::chrono::milliseconds WATCHDOG_TIMEOUT
Definition of the scanner protocol. It is initialized using the StateMachineArgs class.
std::function< void(const std::string &)> StartErrorCallback
virtual std::unique_ptr< util::Watchdog > create(const util::Watchdog::Timeout &timeout, const TimeoutCallback &timeout_callback)=0
boost::optional< data_conversion_layer::monitoring_frame::Message > zoneset_reference_msg_
#define STATE(state_name)
Higher level data type representing a reply message from the scanner.
Buffers and validates monitoring frames for a scan round.
Definition: scan_buffer.h:79
static constexpr uint32_t DEFAULT_NUM_MSG_PER_ROUND


psen_scan_v2
Author(s): Pilz GmbH + Co. KG
autogenerated on Sat Nov 5 2022 02:13:36