allocation_request_manager.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_DYNAMIC_NODE_ID_SERVER_ALLOCATION_REQUEST_MANAGER_HPP_INCLUDED
6 #define UAVCAN_PROTOCOL_DYNAMIC_NODE_ID_SERVER_ALLOCATION_REQUEST_MANAGER_HPP_INCLUDED
7 
9 #include <uavcan/debug.hpp>
15 // UAVCAN types
16 #include <uavcan/protocol/dynamic_node_id/Allocation.hpp>
17 
18 namespace uavcan
19 {
20 namespace dynamic_node_id_server
21 {
26 {
27 public:
31  virtual bool canPublishFollowupAllocationResponse() const = 0;
32 
36  virtual void handleAllocationRequest(const UniqueID& unique_id, NodeID preferred_node_id) = 0;
37 
39 };
40 
46 {
50 
52 
55  Allocation::FieldTypes::unique_id current_unique_id_;
56 
59 
62 
63  enum { InvalidStage = 0 };
64 
65  void trace(TraceCode code, int64_t argument) { tracer_.onEvent(code, argument); }
66 
67  static uint8_t detectRequestStage(const Allocation& msg)
68  {
69  const uint8_t max_bytes_per_request = Allocation::MAX_LENGTH_OF_UNIQUE_ID_IN_REQUEST;
70 
71  if ((msg.unique_id.size() != max_bytes_per_request) &&
72  (msg.unique_id.size() != (msg.unique_id.capacity() - max_bytes_per_request * 2U)) &&
73  (msg.unique_id.size() != msg.unique_id.capacity())) // Future proofness for CAN FD
74  {
75  return InvalidStage;
76  }
77  if (msg.first_part_of_unique_id)
78  {
79  return 1; // Note that CAN FD frames can deliver the unique ID in one stage!
80  }
81  if (msg.unique_id.size() == Allocation::MAX_LENGTH_OF_UNIQUE_ID_IN_REQUEST)
82  {
83  return 2;
84  }
85  if (msg.unique_id.size() < Allocation::MAX_LENGTH_OF_UNIQUE_ID_IN_REQUEST)
86  {
87  return 3;
88  }
89  return InvalidStage;
90  }
91 
93  {
94  if (current_unique_id_.empty())
95  {
96  return 1;
97  }
98  if (current_unique_id_.size() >= (Allocation::MAX_LENGTH_OF_UNIQUE_ID_IN_REQUEST * 2))
99  {
100  return 3;
101  }
102  if (current_unique_id_.size() >= Allocation::MAX_LENGTH_OF_UNIQUE_ID_IN_REQUEST)
103  {
104  return 2;
105  }
106  return InvalidStage;
107  }
108 
110  {
111  Allocation msg;
112  msg.unique_id = current_unique_id_;
113  UAVCAN_ASSERT(msg.unique_id.size() < msg.unique_id.capacity());
114 
115  UAVCAN_TRACE("AllocationRequestManager", "Intermediate response with %u bytes of unique ID",
116  unsigned(msg.unique_id.size()));
117 
118  trace(TraceAllocationFollowupResponse, msg.unique_id.size());
119 
120  const int res = allocation_pub_.broadcast(msg);
121  if (res < 0)
122  {
123  trace(TraceError, res);
124  allocation_pub_.getNode().registerInternalFailure("Dynamic allocation broadcast");
125  }
126  }
127 
129  {
132 
133  if (!msg.isAnonymousTransfer())
134  {
135  return; // This is a response from another allocator, ignore
136  }
137 
138  /*
139  * Reset the expected stage on timeout
140  */
142  {
143  UAVCAN_TRACE("AllocationRequestManager", "Stage timeout, reset");
144  current_unique_id_.clear();
146  }
147 
148  /*
149  * Checking if request stage matches the expected stage
150  */
151  const uint8_t request_stage = detectRequestStage(msg);
152  if (request_stage == InvalidStage)
153  {
154  trace(TraceAllocationBadRequest, msg.unique_id.size());
155  return; // Malformed request - ignore without resetting
156  }
157 
158  const uint8_t expected_stage = getExpectedStage();
159  if (expected_stage == InvalidStage)
160  {
161  UAVCAN_ASSERT(0);
162  return;
163  }
164 
165  if (request_stage != expected_stage)
166  {
167  trace(TraceAllocationUnexpectedStage, request_stage);
168  return; // Ignore - stage mismatch
169  }
170 
171  const uint8_t max_expected_bytes =
172  static_cast<uint8_t>(current_unique_id_.capacity() - current_unique_id_.size());
173  UAVCAN_ASSERT(max_expected_bytes > 0);
174  if (msg.unique_id.size() > max_expected_bytes)
175  {
176  trace(TraceAllocationBadRequest, msg.unique_id.size());
177  return; // Malformed request
178  }
179 
180  /*
181  * Updating the local state
182  */
183  for (uint8_t i = 0; i < msg.unique_id.size(); i++)
184  {
185  current_unique_id_.push_back(msg.unique_id[i]);
186  }
187 
189 
190  /*
191  * Proceeding with allocation if possible
192  * Note that single-frame CAN FD allocation requests will be delivered to the server even if it's not leader.
193  */
194  if (current_unique_id_.size() == current_unique_id_.capacity())
195  {
196  UAVCAN_TRACE("AllocationRequestManager", "Allocation request received; preferred node ID: %d",
197  int(msg.node_id));
198 
199  UniqueID unique_id;
200  copy(current_unique_id_.begin(), current_unique_id_.end(), unique_id.begin());
201  current_unique_id_.clear();
202 
203  {
204  uint64_t event_agrument = 0;
205  for (uint8_t i = 0; i < 8; i++)
206  {
207  event_agrument |= static_cast<uint64_t>(unique_id[i]) << (56U - i * 8U);
208  }
209  trace(TraceAllocationExchangeComplete, static_cast<int64_t>(event_agrument));
210  }
211 
212  handler_.handleAllocationRequest(unique_id, msg.node_id);
213  }
214  else
215  {
217  {
219  }
220  else
221  {
223  current_unique_id_.clear();
224  }
225  }
226 
227  /*
228  * It is super important to update timestamp only if the request has been processed successfully.
229  */
231  }
232 
233 public:
235  : stage_timeout_(MonotonicDuration::fromMSec(Allocation::FOLLOWUP_TIMEOUT_MS))
236  , handler_(handler)
237  , tracer_(tracer)
240  { }
241 
242  int init(const TransferPriority priority)
243  {
244  int res = allocation_pub_.init(priority);
245  if (res < 0)
246  {
247  return res;
248  }
249  allocation_pub_.setTxTimeout(MonotonicDuration::fromMSec(Allocation::FOLLOWUP_TIMEOUT_MS));
250 
252  if (res < 0)
253  {
254  return res;
255  }
256  allocation_sub_.allowAnonymousTransfers();
257 
258  return 0;
259  }
260 
261  int broadcastAllocationResponse(const UniqueID& unique_id, NodeID allocated_node_id)
262  {
263  Allocation msg;
264 
265  msg.unique_id.resize(msg.unique_id.capacity());
266  copy(unique_id.begin(), unique_id.end(), msg.unique_id.begin());
267 
268  msg.node_id = allocated_node_id.get();
269 
270  trace(TraceAllocationResponse, msg.node_id);
272 
273  return allocation_pub_.broadcast(msg);
274  }
275 
281 };
282 
283 }
284 }
285 
286 #endif // Include guard
uavcan::dynamic_node_id_server::AllocationRequestManager::detectRequestStage
static uint8_t detectRequestStage(const Allocation &msg)
Definition: allocation_request_manager.hpp:67
subscriber.hpp
uavcan::INode::getMonotonicTime
MonotonicTime getMonotonicTime() const
Definition: abstract_node.hpp:32
uavcan::dynamic_node_id_server::AllocationRequestManager::InvalidStage
@ InvalidStage
Definition: allocation_request_manager.hpp:63
TraceError
TraceError
Definition: event.hpp:23
uavcan::dynamic_node_id_server::AllocationRequestManager::allocation_sub_
Subscriber< Allocation, AllocationCallback > allocation_sub_
Definition: allocation_request_manager.hpp:60
uavcan::uint64_t
std::uint64_t uint64_t
Definition: std.hpp:27
types.hpp
debug.hpp
uavcan::dynamic_node_id_server::AllocationRequestManager::publishFollowupAllocationResponse
void publishFollowupAllocationResponse()
Definition: allocation_request_manager.hpp:109
uavcan::Subscriber
Definition: subscriber.hpp:45
TraceAllocationFollowupDenied
TraceAllocationFollowupDenied
Definition: event.hpp:60
uavcan::dynamic_node_id_server::AllocationRequestManager::last_activity_timestamp_
MonotonicTime last_activity_timestamp_
Definition: allocation_request_manager.hpp:54
uavcan::GenericPublisherBase::setTxTimeout
void setTxTimeout(MonotonicDuration tx_timeout)
Definition: uc_generic_publisher.cpp:56
uavcan::Publisher< Allocation >
TraceAllocationActivity
TraceAllocationActivity
Definition: event.hpp:68
uavcan::GenericPublisherBase::getNode
INode & getNode() const
Definition: generic_publisher.hpp:76
uavcan::dynamic_node_id_server::AllocationRequestManager::current_unique_id_
Allocation::FieldTypes::unique_id current_unique_id_
Definition: allocation_request_manager.hpp:55
uavcan::dynamic_node_id_server::IAllocationRequestHandler::handleAllocationRequest
virtual void handleAllocationRequest(const UniqueID &unique_id, NodeID preferred_node_id)=0
uavcan::NodeID::get
uint8_t get() const
Definition: transfer.hpp:132
uavcan::NodeID
Definition: transfer.hpp:112
uavcan::DurationBase< MonotonicDuration >::fromMSec
static MonotonicDuration fromMSec(int64_t ms)
Definition: time.hpp:41
uavcan::dynamic_node_id_server::AllocationRequestManager::broadcastAllocationResponse
int broadcastAllocationResponse(const UniqueID &unique_id, NodeID allocated_node_id)
Definition: allocation_request_manager.hpp:261
uavcan::dynamic_node_id_server::AllocationRequestManager::tracer_
IEventTracer & tracer_
Definition: allocation_request_manager.hpp:58
event.hpp
TraceAllocationResponse
TraceAllocationResponse
Definition: event.hpp:67
TraceAllocationUnexpectedStage
TraceAllocationUnexpectedStage
Definition: event.hpp:63
uavcan::dynamic_node_id_server::AllocationRequestManager::init
int init(const TransferPriority priority)
Definition: allocation_request_manager.hpp:242
uavcan::dynamic_node_id_server::IAllocationRequestHandler
Definition: allocation_request_manager.hpp:25
uavcan::ReceivedDataStructure
Definition: generic_subscriber.hpp:39
uavcan::dynamic_node_id_server::IAllocationRequestHandler::canPublishFollowupAllocationResponse
virtual bool canPublishFollowupAllocationResponse() const =0
uavcan::dynamic_node_id_server::AllocationRequestManager::allocation_pub_
Publisher< Allocation > allocation_pub_
Definition: allocation_request_manager.hpp:61
uavcan::dynamic_node_id_server::AllocationRequestManager::handleAllocation
void handleAllocation(const ReceivedDataStructure< Allocation > &msg)
Definition: allocation_request_manager.hpp:128
uavcan::dynamic_node_id_server::AllocationRequestManager::trace
void trace(TraceCode code, int64_t argument)
Definition: allocation_request_manager.hpp:65
UAVCAN_TRACE
#define UAVCAN_TRACE(...)
Definition: libuavcan/libuavcan/include/uavcan/debug.hpp:31
uavcan::int64_t
std::int64_t int64_t
Definition: std.hpp:32
uavcan::MonotonicDuration
Definition: time.hpp:182
publisher.hpp
uavcan::dynamic_node_id_server::AllocationRequestManager::getExpectedStage
uint8_t getExpectedStage() const
Definition: allocation_request_manager.hpp:92
uavcan::INode::registerInternalFailure
virtual void registerInternalFailure(const char *msg)=0
uavcan::uint8_t
std::uint8_t uint8_t
Definition: std.hpp:24
uavcan::dynamic_node_id_server::AllocationRequestManager::stage_timeout_
const MonotonicDuration stage_timeout_
Definition: allocation_request_manager.hpp:51
uavcan::dynamic_node_id_server::AllocationRequestManager::last_message_timestamp_
MonotonicTime last_message_timestamp_
Definition: allocation_request_manager.hpp:53
TraceAllocationBadRequest
TraceAllocationBadRequest
Definition: event.hpp:62
method_binder.hpp
uavcan::INode
Definition: abstract_node.hpp:19
uavcan::TransferPriority
Definition: transfer.hpp:28
build_config.hpp
uavcan::dynamic_node_id_server::IEventTracer::onEvent
virtual void onEvent(TraceCode event_code, int64_t event_argument)=0
uavcan::GenericPublisher::init
int init()
Definition: generic_publisher.hpp:118
TraceAllocationFollowupResponse
TraceAllocationFollowupResponse
Definition: event.hpp:59
uavcan::dynamic_node_id_server::IEventTracer
Definition: event.hpp:90
uavcan::dynamic_node_id_server::AllocationRequestManager::AllocationCallback
MethodBinder< AllocationRequestManager *, void(AllocationRequestManager::*)(const ReceivedDataStructure< Allocation > &)> AllocationCallback
Definition: allocation_request_manager.hpp:49
TraceAllocationRequestAccepted
TraceAllocationRequestAccepted
Definition: event.hpp:65
uavcan::MethodBinder
Definition: method_binder.hpp:20
uavcan::dynamic_node_id_server::AllocationRequestManager::getTimeOfLastAllocationActivity
MonotonicTime getTimeOfLastAllocationActivity() const
Definition: allocation_request_manager.hpp:280
uavcan::dynamic_node_id_server::IAllocationRequestHandler::~IAllocationRequestHandler
virtual ~IAllocationRequestHandler()
Definition: allocation_request_manager.hpp:38
uavcan::ReceivedDataStructure::getMonotonicTimestamp
MonotonicTime getMonotonicTimestamp() const
Definition: generic_subscriber.hpp:67
uavcan::Publisher::broadcast
int broadcast(const DataType &message)
Definition: publisher.hpp:52
pyuavcan_v0.introspect.node
node
Definition: introspect.py:398
uavcan::MonotonicTime
Definition: time.hpp:184
uavcan::dynamic_node_id_server::AllocationRequestManager::handler_
IAllocationRequestHandler & handler_
Definition: allocation_request_manager.hpp:57
uavcan
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:204
uavcan::ReceivedDataStructure::getSrcNodeID
NodeID getSrcNodeID() const
Definition: generic_subscriber.hpp:75
uavcan::dynamic_node_id_server::AllocationRequestManager
Definition: allocation_request_manager.hpp:45
uavcan::copy
UAVCAN_EXPORT OutputIt copy(InputIt first, InputIt last, OutputIt result)
Definition: templates.hpp:238
uavcan::dynamic_node_id_server::UniqueID
protocol::dynamic_node_id::server::Entry::FieldTypes::unique_id UniqueID
Definition: protocol/dynamic_node_id_server/types.hpp:22
TraceAllocationExchangeComplete
TraceAllocationExchangeComplete
Definition: event.hpp:66
uavcan::dynamic_node_id_server::AllocationRequestManager::AllocationRequestManager
AllocationRequestManager(INode &node, IEventTracer &tracer, IAllocationRequestHandler &handler)
Definition: allocation_request_manager.hpp:234
UAVCAN_ASSERT
#define UAVCAN_ASSERT(x)
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:184
uavcan::ReceivedDataStructure::isAnonymousTransfer
bool isAnonymousTransfer() const
Definition: generic_subscriber.hpp:77
TraceAllocationFollowupTimeout
TraceAllocationFollowupTimeout
Definition: event.hpp:61


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