libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers can.hpp Source File

can.hpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #pragma once
00006 
00007 #include <uavcan_stm32/build_config.hpp>
00008 #include <uavcan_stm32/thread.hpp>
00009 #include <uavcan/driver/can.hpp>
00010 #include <uavcan_stm32/bxcan.hpp>
00011 
00012 namespace uavcan_stm32
00013 {
00014 /**
00015  * Driver error codes.
00016  * These values can be returned from driver functions negated.
00017  */
00018 //static const uavcan::int16_t ErrUnknown               = 1000; ///< Reserved for future use
00019 static const uavcan::int16_t ErrNotImplemented          = 1001; ///< Feature not implemented
00020 static const uavcan::int16_t ErrInvalidBitRate          = 1002; ///< Bit rate not supported
00021 static const uavcan::int16_t ErrLogic                   = 1003; ///< Internal logic error
00022 static const uavcan::int16_t ErrUnsupportedFrame        = 1004; ///< Frame not supported (e.g. RTR, CAN FD, etc)
00023 static const uavcan::int16_t ErrMsrInakNotSet           = 1005; ///< INAK bit of the MSR register is not 1
00024 static const uavcan::int16_t ErrMsrInakNotCleared       = 1006; ///< INAK bit of the MSR register is not 0
00025 static const uavcan::int16_t ErrBitRateNotDetected      = 1007; ///< Auto bit rate detection could not be finished
00026 static const uavcan::int16_t ErrFilterNumConfigs        = 1008; ///< Number of filters is more than supported
00027 
00028 /**
00029  * RX queue item.
00030  * The application shall not use this directly.
00031  */
00032 struct CanRxItem
00033 {
00034     uavcan::uint64_t utc_usec;
00035     uavcan::CanFrame frame;
00036     uavcan::CanIOFlags flags;
00037     CanRxItem()
00038         : utc_usec(0)
00039         , flags(0)
00040     { }
00041 };
00042 
00043 /**
00044  * Single CAN iface.
00045  * The application shall not use this directly.
00046  */
00047 class CanIface : public uavcan::ICanIface, uavcan::Noncopyable
00048 {
00049     class RxQueue
00050     {
00051         CanRxItem* const buf_;
00052         const uavcan::uint8_t capacity_;
00053         uavcan::uint8_t in_;
00054         uavcan::uint8_t out_;
00055         uavcan::uint8_t len_;
00056         uavcan::uint32_t overflow_cnt_;
00057 
00058         void registerOverflow();
00059 
00060     public:
00061         RxQueue(CanRxItem* buf, uavcan::uint8_t capacity)
00062             : buf_(buf)
00063             , capacity_(capacity)
00064             , in_(0)
00065             , out_(0)
00066             , len_(0)
00067             , overflow_cnt_(0)
00068         { }
00069 
00070         void push(const uavcan::CanFrame& frame, const uint64_t& utc_usec, uavcan::CanIOFlags flags);
00071         void pop(uavcan::CanFrame& out_frame, uavcan::uint64_t& out_utc_usec, uavcan::CanIOFlags& out_flags);
00072 
00073         void reset();
00074 
00075         unsigned getLength() const { return len_; }
00076 
00077         uavcan::uint32_t getOverflowCount() const { return overflow_cnt_; }
00078     };
00079 
00080     struct Timings
00081     {
00082         uavcan::uint16_t prescaler;
00083         uavcan::uint8_t sjw;
00084         uavcan::uint8_t bs1;
00085         uavcan::uint8_t bs2;
00086 
00087         Timings()
00088             : prescaler(0)
00089             , sjw(0)
00090             , bs1(0)
00091             , bs2(0)
00092         { }
00093     };
00094 
00095     struct TxItem
00096     {
00097         uavcan::MonotonicTime deadline;
00098         uavcan::CanFrame frame;
00099         bool pending;
00100         bool loopback;
00101         bool abort_on_error;
00102 
00103         TxItem()
00104             : pending(false)
00105             , loopback(false)
00106             , abort_on_error(false)
00107         { }
00108     };
00109 
00110     enum { NumTxMailboxes = 3 };
00111     enum { NumFilters = 14 };
00112 
00113     static const uavcan::uint32_t TSR_ABRQx[NumTxMailboxes];
00114 
00115     RxQueue rx_queue_;
00116     bxcan::CanType* const can_;
00117     uavcan::uint64_t error_cnt_;
00118     uavcan::uint32_t served_aborts_cnt_;
00119     BusEvent& update_event_;
00120     TxItem pending_tx_[NumTxMailboxes];
00121     uavcan::uint8_t peak_tx_mailbox_index_;
00122     const uavcan::uint8_t self_index_;
00123     bool had_activity_;
00124 
00125     int computeTimings(uavcan::uint32_t target_bitrate, Timings& out_timings);
00126 
00127     virtual uavcan::int16_t send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline,
00128                                  uavcan::CanIOFlags flags);
00129 
00130     virtual uavcan::int16_t receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic,
00131                                     uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags);
00132 
00133     virtual uavcan::int16_t configureFilters(const uavcan::CanFilterConfig* filter_configs,
00134                                              uavcan::uint16_t num_configs);
00135 
00136     virtual uavcan::uint16_t getNumFilters() const { return NumFilters; }
00137 
00138     void handleTxMailboxInterrupt(uavcan::uint8_t mailbox_index, bool txok, uavcan::uint64_t utc_usec);
00139 
00140     bool waitMsrINakBitStateChange(bool target_state);
00141 
00142 public:
00143     enum { MaxRxQueueCapacity = 254 };
00144 
00145     enum OperatingMode
00146     {
00147         NormalMode,
00148         SilentMode
00149     };
00150 
00151     CanIface(bxcan::CanType* can, BusEvent& update_event, uavcan::uint8_t self_index,
00152              CanRxItem* rx_queue_buffer, uavcan::uint8_t rx_queue_capacity)
00153         : rx_queue_(rx_queue_buffer, rx_queue_capacity)
00154         , can_(can)
00155         , error_cnt_(0)
00156         , served_aborts_cnt_(0)
00157         , update_event_(update_event)
00158         , peak_tx_mailbox_index_(0)
00159         , self_index_(self_index)
00160         , had_activity_(false)
00161     {
00162         UAVCAN_ASSERT(self_index_ < UAVCAN_STM32_NUM_IFACES);
00163     }
00164 
00165     /**
00166      * Initializes the hardware CAN controller.
00167      * Assumes:
00168      *   - Iface clock is enabled
00169      *   - Iface has been resetted via RCC
00170      *   - Caller will configure NVIC by itself
00171      */
00172     int init(const uavcan::uint32_t bitrate, const OperatingMode mode);
00173 
00174     void handleTxInterrupt(uavcan::uint64_t utc_usec);
00175     void handleRxInterrupt(uavcan::uint8_t fifo_index, uavcan::uint64_t utc_usec);
00176 
00177     /**
00178      * This method is used to count errors and abort transmission on error if necessary.
00179      * This functionality used to be implemented in the SCE interrupt handler, but that approach was
00180      * generating too much processing overhead, especially on disconnected interfaces.
00181      *
00182      * Should be called from RX ISR, TX ISR, and select(); interrupts must be enabled.
00183      */
00184     void pollErrorFlagsFromISR();
00185 
00186     void discardTimedOutTxMailboxes(uavcan::MonotonicTime current_time);
00187 
00188     bool canAcceptNewTxFrame(const uavcan::CanFrame& frame) const;
00189     bool isRxBufferEmpty() const;
00190 
00191     /**
00192      * Number of RX frames lost due to queue overflow.
00193      * This is an atomic read, it doesn't require a critical section.
00194      */
00195     uavcan::uint32_t getRxQueueOverflowCount() const { return rx_queue_.getOverflowCount(); }
00196 
00197     /**
00198      * Total number of hardware failures and other kinds of errors (e.g. queue overruns).
00199      * May increase continuously if the interface is not connected to the bus.
00200      */
00201     virtual uavcan::uint64_t getErrorCount() const;
00202 
00203     /**
00204      * Number of times the driver exercised library's requirement to abort transmission on first error.
00205      * This is an atomic read, it doesn't require a critical section.
00206      * See @ref uavcan::CanIOFlagAbortOnError.
00207      */
00208     uavcan::uint32_t getVoluntaryTxAbortCount() const { return served_aborts_cnt_; }
00209 
00210     /**
00211      * Returns the number of frames pending in the RX queue.
00212      * This is intended for debug use only.
00213      */
00214     unsigned getRxQueueLength() const;
00215 
00216     /**
00217      * Whether this iface had at least one successful IO since the previous call of this method.
00218      * This is designed for use with iface activity LEDs.
00219      */
00220     bool hadActivity();
00221 
00222     /**
00223      * Peak number of TX mailboxes used concurrently since initialization.
00224      * Range is [1, 3].
00225      * Value of 3 suggests that priority inversion could be taking place.
00226      */
00227     uavcan::uint8_t getPeakNumTxMailboxesUsed() const { return uavcan::uint8_t(peak_tx_mailbox_index_ + 1); }
00228 };
00229 
00230 /**
00231  * CAN driver, incorporates all available CAN ifaces.
00232  * Please avoid direct use, prefer @ref CanInitHelper instead.
00233  */
00234 class CanDriver : public uavcan::ICanDriver, uavcan::Noncopyable
00235 {
00236     BusEvent update_event_;
00237     CanIface if0_;
00238 #if UAVCAN_STM32_NUM_IFACES > 1
00239     CanIface if1_;
00240 #endif
00241 
00242     virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks,
00243                                    const uavcan::CanFrame* (& pending_tx)[uavcan::MaxCanIfaces],
00244                                    uavcan::MonotonicTime blocking_deadline);
00245 
00246     static void initOnce();
00247 
00248 public:
00249     template <unsigned RxQueueCapacity>
00250     CanDriver(CanRxItem (&rx_queue_storage)[UAVCAN_STM32_NUM_IFACES][RxQueueCapacity])
00251         : update_event_(*this)
00252         , if0_(bxcan::Can[0], update_event_, 0, rx_queue_storage[0], RxQueueCapacity)
00253 #if UAVCAN_STM32_NUM_IFACES > 1
00254         , if1_(bxcan::Can[1], update_event_, 1, rx_queue_storage[1], RxQueueCapacity)
00255 #endif
00256     {
00257         uavcan::StaticAssert<(RxQueueCapacity <= CanIface::MaxRxQueueCapacity)>::check();
00258     }
00259 
00260     /**
00261      * This function returns select masks indicating which interfaces are available for read/write.
00262      */
00263     uavcan::CanSelectMasks makeSelectMasks(const uavcan::CanFrame* (& pending_tx)[uavcan::MaxCanIfaces]) const;
00264 
00265     /**
00266      * Whether there's at least one interface where receive() would return a frame.
00267      */
00268     bool hasReadableInterfaces() const;
00269 
00270     /**
00271      * Returns zero if OK.
00272      * Returns negative value if failed (e.g. invalid bitrate).
00273      */
00274     int init(const uavcan::uint32_t bitrate, const CanIface::OperatingMode mode);
00275 
00276     virtual CanIface* getIface(uavcan::uint8_t iface_index);
00277 
00278     virtual uavcan::uint8_t getNumIfaces() const { return UAVCAN_STM32_NUM_IFACES; }
00279 
00280     /**
00281      * Whether at least one iface had at least one successful IO since previous call of this method.
00282      * This is designed for use with iface activity LEDs.
00283      */
00284     bool hadActivity();
00285 };
00286 
00287 /**
00288  * Helper class.
00289  * Normally only this class should be used by the application.
00290  * 145 usec per Extended CAN frame @ 1 Mbps, e.g. 32 RX slots * 145 usec --> 4.6 msec before RX queue overruns.
00291  */
00292 template <unsigned RxQueueCapacity = 128>
00293 class CanInitHelper
00294 {
00295     CanRxItem queue_storage_[UAVCAN_STM32_NUM_IFACES][RxQueueCapacity];
00296 
00297 public:
00298     enum { BitRateAutoDetect = 0 };
00299 
00300     CanDriver driver;
00301 
00302     CanInitHelper() :
00303         driver(queue_storage_)
00304     { }
00305 
00306     /**
00307      * This overload simply configures the provided bitrate.
00308      * Auto bit rate detection will not be performed.
00309      * Bitrate value must be positive.
00310      * @return  Negative value on error; non-negative on success. Refer to constants Err*.
00311      */
00312     int init(uavcan::uint32_t bitrate)
00313     {
00314         return driver.init(bitrate, CanIface::NormalMode);
00315     }
00316 
00317     /**
00318      * This function can either initialize the driver at a fixed bit rate, or it can perform
00319      * automatic bit rate detection. For theory please refer to the CiA application note #801.
00320      *
00321      * @param delay_callable    A callable entity that suspends execution for strictly more than one second.
00322      *                          The callable entity will be invoked without arguments.
00323      *                          @ref getRecommendedListeningDelay().
00324      *
00325      * @param inout_bitrate     Fixed bit rate or zero. Zero invokes the bit rate detection process.
00326      *                          If auto detection was used, the function will update the argument
00327      *                          with established bit rate. In case of an error the value will be undefined.
00328      *
00329      * @return                  Negative value on error; non-negative on success. Refer to constants Err*.
00330      */
00331     template <typename DelayCallable>
00332     int init(DelayCallable delay_callable, uavcan::uint32_t& inout_bitrate = BitRateAutoDetect)
00333     {
00334         if (inout_bitrate > 0)
00335         {
00336             return driver.init(inout_bitrate, CanIface::NormalMode);
00337         }
00338         else
00339         {
00340             static const uavcan::uint32_t StandardBitRates[] =
00341             {
00342                 1000000,
00343                 500000,
00344                 250000,
00345                 125000
00346             };
00347 
00348             for (uavcan::uint8_t br = 0; br < sizeof(StandardBitRates) / sizeof(StandardBitRates[0]); br++)
00349             {
00350                 inout_bitrate = StandardBitRates[br];
00351 
00352                 const int res = driver.init(inout_bitrate, CanIface::SilentMode);
00353 
00354                 delay_callable();
00355 
00356                 if (res >= 0)
00357                 {
00358                     for (uavcan::uint8_t iface = 0; iface < driver.getNumIfaces(); iface++)
00359                     {
00360                         if (!driver.getIface(iface)->isRxBufferEmpty())
00361                         {
00362                             // Re-initializing in normal mode
00363                             return driver.init(inout_bitrate, CanIface::NormalMode);
00364                         }
00365                     }
00366                 }
00367             }
00368 
00369             return -ErrBitRateNotDetected;
00370         }
00371     }
00372 
00373     /**
00374      * Use this value for listening delay during automatic bit rate detection.
00375      */
00376     static uavcan::MonotonicDuration getRecommendedListeningDelay()
00377     {
00378         return uavcan::MonotonicDuration::fromMSec(1050);
00379     }
00380 };
00381 
00382 }