node_info_retriever.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #ifndef UAVCAN_PROTOCOL_NODE_INFO_RETRIEVER_HPP_INCLUDED
6 #define UAVCAN_PROTOCOL_NODE_INFO_RETRIEVER_HPP_INCLUDED
7 
9 #include <uavcan/debug.hpp>
10 #include <uavcan/util/multiset.hpp>
12 #include <uavcan/node/timer.hpp>
14 #include <uavcan/protocol/GetNodeInfo.hpp>
15 
16 namespace uavcan
17 {
22 {
23 public:
30  virtual void handleNodeInfoRetrieved(NodeID node_id, const protocol::GetNodeInfo::Response& node_info) = 0;
31 
36  virtual void handleNodeInfoUnavailable(NodeID node_id) = 0;
37 
44  {
45  (void)event;
46  }
47 
54  {
55  (void)msg;
56  }
57 
58  virtual ~INodeInfoListener() { }
59 };
60 
92  , TimerBase
93 {
94 public:
95  enum { MaxNumRequestAttempts = 254 };
96  enum { UnlimitedRequestAttempts = 0 };
97 
98 private:
102 
103  struct Entry
104  {
109 
111  : uptime_sec(0)
112  , num_attempts_made(0)
113  , request_needed(false)
114  , updated_since_last_attempt(false)
115  {
116 #if UAVCAN_DEBUG
117  StaticAssert<sizeof(Entry) <= 8>::check();
118 #endif
119  }
120  };
121 
123  {
125  const protocol::GetNodeInfo::Response& node_info;
126 
127  NodeInfoRetrievedHandlerCaller(NodeID arg_node_id, const protocol::GetNodeInfo::Response& arg_node_info)
128  : node_id(arg_node_id)
129  , node_info(arg_node_info)
130  { }
131 
133  {
135  key->handleNodeInfoRetrieved(node_id, node_info);
136  return false;
137  }
138  };
139 
140  template <typename Event>
142  {
143  void (INodeInfoListener::* const method)(Event);
144  Event event;
145 
146  GenericHandlerCaller(void (INodeInfoListener::*arg_method)(Event), Event arg_event)
147  : method(arg_method)
148  , event(arg_event)
149  { }
150 
152  {
154  (key->*method)(event);
155  return false;
156  }
157  };
158 
159  enum { DefaultNumRequestAttempts = 16 };
160  enum { DefaultTimerIntervalMSec = 40 };
161 
162  /*
163  * State
164  */
165  Entry entries_[NodeID::Max]; // [1, NodeID::Max]
166 
168 
170 
172 
174 
176 
177  /*
178  * Methods
179  */
180  const Entry& getEntry(NodeID node_id) const { return const_cast<NodeInfoRetriever*>(this)->getEntry(node_id); }
182  {
183  if (node_id.get() < 1 || node_id.get() > NodeID::Max)
184  {
185  handleFatalError("NodeInfoRetriever NodeID");
186  }
187  return entries_[node_id.get() - 1];
188  }
189 
191  {
192  if (!TimerBase::isRunning())
193  {
194  TimerBase::startPeriodic(request_interval_);
195  UAVCAN_TRACE("NodeInfoRetriever", "Timer started, interval %s sec", request_interval_.toString().c_str());
196  }
197  }
198 
199  NodeID pickNextNodeToQuery(bool& out_at_least_one_request_needed) const
200  {
201  out_at_least_one_request_needed = false;
202 
203  for (unsigned iter_cnt_ = 0; iter_cnt_ < (sizeof(entries_) / sizeof(entries_[0])); iter_cnt_++) // Round-robin
204  {
205  last_picked_node_++;
206  if (last_picked_node_ > NodeID::Max)
207  {
208  last_picked_node_ = 1;
209  }
210  UAVCAN_ASSERT((last_picked_node_ >= 1) &&
211  (last_picked_node_ <= NodeID::Max));
212 
213  const Entry& entry = getEntry(last_picked_node_);
214 
215  if (entry.request_needed)
216  {
217  out_at_least_one_request_needed = true;
218 
219  if (entry.updated_since_last_attempt &&
220  !get_node_info_client_.hasPendingCallToServer(last_picked_node_))
221  {
222  UAVCAN_TRACE("NodeInfoRetriever", "Next node to query: %d", int(last_picked_node_));
223  return NodeID(last_picked_node_);
224  }
225  }
226  }
227 
228  return NodeID(); // No node could be found
229  }
230 
231  virtual void handleTimerEvent(const TimerEvent&)
232  {
233  bool at_least_one_request_needed = false;
234  const NodeID next = pickNextNodeToQuery(at_least_one_request_needed);
235 
236  if (next.isUnicast())
237  {
238  UAVCAN_ASSERT(at_least_one_request_needed);
239  getEntry(next).updated_since_last_attempt = false;
240  const int res = get_node_info_client_.call(next, protocol::GetNodeInfo::Request());
241  if (res < 0)
242  {
243  get_node_info_client_.getNode().registerInternalFailure("NodeInfoRetriever GetNodeInfo call");
244  }
245  }
246  else
247  {
248  if (!at_least_one_request_needed)
249  {
250  TimerBase::stop();
251  UAVCAN_TRACE("NodeInfoRetriever", "Timer stopped");
252  }
253  }
254  }
255 
257  {
258  const bool was_offline = !event.was_known ||
259  (event.old_status.mode == protocol::NodeStatus::MODE_OFFLINE);
260 
261  const bool offline_now = event.status.mode == protocol::NodeStatus::MODE_OFFLINE;
262 
263  if (was_offline || offline_now)
264  {
265  Entry& entry = getEntry(event.node_id);
266 
267  entry.request_needed = !offline_now;
268  entry.num_attempts_made = 0;
269 
270  UAVCAN_TRACE("NodeInfoRetriever", "Offline status change: node ID %d, request needed: %d",
271  int(event.node_id.get()), int(entry.request_needed));
272 
273  if (entry.request_needed)
274  {
275  startTimerIfNotRunning();
276  }
277  }
278 
279  listeners_.forEach(
281  }
282 
284  {
285  Entry& entry = getEntry(msg.getSrcNodeID());
286 
287  if (msg.uptime_sec < entry.uptime_sec)
288  {
289  entry.request_needed = true;
290  entry.num_attempts_made = 0;
291 
292  startTimerIfNotRunning();
293  }
294  entry.uptime_sec = msg.uptime_sec;
295  entry.updated_since_last_attempt = true;
296 
299  }
300 
302  {
303  Entry& entry = getEntry(result.getCallID().server_node_id);
304 
305  if (result.isSuccessful())
306  {
307  /*
308  * Updating the uptime here allows to properly handle a corner case where the service response arrives
309  * after the device has restarted and published its new NodeStatus (although it's unlikely to happen).
310  */
311  entry.uptime_sec = result.getResponse().status.uptime_sec;
312  entry.request_needed = false;
313  listeners_.forEach(NodeInfoRetrievedHandlerCaller(result.getCallID().server_node_id,
314  result.getResponse()));
315  }
316  else
317  {
318  if (num_attempts_ != UnlimitedRequestAttempts)
319  {
320  entry.num_attempts_made++;
321  if (entry.num_attempts_made >= num_attempts_)
322  {
323  entry.request_needed = false;
325  result.getCallID().server_node_id));
326  }
327  }
328  }
329  }
330 
331 public:
334  , TimerBase(node)
335  , listeners_(node.getAllocator())
336  , get_node_info_client_(node)
337  , request_interval_(MonotonicDuration::fromMSec(DefaultTimerIntervalMSec))
338  , last_picked_node_(1)
339  , num_attempts_(DefaultNumRequestAttempts)
340  { }
341 
348  {
349  int res = NodeStatusMonitor::start();
350  if (res < 0)
351  {
352  return res;
353  }
354 
355  res = get_node_info_client_.init(priority);
356  if (res < 0)
357  {
358  return res;
359  }
360  get_node_info_client_.setCallback(GetNodeInfoResponseCallback(this,
362  // Note: the timer will be started ad-hoc
363  return 0;
364  }
365 
371  {
373  get_node_info_client_.cancelAllCalls();
374 
375  for (unsigned i = 0; i < (sizeof(entries_) / sizeof(entries_[0])); i++)
376  {
377  entries_[i] = Entry();
378  }
379  // It is not necessary to reset the last picked node index
380  }
381 
387  {
388  if (listener != UAVCAN_NULLPTR)
389  {
390  removeListener(listener);
391  return (UAVCAN_NULLPTR == listeners_.emplace(listener)) ? -ErrMemory : 0;
392  }
393  else
394  {
395  return -ErrInvalidParam;
396  }
397  }
398 
404  {
405  if (listener != UAVCAN_NULLPTR)
406  {
407  listeners_.removeAll(listener);
408  }
409  else
410  {
411  UAVCAN_ASSERT(0);
412  }
413  }
414 
415  unsigned getNumListeners() const { return listeners_.getSize(); }
416 
422  uint8_t getNumRequestAttempts() const { return num_attempts_; }
424  {
425  num_attempts_ = min(static_cast<uint8_t>(MaxNumRequestAttempts), num);
426  }
427 
432  MonotonicDuration getRequestInterval() const { return request_interval_; }
434  {
435  if (interval.isPositive())
436  {
437  request_interval_ = interval;
438  if (TimerBase::isRunning())
439  {
440  TimerBase::startPeriodic(request_interval_);
441  }
442  }
443  else
444  {
445  UAVCAN_ASSERT(0);
446  }
447  }
448 
452  bool isRetrievingInProgress() const { return TimerBase::isRunning(); }
453 
455  {
456  const unsigned num = get_node_info_client_.getNumPendingCalls();
457  UAVCAN_ASSERT(num <= 0xFF);
458  return static_cast<uint8_t>(num);
459  }
460 };
461 
462 }
463 
464 #endif // Include guard
uavcan::NodeStatusMonitor::NodeStatusChangeEvent::node_id
NodeID node_id
Definition: node_status_monitor.hpp:62
uavcan::TimerBase
Definition: timer.hpp:46
check
ROSCPP_DECL bool check()
uavcan::NodeInfoRetriever::get_node_info_client_
ServiceClient< protocol::GetNodeInfo, GetNodeInfoResponseCallback > get_node_info_client_
Definition: node_info_retriever.hpp:169
uavcan::NodeInfoRetriever::request_interval_
MonotonicDuration request_interval_
Definition: node_info_retriever.hpp:171
uavcan::NodeInfoRetriever::handleNodeStatusMessage
virtual void handleNodeStatusMessage(const ReceivedDataStructure< protocol::NodeStatus > &msg)
Definition: node_info_retriever.hpp:283
UAVCAN_NULLPTR
#define UAVCAN_NULLPTR
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:51
uavcan::NodeInfoRetriever::removeListener
void removeListener(INodeInfoListener *listener)
Definition: node_info_retriever.hpp:403
uavcan::NodeInfoRetriever::pickNextNodeToQuery
NodeID pickNextNodeToQuery(bool &out_at_least_one_request_needed) const
Definition: node_info_retriever.hpp:199
uavcan::NodeInfoRetriever::getNumRequestAttempts
uint8_t getNumRequestAttempts() const
Definition: node_info_retriever.hpp:422
multiset.hpp
uavcan::NodeInfoRetriever::start
int start(const TransferPriority priority=TransferPriority::OneHigherThanLowest)
Definition: node_info_retriever.hpp:347
uavcan::NodeInfoRetriever::Entry::request_needed
bool request_needed
Always false for unknown nodes.
Definition: node_info_retriever.hpp:107
debug.hpp
uavcan::uint32_t
std::uint32_t uint32_t
Definition: std.hpp:26
uavcan::NodeInfoRetriever::Entry::updated_since_last_attempt
bool updated_since_last_attempt
Always false for unknown nodes.
Definition: node_info_retriever.hpp:108
uavcan::ServiceCallResult::getCallID
ServiceCallID getCallID() const
Definition: service_client.hpp:83
uavcan::NodeInfoRetriever::setNumRequestAttempts
void setNumRequestAttempts(const uint8_t num)
Definition: node_info_retriever.hpp:423
uavcan::INodeInfoListener
Definition: node_info_retriever.hpp:21
uavcan::NodeID::get
uint8_t get() const
Definition: transfer.hpp:132
uavcan::NodeInfoRetriever::NodeInfoRetrievedHandlerCaller::node_info
const protocol::GetNodeInfo::Response & node_info
Definition: node_info_retriever.hpp:125
uavcan::NodeID
Definition: transfer.hpp:112
uavcan::NodeInfoRetriever::getEntry
const Entry & getEntry(NodeID node_id) const
Definition: node_info_retriever.hpp:180
uavcan::NodeInfoRetriever::Entry
Definition: node_info_retriever.hpp:103
service_client.hpp
uavcan::INodeInfoListener::handleNodeStatusChange
virtual void handleNodeStatusChange(const NodeStatusMonitor::NodeStatusChangeEvent &event)
Definition: node_info_retriever.hpp:43
uavcan::Multiset::getSize
unsigned getSize() const
Definition: multiset.hpp:461
uavcan::NodeInfoRetriever::num_attempts_
uint8_t num_attempts_
Definition: node_info_retriever.hpp:175
uavcan::ReceivedDataStructure
Definition: generic_subscriber.hpp:39
UAVCAN_TRACE
#define UAVCAN_TRACE(...)
Definition: libuavcan/libuavcan/include/uavcan/debug.hpp:31
uavcan::StaticAssert
struct UAVCAN_EXPORT StaticAssert
Definition: templates.hpp:29
uavcan::NodeInfoRetriever::NodeInfoRetrievedHandlerCaller
Definition: node_info_retriever.hpp:122
uavcan::MonotonicDuration
Definition: time.hpp:182
uavcan::NodeInfoRetriever::getRequestInterval
MonotonicDuration getRequestInterval() const
Definition: node_info_retriever.hpp:432
uavcan::NodeStatusMonitor
Definition: node_status_monitor.hpp:22
uavcan::NodeInfoRetriever::Entry::uptime_sec
uint32_t uptime_sec
Definition: node_info_retriever.hpp:105
timer.hpp
uavcan::ServiceCallResult
Definition: service_client.hpp:54
uavcan::TimerBase::startPeriodic
void startPeriodic(MonotonicDuration period)
Definition: uc_timer.cpp:42
uavcan::NodeInfoRetriever::NodeInfoRetrievedHandlerCaller::operator()
bool operator()(INodeInfoListener *key)
Definition: node_info_retriever.hpp:132
uavcan::NodeInfoRetriever::GenericHandlerCaller::event
Event event
Definition: node_info_retriever.hpp:144
uavcan::INodeInfoListener::handleNodeStatusMessage
virtual void handleNodeStatusMessage(const ReceivedDataStructure< protocol::NodeStatus > &msg)
Definition: node_info_retriever.hpp:53
uavcan::INodeInfoListener::~INodeInfoListener
virtual ~INodeInfoListener()
Definition: node_info_retriever.hpp:58
uavcan::NodeInfoRetriever::handleTimerEvent
virtual void handleTimerEvent(const TimerEvent &)
Definition: node_info_retriever.hpp:231
uavcan::Multiset::removeAll
void removeAll(const T &ref)
Definition: multiset.hpp:269
uavcan::uint8_t
std::uint8_t uint8_t
Definition: std.hpp:24
uavcan::TransferPriority::OneHigherThanLowest
static const TransferPriority OneHigherThanLowest
Definition: transfer.hpp:40
node_status_monitor.hpp
uavcan::NodeInfoRetriever::isRetrievingInProgress
bool isRetrievingInProgress() const
Definition: node_info_retriever.hpp:452
uavcan::NodeInfoRetriever::GenericHandlerCaller::GenericHandlerCaller
GenericHandlerCaller(void(INodeInfoListener::*arg_method)(Event), Event arg_event)
Definition: node_info_retriever.hpp:146
uavcan::NodeInfoRetriever::handleNodeStatusChange
virtual void handleNodeStatusChange(const NodeStatusChangeEvent &event)
Definition: node_info_retriever.hpp:256
uavcan::ServiceClient::cancelAllCalls
void cancelAllCalls()
Definition: service_client.hpp:564
uavcan::NodeInfoRetriever::Entry::Entry
Entry()
Definition: node_info_retriever.hpp:110
uavcan::ServiceClient::init
int init()
Definition: service_client.hpp:300
uavcan::NodeInfoRetriever::GenericHandlerCaller::operator()
bool operator()(INodeInfoListener *key)
Definition: node_info_retriever.hpp:151
uavcan::NodeID::isUnicast
bool isUnicast() const
Definition: transfer.hpp:136
uavcan::DurationBase::isPositive
bool isPositive() const
Definition: time.hpp:48
uavcan::INodeInfoListener::handleNodeInfoRetrieved
virtual void handleNodeInfoRetrieved(NodeID node_id, const protocol::GetNodeInfo::Response &node_info)=0
UAVCAN_EXPORT
#define UAVCAN_EXPORT
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:108
uavcan::min
const UAVCAN_EXPORT T & min(const T &a, const T &b)
Definition: templates.hpp:281
uavcan::NodeInfoRetriever::listeners_
Multiset< INodeInfoListener * > listeners_
Definition: node_info_retriever.hpp:167
uavcan::INode
Definition: abstract_node.hpp:19
uavcan::NodeInfoRetriever::NodeInfoRetrievedHandlerCaller::node_id
const NodeID node_id
Definition: node_info_retriever.hpp:124
uavcan::ServiceClient
Definition: service_client.hpp:217
uavcan::TransferPriority
Definition: transfer.hpp:28
uavcan::ServiceCallResult::getResponse
const ResponseFieldType & getResponse() const
Definition: service_client.hpp:88
uavcan::ServiceCallResult::isSuccessful
bool isSuccessful() const
Definition: service_client.hpp:79
build_config.hpp
uavcan::NodeInfoRetriever::NodeInfoRetriever
NodeInfoRetriever(INode &node)
Definition: node_info_retriever.hpp:332
uavcan::DeadlineHandler::isRunning
bool isRunning() const
Definition: uc_scheduler.cpp:32
uavcan::GenericSubscriberBase::getNode
INode & getNode() const
Definition: generic_subscriber.hpp:120
uavcan::DeadlineHandler::stop
void stop()
Definition: uc_scheduler.cpp:27
uavcan::ServiceClient::hasPendingCallToServer
bool hasPendingCallToServer(NodeID server_node_id) const
Definition: service_client.hpp:571
uavcan::DurationBase::toString
void toString(char buf[StringBufSize]) const
Prints time in seconds with microsecond resolution.
Definition: time.hpp:224
uavcan::ServiceClient::getNumPendingCalls
unsigned getNumPendingCalls() const
Definition: service_client.hpp:364
uavcan::NodeInfoRetriever::getNumPendingRequests
uint8_t getNumPendingRequests() const
Definition: node_info_retriever.hpp:454
uavcan::Multiset::forEach
void forEach(Operator oper)
Definition: multiset.hpp:294
uavcan::MethodBinder
Definition: method_binder.hpp:20
uavcan::NodeInfoRetriever::GenericHandlerCaller
Definition: node_info_retriever.hpp:141
uavcan::NodeInfoRetriever::setRequestInterval
void setRequestInterval(const MonotonicDuration interval)
Definition: node_info_retriever.hpp:433
uavcan::INodeInfoListener::handleNodeInfoUnavailable
virtual void handleNodeInfoUnavailable(NodeID node_id)=0
uavcan::NodeInfoRetriever::Entry::num_attempts_made
uint8_t num_attempts_made
Definition: node_info_retriever.hpp:106
uavcan::ServiceClient::setCallback
void setCallback(const Callback &cb)
Definition: service_client.hpp:358
uavcan::handleFatalError
UAVCAN_EXPORT void handleFatalError(const char *msg)
Definition: uc_error.cpp:20
uavcan::NodeInfoRetriever::addListener
int addListener(INodeInfoListener *listener)
Definition: node_info_retriever.hpp:386
uavcan::NodeStatusMonitor::forgetAllNodes
void forgetAllNodes()
Definition: node_status_monitor.hpp:226
uavcan::NodeInfoRetriever::handleGetNodeInfoResponse
void handleGetNodeInfoResponse(const ServiceCallResult< protocol::GetNodeInfo > &result)
Definition: node_info_retriever.hpp:301
uavcan::NodeInfoRetriever::last_picked_node_
uint8_t last_picked_node_
Definition: node_info_retriever.hpp:173
uavcan::NodeID::Max
static const uint8_t Max
Definition: transfer.hpp:120
uavcan::NodeInfoRetriever::invalidateAll
void invalidateAll()
Definition: node_info_retriever.hpp:370
uavcan::NodeInfoRetriever::getEntry
Entry & getEntry(NodeID node_id)
Definition: node_info_retriever.hpp:181
uavcan::NodeInfoRetriever
Definition: node_info_retriever.hpp:91
pyuavcan_v0.introspect.node
node
Definition: introspect.py:398
uavcan::NodeInfoRetriever::NodeInfoRetrievedHandlerCaller::NodeInfoRetrievedHandlerCaller
NodeInfoRetrievedHandlerCaller(NodeID arg_node_id, const protocol::GetNodeInfo::Response &arg_node_info)
Definition: node_info_retriever.hpp:127
uavcan
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:204
uavcan::ReceivedDataStructure::getSrcNodeID
NodeID getSrcNodeID() const
Definition: generic_subscriber.hpp:75
uavcan::ServiceClient::call
int call(NodeID server_node_id, const RequestType &request)
Definition: service_client.hpp:488
uavcan::NodeInfoRetriever::getNumListeners
unsigned getNumListeners() const
Definition: node_info_retriever.hpp:415
uavcan::Multiset
Definition: multiset.hpp:29
uavcan::NodeInfoRetriever::startTimerIfNotRunning
void startTimerIfNotRunning()
Definition: node_info_retriever.hpp:190
uavcan::NodeStatusMonitor::NodeStatusChangeEvent
Definition: node_status_monitor.hpp:60
uavcan::Multiset::emplace
T * emplace()
Definition: multiset.hpp:205
UAVCAN_ASSERT
#define UAVCAN_ASSERT(x)
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:184
uavcan::TimerEvent
Definition: timer.hpp:32
uavcan::NodeStatusMonitor::start
int start()
Definition: node_status_monitor.hpp:196


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:02