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 {
48  void (AllocationRequestManager::*)(const ReceivedDataStructure<Allocation>&)>
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  {
130  trace(TraceAllocationActivity, msg.getSrcNodeID().get());
131  last_activity_timestamp_ = msg.getMonotonicTimestamp();
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  */
141  if (msg.getMonotonicTimestamp() > (last_message_timestamp_ + stage_timeout_))
142  {
143  UAVCAN_TRACE("AllocationRequestManager", "Stage timeout, reset");
144  current_unique_id_.clear();
145  trace(TraceAllocationFollowupTimeout, (msg.getMonotonicTimestamp() - last_message_timestamp_).toUSec());
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 
188  trace(TraceAllocationRequestAccepted, current_unique_id_.size());
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  {
218  publishFollowupAllocationResponse();
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  */
230  last_message_timestamp_ = msg.getMonotonicTimestamp();
231  }
232 
233 public:
235  : stage_timeout_(MonotonicDuration::fromMSec(Allocation::FOLLOWUP_TIMEOUT_MS))
236  , handler_(handler)
237  , tracer_(tracer)
238  , allocation_sub_(node)
239  , allocation_pub_(node)
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);
271  last_activity_timestamp_ = allocation_pub_.getNode().getMonotonicTime();
272 
273  return allocation_pub_.broadcast(msg);
274  }
275 
280  MonotonicTime getTimeOfLastAllocationActivity() const { return last_activity_timestamp_; }
281 };
282 
283 }
284 }
285 
286 #endif // Include guard
std::uint8_t uint8_t
Definition: std.hpp:24
void handleAllocation(const ReceivedDataStructure< Allocation > &msg)
AllocationRequestManager(INode &node, IEventTracer &tracer, IAllocationRequestHandler &handler)
virtual void handleAllocationRequest(const UniqueID &unique_id, NodeID preferred_node_id)=0
virtual void onEvent(TraceCode event_code, int64_t event_argument)=0
void setTxTimeout(MonotonicDuration tx_timeout)
TraceAllocationBadRequest
Definition: event.hpp:23
TraceAllocationRequestAccepted
Definition: event.hpp:23
Subscriber< Allocation, AllocationCallback > allocation_sub_
uint8_t get() const
Definition: transfer.hpp:132
UAVCAN_EXPORT OutputIt copy(InputIt first, InputIt last, OutputIt result)
Definition: templates.hpp:238
TraceAllocationUnexpectedStage
Definition: event.hpp:23
TraceAllocationExchangeComplete
Definition: event.hpp:23
protocol::dynamic_node_id::server::Entry::FieldTypes::unique_id UniqueID
virtual void registerInternalFailure(const char *msg)=0
std::uint64_t uint64_t
Definition: std.hpp:27
MonotonicTime getMonotonicTimestamp() const
int start(const Callback &callback)
Definition: subscriber.hpp:83
int broadcastAllocationResponse(const UniqueID &unique_id, NodeID allocated_node_id)
TraceAllocationActivity
Definition: event.hpp:23
std::int64_t int64_t
Definition: std.hpp:32
TraceAllocationFollowupTimeout
Definition: event.hpp:23
static MonotonicDuration fromMSec(int64_t ms)
Definition: time.hpp:41
TraceError
Definition: event.hpp:23
TraceAllocationResponse
Definition: event.hpp:23
TraceAllocationFollowupDenied
Definition: event.hpp:23
MonotonicTime getMonotonicTime() const
int broadcast(const DataType &message)
Definition: publisher.hpp:52
TraceAllocationFollowupResponse
Definition: event.hpp:23


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