Line data Source code
1 : /* 2 : * Copyright (C) 2020 Siddharth B Purohit 3 : * 4 : * This file is free software: you can redistribute it and/or modify it 5 : * under the terms of the GNU General Public License as published by the 6 : * Free Software Foundation, either version 3 of the License, or 7 : * (at your option) any later version. 8 : * 9 : * This file is distributed in the hope that it will be useful, but 10 : * WITHOUT ANY WARRANTY; without even the implied warranty of 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 : * See the GNU General Public License for more details. 13 : * 14 : * You should have received a copy of the GNU General Public License along 15 : * with this program. If not, see <http://www.gnu.org/licenses/>. 16 : */ 17 : 18 : #pragma once 19 : 20 : #include <stdint.h> 21 : #include "AP_HAL_Namespace.h" 22 : #include "AP_HAL_Boards.h" 23 : 24 : class ExpandingString; 25 : 26 : /** 27 : * Raw CAN frame, as passed to/from the CAN driver. 28 : */ 29 : struct AP_HAL::CANFrame { 30 : static const uint32_t MaskStdID = 0x000007FFU; 31 : static const uint32_t MaskExtID = 0x1FFFFFFFU; 32 : static const uint32_t FlagEFF = 1U << 31; ///< Extended frame format 33 : static const uint32_t FlagRTR = 1U << 30; ///< Remote transmission request 34 : static const uint32_t FlagERR = 1U << 29; ///< Error frame 35 : 36 : #if HAL_CANFD_SUPPORTED 37 : static const uint8_t NonFDCANMaxDataLen = 8; 38 : static const uint8_t MaxDataLen = 64; 39 : #else 40 : static const uint8_t NonFDCANMaxDataLen = 8; 41 : static const uint8_t MaxDataLen = 8; 42 : #endif 43 : uint32_t id; ///< CAN ID with flags (above) 44 : union { 45 : uint8_t data[MaxDataLen]; 46 : uint32_t data_32[MaxDataLen/4]; 47 : }; 48 : uint8_t dlc; ///< Data Length Code 49 : bool canfd; 50 : 51 162534 : CANFrame() : 52 162534 : id(0), 53 162534 : dlc(0), 54 162534 : canfd(false) 55 : { 56 162534 : memset(data,0, MaxDataLen); 57 162534 : } 58 : 59 : CANFrame(uint32_t can_id, const uint8_t* can_data, uint8_t data_len, bool canfd_frame = false); 60 : 61 : bool operator!=(const CANFrame& rhs) const 62 : { 63 : return !operator==(rhs); 64 : } 65 : bool operator==(const CANFrame& rhs) const 66 : { 67 : return (id == rhs.id) && (dlc == rhs.dlc) && (memcmp(data, rhs.data, dlc) == 0); 68 : } 69 : 70 : // signed version of id, for use by scriping where uint32_t is expensive 71 0 : int32_t id_signed(void) const { 72 0 : return isExtended()? int32_t(id & MaskExtID) : int32_t(id & MaskStdID); 73 : } 74 : 75 152 : bool isExtended() const 76 : { 77 152 : return id & FlagEFF; 78 : } 79 0 : bool isRemoteTransmissionRequest() const 80 : { 81 0 : return id & FlagRTR; 82 : } 83 0 : bool isErrorFrame() const 84 : { 85 0 : return id & FlagERR; 86 : } 87 : void setCanFD(bool canfd_frame) 88 : { 89 : canfd = canfd_frame; 90 : } 91 : 92 0 : bool isCanFDFrame() const 93 : { 94 0 : return canfd; 95 : } 96 : 97 : static uint8_t dlcToDataLength(uint8_t dlc); 98 : 99 : static uint8_t dataLengthToDlc(uint8_t data_length); 100 : /** 101 : * CAN frame arbitration rules, particularly STD vs EXT: 102 : * Marco Di Natale - "Understanding and using the Controller Area Network" 103 : * http://www6.in.tum.de/pub/Main/TeachingWs2013MSE/CANbus.pdf 104 : */ 105 : bool priorityHigherThan(const CANFrame& rhs) const; 106 0 : bool priorityLowerThan(const CANFrame& rhs) const 107 : { 108 0 : return rhs.priorityHigherThan(*this); 109 : } 110 : }; 111 : 112 : class AP_HAL::CANIface 113 : { 114 : public: 115 : 116 : typedef uint16_t CanIOFlags; 117 : static const CanIOFlags Loopback = 1; 118 : static const CanIOFlags AbortOnError = 2; 119 : static const CanIOFlags IsForwardedFrame = 4; 120 : 121 : // Single Rx Frame with related info 122 : struct CanRxItem { 123 : uint64_t timestamp_us = 0; 124 : CanIOFlags flags = 0; 125 : CANFrame frame; 126 : }; 127 : 128 : // Single Tx Frame with related info 129 : struct CanTxItem { 130 : uint64_t deadline = 0; 131 : CANFrame frame; 132 : uint32_t index = 0; 133 : bool loopback:1; 134 : bool abort_on_error:1; 135 : bool aborted:1; 136 : bool pushed:1; 137 : bool setup:1; 138 : bool canfd_frame:1; 139 : 140 0 : bool operator<(const CanTxItem& rhs) const 141 : { 142 0 : if (frame.priorityLowerThan(rhs.frame)) { 143 0 : return true; 144 : } 145 0 : if (frame.priorityHigherThan(rhs.frame)) { 146 0 : return false; 147 : } 148 0 : return index > rhs.index; 149 : } 150 : }; 151 : 152 0 : virtual bool init(const uint32_t bitrate, const uint32_t fdbitrate) { 153 0 : return init(bitrate); 154 : } 155 : 156 : // Initialise the interface with hardware configuration required to start comms. 157 : virtual bool init(const uint32_t bitrate) = 0; 158 : 159 : // Select method to notify user of Rx and Tx buffer state. 160 : // fill read select with true if a frame is available in Rx buffer 161 : // fill write select with true if space is available in Tx buffer 162 : // Also waits for Rx or Tx event depending on read_select and write_select values 163 : // passed to the method until timeout. Returns true if the Rx/Tx even occurred 164 : // while waiting, false if timedout 165 0 : virtual bool select(bool &read_select, bool &write_select, 166 : const CANFrame* const pending_tx, uint64_t timeout) 167 : { 168 0 : return false; 169 : } 170 : 171 0 : virtual bool set_event_handle(AP_HAL::BinarySemaphore *sem_handle) 172 : { 173 0 : return true; 174 : } 175 : 176 : // Put frame in queue to be sent, return negative if error occurred, 0 if no space, and 1 if successful 177 : // must be called on child class 178 : virtual int16_t send(const CANFrame& frame, uint64_t tx_deadline, CanIOFlags flags); 179 : 180 : // Non blocking receive frame that pops the frames received inside the buffer, return negative if error occurred, 181 : // 0 if no frame available, 1 if successful 182 : // must be called on child class 183 : virtual int16_t receive(CANFrame& out_frame, uint64_t& out_ts_monotonic, CanIOFlags& out_flags); 184 : 185 : //Return Total Error Count generated so far 186 0 : virtual uint32_t getErrorCount() const 187 : { 188 0 : return 0; 189 : } 190 : 191 : typedef struct { 192 : uint32_t tx_requests; 193 : uint32_t tx_rejected; 194 : uint32_t tx_overflow; 195 : uint32_t tx_success; 196 : uint32_t tx_timedout; 197 : uint32_t tx_abort; 198 : uint32_t rx_received; 199 : uint32_t rx_overflow; 200 : uint32_t rx_errors; 201 : uint32_t num_busoff_err; 202 : uint64_t last_transmit_us; 203 : } bus_stats_t; 204 : 205 : #if !defined(HAL_BOOTLOADER_BUILD) 206 : //Get status info of the interface 207 0 : virtual void get_stats(ExpandingString &str) {} 208 : 209 : /* 210 : return bus statistics for logging 211 : return nullptr if no statistics available 212 : */ 213 0 : virtual const bus_stats_t *get_statistics(void) const { return nullptr; }; 214 : #endif 215 : 216 : // return true if busoff was detected and not cleared 217 0 : virtual bool is_busoff() const 218 : { 219 0 : return false; 220 : } 221 : 222 : // Methods to be used only while testing CANBus 223 : // Not for normal operation or use case 224 0 : virtual void flush_tx() {} 225 0 : virtual void clear_rx() {} 226 : 227 : // return true if init was called and successful 228 : virtual bool is_initialized() const = 0; 229 : 230 : FUNCTOR_TYPEDEF(FrameCb, void, uint8_t, const AP_HAL::CANFrame &, CanIOFlags); 231 : 232 : // register a frame callback function 233 : virtual bool register_frame_callback(FrameCb cb, uint8_t &cb_id); 234 : virtual void unregister_frame_callback(uint8_t cb_id); 235 : 236 : protected: 237 : virtual int8_t get_iface_num() const = 0; 238 : virtual bool add_to_rx_queue(const CanRxItem &rx_item) = 0; 239 : 240 : struct { 241 : #ifndef HAL_BOOTLOADER_BUILD 242 : HAL_Semaphore sem; 243 : #endif 244 : // allow up to 3 callbacks per interface 245 : FrameCb cb[3]; 246 : } callbacks; 247 : 248 : uint32_t bitrate_; 249 : };