uc_can_io.cpp
Go to the documentation of this file.
1 /*
2  * CAN bus IO logic.
3  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
4  * Copyright (C) 2019 Theodoros Ntakouris <zarkopafilis@gmail.com>
5  */
6 
7 #include <cassert>
8 #include <functional>
10 #include <uavcan/debug.hpp>
11 
12 namespace uavcan
13 {
14 /*
15  * CanRxFrame
16  */
17 #if UAVCAN_TOSTRING
18 std::string CanRxFrame::toString(StringRepresentation mode) const
19 {
20  std::string out = CanFrame::toString(mode);
21  out.reserve(128);
22  out += " ts_m=" + ts_mono.toString();
23  out += " ts_utc=" + ts_utc.toString();
24  out += " iface=";
25  out += char('0' + iface_index);
26  return out;
27 }
28 #endif
29 
30 /*
31  * CanTxQueueEntry
32  */
33  #if UAVCAN_TOSTRING
34 std::string CanTxQueueEntry::toString() const
35 {
36  return frame.toString();
37 }
38 #endif
39 
41  if (obj != UAVCAN_NULLPTR) {
42  obj->~CanTxQueueEntry();
43  allocator.deallocate(obj);
44  obj = UAVCAN_NULLPTR;
45  }
46 }
47 
48 /*
49  * CanTxQueue
50  */
52  // Remove all nodes & node contents of the tree without performing re-balancing steps
54  // Step 2: AvlTree destructor is called to remove all the Node* (automatically after)
55 }
56 
58  if (n == UAVCAN_NULLPTR) {
59  return;
60  }
61 
65 }
66 
67 bool CanTxQueue::contains(const CanFrame& frame) const {
68  Node* n = root_;
69 
70  while (n != UAVCAN_NULLPTR) {
71  if (frame.priorityHigherThan(n->data->frame)) {
72  n = n->right;
73  continue;
74  }
75 
76  if (frame.priorityLowerThan(n->data->frame)) {
77  n = n->left;
78  continue;
79  }
80 
81  return linkedListContains(n, frame);
82  }
83  return false;
84 }
85 
87  Node* next = head;
88  while(next != UAVCAN_NULLPTR) {
89  if (next->data->frame == frame) {
90  return true;
91  }
92 
93  next = head->equal_keys;
94  }
95  return false;
96 }
97 
101  }
102 }
103 
104 void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, CanIOFlags flags) {
105  const MonotonicTime timestamp = sysclock_.getMonotonic();
106 
107  if (timestamp >= tx_deadline) {
108  UAVCAN_TRACE("CanTxQueue", "Push rejected: already expired");
110  return;
111  }
112 
113  void* praw = allocator_.allocate(sizeof(CanTxQueueEntry));
114  if (praw == UAVCAN_NULLPTR) {
115  UAVCAN_TRACE("CanTxQueue", "Push rejected: OOM (CanTxQueueEntry)");
117  return;
118  }
119 
120  CanTxQueueEntry* entry = new(praw) CanTxQueueEntry(frame, tx_deadline, flags);
121  UAVCAN_ASSERT(entry);
122  bool result = AvlTree::insert(entry);
123 
124  if (!result) {
125  /* AVL Tree could not allocate a new node */
126  UAVCAN_TRACE("CanTxQueue", "Push rejected: OOM (AvlTree::Node)");
129  }
130 }
131 
133  if (entry == UAVCAN_NULLPTR) {
134  return;
135  }
136 
137  // Make the AvlTree remove the specific entry deleting it's Node *
138  this->AvlTree::removeEntry(entry);
139  // Then let the entry destroy it's own contents
141 }
142 
144  Node* maxNode = searchForNonExpiredMax(root_);
145 
146  if (maxNode == UAVCAN_NULLPTR) {
147  return UAVCAN_NULLPTR;
148  }
149 
150  return maxNode->data;
151 }
152 
154  CanTxQueueEntry* peek_entry = peek();
155  if (peek_entry == UAVCAN_NULLPTR) {
156  return false;
157  }
158  return !rhs_frame.priorityHigherThan(peek_entry->frame);
159 }
160 
162  if (n == UAVCAN_NULLPTR) {
163  return UAVCAN_NULLPTR;
164  }
165 
166  const MonotonicTime timestamp = sysclock_.getMonotonic();
167 
168  while(n->data->isExpired(timestamp)) {
169  remove(n->data);
171  }
172 
173  while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)) {
174  CanTxQueueEntry* expiredEntry = n->data;
175  n->right = this->AvlTree::removeNode(n, n->data);
176  CanTxQueueEntry::destroy(expiredEntry, allocator_);
177  }
178 
179  Node* r = searchForNonExpiredMax(n->right);
180 
181  if (r != UAVCAN_NULLPTR) {
182  return r;
183  }
184 
185  return n;
186 }
187 
188 /*
189  * CanIOManager
190  */
191 int
192 CanIOManager::sendToIface(uint8_t iface_index, const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags)
193 {
194  UAVCAN_ASSERT(iface_index < MaxCanIfaces);
195  ICanIface *const iface = driver_.getIface(iface_index);
196  if (iface == UAVCAN_NULLPTR)
197  {
198  UAVCAN_ASSERT(0); // Nonexistent interface
199  return -ErrLogic;
200  }
201  const int res = iface->send(frame, tx_deadline, flags);
202  if (res != 1)
203  {
204  UAVCAN_TRACE("CanIOManager", "Send failed: code %i, iface %i, frame %s",
205  res, iface_index, frame.toString().c_str());
206  }
207  if (res > 0)
208  {
209  counters_[iface_index].frames_tx += unsigned(res);
210  }
211  return res;
212 }
213 
215 {
216  UAVCAN_ASSERT(iface_index < MaxCanIfaces);
217  CanTxQueueEntry* entry = tx_queues_[iface_index]->peek();
218  if (entry == UAVCAN_NULLPTR)
219  {
220  return 0;
221  }
222  const int res = sendToIface(iface_index, entry->frame, entry->deadline, entry->flags);
223  if (res > 0)
224  {
225  tx_queues_[iface_index]->remove(entry);
226  }
227  return res;
228 }
229 
230 int CanIOManager::callSelect(CanSelectMasks &inout_masks, const CanFrame *(&pending_tx)[MaxCanIfaces],
231  MonotonicTime blocking_deadline)
232 {
233  const CanSelectMasks in_masks = inout_masks;
234 
235  const int res = driver_.select(inout_masks, pending_tx, blocking_deadline);
236  if (res < 0)
237  {
238  return -ErrDriver;
239  }
240 
241  inout_masks.read &= in_masks.read; // Driver is not required to clean the masks
242  inout_masks.write &= in_masks.write;
243  return res;
244 }
245 
247  std::size_t mem_blocks_per_iface)
248  : driver_(driver), sysclock_(sysclock), num_ifaces_(driver.getNumIfaces())
249 {
250  if (num_ifaces_ < 1 || num_ifaces_ > MaxCanIfaces)
251  {
252  handleFatalError("Num ifaces");
253  }
254 
255  if (mem_blocks_per_iface == 0)
256  {
257  mem_blocks_per_iface = allocator.getBlockCapacity() / (num_ifaces_ + 1U) + 1U;
258  }
259  UAVCAN_TRACE("CanIOManager", "Memory blocks per iface: %u, total: %u",
260  unsigned(mem_blocks_per_iface), unsigned(allocator.getBlockCapacity()));
261 
262  for (int i = 0; i < num_ifaces_; i++)
263  {
265  (allocator, sysclock, mem_blocks_per_iface);
266  }
267 }
268 
270 {
271  uint8_t write_mask = 0;
272  for (uint8_t i = 0; i < getNumIfaces(); i++)
273  {
274  if (!tx_queues_[i]->isEmpty())
275  {
276  write_mask = uint8_t(write_mask | (1 << i));
277  }
278  }
279  return write_mask;
280 }
281 
283 {
284  ICanIface *const iface = driver_.getIface(iface_index);
285  if (iface == UAVCAN_NULLPTR || iface_index >= MaxCanIfaces)
286  {
287  UAVCAN_ASSERT(0);
288  return CanIfacePerfCounters();
289  }
291  cnt.errors = iface->getErrorCount() + tx_queues_[iface_index]->getRejectedFrameCount();
292  cnt.frames_rx = counters_[iface_index].frames_rx;
293  cnt.frames_tx = counters_[iface_index].frames_tx;
294  return cnt;
295 }
296 
297 int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline,
298  uint8_t iface_mask, CanIOFlags flags)
299 {
300  const uint8_t num_ifaces = getNumIfaces();
301  const uint8_t all_ifaces_mask = uint8_t((1U << num_ifaces) - 1);
302  iface_mask &= all_ifaces_mask;
303 
304  if (blocking_deadline > tx_deadline)
305  {
306  blocking_deadline = tx_deadline;
307  }
308 
309  int retval = 0;
310 
311  while (true) // Somebody please refactor this.
312  {
313  if (iface_mask == 0)
314  {
315  break;
316  }
317 
318  CanSelectMasks masks;
319  masks.write = iface_mask | makePendingTxMask();
320  {
321  // Building the list of next pending frames per iface.
322  // This is needed to avoid inner priority inversion in the TX queue.
323  // This is explained in the section 4.4.3.3 of the spec.
324  const CanFrame* pending_tx[MaxCanIfaces] = {};
325  for (int i = 0; i < num_ifaces; i++)
326  {
327  CanTxQueue &q = *tx_queues_[i];
328  CanTxQueueEntry* peek_entry = q.peek();
329  const CanFrame *peek_frame = peek_entry == UAVCAN_NULLPTR ? UAVCAN_NULLPTR : &peek_entry->frame;
330 
331  if (iface_mask & (1 << i)) // I hate myself so much right now.
332  {
333  bool has_priority = false;
334 
335  // This may seem duplicate of topPriorityHigherOrEqual but we want to avoid traversing the queue again
336  if (peek_entry != UAVCAN_NULLPTR)
337  {
338  has_priority = !frame.priorityHigherThan(*peek_frame);
339  }
340 
341  pending_tx[i] = has_priority ? peek_frame : &frame;
342  }
343  else
344  {
345  pending_tx[i] = peek_frame;
346  }
347  }
348 
349  const int select_res = callSelect(masks, pending_tx, blocking_deadline);
350  if (select_res < 0)
351  {
352  return -ErrDriver;
353  }
354  UAVCAN_ASSERT(masks.read == 0);
355  }
356 
357  // Transmission
358  for (uint8_t i = 0; i < num_ifaces; i++)
359  {
360  if (masks.write & (1 << i))
361  {
362  int res = 0;
363  if (iface_mask & (1 << i))
364  {
365  if (tx_queues_[i]->topPriorityHigherOrEqual(frame))
366  {
367  res = sendFromTxQueue(
368  i); // May return 0 if nothing to transmit (e.g. expired)
369  }
370  if (res <= 0)
371  {
372  res = sendToIface(i, frame, tx_deadline, flags);
373  if (res > 0)
374  {
375  iface_mask &= uint8_t(~(1 << i)); // Mark transmitted
376  }
377  }
378  }
379  else
380  {
381  res = sendFromTxQueue(i);
382  }
383  if (res > 0)
384  {
385  retval++;
386  }
387  }
388  }
389 
390  // Timeout. Enqueue the frame if wasn't transmitted and leave.
391  const bool timed_out = sysclock_.getMonotonic() >= blocking_deadline;
392  if (masks.write == 0 || timed_out)
393  {
394  if (!timed_out)
395  {
396  UAVCAN_TRACE("CanIOManager", "Send: Premature timeout in select(), will try again");
397  continue;
398  }
399  for (uint8_t i = 0; i < num_ifaces; i++)
400  {
401  if (iface_mask & (1 << i))
402  {
403  tx_queues_[i]->push(frame, tx_deadline, flags);
404  }
405  }
406  break;
407  }
408  }
409  return retval;
410 }
411 
412 int CanIOManager::receive(CanRxFrame &out_frame, MonotonicTime blocking_deadline, CanIOFlags &out_flags)
413 {
414  const uint8_t num_ifaces = getNumIfaces();
415 
416  while (true)
417  {
418  CanSelectMasks masks;
419  masks.write = makePendingTxMask();
420  masks.read = uint8_t((1 << num_ifaces) - 1);
421  {
422  const CanFrame* pending_tx[MaxCanIfaces] = {};
423  for (int i = 0; i < num_ifaces; i++) // Dear compiler, kindly unroll this. Thanks.
424  {
425  CanTxQueueEntry* entry = tx_queues_[i]->peek();
426  pending_tx[i] = (entry == UAVCAN_NULLPTR) ? UAVCAN_NULLPTR : &entry->frame;
427  }
428 
429  const int select_res = callSelect(masks, pending_tx, blocking_deadline);
430  if (select_res < 0)
431  {
432  return -ErrDriver;
433  }
434  }
435 
436  // Write - if buffers are not empty, one frame will be sent for each iface per one receive() call
437  for (uint8_t i = 0; i < num_ifaces; i++)
438  {
439  if (masks.write & (1 << i))
440  {
441  (void) sendFromTxQueue(
442  i); // It may fail, we don't care. Requested operation was receive, not send.
443  }
444  }
445 
446  // Read
447  for (uint8_t i = 0; i < num_ifaces; i++)
448  {
449  if (masks.read & (1 << i))
450  {
451  ICanIface *const iface = driver_.getIface(i);
452  if (iface == UAVCAN_NULLPTR)
453  {
454  UAVCAN_ASSERT(0); // Nonexistent interface
455  continue;
456  }
457 
458  const int res = iface->receive(out_frame, out_frame.ts_mono, out_frame.ts_utc, out_flags);
459  if (res == 0)
460  {
461  UAVCAN_ASSERT(0); // select() reported that iface has pending RX frames, but receive() returned none
462  continue;
463  }
464  out_frame.iface_index = i;
465 
466  if ((res > 0) && !(out_flags & CanIOFlagLoopback))
467  {
468  counters_[i].frames_rx += 1;
469  }
470  return (res < 0) ? -ErrDriver : res;
471  }
472  }
473 
474  // Timeout checked in the last order - this way we can operate with expired deadline:
475  if (sysclock_.getMonotonic() >= blocking_deadline)
476  {
477  break;
478  }
479  }
480  return 0;
481 }
482 
483 }
uavcan::CanIfacePerfCounters
Definition: can_io.hpp:115
uavcan::CanTxQueue::linkedListContains
bool linkedListContains(Node *head, const CanFrame &frame) const
Definition: uc_can_io.cpp:86
UAVCAN_NULLPTR
#define UAVCAN_NULLPTR
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:51
uavcan::ICanIface::send
virtual int16_t send(const CanFrame &frame, MonotonicTime tx_deadline, CanIOFlags flags)=0
uavcan::CanTxQueue::peek
CanTxQueueEntry * peek()
Definition: uc_can_io.cpp:143
uavcan::CanIfacePerfCounters::frames_tx
uint64_t frames_tx
Definition: can_io.hpp:117
uavcan::CanTxQueue::searchForNonExpiredMax
AvlTree::Node * searchForNonExpiredMax(Node *n)
Definition: uc_can_io.cpp:161
uavcan::CanIOManager::counters_
IfaceFrameCounters counters_[MaxCanIfaces]
Definition: can_io.hpp:145
uavcan::AvlTree::Node
Definition: avl_tree.hpp:25
std::size_t
unsigned long size_t
Definition: coverity_scan_model.cpp:19
uavcan::CanTxQueue::remove
void remove(CanTxQueueEntry *entry)
Definition: uc_can_io.cpp:132
debug.hpp
uavcan::IPoolAllocator::getBlockCapacity
virtual uint16_t getBlockCapacity() const =0
uavcan::CanTxQueueEntry::deadline
MonotonicTime deadline
Definition: can_io.hpp:42
uavcan::CanTxQueue::~CanTxQueue
~CanTxQueue() override
Definition: uc_can_io.cpp:51
uavcan::ICanDriver
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:207
uavcan::CanTxQueueEntry::frame
const CanFrame frame
Definition: can_io.hpp:43
uavcan::CanFrame
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:24
uavcan::CanIOFlagLoopback
static const CanIOFlags CanIOFlagLoopback
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:141
uavcan::AvlTree::removeEntry
void removeEntry(T *data)
Definition: avl_tree.hpp:324
UAVCAN_TRACE
#define UAVCAN_TRACE(...)
Definition: libuavcan/libuavcan/include/uavcan/debug.hpp:31
uavcan::CanTxQueue::rejected_frames_cnt_
uint32_t rejected_frames_cnt_
Definition: can_io.hpp:85
uavcan::CanRxFrame
Definition: can_io.hpp:25
uavcan::MaxCanIfaces
@ MaxCanIfaces
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:19
uavcan::CanIOManager::getIfacePerfCounters
CanIfacePerfCounters getIfacePerfCounters(uint8_t iface_index) const
Definition: uc_can_io.cpp:282
uavcan::CanIOManager::sendFromTxQueue
int sendFromTxQueue(uint8_t iface_index)
Definition: uc_can_io.cpp:214
uavcan::ICanDriver::select
virtual int16_t select(CanSelectMasks &inout_masks, const CanFrame *(&pending_tx)[MaxCanIfaces], MonotonicTime blocking_deadline)=0
uavcan::CanTxQueue::sysclock_
ISystemClock & sysclock_
Definition: can_io.hpp:84
uavcan::CanIOManager::driver_
ICanDriver & driver_
Definition: can_io.hpp:141
uavcan::CanTxQueue::push
void push(const CanFrame &frame, MonotonicTime tx_deadline, CanIOFlags flags)
Definition: uc_can_io.cpp:104
uavcan::AvlTree< CanTxQueueEntry >::root_
Node * root_
Definition: avl_tree.hpp:33
uavcan::CanSelectMasks::read
uint8_t read
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:121
uavcan::LimitedPoolAllocator::allocate
virtual void * allocate(std::size_t size)
Definition: uc_dynamic_memory.cpp:12
uavcan::CanRxFrame::ts_utc
UtcTime ts_utc
Definition: can_io.hpp:28
uavcan_kinetis::ErrLogic
static const uavcan::int16_t ErrLogic
Internal logic error.
Definition: platform_specific_components/kinetis/libuavcan/driver/include/uavcan_kinetis/can.hpp:22
uavcan::IPoolAllocator::deallocate
virtual void deallocate(const void *ptr)=0
uavcan::uint8_t
std::uint8_t uint8_t
Definition: std.hpp:24
uavcan::CanFrame::priorityLowerThan
bool priorityLowerThan(const CanFrame &rhs) const
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:91
uavcan::CanIOManager::getNumIfaces
uint8_t getNumIfaces() const
Definition: can_io.hpp:158
uavcan::AvlTree< CanTxQueueEntry >::allocator_
LimitedPoolAllocator allocator_
Definition: avl_tree.hpp:221
uavcan::CanIOManager::send
int send(const CanFrame &frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, uint8_t iface_mask, CanIOFlags flags)
Definition: uc_can_io.cpp:297
uavcan::max
const UAVCAN_EXPORT T & max(const T &a, const T &b)
Definition: templates.hpp:291
uavcan::CanIfacePerfCounters::frames_rx
uint64_t frames_rx
Definition: can_io.hpp:118
can_io.hpp
uavcan::IPoolAllocator
Definition: dynamic_memory.hpp:21
uavcan::CanSelectMasks
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:119
uavcan::AvlTree::removeNode
Node * removeNode(Node *node, T *data)
Definition: avl_tree.hpp:233
uavcan::CanSelectMasks::write
uint8_t write
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:122
toString
static std::string toString(long x)
Definition: multiset.cpp:16
uavcan::CanTxQueue::safeIncrementRejectedFrames
void safeIncrementRejectedFrames()
Definition: uc_can_io.cpp:98
uavcan::CanTxQueueEntry::destroy
static void destroy(CanTxQueueEntry *&obj, IPoolAllocator &allocator)
Definition: uc_can_io.cpp:40
uavcan::CanIOManager::IfaceFrameCounters::frames_tx
uint64_t frames_tx
Definition: can_io.hpp:132
uavcan::CanRxFrame::iface_index
uint8_t iface_index
Definition: can_io.hpp:29
uavcan::CanIOManager::receive
int receive(CanRxFrame &out_frame, MonotonicTime blocking_deadline, CanIOFlags &out_flags)
Definition: uc_can_io.cpp:412
uavcan::ICanIface::getErrorCount
virtual uint64_t getErrorCount() const =0
uavcan::CanIOManager::tx_queues_
LazyConstructor< CanTxQueue > tx_queues_[MaxCanIfaces]
Definition: can_io.hpp:144
uavcan::CanIOManager::sendToIface
int sendToIface(uint8_t iface_index, const CanFrame &frame, MonotonicTime tx_deadline, CanIOFlags flags)
Definition: uc_can_io.cpp:192
uavcan::AvlTree::insert
bool insert(T *data)
Definition: avl_tree.hpp:328
frame
uavcan::CanFrame frame
Definition: can.cpp:78
uavcan::CanTxQueue::contains
bool contains(const CanFrame &frame) const
Definition: uc_can_io.cpp:67
uavcan::CanTxQueueEntry
Definition: can_io.hpp:40
uavcan::ICanDriver::getIface
virtual ICanIface * getIface(uint8_t iface_index)=0
uavcan::CanIOManager::CanIOManager
CanIOManager(ICanDriver &driver, IPoolAllocator &allocator, ISystemClock &sysclock, std::size_t mem_blocks_per_iface=0)
Definition: uc_can_io.cpp:246
uavcan::CanTxQueue::postOrderTraverseEntryCleanup
void postOrderTraverseEntryCleanup(Node *n)
Definition: uc_can_io.cpp:57
uavcan::CanIOManager::num_ifaces_
const uint8_t num_ifaces_
Definition: can_io.hpp:147
uavcan::CanIfacePerfCounters::errors
uint64_t errors
Definition: can_io.hpp:119
uavcan::handleFatalError
UAVCAN_EXPORT void handleFatalError(const char *msg)
Definition: uc_error.cpp:20
uavcan::CanIOManager::IfaceFrameCounters::frames_rx
uint64_t frames_rx
Definition: can_io.hpp:133
uavcan::ICanIface::receive
virtual int16_t receive(CanFrame &out_frame, MonotonicTime &out_ts_monotonic, UtcTime &out_ts_utc, CanIOFlags &out_flags)=0
uavcan::CanIOFlags
uint16_t CanIOFlags
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:140
uavcan::CanTxQueueEntry::flags
CanIOFlags flags
Definition: can_io.hpp:44
uavcan::CanTxQueue
Definition: can_io.hpp:78
uavcan::MonotonicTime
Definition: time.hpp:184
uavcan::CanTxQueue::topPriorityHigherOrEqual
bool topPriorityHigherOrEqual(const CanFrame &rhs_frame)
Definition: uc_can_io.cpp:153
uavcan::CanIOManager::sysclock_
ISystemClock & sysclock_
Definition: can_io.hpp:142
uavcan
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:204
uavcan::CanFrame::priorityHigherThan
bool priorityHigherThan(const CanFrame &rhs) const
Definition: uc_can.cpp:19
uavcan::ISystemClock
Definition: system_clock.hpp:19
uavcan::ICanIface
Definition: libuavcan/libuavcan/include/uavcan/driver/can.hpp:147
uavcan::TimeBase::toString
void toString(char buf[StringBufSize]) const
Prints time in seconds with microsecond resolution.
Definition: time.hpp:238
uavcan::CanRxFrame::ts_mono
MonotonicTime ts_mono
Definition: can_io.hpp:27
uavcan::ISystemClock::getMonotonic
virtual MonotonicTime getMonotonic() const =0
uavcan::Node
Definition: node.hpp:38
UAVCAN_ASSERT
#define UAVCAN_ASSERT(x)
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:184
uavcan::CanIOManager::makePendingTxMask
uint8_t makePendingTxMask() const
Definition: uc_can_io.cpp:269
uavcan::CanIOManager::callSelect
int callSelect(CanSelectMasks &inout_masks, const CanFrame *(&pending_tx)[MaxCanIfaces], MonotonicTime blocking_deadline)
Definition: uc_can_io.cpp:230


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