/* * CAN bus driver interface. * Copyright (C) 2014 Pavel Kirienko */ #ifndef UAVCAN_DRIVER_CAN_HPP_INCLUDED #define UAVCAN_DRIVER_CAN_HPP_INCLUDED #include #include #include #include namespace uavcan { /** * This limit is defined by the specification. */ enum { MaxCanIfaces = 3 }; /** * Raw CAN frame, as passed to/from the CAN driver. */ struct UAVCAN_EXPORT CanFrame { static const uint32_t MaskStdID = 0x000007FFU; static const uint32_t MaskExtID = 0x1FFFFFFFU; static const uint32_t FlagEFF = 1U << 31; ///< Extended frame format static const uint32_t FlagRTR = 1U << 30; ///< Remote transmission request static const uint32_t FlagERR = 1U << 29; ///< Error frame static const uint8_t MaxDataLen = 8; uint32_t id; ///< CAN ID with flags (above) uint8_t data[MaxDataLen]; uint8_t dlc; ///< Data Length Code CanFrame() : id(0), dlc(0) { fill(data, data + MaxDataLen, uint8_t(0)); } CanFrame(uint32_t can_id, const uint8_t* can_data, uint8_t data_len) : id(can_id), dlc((data_len > MaxDataLen) ? MaxDataLen : data_len) { UAVCAN_ASSERT(can_data != NULL); UAVCAN_ASSERT(data_len == dlc); (void)copy(can_data, can_data + dlc, this->data); } bool operator!=(const CanFrame& rhs) const { return !operator==(rhs); } bool operator==(const CanFrame& rhs) const { return (id == rhs.id) && (dlc == rhs.dlc) && equal(data, data + dlc, rhs.data); } bool isExtended() const { return id & FlagEFF; } bool isRemoteTransmissionRequest() const { return id & FlagRTR; } bool isErrorFrame() const { return id & FlagERR; } #if UAVCAN_TOSTRING enum StringRepresentation { StrTight, ///< Minimum string length (default) StrAligned ///< Fixed formatting for any frame }; std::string toString(StringRepresentation mode = StrTight) const; #endif /** * CAN frame arbitration rules, particularly STD vs EXT: * Marco Di Natale - "Understanding and using the Controller Area Network" * http://www6.in.tum.de/pub/Main/TeachingWs2013MSE/CANbus.pdf */ bool priorityHigherThan(const CanFrame& rhs) const; bool priorityLowerThan(const CanFrame& rhs) const { return rhs.priorityHigherThan(*this); } }; /** * CAN hardware filter config struct. * Flags from @ref CanFrame can be applied to define frame type (EFF, EXT, etc.). * @ref ICanIface::configureFilters(). */ struct UAVCAN_EXPORT CanFilterConfig { uint32_t id; uint32_t mask; bool operator==(const CanFilterConfig& rhs) const { return rhs.id == id && rhs.mask == mask; } CanFilterConfig() : id(0), mask(0) { } }; /** * Events to look for during @ref ICanDriver::select() call. * Bit position defines iface index, e.g. read = 1 << 2 to read from the third iface. */ struct UAVCAN_EXPORT CanSelectMasks { uint8_t read; uint8_t write; CanSelectMasks() : read(0), write(0) { } }; /** * Special IO flags. * * @ref CanIOFlagLoopback - Send the frame back to RX with true TX timestamps. * * @ref CanIOFlagAbortOnError - Abort transmission on first bus error instead of retransmitting. This does not * affect the case of arbitration loss, in which case the retransmission will work * as usual. This flag is used together with anonymous messages which allows to * implement CSMA bus access. Read the spec for details. */ typedef uint16_t CanIOFlags; static const CanIOFlags CanIOFlagLoopback = 1; static const CanIOFlags CanIOFlagAbortOnError = 2; /** * Single non-blocking CAN interface. */ class UAVCAN_EXPORT ICanIface { public: virtual ~ICanIface() { } /** * Non-blocking transmission. * * If the frame wasn't transmitted upon TX deadline, the driver should discard it. * * Note that it is LIKELY that the library will want to send the frames that were passed into the select() * method as the next ones to transmit, but it is NOT guaranteed. The library can replace those with new * frames between the calls. * * @return 1 = one frame transmitted, 0 = TX buffer full, negative for error. */ virtual int16_t send(const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags) = 0; /** * Non-blocking reception. * * Timestamps should be provided by the CAN driver, ideally by the hardware CAN controller. * * Monotonic timestamp is required and can be not precise since it is needed only for * protocol timing validation (transfer timeouts and inter-transfer intervals). * * UTC timestamp is optional, if available it will be used for precise time synchronization; * must be set to zero if not available. * * Refer to @ref ISystemClock to learn more about timestamps. * * @param [out] out_ts_monotonic Monotonic timestamp, mandatory. * @param [out] out_ts_utc UTC timestamp, optional, zero if unknown. * @return 1 = one frame received, 0 = RX buffer empty, negative for error. */ virtual int16_t receive(CanFrame& out_frame, MonotonicTime& out_ts_monotonic, UtcTime& out_ts_utc, CanIOFlags& out_flags) = 0; /** * Configure the hardware CAN filters. @ref CanFilterConfig. * * @return 0 = success, negative for error. */ virtual int16_t configureFilters(const CanFilterConfig* filter_configs, uint16_t num_configs) = 0; /** * Number of available hardware filters. */ virtual uint16_t getNumFilters() const = 0; /** * Continuously incrementing counter of hardware errors. * Arbitration lost should not be treated as a hardware error. */ virtual uint64_t getErrorCount() const = 0; }; /** * Generic CAN driver. */ class UAVCAN_EXPORT ICanDriver { public: virtual ~ICanDriver() { } /** * Returns an interface by index, or null pointer if the index is out of range. */ virtual ICanIface* getIface(uint8_t iface_index) = 0; /** * Default implementation of this method calls the non-const overload of getIface(). * Can be overriden by the application if necessary. */ virtual const ICanIface* getIface(uint8_t iface_index) const { return const_cast(this)->getIface(iface_index); } /** * Total number of available CAN interfaces. * This value shall not change after initialization. */ virtual uint8_t getNumIfaces() const = 0; /** * Block until the deadline, or one of the specified interfaces becomes available for read or write. * * Iface masks will be modified by the driver to indicate which exactly interfaces are available for IO. * * Bit position in the masks defines interface index. * * Note that it is allowed to return from this method even if no requested events actually happened, or if * there are events that were not requested by the library. * * The pending TX argument contains an array of pointers to CAN frames that the library wants to transmit * next, per interface. This is intended to allow the driver to properly prioritize transmissions; many * drivers will not need to use it. If a write flag for the given interface is set to one in the select mask * structure, then the corresponding pointer is guaranteed to be valid (not NULL). * * @param [in,out] inout_masks Masks indicating which interfaces are needed/available for IO. * @param [in] pending_tx Array of frames, per interface, that are likely to be transmitted next. * @param [in] blocking_deadline Zero means non-blocking operation. * @return Positive number of ready interfaces or negative error code. */ virtual int16_t select(CanSelectMasks& inout_masks, const CanFrame* (& pending_tx)[MaxCanIfaces], MonotonicTime blocking_deadline) = 0; }; } #endif // UAVCAN_DRIVER_CAN_HPP_INCLUDED