38 #include <nuttx/config.h> 46 #include <semaphore.h> 49 #include <uavcan/node/sub_node.hpp> 50 #include <uavcan/protocol/node_status_monitor.hpp> 72 (void)pthread_mutex_lock(&m);
77 (void)pthread_mutex_unlock(&thier_mutex_);
80 static int init(pthread_mutex_t &thier_mutex_)
82 return pthread_mutex_init(&thier_mutex_, NULL);
85 static int deinit(pthread_mutex_t &thier_mutex_)
87 return pthread_mutex_destroy(&thier_mutex_);
99 struct Item :
public uavcan::LinkedListNode<Item> {
102 template <
typename... Args>
103 Item(Args... args) : payload(args...) { }
110 Queue(uavcan::IPoolAllocator &arg_allocator, std::size_t block_allocation_quota) :
111 allocator_(arg_allocator, block_allocation_quota)
113 uavcan::IsDynamicallyAllocatable<Item>::check();
123 bool isEmpty()
const {
return list_.isEmpty(); }
130 template <
typename... Args>
134 void *
const ptr = allocator_.allocate(
sizeof(Item));
136 if (ptr ==
nullptr) {
141 Item *
const item =
new (ptr) Item(args...);
142 assert(item !=
nullptr);
145 Item *p = list_.get();
151 while (p->getNextListNode() !=
nullptr) {
152 p = p->getNextListNode();
155 assert(p->getNextListNode() ==
nullptr);
156 p->setNextListNode(item);
157 assert(p->getNextListNode()->getNextListNode() ==
nullptr);
168 T *
peek() {
return isEmpty() ? nullptr : &list_.get()->payload; }
169 const T *
peek()
const {
return isEmpty() ? nullptr : &list_.get()->payload; }
178 Item *
const item = list_.get();
179 assert(item !=
nullptr);
181 if (item !=
nullptr) {
184 allocator_.deallocate(item);
207 RxItem(
const uavcan::CanRxFrame &arg_frame, uavcan::CanIOFlags arg_flags) :
208 uavcan::CanFrame(arg_frame),
209 ts_mono(arg_frame.ts_mono),
210 ts_utc(arg_frame.ts_utc),
212 iface_index(arg_frame.iface_index)
215 static_assert(
sizeof(
RxItem) <= (uavcan::MemPoolBlockSize - 8),
"Bad coder, no coffee");
224 int16_t
send(
const uavcan::CanFrame &frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags)
override 227 prioritized_tx_queue_.push(frame, tx_deadline, uavcan::CanTxQueue::Volatile, flags);
231 int16_t
receive(uavcan::CanFrame &out_frame, uavcan::MonotonicTime &out_ts_monotonic,
232 uavcan::UtcTime &out_ts_utc, uavcan::CanIOFlags &out_flags)
override 240 const auto item = *rx_queue_.
peek();
244 out_ts_monotonic = item.ts_mono;
245 out_ts_utc = item.ts_utc;
246 out_flags = item.flags;
251 int16_t
configureFilters(
const uavcan::CanFilterConfig *, std::uint16_t)
override {
return -uavcan::ErrDriver; }
257 pthread_mutex_t &arg_mutex,
unsigned quota_per_queue) :
258 common_driver_mutex_(arg_mutex),
259 prioritized_tx_queue_(allocator, clock, quota_per_queue),
260 rx_queue_(allocator, quota_per_queue)
273 void addRxFrame(
const uavcan::CanRxFrame &frame, uavcan::CanIOFlags flags)
290 const std::uint8_t iface_mask =
static_cast<std::uint8_t
>(1U << iface_index);
292 while (
auto e = prioritized_tx_queue_.peek()) {
293 UAVCAN_TRACE(
"VirtualCanIface",
"TX injection [iface=0x%02x]: %s",
294 unsigned(iface_mask), e->toString().c_str());
296 const int res = main_node.injectTxFrame(e->frame, e->deadline, iface_mask,
297 uavcan::CanTxQueue::Qos(e->qos), e->flags);
299 prioritized_tx_queue_.remove(e);
332 virtual void injectTxFramesInto(uavcan::INode &main_node) = 0;
340 public uavcan::IRxFrameListener,
353 int rv = px4_sem_init(&sem, 0, 0);
356 px4_sem_setprotocol(&sem, SEM_PRIO_NONE);
364 return px4_sem_destroy(&sem);
380 void waitFor(uavcan::MonotonicDuration duration)
382 static const int NsPerSec = 1000000000;
384 if (duration.isPositive()) {
385 auto abstime = ::timespec();
387 if (clock_gettime(CLOCK_REALTIME, &abstime) >= 0) {
388 abstime.tv_nsec += duration.toUSec() * 1000;
390 if (abstime.tv_nsec >= NsPerSec) {
392 abstime.tv_nsec -= NsPerSec;
395 (void)px4_sem_timedwait(&sem, &abstime);
403 int rv = px4_sem_getvalue(&sem, &count);
405 if (rv == 0 && count <= 0) {
413 uavcan::LazyConstructor<VirtualCanIface> ifaces_[uavcan::MaxCanIfaces];
417 uavcan::ICanIface *
getIface(uint8_t iface_index)
override 419 return (iface_index < num_ifaces_) ? ifaces_[iface_index].operator
VirtualCanIface * () :
nullptr;
427 int16_t
select(uavcan::CanSelectMasks &inout_masks,
428 const uavcan::CanFrame * (&)[uavcan::MaxCanIfaces],
429 uavcan::MonotonicTime blocking_deadline)
override 431 bool need_block = (inout_masks.write == 0);
433 for (
unsigned i = 0; need_block && (i < num_ifaces_); i++) {
434 const bool need_read = inout_masks.read & (1U << i);
436 if (need_read && ifaces_[i]->hasDataInRxQueue()) {
442 event_.
waitFor(blocking_deadline - clock_.getMonotonic());
445 inout_masks = uavcan::CanSelectMasks();
447 for (
unsigned i = 0; i < num_ifaces_; i++) {
448 const std::uint8_t iface_mask = 1U << i;
449 inout_masks.write |= iface_mask;
451 if (ifaces_[i]->hasDataInRxQueue()) {
452 inout_masks.read |= iface_mask;
462 void handleRxFrame(
const uavcan::CanRxFrame &frame, uavcan::CanIOFlags flags)
override 464 UAVCAN_TRACE(
"VirtualCanDriver",
"RX [flags=%u]: %s",
unsigned(flags), frame.toString().c_str());
466 if (frame.iface_index < num_ifaces_) {
467 ifaces_[frame.iface_index]->addRxFrame(frame, flags);
478 for (
unsigned i = 0; i < num_ifaces_; i++) {
479 ifaces_[i]->flushTxQueueTo(main_node, i);
487 uavcan::ISystemClock &system_clock,
488 uavcan::IPoolAllocator &allocator,
489 unsigned virtual_iface_block_allocation_quota) :
490 num_ifaces_(arg_num_ifaces),
496 assert(num_ifaces_ > 0 && num_ifaces_ <= uavcan::MaxCanIfaces);
498 const unsigned quota_per_queue = virtual_iface_block_allocation_quota;
500 for (
unsigned i = 0; i < num_ifaces_; i++) {
501 ifaces_[i].construct<uavcan::IPoolAllocator &, uavcan::ISystemClock &, pthread_mutex_t &,
502 unsigned>(allocator, clock_, driver_mutex_, quota_per_queue);
const unsigned num_ifaces_
Objects of this class are owned by the sub-node thread.
void injectTxFramesInto(uavcan::INode &main_node) override
This method will be invoked by the main node thread.
int16_t send(const uavcan::CanFrame &frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags) override
T * peek()
Accesses the first element.
void flushTxQueueTo(uavcan::INode &main_node, std::uint8_t iface_index)
Call this from the main thread only.
uint64_t getErrorCount() const override
RxItem(const uavcan::CanRxFrame &arg_frame, uavcan::CanIOFlags arg_flags)
pthread_mutex_t & thier_mutex_
uavcan::CanTxQueue prioritized_tx_queue_
Queue< RxItem > rx_queue_
static int deinit(pthread_mutex_t &thier_mutex_)
virtual ~ITxQueueInjector()
uavcan::ICanIface * getIface(uint8_t iface_index) override
uint16_t getNumFilters() const override
const uavcan::MonotonicTime ts_mono
void waitFor(uavcan::MonotonicDuration duration)
uavcan::ISystemClock & clock_
int16_t receive(uavcan::CanFrame &out_frame, uavcan::MonotonicTime &out_ts_monotonic, uavcan::UtcTime &out_ts_utc, uavcan::CanIOFlags &out_flags) override
VirtualCanIface(uavcan::IPoolAllocator &allocator, uavcan::ISystemClock &clock, pthread_mutex_t &arg_mutex, unsigned quota_per_queue)
const uavcan::CanIOFlags flags
Event event_
Used to unblock the select() call when IO happens.
int16_t configureFilters(const uavcan::CanFilterConfig *, std::uint16_t) override
pthread_mutex_t & common_driver_mutex_
static int init(pthread_mutex_t &thier_mutex_)
void addRxFrame(const uavcan::CanRxFrame &frame, uavcan::CanIOFlags flags)
Note that RX queue overwrites oldest items when overflowed.
bool hasDataInRxQueue()
Call this from the sub-node thread only.
bool tryEmplace(Args... args)
Creates one item in-place at the end of the list.
uavcan::LimitedPoolAllocator allocator_
void pop()
Removes the first element.
pthread_mutex_t driver_mutex_
Shared across all ifaces.
int16_t select(uavcan::CanSelectMasks &inout_masks, const uavcan::CanFrame *(&)[uavcan::MaxCanIfaces], uavcan::MonotonicTime blocking_deadline) override
This and other methods of ICanDriver will be invoked by the sub-node thread.
Queue(uavcan::IPoolAllocator &arg_allocator, std::size_t block_allocation_quota)
uavcan::LinkedListRoot< Item > list_
uint8_t getNumIfaces() const override
const uavcan::UtcTime ts_utc
Generic queue based on the linked list class defined in libuavcan.
const uint8_t iface_index
void handleRxFrame(const uavcan::CanRxFrame &frame, uavcan::CanIOFlags flags) override
This handler will be invoked by the main node thread.
VirtualCanDriver(unsigned arg_num_ifaces, uavcan::ISystemClock &system_clock, uavcan::IPoolAllocator &allocator, unsigned virtual_iface_block_allocation_quota)
This class re-defines uavcan::RxCanFrame with flags.
Objects of this class are owned by the sub-node thread.
This interface defines one method that will be called by the main node thread periodically in order t...