Руслан Урядинский / libuavcan

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers can_io.hpp Source File

can_io.hpp

00001 /*
00002  * CAN bus IO logic.
00003  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00004  */
00005 
00006 #ifndef UAVCAN_TRANSPORT_CAN_IO_HPP_INCLUDED
00007 #define UAVCAN_TRANSPORT_CAN_IO_HPP_INCLUDED
00008 
00009 #include <cassert>
00010 #include <uavcan/error.hpp>
00011 #include <uavcan/std.hpp>
00012 #include <uavcan/util/linked_list.hpp>
00013 #include <uavcan/dynamic_memory.hpp>
00014 #include <uavcan/build_config.hpp>
00015 #include <uavcan/util/templates.hpp>
00016 #include <uavcan/util/lazy_constructor.hpp>
00017 #include <uavcan/driver/can.hpp>
00018 #include <uavcan/driver/system_clock.hpp>
00019 #include <uavcan/time.hpp>
00020 
00021 namespace uavcan
00022 {
00023 
00024 struct UAVCAN_EXPORT CanRxFrame : public CanFrame
00025 {
00026     MonotonicTime ts_mono;
00027     UtcTime ts_utc;
00028     uint8_t iface_index;
00029 
00030     CanRxFrame()
00031         : iface_index(0)
00032     { }
00033 
00034 #if UAVCAN_TOSTRING
00035     std::string toString(StringRepresentation mode = StrTight) const;
00036 #endif
00037 };
00038 
00039 
00040 class UAVCAN_EXPORT CanTxQueue : Noncopyable
00041 {
00042 public:
00043     enum Qos { Volatile, Persistent };
00044 
00045     struct Entry : public LinkedListNode<Entry>  // Not required to be packed - fits the block in any case
00046     {
00047         MonotonicTime deadline;
00048         CanFrame frame;
00049         uint8_t qos;
00050         CanIOFlags flags;
00051 
00052         Entry(const CanFrame& arg_frame, MonotonicTime arg_deadline, Qos arg_qos, CanIOFlags arg_flags)
00053             : deadline(arg_deadline)
00054             , frame(arg_frame)
00055             , qos(uint8_t(arg_qos))
00056             , flags(arg_flags)
00057         {
00058             UAVCAN_ASSERT((qos == Volatile) || (qos == Persistent));
00059             IsDynamicallyAllocatable<Entry>::check();
00060         }
00061 
00062         static void destroy(Entry*& obj, IPoolAllocator& allocator);
00063 
00064         bool isExpired(MonotonicTime timestamp) const { return timestamp > deadline; }
00065 
00066         bool qosHigherThan(const CanFrame& rhs_frame, Qos rhs_qos) const;
00067         bool qosLowerThan(const CanFrame& rhs_frame, Qos rhs_qos) const;
00068         bool qosHigherThan(const Entry& rhs) const { return qosHigherThan(rhs.frame, Qos(rhs.qos)); }
00069         bool qosLowerThan(const Entry& rhs)  const { return qosLowerThan(rhs.frame, Qos(rhs.qos)); }
00070 
00071 #if UAVCAN_TOSTRING
00072         std::string toString() const;
00073 #endif
00074     };
00075 
00076 private:
00077     class PriorityInsertionComparator
00078     {
00079         const CanFrame& frm_;
00080     public:
00081         explicit PriorityInsertionComparator(const CanFrame& frm) : frm_(frm) { }
00082         bool operator()(const Entry* entry)
00083         {
00084             UAVCAN_ASSERT(entry);
00085             return frm_.priorityHigherThan(entry->frame);
00086         }
00087     };
00088 
00089     LinkedListRoot<Entry> queue_;
00090     LimitedPoolAllocator allocator_;
00091     ISystemClock& sysclock_;
00092     uint32_t rejected_frames_cnt_;
00093 
00094     void registerRejectedFrame();
00095 
00096 public:
00097     CanTxQueue(IPoolAllocator& allocator, ISystemClock& sysclock, std::size_t allocator_quota)
00098         : allocator_(allocator, allocator_quota)
00099         , sysclock_(sysclock)
00100         , rejected_frames_cnt_(0)
00101     { }
00102 
00103     ~CanTxQueue();
00104 
00105     void push(const CanFrame& frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags);
00106 
00107     Entry* peek();               // Modifier
00108     void remove(Entry*& entry);
00109     const CanFrame* getTopPriorityPendingFrame() const;
00110 
00111     /// The 'or equal' condition is necessary to avoid frame reordering.
00112     bool topPriorityHigherOrEqual(const CanFrame& rhs_frame) const;
00113 
00114     uint32_t getRejectedFrameCount() const { return rejected_frames_cnt_; }
00115 
00116     bool isEmpty() const { return queue_.isEmpty(); }
00117 };
00118 
00119 
00120 struct UAVCAN_EXPORT CanIfacePerfCounters
00121 {
00122     uint64_t frames_tx;
00123     uint64_t frames_rx;
00124     uint64_t errors;
00125 
00126     CanIfacePerfCounters()
00127         : frames_tx(0)
00128         , frames_rx(0)
00129         , errors(0)
00130     { }
00131 };
00132 
00133 
00134 class UAVCAN_EXPORT CanIOManager : Noncopyable
00135 {
00136     struct IfaceFrameCounters
00137     {
00138         uint64_t frames_tx;
00139         uint64_t frames_rx;
00140 
00141         IfaceFrameCounters()
00142             : frames_tx(0)
00143             , frames_rx(0)
00144         { }
00145     };
00146 
00147     ICanDriver& driver_;
00148     ISystemClock& sysclock_;
00149 
00150     LazyConstructor<CanTxQueue> tx_queues_[MaxCanIfaces];
00151     IfaceFrameCounters counters_[MaxCanIfaces];
00152 
00153     const uint8_t num_ifaces_;
00154 
00155     int sendToIface(uint8_t iface_index, const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags);
00156     int sendFromTxQueue(uint8_t iface_index);
00157     int callSelect(CanSelectMasks& inout_masks, const CanFrame* (& pending_tx)[MaxCanIfaces],
00158                    MonotonicTime blocking_deadline);
00159 
00160 public:
00161     CanIOManager(ICanDriver& driver, IPoolAllocator& allocator, ISystemClock& sysclock,
00162                  std::size_t mem_blocks_per_iface = 0);
00163 
00164     uint8_t getNumIfaces() const { return num_ifaces_; }
00165 
00166     CanIfacePerfCounters getIfacePerfCounters(uint8_t iface_index) const;
00167 
00168     const ICanDriver& getCanDriver() const { return driver_; }
00169     ICanDriver& getCanDriver()             { return driver_; }
00170 
00171     uint8_t makePendingTxMask() const;
00172 
00173     /**
00174      * Returns:
00175      *  0 - rejected/timedout/enqueued
00176      *  1+ - sent/received
00177      *  negative - failure
00178      */
00179     int send(const CanFrame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline,
00180              uint8_t iface_mask, CanTxQueue::Qos qos, CanIOFlags flags);
00181     int receive(CanRxFrame& out_frame, MonotonicTime blocking_deadline, CanIOFlags& out_flags);
00182 };
00183 
00184 }
00185 
00186 #endif // UAVCAN_TRANSPORT_CAN_IO_HPP_INCLUDED