node_status_monitor.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #ifndef UAVCAN_PROTOCOL_NODE_STATUS_MONITOR_HPP_INCLUDED
6 #define UAVCAN_PROTOCOL_NODE_STATUS_MONITOR_HPP_INCLUDED
7 
8 #include <uavcan/debug.hpp>
11 #include <uavcan/node/timer.hpp>
12 #include <uavcan/protocol/NodeStatus.hpp>
13 #include <cassert>
14 #include <cstdlib>
15 
16 namespace uavcan
17 {
23 {
24 public:
25  struct NodeStatus
26  {
30 
32  health(protocol::NodeStatus::HEALTH_CRITICAL),
33  mode(protocol::NodeStatus::MODE_OFFLINE),
34  sub_mode(0)
35  {
36  StaticAssert<protocol::NodeStatus::FieldTypes::health::BitLen == 2>::check();
37  StaticAssert<protocol::NodeStatus::FieldTypes::mode::BitLen == 3>::check();
38  StaticAssert<protocol::NodeStatus::FieldTypes::sub_mode::BitLen == 3>::check();
39  }
40 
41  bool operator!=(const NodeStatus rhs) const { return !operator==(rhs); }
42  bool operator==(const NodeStatus rhs) const
43  {
44  return ( this->health == rhs.health
45  && this->mode == rhs.mode
46  && this->sub_mode == rhs.sub_mode
47  );
48  }
49 
50 #if UAVCAN_TOSTRING
51  std::string toString() const
52  {
53  char buf[40];
54  (void)snprintf(buf, sizeof(buf), "health=%d mode=%d sub_mode=%d", int(health), int(mode), int(sub_mode));
55  return std::string(buf);
56  }
57 #endif
58  };
59 
61  {
65  bool was_known;
66 
68  was_known(false)
69  { }
70  };
71 
72 private:
73  enum { TimerPeriodMs100 = 2 };
74 
76  void (NodeStatusMonitor::*)(const ReceivedDataStructure<protocol::NodeStatus>&)>
78 
80 
82 
84 
85  struct Entry
86  {
89  Entry() :
90  time_since_last_update_ms100(-1)
91  { }
92  };
93 
94  mutable Entry entries_[NodeID::Max]; // [1, NodeID::Max]
95 
96  Entry& getEntry(NodeID node_id) const
97  {
98  if (node_id.get() < 1 || node_id.get() > NodeID::Max)
99  {
100  handleFatalError("NodeStatusMonitor NodeID");
101  }
102  return entries_[node_id.get() - 1];
103  }
104 
105  void changeNodeStatus(const NodeID node_id, const Entry new_entry_value)
106  {
107  Entry& entry = getEntry(node_id);
108  if (entry.status != new_entry_value.status)
109  {
110  NodeStatusChangeEvent event;
111  event.node_id = node_id;
112  event.old_status = entry.status;
113  event.status = new_entry_value.status;
114  event.was_known = entry.time_since_last_update_ms100 >= 0;
115 
116  UAVCAN_TRACE("NodeStatusMonitor", "Node %i [%s] status change: [%s] --> [%s]", int(node_id.get()),
117  (event.was_known ? "known" : "new"),
118  event.old_status.toString().c_str(), event.status.toString().c_str());
119 
120  handleNodeStatusChange(event);
121  }
122  entry = new_entry_value;
123  }
124 
126  {
127  Entry new_entry;
128  new_entry.time_since_last_update_ms100 = 0;
129  new_entry.status.health = msg.health & ((1 << protocol::NodeStatus::FieldTypes::health::BitLen) - 1);
130  new_entry.status.mode = msg.mode & ((1 << protocol::NodeStatus::FieldTypes::mode::BitLen) - 1);
131  new_entry.status.sub_mode = msg.sub_mode & ((1 << protocol::NodeStatus::FieldTypes::sub_mode::BitLen) - 1);
132 
133  changeNodeStatus(msg.getSrcNodeID(), new_entry);
134 
135  handleNodeStatusMessage(msg);
136  }
137 
139  {
140  const int OfflineTimeoutMs100 = protocol::NodeStatus::OFFLINE_TIMEOUT_MS / 100;
141 
142  for (uint8_t i = 1; i <= NodeID::Max; i++)
143  {
144  Entry& entry = getEntry(i);
145  if (entry.time_since_last_update_ms100 >= 0 &&
146  entry.status.mode != protocol::NodeStatus::MODE_OFFLINE)
147  {
149  int8_t(entry.time_since_last_update_ms100 + int8_t(TimerPeriodMs100));
150 
151  if (entry.time_since_last_update_ms100 > OfflineTimeoutMs100)
152  {
153  Entry new_entry_value = entry;
154  new_entry_value.time_since_last_update_ms100 = OfflineTimeoutMs100;
155  new_entry_value.status.mode = protocol::NodeStatus::MODE_OFFLINE;
156  changeNodeStatus(i, new_entry_value);
157  }
158  }
159  }
160  }
161 
162 protected:
169  {
170  (void)event;
171  }
172 
179  {
180  (void)msg;
181  }
182 
183 public:
185  : sub_(node)
186  , timer_(node)
187  { }
188 
189  virtual ~NodeStatusMonitor() { }
190 
196  int start()
197  {
198  const int res = sub_.start(NodeStatusCallback(this, &NodeStatusMonitor::handleNodeStatus));
199  if (res >= 0)
200  {
201  timer_.setCallback(TimerCallback(this, &NodeStatusMonitor::handleTimerEvent));
202  timer_.startPeriodic(MonotonicDuration::fromMSec(TimerPeriodMs100 * 100));
203  }
204  return res;
205  }
206 
210  void forgetNode(NodeID node_id)
211  {
212  if (node_id.isValid())
213  {
214  Entry& entry = getEntry(node_id);
215  entry = Entry();
216  }
217  else
218  {
219  UAVCAN_ASSERT(0);
220  }
221  }
222 
227  {
228  for (unsigned i = 0; i < (sizeof(entries_) / sizeof(entries_[0])); i++)
229  {
230  entries_[i] = Entry();
231  }
232  }
233 
240  {
241  if (!node_id.isValid())
242  {
243  UAVCAN_ASSERT(0);
244  return NodeStatus();
245  }
246 
247  const Entry& entry = getEntry(node_id);
248  if (entry.time_since_last_update_ms100 >= 0)
249  {
250  return entry.status;
251  }
252  else
253  {
254  return NodeStatus();
255  }
256  }
257 
262  bool isNodeKnown(NodeID node_id) const
263  {
264  if (!node_id.isValid())
265  {
266  UAVCAN_ASSERT(0);
267  return false;
268  }
269  return getEntry(node_id).time_since_last_update_ms100 >= 0;
270  }
271 
278  {
279  NodeID nid_with_worst_health;
280  uint8_t worst_health = protocol::NodeStatus::HEALTH_OK;
281 
282  for (uint8_t i = 1; i <= NodeID::Max; i++)
283  {
284  const NodeID nid(i);
285  UAVCAN_ASSERT(nid.isUnicast());
286  const Entry& entry = getEntry(nid);
287  if (entry.time_since_last_update_ms100 >= 0)
288  {
289  if (entry.status.health > worst_health || !nid_with_worst_health.isValid())
290  {
291  nid_with_worst_health = nid;
292  worst_health = entry.status.health;
293  }
294  }
295  }
296 
297  return nid_with_worst_health;
298  }
299 
305  template <typename Operator>
306  void forEachNode(Operator op) const
307  {
308  for (uint8_t i = 1; i <= NodeID::Max; i++)
309  {
310  const NodeID nid(i);
311  UAVCAN_ASSERT(nid.isUnicast());
312  const Entry& entry = getEntry(nid);
313  if (entry.time_since_last_update_ms100 >= 0)
314  {
315  op(nid, entry.status);
316  }
317  }
318  }
319 };
320 
321 }
322 
323 #endif // UAVCAN_PROTOCOL_NODE_STATUS_MONITOR_HPP_INCLUDED
std::uint8_t uint8_t
Definition: std.hpp:24
void changeNodeStatus(const NodeID node_id, const Entry new_entry_value)
virtual void handleNodeStatusChange(const NodeStatusChangeEvent &event)
MethodBinder< NodeStatusMonitor *, void(NodeStatusMonitor::*)(const TimerEvent &)> TimerCallback
bool isNodeKnown(NodeID node_id) const
void startPeriodic(MonotonicDuration period)
Definition: uc_timer.cpp:42
bool isUnicast() const
Definition: transfer.hpp:136
std::int8_t int8_t
Definition: std.hpp:29
UAVCAN_EXPORT void handleFatalError(const char *msg)
Definition: uc_error.cpp:20
virtual void handleNodeStatusMessage(const ReceivedDataStructure< protocol::NodeStatus > &msg)
void setCallback(const Callback &callback)
Definition: timer.hpp:132
static std::string toString(long x)
Definition: multiset.cpp:16
uint8_t get() const
Definition: transfer.hpp:132
TimerEventForwarder< TimerCallback > timer_
static const uint8_t Max
Definition: transfer.hpp:120
UAVCAN_EXPORT EnableIf<!IsSameType< R, Array< T, ArrayMode, MaxSize > >::Result, bool >::Type operator==(const R &rhs, const Array< T, ArrayMode, MaxSize > &lhs)
Definition: array.hpp:1101
bool isValid() const
Definition: transfer.hpp:134
NodeStatus getNodeStatus(NodeID node_id) const
bool operator==(const NodeStatus rhs) const
int start(const Callback &callback)
Definition: subscriber.hpp:83
Subscriber< protocol::NodeStatus, NodeStatusCallback > sub_
void handleNodeStatus(const ReceivedDataStructure< protocol::NodeStatus > &msg)
void handleTimerEvent(const TimerEvent &)
Entry & getEntry(NodeID node_id) const
static MonotonicDuration fromMSec(int64_t ms)
Definition: time.hpp:41
void forgetNode(NodeID node_id)
bool operator!=(const NodeStatus rhs) const
void forEachNode(Operator op) const
int snprintf(char *out, std::size_t maxlen, const char *format,...)
Definition: std.hpp:73
int
Definition: libstubs.cpp:120


uavcan_communicator
Author(s):
autogenerated on Wed Jan 11 2023 03:59:39