libuav original
Dependents: UAVCAN UAVCAN_Subscriber
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 }
Generated on Tue Jul 12 2022 17:17:30 by
1.7.2