firmware_update_trigger.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_FIRMWARE_UPDATE_TRIGGER_HPP_INCLUDED
6 #define UAVCAN_PROTOCOL_FIRMWARE_UPDATE_TRIGGER_HPP_INCLUDED
7 
9 #include <uavcan/debug.hpp>
12 #include <uavcan/util/map.hpp>
14 // UAVCAN types
15 #include <uavcan/protocol/file/BeginFirmwareUpdate.hpp>
16 
17 namespace uavcan
18 {
24 {
25 public:
31 
38 
53  virtual bool shouldRequestFirmwareUpdate(NodeID node_id, const protocol::GetNodeInfo::Response& node_info,
54  FirmwareFilePath& out_firmware_file_path) = 0;
55 
75  virtual bool shouldRetryFirmwareUpdate(NodeID node_id,
76  const protocol::file::BeginFirmwareUpdate::Response& error_response,
77  FirmwareFilePath& out_firmware_file_path) = 0;
78 
90  const protocol::file::BeginFirmwareUpdate::Response& response)
91  {
92  (void)node_id;
93  (void)response;
94  }
95 
97 };
98 
137  private TimerBase
138 {
142 
144 
145  enum { DefaultRequestIntervalMs = 1000 };
146 
148  {
149  enum { DefaultOutput = 0xFFU };
150 
153 
155  : owner(arg_owner)
157  { }
158 
159  bool operator()(const NodeID node_id, const FirmwareFilePath&)
160  {
161  if (node_id.get() > owner.last_queried_node_id_ &&
162  !owner.begin_fw_update_client_.hasPendingCallToServer(node_id))
163  {
164  output = min(output, node_id.get());
165  }
166  return false;
167  }
168  };
169 
170  /*
171  * State
172  */
174 
176 
178 
180 
182 
184 
186 
187  /*
188  * Methods of INodeInfoListener
189  */
190  virtual void handleNodeInfoUnavailable(NodeID node_id)
191  {
192  UAVCAN_TRACE("FirmwareUpdateTrigger", "Node ID %d could not provide GetNodeInfo response", int(node_id.get()));
193  pending_nodes_.remove(node_id); // For extra paranoia
194  }
195 
196  virtual void handleNodeInfoRetrieved(const NodeID node_id, const protocol::GetNodeInfo::Response& node_info)
197  {
198  FirmwareFilePath firmware_file_path;
199  const bool update_needed = checker_.shouldRequestFirmwareUpdate(node_id, node_info, firmware_file_path);
200  if (update_needed)
201  {
202  UAVCAN_TRACE("FirmwareUpdateTrigger", "Node ID %d requires update; file path: %s",
203  int(node_id.get()), firmware_file_path.c_str());
204  trySetPendingNode(node_id, firmware_file_path);
205  }
206  else
207  {
208  UAVCAN_TRACE("FirmwareUpdateTrigger", "Node ID %d does not need update", int(node_id.get()));
209  pending_nodes_.remove(node_id);
210  }
211  }
212 
214  {
215  if (event.status.mode == protocol::NodeStatus::MODE_OFFLINE)
216  {
217  pending_nodes_.remove(event.node_id);
218  UAVCAN_TRACE("FirmwareUpdateTrigger", "Node ID %d is offline hence forgotten", int(event.node_id.get()));
219  }
220  }
221 
222  /*
223  * Own methods
224  */
225  INode& getNode() { return begin_fw_update_client_.getNode(); }
226 
227  void trySetPendingNode(const NodeID node_id, const FirmwareFilePath& path)
228  {
229  if (UAVCAN_NULLPTR != pending_nodes_.insert(node_id, path))
230  {
231  if (!TimerBase::isRunning())
232  {
234  UAVCAN_TRACE("FirmwareUpdateTrigger", "Timer started");
235  }
236  }
237  else
238  {
239  getNode().registerInternalFailure("FirmwareUpdateTrigger OOM");
240  }
241  }
242 
244  {
245  // We can't do index search because indices are unstable in Map<>
246  // First try - from the current node up
247  NextNodeIDSearchPredicate s1(*this);
248  (void)pending_nodes_.find<NextNodeIDSearchPredicate&>(s1);
249 
251  {
253  }
254  else if (last_queried_node_id_ != 0)
255  {
256  // Nothing was found, resetting the selector and trying again
257  UAVCAN_TRACE("FirmwareUpdateTrigger", "Node selector reset, last value: %d", int(last_queried_node_id_));
259 
260  NextNodeIDSearchPredicate s2(*this);
261  (void)pending_nodes_.find<NextNodeIDSearchPredicate&>(s2);
262 
264  {
266  }
267  }
268  else
269  {
270  ; // Hopeless
271  }
272  UAVCAN_TRACE("FirmwareUpdateTrigger", "Next node ID to query: %d, pending nodes: %u, pending calls: %u",
273  int(last_queried_node_id_), pending_nodes_.getSize(),
274  begin_fw_update_client_.getNumPendingCalls());
275  return last_queried_node_id_;
276  }
277 
279  {
280  if (!result.isSuccessful())
281  {
282  UAVCAN_TRACE("FirmwareUpdateTrigger", "Request to %d has timed out, will retry",
283  int(result.getCallID().server_node_id.get()));
284  return;
285  }
286 
287  FirmwareFilePath* const old_path = pending_nodes_.access(result.getCallID().server_node_id);
288  if (old_path == UAVCAN_NULLPTR)
289  {
290  // The entry has been removed, assuming that it's not needed anymore
291  return;
292  }
293 
294  const bool confirmed =
295  result.getResponse().error == protocol::file::BeginFirmwareUpdate::Response::ERROR_OK ||
296  result.getResponse().error == protocol::file::BeginFirmwareUpdate::Response::ERROR_IN_PROGRESS;
297 
298  if (confirmed)
299  {
300  UAVCAN_TRACE("FirmwareUpdateTrigger", "Node %d confirmed the update request",
301  int(result.getCallID().server_node_id.get()));
302  pending_nodes_.remove(result.getCallID().server_node_id);
303  checker_.handleFirmwareUpdateConfirmation(result.getCallID().server_node_id, result.getResponse());
304  }
305  else
306  {
307  UAVCAN_ASSERT(old_path != UAVCAN_NULLPTR);
309  // We won't have to call trySetPendingNode(), because we'll directly update the old path via the pointer
310 
311  const bool update_needed =
312  checker_.shouldRetryFirmwareUpdate(result.getCallID().server_node_id, result.getResponse(), *old_path);
313 
314  if (!update_needed)
315  {
316  UAVCAN_TRACE("FirmwareUpdateTrigger", "Node %d does not need retry",
317  int(result.getCallID().server_node_id.get()));
318  pending_nodes_.remove(result.getCallID().server_node_id);
319  }
320  }
321  }
322 
323  virtual void handleTimerEvent(const TimerEvent&)
324  {
325  if (pending_nodes_.isEmpty())
326  {
327  TimerBase::stop();
328  UAVCAN_TRACE("FirmwareUpdateTrigger", "Timer stopped");
329  return;
330  }
331 
332  const NodeID node_id = pickNextNodeID();
333  if (!node_id.isUnicast())
334  {
335  return;
336  }
337 
338  FirmwareFilePath* const path = pending_nodes_.access(node_id);
339  if (path == UAVCAN_NULLPTR)
340  {
341  UAVCAN_ASSERT(0); // pickNextNodeID() returned a node ID that is not present in the map
342  return;
343  }
344 
345  protocol::file::BeginFirmwareUpdate::Request req;
346 
347  req.source_node_id = getNode().getNodeID().get();
348  if (!common_path_prefix_.empty())
349  {
350  req.image_file_remote_path.path += common_path_prefix_.c_str();
351  req.image_file_remote_path.path.push_back(protocol::file::Path::SEPARATOR);
352  }
353  req.image_file_remote_path.path += path->c_str();
354 
355  UAVCAN_TRACE("FirmwareUpdateTrigger", "Request to %d with path: %s",
356  int(node_id.get()), req.image_file_remote_path.path.c_str());
357 
358  const int call_res = begin_fw_update_client_.call(node_id, req);
359  if (call_res < 0)
360  {
361  getNode().registerInternalFailure("FirmwareUpdateTrigger call");
362  }
363  }
364 
365 public:
367  : TimerBase(node)
369  , checker_(checker)
371  , pending_nodes_(node.getAllocator())
374  { }
375 
377  {
379  {
381  }
382  }
383 
397  int start(NodeInfoRetriever& node_info_retriever,
398  const FirmwareFilePath& arg_common_path_prefix = FirmwareFilePath(),
400  {
401  /*
402  * Configuring the node info retriever
403  */
404  node_info_retriever_ = &node_info_retriever;
405 
406  int res = node_info_retriever_->addListener(this);
407  if (res < 0)
408  {
409  return res;
410  }
411 
412  /*
413  * Initializing the prefix, removing only the last trailing path separator.
414  */
415  common_path_prefix_ = arg_common_path_prefix;
416 
417  if (!common_path_prefix_.empty() &&
418  *(common_path_prefix_.end() - 1) == protocol::file::Path::SEPARATOR)
419  {
421  }
422 
423  /*
424  * Initializing the client
425  */
426  res = begin_fw_update_client_.init(priority);
427  if (res < 0)
428  {
429  return res;
430  }
431  begin_fw_update_client_.setCallback(
433 
434  // The timer will be started ad-hoc
435  return 0;
436  }
437 
444  {
445  if (interval.isPositive())
446  {
447  request_interval_ = interval;
448  if (TimerBase::isRunning()) // Restarting with new interval
449  {
451  }
452  }
453  else
454  {
455  UAVCAN_ASSERT(0);
456  }
457  }
458 
463  bool isTimerRunning() const { return TimerBase::isRunning(); }
464 
465  unsigned getNumPendingNodes() const
466  {
467  const unsigned ret = pending_nodes_.getSize();
468  UAVCAN_ASSERT((ret > 0) ? isTimerRunning() : true);
469  return ret;
470  }
471 
472 };
473 
474 }
475 
476 #endif // Include guard
uavcan::FirmwareUpdateTrigger::NextNodeIDSearchPredicate::NextNodeIDSearchPredicate
NextNodeIDSearchPredicate(const FirmwareUpdateTrigger &arg_owner)
Definition: firmware_update_trigger.hpp:154
uavcan::NodeStatusMonitor::NodeStatusChangeEvent::node_id
NodeID node_id
Definition: node_status_monitor.hpp:62
response
const std::string response
uavcan::TimerBase
Definition: timer.hpp:46
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::Array::resize
void resize(SizeType new_size, const ValueType &filler)
Definition: array.hpp:727
uavcan::FirmwareUpdateTrigger::NextNodeIDSearchPredicate
Definition: firmware_update_trigger.hpp:147
uavcan::Array::size
EnableIf< sizeof((reinterpret_cast< const R * >0)) -> size()) &&sizeof((*(reinterpret_cast< const R * >(0)))[0])
uavcan::Noncopyable
Definition: templates.hpp:46
uavcan::FirmwareUpdateTrigger::getNumPendingNodes
unsigned getNumPendingNodes() const
Definition: firmware_update_trigger.hpp:465
debug.hpp
uavcan::ArrayImpl::end
ValueType * end()
Definition: array.hpp:351
uavcan::FirmwareUpdateTrigger::common_path_prefix_
FirmwareFilePath common_path_prefix_
Definition: firmware_update_trigger.hpp:183
uavcan::IFirmwareVersionChecker::~IFirmwareVersionChecker
virtual ~IFirmwareVersionChecker()
Definition: firmware_update_trigger.hpp:96
uavcan::FirmwareUpdateTrigger::handleNodeInfoUnavailable
virtual void handleNodeInfoUnavailable(NodeID node_id)
Definition: firmware_update_trigger.hpp:190
uavcan::FirmwareUpdateTrigger::NextNodeIDSearchPredicate::output
uint8_t output
Definition: firmware_update_trigger.hpp:152
uavcan::ServiceCallResult::getCallID
ServiceCallID getCallID() const
Definition: service_client.hpp:83
uavcan::Array::empty
bool empty() const
Definition: array.hpp:712
uavcan::INodeInfoListener
Definition: node_info_retriever.hpp:21
uavcan::NodeID::get
uint8_t get() const
Definition: transfer.hpp:132
uavcan::FirmwareUpdateTrigger::FirmwareFilePath
IFirmwareVersionChecker::FirmwareFilePath FirmwareFilePath
Definition: firmware_update_trigger.hpp:143
uavcan::NodeID
Definition: transfer.hpp:112
uavcan::FirmwareUpdateTrigger::node_info_retriever_
NodeInfoRetriever * node_info_retriever_
Definition: firmware_update_trigger.hpp:177
uavcan::FirmwareUpdateTrigger::last_queried_node_id_
uint8_t last_queried_node_id_
Definition: firmware_update_trigger.hpp:185
map.hpp
service_client.hpp
uavcan::IFirmwareVersionChecker::handleFirmwareUpdateConfirmation
virtual void handleFirmwareUpdateConfirmation(NodeID node_id, const protocol::file::BeginFirmwareUpdate::Response &response)
Definition: firmware_update_trigger.hpp:89
uavcan::IFirmwareVersionChecker::MaxFirmwareFilePathLength
@ MaxFirmwareFilePathLength
Definition: firmware_update_trigger.hpp:30
UAVCAN_TRACE
#define UAVCAN_TRACE(...)
Definition: libuavcan/libuavcan/include/uavcan/debug.hpp:31
uavcan::FirmwareUpdateTrigger::handleBeginFirmwareUpdateResponse
void handleBeginFirmwareUpdateResponse(const ServiceCallResult< protocol::file::BeginFirmwareUpdate > &result)
Definition: firmware_update_trigger.hpp:278
uavcan::MonotonicDuration
Definition: time.hpp:182
uavcan::FirmwareUpdateTrigger::request_interval_
MonotonicDuration request_interval_
Definition: firmware_update_trigger.hpp:181
uavcan::FirmwareUpdateTrigger::NextNodeIDSearchPredicate::operator()
bool operator()(const NodeID node_id, const FirmwareFilePath &)
Definition: firmware_update_trigger.hpp:159
uavcan::ServiceCallResult
Definition: service_client.hpp:54
uavcan::IFirmwareVersionChecker
Definition: firmware_update_trigger.hpp:23
uavcan::NodeStatusMonitor::NodeStatus::mode
uint8_t mode
Definition: node_status_monitor.hpp:28
uavcan::TimerBase::startPeriodic
void startPeriodic(MonotonicDuration period)
Definition: uc_timer.cpp:42
uavcan::NodeStatusMonitor::NodeStatusChangeEvent::status
NodeStatus status
Definition: node_status_monitor.hpp:63
uavcan::FirmwareUpdateTrigger::handleNodeStatusChange
virtual void handleNodeStatusChange(const NodeStatusMonitor::NodeStatusChangeEvent &event)
Definition: firmware_update_trigger.hpp:213
uavcan::Array
Definition: array.hpp:424
uavcan::FirmwareUpdateTrigger::NextNodeIDSearchPredicate::DefaultOutput
@ DefaultOutput
Definition: firmware_update_trigger.hpp:149
uavcan::IFirmwareVersionChecker::FirmwareFilePath
MakeString< MaxFirmwareFilePathLength >::Type FirmwareFilePath
Definition: firmware_update_trigger.hpp:37
uavcan::FirmwareUpdateTrigger::setRequestInterval
void setRequestInterval(const MonotonicDuration interval)
Definition: firmware_update_trigger.hpp:443
uavcan::FirmwareUpdateTrigger::handleNodeInfoRetrieved
virtual void handleNodeInfoRetrieved(const NodeID node_id, const protocol::GetNodeInfo::Response &node_info)
Definition: firmware_update_trigger.hpp:196
uavcan::INode::registerInternalFailure
virtual void registerInternalFailure(const char *msg)=0
uavcan::FirmwareUpdateTrigger::pickNextNodeID
NodeID pickNextNodeID() const
Definition: firmware_update_trigger.hpp:243
uavcan::uint8_t
std::uint8_t uint8_t
Definition: std.hpp:24
uavcan::TransferPriority::OneHigherThanLowest
static const TransferPriority OneHigherThanLowest
Definition: transfer.hpp:40
uavcan::Map
Definition: map.hpp:33
uavcan::FirmwareUpdateTrigger::isTimerRunning
bool isTimerRunning() const
Definition: firmware_update_trigger.hpp:463
node_info_retriever.hpp
uavcan::FirmwareUpdateTrigger::FirmwareUpdateTrigger
FirmwareUpdateTrigger(INode &node, IFirmwareVersionChecker &checker)
Definition: firmware_update_trigger.hpp:366
uavcan::NodeID::isUnicast
bool isUnicast() const
Definition: transfer.hpp:136
uavcan::DurationBase::isPositive
bool isPositive() const
Definition: time.hpp:48
uavcan::IFirmwareVersionChecker::shouldRequestFirmwareUpdate
virtual bool shouldRequestFirmwareUpdate(NodeID node_id, const protocol::GetNodeInfo::Response &node_info, FirmwareFilePath &out_firmware_file_path)=0
uavcan::min
const UAVCAN_EXPORT T & min(const T &a, const T &b)
Definition: templates.hpp:281
method_binder.hpp
uavcan::INode
Definition: abstract_node.hpp:19
uavcan::FirmwareUpdateTrigger::trySetPendingNode
void trySetPendingNode(const NodeID node_id, const FirmwareFilePath &path)
Definition: firmware_update_trigger.hpp:227
uavcan::ServiceClient
Definition: service_client.hpp:217
uavcan::TransferPriority
Definition: transfer.hpp:28
uavcan::FirmwareUpdateTrigger::getNode
INode & getNode()
Definition: firmware_update_trigger.hpp:225
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::DeadlineHandler::isRunning
bool isRunning() const
Definition: uc_scheduler.cpp:32
uavcan::INode::getNodeID
NodeID getNodeID() const
Definition: abstract_node.hpp:39
uavcan::DeadlineHandler::stop
void stop()
Definition: uc_scheduler.cpp:27
uavcan::FirmwareUpdateTrigger::DefaultRequestIntervalMs
@ DefaultRequestIntervalMs
Definition: firmware_update_trigger.hpp:145
uavcan::MethodBinder
Definition: method_binder.hpp:20
uavcan::FirmwareUpdateTrigger::pending_nodes_
Map< NodeID, FirmwareFilePath > pending_nodes_
Definition: firmware_update_trigger.hpp:179
uavcan::FirmwareUpdateTrigger::handleTimerEvent
virtual void handleTimerEvent(const TimerEvent &)
Definition: firmware_update_trigger.hpp:323
uavcan::FirmwareUpdateTrigger::~FirmwareUpdateTrigger
~FirmwareUpdateTrigger()
Definition: firmware_update_trigger.hpp:376
uavcan::NodeInfoRetriever::addListener
int addListener(INodeInfoListener *listener)
Definition: node_info_retriever.hpp:386
uavcan::NodeInfoRetriever
Definition: node_info_retriever.hpp:91
pyuavcan_v0.introspect.node
node
Definition: introspect.py:398
uavcan
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:204
uavcan::FirmwareUpdateTrigger::begin_fw_update_client_
ServiceClient< protocol::file::BeginFirmwareUpdate, BeginFirmwareUpdateResponseCallback > begin_fw_update_client_
Definition: firmware_update_trigger.hpp:173
uavcan::FirmwareUpdateTrigger::BeginFirmwareUpdateResponseCallback
MethodBinder< FirmwareUpdateTrigger *, void(FirmwareUpdateTrigger::*)(const ServiceCallResult< protocol::file::BeginFirmwareUpdate > &)> BeginFirmwareUpdateResponseCallback
Definition: firmware_update_trigger.hpp:141
uavcan::FirmwareUpdateTrigger::start
int start(NodeInfoRetriever &node_info_retriever, const FirmwareFilePath &arg_common_path_prefix=FirmwareFilePath(), const TransferPriority priority=TransferPriority::OneHigherThanLowest)
Definition: firmware_update_trigger.hpp:397
uavcan::ArrayImpl::c_str
const char * c_str() const
Definition: array.hpp:321
uavcan::FirmwareUpdateTrigger::checker_
IFirmwareVersionChecker & checker_
Definition: firmware_update_trigger.hpp:175
uavcan::FirmwareUpdateTrigger::getRequestInterval
MonotonicDuration getRequestInterval() const
Definition: firmware_update_trigger.hpp:442
uavcan::NodeStatusMonitor::NodeStatusChangeEvent
Definition: node_status_monitor.hpp:60
uavcan::FirmwareUpdateTrigger
Definition: firmware_update_trigger.hpp:136
uavcan::IFirmwareVersionChecker::shouldRetryFirmwareUpdate
virtual bool shouldRetryFirmwareUpdate(NodeID node_id, const protocol::file::BeginFirmwareUpdate::Response &error_response, FirmwareFilePath &out_firmware_file_path)=0
UAVCAN_ASSERT
#define UAVCAN_ASSERT(x)
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:184
uavcan::TimerEvent
Definition: timer.hpp:32
uavcan::FirmwareUpdateTrigger::NextNodeIDSearchPredicate::owner
const FirmwareUpdateTrigger & owner
Definition: firmware_update_trigger.hpp:151


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