| /* |
| * Copyright (c) 2021 Vestas Wind Systems A/S |
| * Copyright (c) 2018 Alexander Wachter |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef ZEPHYR_INCLUDE_DRIVERS_CAN_H_ |
| #define ZEPHYR_INCLUDE_DRIVERS_CAN_H_ |
| |
| #include <zephyr/types.h> |
| #include <device.h> |
| #include <string.h> |
| #include <sys/util.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @brief CAN Interface |
| * @defgroup can_interface CAN Interface |
| * @ingroup io_interfaces |
| * @{ |
| */ |
| |
| /** |
| * @name CAN frame definitions |
| * @{ |
| */ |
| |
| /** |
| * @brief Bit mask for a standard (11-bit) CAN identifier. |
| */ |
| #define CAN_STD_ID_MASK 0x7FFU |
| /** |
| * @brief Maximum value for a standard (11-bit) CAN identifier. |
| */ |
| #define CAN_MAX_STD_ID CAN_STD_ID_MASK |
| /** |
| * @brief Bit mask for an extended (29-bit) CAN identifier. |
| */ |
| #define CAN_EXT_ID_MASK 0x1FFFFFFFU |
| /** |
| * @brief Maximum value for an extended (29-bit) CAN identifier. |
| */ |
| #define CAN_MAX_EXT_ID CAN_EXT_ID_MASK |
| /** |
| * @brief Maximum data length code for CAN 2.0A/2.0B. |
| */ |
| #define CAN_MAX_DLC 8U |
| /** |
| * @brief Maximum data length code for CAN-FD. |
| */ |
| #define CANFD_MAX_DLC CONFIG_CANFD_MAX_DLC |
| |
| /** |
| * @cond INTERNAL_HIDDEN |
| * Internally calculated maximum data length |
| */ |
| #ifndef CONFIG_CANFD_MAX_DLC |
| #define CAN_MAX_DLEN 8U |
| #else |
| #if CONFIG_CANFD_MAX_DLC <= 8 |
| #define CAN_MAX_DLEN CONFIG_CANFD_MAX_DLC |
| #elif CONFIG_CANFD_MAX_DLC <= 12 |
| #define CAN_MAX_DLEN (CONFIG_CANFD_MAX_DLC + (CONFIG_CANFD_MAX_DLC - 8U) * 4U) |
| #elif CONFIG_CANFD_MAX_DLC == 13 |
| #define CAN_MAX_DLEN 32U |
| #elif CONFIG_CANFD_MAX_DLC == 14 |
| #define CAN_MAX_DLEN 48U |
| #elif CONFIG_CANFD_MAX_DLC == 15 |
| #define CAN_MAX_DLEN 64U |
| #endif |
| #endif /* CONFIG_CANFD_MAX_DLC */ |
| |
| /** @endcond */ |
| |
| /** @} */ |
| |
| /** |
| * @brief Defines the mode of the CAN controller |
| */ |
| enum can_mode { |
| /** Normal mode. */ |
| CAN_NORMAL_MODE, |
| /** Controller is not allowed to send dominant bits. */ |
| CAN_SILENT_MODE, |
| /** Controller is in loopback mode (receives own frames). */ |
| CAN_LOOPBACK_MODE, |
| /** Combination of loopback and silent modes. */ |
| CAN_SILENT_LOOPBACK_MODE |
| }; |
| |
| /** |
| * @brief Defines the state of the CAN bus |
| */ |
| enum can_state { |
| /** Error-active state (RX/TX error count < 96). */ |
| CAN_ERROR_ACTIVE, |
| /** Error-warning state (RX/TX error count < 128). */ |
| CAN_ERROR_WARNING, |
| /** Error-passive state (RX/TX error count < 256). */ |
| CAN_ERROR_PASSIVE, |
| /** Bus-off state (RX/TX error count >= 256). */ |
| CAN_BUS_OFF, |
| }; |
| |
| /** |
| * @brief Defines if the CAN frame has a standard (11-bit) or extended (29-bit) |
| * CAN identifier |
| */ |
| enum can_ide { |
| /** Standard (11-bit) CAN identifier. */ |
| CAN_STANDARD_IDENTIFIER, |
| /** Extended (29-bit) CAN identifier. */ |
| CAN_EXTENDED_IDENTIFIER |
| }; |
| |
| /** |
| * @brief Defines if the CAN frame is a data frame or a Remote Transmission Request (RTR) frame |
| */ |
| enum can_rtr { |
| /** Data frame. */ |
| CAN_DATAFRAME, |
| /** Remote Transmission Request (RTR) frame. */ |
| CAN_REMOTEREQUEST |
| }; |
| |
| /** |
| * @brief CAN frame structure |
| */ |
| struct zcan_frame { |
| /** Standard (11-bit) or extended (29-bit) CAN identifier. */ |
| uint32_t id : 29; |
| /** Frame is in the CAN-FD frame format if set to true. */ |
| uint32_t fd : 1; |
| /** Remote Transmission Request (RTR) flag. Use @a can_rtr enum for assignment. */ |
| uint32_t rtr : 1; |
| /** CAN identifier type (standard or extended). Use @a can_ide enum for assignment. */ |
| uint32_t id_type : 1; |
| /** Data Length Code (DLC) indicating data length in bytes. */ |
| uint8_t dlc; |
| /** Baud Rate Switch (BRS). Only valid for CAN-FD. */ |
| uint8_t brs : 1; |
| /** @cond INTERNAL_HIDDEN */ |
| uint8_t res : 7; /* reserved/padding. */ |
| /** @endcond */ |
| #if defined(CONFIG_CAN_RX_TIMESTAMP) || defined(__DOXYGEN__) |
| /** Captured value of the free-running timer in the CAN controller when |
| * this frame was received. The timer is incremented every bit time and |
| * captured at the start of frame bit (SOF). |
| * |
| * @note @kconfig{CONFIG_CAN_RX_TIMESTAMP} must be selected for this |
| * field to be available. |
| */ |
| uint16_t timestamp; |
| #else |
| /** @cond INTERNAL_HIDDEN */ |
| uint8_t res0; /* reserved/padding. */ |
| uint8_t res1; /* reserved/padding. */ |
| /** @endcond */ |
| #endif |
| /** The frame payload data. */ |
| union { |
| uint8_t data[CAN_MAX_DLEN]; |
| uint32_t data_32[ceiling_fraction(CAN_MAX_DLEN, sizeof(uint32_t))]; |
| }; |
| }; |
| |
| /** |
| * @brief CAN filter structure |
| */ |
| struct zcan_filter { |
| /** CAN identifier to match. */ |
| uint32_t id : 29; |
| /** @cond INTERNAL_HIDDEN */ |
| uint32_t res0 : 1; |
| /** @endcond */ |
| /** Match data frame or Remote Transmission Request (RTR) frame. */ |
| uint32_t rtr : 1; |
| /** Standard or extended CAN identifier. Use @a can_ide enum for assignment. */ |
| uint32_t id_type : 1; |
| /** CAN identifier matching mask. If a bit in this mask is 0, the value |
| * of the corresponding bit in the ``id`` field is ignored by the filter. |
| */ |
| uint32_t id_mask : 29; |
| /** @cond INTERNAL_HIDDEN */ |
| uint32_t res1 : 1; |
| /** @endcond */ |
| /** Data frame/Remote Transmission Request (RTR) bit matching mask. If |
| * this bit is 0, the value of the ``rtr`` field is ignored by the |
| * filter. |
| */ |
| uint32_t rtr_mask : 1; |
| /** @cond INTERNAL_HIDDEN */ |
| uint32_t res2 : 1; |
| /** @endcond */ |
| }; |
| |
| /** |
| * @brief CAN controller error counters |
| */ |
| struct can_bus_err_cnt { |
| /** Value of the CAN controller transmit error counter. */ |
| uint8_t tx_err_cnt; |
| /** Value of the CAN controller receive error counter. */ |
| uint8_t rx_err_cnt; |
| }; |
| |
| /** |
| * @brief CAN bus timing structure |
| * |
| * This struct is used to pass bus timing values to the configuration and |
| * bitrate calculation functions. |
| * |
| * The propagation segment represents the time of the signal propagation. Phase |
| * segment 1 and phase segment 2 define the sampling point. The ``prop_seg`` and |
| * ``phase_seg1`` values affect the sampling point in the same way and some |
| * controllers only have a register for the sum of those two. The sync segment |
| * always has a length of 1 time quantum (see below). |
| * |
| * @code{.unparsed} |
| * |
| * +---------+----------+------------+------------+ |
| * |sync_seg | prop_seg | phase_seg1 | phase_seg2 | |
| * +---------+----------+------------+------------+ |
| * ^ |
| * Sampling-Point |
| * |
| * @endcode |
| * |
| * 1 time quantum (tq) has the length of 1/(core_clock / prescaler). The bitrate |
| * is defined by the core clock divided by the prescaler and the sum of the |
| * segments: |
| * |
| * br = (core_clock / prescaler) / (1 + prop_seg + phase_seg1 + phase_seg2) |
| * |
| * The Synchronization Jump Width (SJW) defines the amount of time quanta the |
| * sample point can be moved. The sample point is moved when resynchronization |
| * is needed. |
| */ |
| struct can_timing { |
| /** Synchronisation jump width. */ |
| uint16_t sjw; |
| /** Propagation segment. */ |
| uint16_t prop_seg; |
| /** Phase segment 1. */ |
| uint16_t phase_seg1; |
| /** Phase segment 2. */ |
| uint16_t phase_seg2; |
| /** Prescaler value. */ |
| uint16_t prescaler; |
| }; |
| |
| /** |
| * @typedef can_tx_callback_t |
| * @brief Defines the application callback handler function signature |
| * |
| * @param error Status of the performed send operation. See the list of |
| * return values for @a can_send() for value descriptions. |
| * @param user_data User data provided when the frame was sent. |
| */ |
| typedef void (*can_tx_callback_t)(int error, void *user_data); |
| |
| /** |
| * @typedef can_rx_callback_t |
| * @brief Defines the application callback handler function signature for receiving. |
| * |
| * @param frame Received frame. |
| * @param user_data User data provided when the filter was added. |
| */ |
| typedef void (*can_rx_callback_t)(struct zcan_frame *frame, void *user_data); |
| |
| /** |
| * @typedef can_state_change_callback_t |
| * @brief Defines the state change callback handler function signature |
| * |
| * @param state State of the CAN controller. |
| * @param err_cnt CAN controller error counter values. |
| * @param user_data User data provided the callback was set. |
| */ |
| typedef void (*can_state_change_callback_t)(enum can_state state, |
| struct can_bus_err_cnt err_cnt, |
| void *user_data); |
| |
| /** |
| * @cond INTERNAL_HIDDEN |
| * |
| * For internal driver use only, skip these in public documentation. |
| */ |
| |
| /** |
| * @typedef can_set_timing_t |
| * @brief Callback API upon setting CAN bus timing |
| * See @a can_set_timing() for argument description |
| */ |
| typedef int (*can_set_timing_t)(const struct device *dev, |
| const struct can_timing *timing, |
| const struct can_timing *timing_data); |
| |
| /** |
| * @typedef can_set_mode_t |
| * @brief Callback API upon setting CAN controller mode |
| * See @a can_set_mode() for argument description |
| */ |
| typedef int (*can_set_mode_t)(const struct device *dev, enum can_mode mode); |
| |
| /** |
| * @typedef can_send_t |
| * @brief Callback API upon sending a CAN frame |
| * See @a can_send() for argument description |
| */ |
| typedef int (*can_send_t)(const struct device *dev, |
| const struct zcan_frame *frame, |
| k_timeout_t timeout, can_tx_callback_t callback, |
| void *user_data); |
| |
| /** |
| * @typedef can_add_rx_filter_t |
| * @brief Callback API upon adding an RX filter |
| * See @a can_add_rx_callback() for argument description |
| */ |
| typedef int (*can_add_rx_filter_t)(const struct device *dev, |
| can_rx_callback_t callback, |
| void *user_data, |
| const struct zcan_filter *filter); |
| |
| /** |
| * @typedef can_remove_rx_filter_t |
| * @brief Callback API upon removing an RX filter |
| * See @a can_remove_rx_filter() for argument description |
| */ |
| typedef void (*can_remove_rx_filter_t)(const struct device *dev, int filter_id); |
| |
| /** |
| * @typedef can_recover_t |
| * @brief Callback API upon recovering the CAN bus |
| * See @a can_recover() for argument description |
| */ |
| typedef int (*can_recover_t)(const struct device *dev, k_timeout_t timeout); |
| |
| /** |
| * @typedef can_get_state_t |
| * @brief Callback API upon getting the CAN controller state |
| * See @a can_get_state() for argument description |
| */ |
| typedef int (*can_get_state_t)(const struct device *dev, enum can_state *state, |
| struct can_bus_err_cnt *err_cnt); |
| |
| /** |
| * @typedef can_set_state_change_callback_t |
| * @brief Callback API upon setting a state change callback |
| * See @a can_set_state_change_callback() for argument description |
| */ |
| typedef void(*can_set_state_change_callback_t)(const struct device *dev, |
| can_state_change_callback_t callback, |
| void *user_data); |
| |
| /** |
| * @typedef can_get_core_clock_t |
| * @brief Callback API upon getting the CAN core clock rate |
| * See @a can_get_core_clock() for argument description |
| */ |
| typedef int (*can_get_core_clock_t)(const struct device *dev, uint32_t *rate); |
| |
| /** |
| * @typedef can_get_max_filters_t |
| * @brief Callback API upon getting the maximum number of concurrent CAN RX filters |
| * See @a can_get_max_filters() for argument description |
| */ |
| typedef int (*can_get_max_filters_t)(const struct device *dev, enum can_ide id_type); |
| |
| __subsystem struct can_driver_api { |
| can_set_mode_t set_mode; |
| can_set_timing_t set_timing; |
| can_send_t send; |
| can_add_rx_filter_t add_rx_filter; |
| can_remove_rx_filter_t remove_rx_filter; |
| #if !defined(CONFIG_CAN_AUTO_BUS_OFF_RECOVERY) || defined(__DOXYGEN__) |
| can_recover_t recover; |
| #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ |
| can_get_state_t get_state; |
| can_set_state_change_callback_t set_state_change_callback; |
| can_get_core_clock_t get_core_clock; |
| can_get_max_filters_t get_max_filters; |
| /* Min values for the timing registers */ |
| struct can_timing timing_min; |
| /* Max values for the timing registers */ |
| struct can_timing timing_max; |
| #if defined(CONFIG_CAN_FD_MODE) || defined(__DOXYGEN__) |
| /* Min values for the timing registers during the data phase */ |
| struct can_timing timing_min_data; |
| /* Max values for the timing registers during the data phase */ |
| struct can_timing timing_max_data; |
| #endif /* CONFIG_CAN_FD_MODE */ |
| }; |
| |
| /** @endcond */ |
| |
| /** |
| * @name CAN controller configuration |
| * |
| * @{ |
| */ |
| |
| /** |
| * @brief Get the CAN core clock rate |
| * |
| * Returns the CAN core clock rate. One time quantum is 1/(core clock rate). |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param[out] rate CAN core clock rate in Hz. |
| * |
| * @return 0 on success, or a negative error code on error |
| */ |
| __syscall int can_get_core_clock(const struct device *dev, uint32_t *rate); |
| |
| static inline int z_impl_can_get_core_clock(const struct device *dev, uint32_t *rate) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| return api->get_core_clock(dev, rate); |
| } |
| |
| /** |
| * @brief Calculate timing parameters from bitrate and sample point |
| * |
| * Calculate the timing parameters from a given bitrate in bits/s and the |
| * sampling point in permill (1/1000) of the entire bit time. The bitrate must |
| * alway match perfectly. If no result can be reached for the given parameters, |
| * -EINVAL is returned. |
| * |
| * @note The requested ``sample_pnt`` will not always be matched perfectly. The |
| * algorithm calculates the best possible match. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param[out] res Result is written into the @a can_timing struct provided. |
| * @param bitrate Target bitrate in bits/s. |
| * @param sample_pnt Sampling point in permill of the entire bit time. |
| * |
| * @retval 0 or positive sample point error on success. |
| * @retval -EINVAL if there is no solution for the desired values. |
| * @retval -EIO if @a can_get_core_clock() is not available. |
| */ |
| int can_calc_timing(const struct device *dev, struct can_timing *res, |
| uint32_t bitrate, uint16_t sample_pnt); |
| |
| #if defined(CONFIG_CAN_FD_MODE) || defined(__DOXYGEN__) |
| /** |
| * @brief Calculate timing parameters for the data phase |
| * |
| * Same as @a can_calc_timing() but with the maximum and minimum values from the |
| * data phase. |
| * |
| * @note @kconfig{CONFIG_CAN_FD_MODE} must be selected for this function to be |
| * available. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param[out] res Result is written into the @a can_timing struct provided. |
| * @param bitrate Target bitrate for the data phase in bits/s |
| * @param sample_pnt Sampling point for the data phase in permille of the entire bit time. |
| * |
| * @retval 0 or positive sample point error on success. |
| * @retval -EINVAL if there is no solution for the desired values. |
| * @retval -EIO if @a can_get_core_clock() is not available. |
| */ |
| int can_calc_timing_data(const struct device *dev, struct can_timing *res, |
| uint32_t bitrate, uint16_t sample_pnt); |
| #endif /* CONFIG_CAN_FD_MODE */ |
| |
| /** |
| * @brief Fill in the prescaler value for a given bitrate and timing |
| * |
| * Fill the prescaler value in the timing struct. The sjw, prop_seg, phase_seg1 |
| * and phase_seg2 must be given. |
| * |
| * The returned bitrate error is reminder of the devision of the clock rate by |
| * the bitrate times the timing segments. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param timing Result is written into the can_timing struct provided. |
| * @param bitrate Target bitrate. |
| * |
| * @retval 0 or positive bitrate error. |
| * @retval Negative error code on error. |
| */ |
| int can_calc_prescaler(const struct device *dev, struct can_timing *timing, |
| uint32_t bitrate); |
| |
| /** Synchronization Jump Width (SJW) value to indicate that the SJW should not |
| * be changed by the timing calculation. |
| */ |
| #define CAN_SJW_NO_CHANGE 0 |
| |
| /** |
| * @brief Configure the bus timing of a CAN controller. |
| * |
| * If the sjw equals CAN_SJW_NO_CHANGE, the sjw parameter is not changed. |
| * |
| * @note The parameter ``timing_data`` is only relevant for CAN-FD. If the |
| * controller does not support CAN-FD or if @kconfig{CONFIG_CAN_FD_MODE} is not |
| * selected, the value of this parameter is ignored. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param timing Bus timings. |
| * @param timing_data Bus timings for data phase (CAN-FD only). |
| * |
| * @retval 0 If successful. |
| * @retval -EIO General input/output error, failed to configure device. |
| */ |
| __syscall int can_set_timing(const struct device *dev, |
| const struct can_timing *timing, |
| const struct can_timing *timing_data); |
| |
| static inline int z_impl_can_set_timing(const struct device *dev, |
| const struct can_timing *timing, |
| const struct can_timing *timing_data) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| return api->set_timing(dev, timing, timing_data); |
| } |
| |
| /** |
| * @brief Set the CAN controller to the given operation mode |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param mode Operation mode. |
| * |
| * @retval 0 If successful. |
| * @retval -EIO General input/output error, failed to configure device. |
| */ |
| __syscall int can_set_mode(const struct device *dev, enum can_mode mode); |
| |
| static inline int z_impl_can_set_mode(const struct device *dev, enum can_mode mode) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| return api->set_mode(dev, mode); |
| } |
| |
| /** |
| * @brief Set the bitrate of the CAN controller |
| * |
| * The sample point is set to the CiA DS 301 recommended value of 87.5%. |
| * |
| * @note The parameter ``bitrate_data`` is only relevant for CAN-FD. If the |
| * controller does not support CAN-FD or if @kconfig{CONFIG_CAN_FD_MODE} is not |
| * selected, the value of this parameter is ignored. |
| |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param bitrate Desired arbitration phase bitrate. |
| * @param bitrate_data Desired data phase bitrate. |
| * |
| * @retval 0 If successful. |
| * @retval -EINVAL bitrate cannot be met. |
| * @retval -EIO General input/output error, failed to set bitrate. |
| */ |
| static inline int can_set_bitrate(const struct device *dev, |
| uint32_t bitrate, |
| uint32_t bitrate_data) |
| { |
| struct can_timing timing; |
| #ifdef CONFIG_CAN_FD_MODE |
| struct can_timing timing_data; |
| #endif |
| int ret; |
| |
| ret = can_calc_timing(dev, &timing, bitrate, 875); |
| if (ret < 0) { |
| return -EINVAL; |
| } |
| |
| timing.sjw = CAN_SJW_NO_CHANGE; |
| |
| #ifdef CONFIG_CAN_FD_MODE |
| ret = can_calc_timing_data(dev, &timing_data, bitrate_data, 875); |
| if (ret < 0) { |
| return -EINVAL; |
| } |
| |
| timing_data.sjw = CAN_SJW_NO_CHANGE; |
| |
| return can_set_timing(dev, &timing, &timing_data); |
| #else /* CONFIG_CAN_FD_MODE */ |
| return can_set_timing(dev, &timing, NULL); |
| #endif /* !CONFIG_CAN_FD_MODE */ |
| } |
| |
| /** @} */ |
| |
| /** |
| * @name Transmitting CAN frames |
| * |
| * @{ |
| */ |
| |
| /** |
| * @brief Transmit a CAN frame on the CAN bus |
| * |
| * Transmit a CAN frame on the CAN bus with optional timeout and completion |
| * callback function. |
| * |
| * By default, the CAN controller will automatically retry transmission in case |
| * of lost bus arbitration or missing acknowledge. Some CAN controllers support |
| * disabling automatic retransmissions ("one-shot" mode) via a devicetree |
| * property. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param frame CAN frame to transmit. |
| * @param timeout Timeout waiting for a empty TX mailbox or ``K_FOREVER``. |
| * @param callback Optional callback for when the frame was sent or a |
| * transmission error occurred. If ``NULL``, this function is |
| * blocking until frame is sent. The callback must be ``NULL`` |
| * if called from user mode. |
| * @param user_data User data to pass to callback function. |
| * |
| * @retval 0 if successful. |
| * @retval -EINVAL if an invalid parameter was passed to the function. |
| * @retval -ENETDOWN if the CAN controller is in bus-off state. |
| * @retval -EBUSY if CAN bus arbitration was lost (only applicable if automatic |
| * retransmissions are disabled). |
| * @retval -EIO if a general transmit error occurred (e.g. missing ACK if |
| * automatic retransmissions are disabled). |
| * @retval -EAGAIN on timeout. |
| */ |
| __syscall int can_send(const struct device *dev, const struct zcan_frame *frame, |
| k_timeout_t timeout, can_tx_callback_t callback, |
| void *user_data); |
| |
| static inline int z_impl_can_send(const struct device *dev, const struct zcan_frame *frame, |
| k_timeout_t timeout, can_tx_callback_t callback, |
| void *user_data) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| return api->send(dev, frame, timeout, callback, user_data); |
| } |
| |
| /** @} */ |
| |
| /** |
| * @name Receiving CAN frames |
| * |
| * @{ |
| */ |
| |
| /** |
| * @brief Add a callback function for a given CAN filter |
| * |
| * Add a callback to CAN identifiers specified by a filter. When a recevied CAN |
| * frame matching the filter is received by the CAN controller, the callback |
| * function is called in interrupt context. |
| * |
| * If a frame matches more than one attached filter, the priority of the match |
| * is hardware dependent. |
| * |
| * The same callback function can be used for multiple filters. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param callback This function is called by the CAN controller driver whenever |
| * a frame matching the filter is received. |
| * @param user_data User data to pass to callback function. |
| * @param filter Pointer to a @a zcan_filter structure defining the filter. |
| * |
| * @retval filter_id on success. |
| * @retval -ENOSPC if there are no free filters. |
| */ |
| static inline int can_add_rx_filter(const struct device *dev, can_rx_callback_t callback, |
| void *user_data, const struct zcan_filter *filter) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| return api->add_rx_filter(dev, callback, user_data, filter); |
| } |
| |
| /** |
| * @brief Statically define and initialize a CAN RX message queue. |
| * |
| * The message queue's ring buffer contains space for @a max_frames CAN frames. |
| * |
| * @see can_add_rx_filter_msgq() |
| * |
| * @param name Name of the message queue. |
| * @param max_frames Maximum number of CAN frames that can be queued. |
| */ |
| #define CAN_MSGQ_DEFINE(name, max_frames) \ |
| K_MSGQ_DEFINE(name, sizeof(struct zcan_frame), max_frames, 4) |
| |
| /** |
| * @brief Wrapper function for adding a message queue for a given filter |
| * |
| * Wrapper function for @a can_add_rx_filter() which puts received CAN frames |
| * matching the filter in a message queue instead of calling a callback. |
| * |
| * If a frame matches more than one attached filter, the priority of the match |
| * is hardware dependent. |
| * |
| * The same message queue can be used for multiple filters. |
| * |
| * @note The message queue must be initialized before calling this function and |
| * the caller must have appropriate permissions on it. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param msgq Pointer to the already initialized @a k_msgq struct. |
| * @param filter Pointer to a @a zcan_filter structure defining the filter. |
| * |
| * @retval filter_id on success. |
| * @retval -ENOSPC if there are no free filters. |
| */ |
| __syscall int can_add_rx_filter_msgq(const struct device *dev, struct k_msgq *msgq, |
| const struct zcan_filter *filter); |
| |
| /** |
| * @brief Remove a CAN RX filter |
| * |
| * This routine removes a CAN RX filter based on the filter ID returned by @a |
| * can_add_rx_filter() or @a can_add_rx_filter_msgq(). |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param filter_id Filter ID |
| */ |
| __syscall void can_remove_rx_filter(const struct device *dev, int filter_id); |
| |
| static inline void z_impl_can_remove_rx_filter(const struct device *dev, int filter_id) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| return api->remove_rx_filter(dev, filter_id); |
| } |
| |
| /** |
| * @brief Get maximum number of RX filters |
| * |
| * Get the maximum number of concurrent RX filters for the CAN controller. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param id_type CAN identifier type (standard or extended). |
| * |
| * @retval Positive number of maximum concurrent filters. |
| * @retval -EIO General input/output error. |
| * @retval -ENOSYS If this function is not implemented by the driver. |
| */ |
| __syscall int can_get_max_filters(const struct device *dev, enum can_ide id_type); |
| |
| static inline int z_impl_can_get_max_filters(const struct device *dev, enum can_ide id_type) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| if (api->get_max_filters == NULL) { |
| return -ENOSYS; |
| } |
| |
| return api->get_max_filters(dev, id_type); |
| } |
| |
| /** @} */ |
| |
| /** |
| * @name CAN bus error reporting and handling |
| * |
| * @{ |
| */ |
| |
| /** |
| * @brief Get current CAN controller state |
| * |
| * Returns the current state and optionally the error counter values of the CAN |
| * controller. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param[out] state Pointer to the state destination enum or NULL. |
| * @param[out] err_cnt Pointer to the err_cnt destination structure or NULL. |
| * |
| * @retval 0 If successful. |
| * @retval -EIO General input/output error, failed to get state. |
| */ |
| __syscall int can_get_state(const struct device *dev, enum can_state *state, |
| struct can_bus_err_cnt *err_cnt); |
| |
| static inline int z_impl_can_get_state(const struct device *dev, enum can_state *state, |
| struct can_bus_err_cnt *err_cnt) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| return api->get_state(dev, state, err_cnt); |
| } |
| |
| /** |
| * @brief Recover from bus-off state |
| * |
| * Recover the CAN controller from bus-off state to error-active state. |
| * |
| * @note @kconfig{CONFIG_CAN_AUTO_BUS_OFF_RECOVERY} must be deselected for this |
| * function to be available. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param timeout Timeout for waiting for the recovery or ``K_FOREVER``. |
| * |
| * @retval 0 on success. |
| * @retval -EAGAIN on timeout. |
| */ |
| #if !defined(CONFIG_CAN_AUTO_BUS_OFF_RECOVERY) || defined(__DOXYGEN__) |
| __syscall int can_recover(const struct device *dev, k_timeout_t timeout); |
| |
| static inline int z_impl_can_recover(const struct device *dev, k_timeout_t timeout) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| return api->recover(dev, timeout); |
| } |
| #else /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ |
| /* This implementation prevents inking errors for auto recovery */ |
| static inline int z_impl_can_recover(const struct device *dev, k_timeout_t timeout) |
| { |
| return 0; |
| } |
| #endif /* !CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ |
| |
| /** |
| * @brief Set a callback for CAN controller state change events |
| * |
| * Set the callback for CAN controller state change events. The callback |
| * function will be called in interrupt context. |
| * |
| * Only one callback can be registered per controller. Calling this function |
| * again overrides any previously registered callback. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param callback Callback function. |
| * @param user_data User data to pass to callback function. |
| */ |
| static inline void can_set_state_change_callback(const struct device *dev, |
| can_state_change_callback_t callback, |
| void *user_data) |
| { |
| const struct can_driver_api *api = (const struct can_driver_api *)dev->api; |
| |
| api->set_state_change_callback(dev, callback, user_data); |
| } |
| |
| /** @} */ |
| |
| /** |
| * @name CAN utility functions |
| * |
| * @{ |
| */ |
| |
| /** |
| * @brief Convert from Data Length Code (DLC) to the number of data bytes |
| * |
| * @param dlc Data Length Code (DLC). |
| * |
| * @retval Number of bytes. |
| */ |
| static inline uint8_t can_dlc_to_bytes(uint8_t dlc) |
| { |
| static const uint8_t dlc_table[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, |
| 16, 20, 24, 32, 48, 64}; |
| |
| return dlc > 0x0F ? 64 : dlc_table[dlc]; |
| } |
| |
| /** |
| * @brief Convert from number of bytes to Data Length Code (DLC) |
| * |
| * @param num_bytes Number of bytes. |
| * |
| * @retval Data Length Code (DLC). |
| */ |
| static inline uint8_t can_bytes_to_dlc(uint8_t num_bytes) |
| { |
| return num_bytes <= 8 ? num_bytes : |
| num_bytes <= 12 ? 9 : |
| num_bytes <= 16 ? 10 : |
| num_bytes <= 20 ? 11 : |
| num_bytes <= 24 ? 12 : |
| num_bytes <= 32 ? 13 : |
| num_bytes <= 48 ? 14 : |
| 15; |
| } |
| |
| /** @} */ |
| |
| /** |
| * @name Linux SocketCAN compatibility |
| * |
| * The following structures and functions provide compatibility with the CAN |
| * frame and CAN filter formats used by Linux SocketCAN. |
| * |
| * @{ |
| */ |
| |
| /** |
| * CAN Identifier structure for Linux SocketCAN compatibility. |
| * |
| * The fields in this type are: |
| * |
| * @code{.unparsed} |
| * |
| * +------+--------------------------------------------------------------+ |
| * | Bits | Description | |
| * +======+==============================================================+ |
| * | 0-28 | CAN identifier (11/29 bit) | |
| * +------+--------------------------------------------------------------+ |
| * | 29 | Error message frame flag (0 = data frame, 1 = error message) | |
| * +------+--------------------------------------------------------------+ |
| * | 30 | Remote transmission request flag (1 = RTR frame) | |
| * +------+--------------------------------------------------------------+ |
| * | 31 | Frame format flag (0 = standard 11 bit, 1 = extended 29 bit) | |
| * +------+--------------------------------------------------------------+ |
| * |
| * @endcode |
| */ |
| typedef uint32_t canid_t; |
| |
| /** |
| * @brief CAN frame for Linux SocketCAN compatibility. |
| */ |
| struct can_frame { |
| /** 32-bit CAN ID + EFF/RTR/ERR flags. */ |
| canid_t can_id; |
| |
| /** The data length code (DLC). */ |
| uint8_t can_dlc; |
| |
| /** @cond INTERNAL_HIDDEN */ |
| uint8_t pad; /* padding. */ |
| uint8_t res0; /* reserved/padding. */ |
| uint8_t res1; /* reserved/padding. */ |
| /** @endcond */ |
| |
| /** The payload data. */ |
| uint8_t data[CAN_MAX_DLEN]; |
| }; |
| |
| /** |
| * @brief CAN filter for Linux SocketCAN compatibility. |
| * |
| * A filter is considered a match when `received_can_id & mask == can_id & can_mask`. |
| */ |
| struct can_filter { |
| /** The CAN identifier to match. */ |
| canid_t can_id; |
| /** The mask applied to @a can_id for matching. */ |
| canid_t can_mask; |
| }; |
| |
| /** |
| * @brief Translate a @a can_frame struct to a @a zcan_frame struct. |
| * |
| * @param frame Pointer to can_frame struct. |
| * @param zframe Pointer to zcan_frame struct. |
| */ |
| static inline void can_copy_frame_to_zframe(const struct can_frame *frame, |
| struct zcan_frame *zframe) |
| { |
| zframe->id_type = (frame->can_id & BIT(31)) >> 31; |
| zframe->rtr = (frame->can_id & BIT(30)) >> 30; |
| zframe->id = frame->can_id & BIT_MASK(29); |
| zframe->dlc = frame->can_dlc; |
| memcpy(zframe->data, frame->data, sizeof(zframe->data)); |
| } |
| |
| /** |
| * @brief Translate a @a zcan_frame struct to a @a can_frame struct. |
| * |
| * @param zframe Pointer to zcan_frame struct. |
| * @param frame Pointer to can_frame struct. |
| */ |
| static inline void can_copy_zframe_to_frame(const struct zcan_frame *zframe, |
| struct can_frame *frame) |
| { |
| frame->can_id = (zframe->id_type << 31) | (zframe->rtr << 30) | zframe->id; |
| frame->can_dlc = zframe->dlc; |
| memcpy(frame->data, zframe->data, sizeof(frame->data)); |
| } |
| |
| /** |
| * @brief Translate a @a can_filter struct to a @a zcan_filter struct. |
| * |
| * @param filter Pointer to can_filter struct. |
| * @param zfilter Pointer to zcan_filter struct. |
| */ |
| static inline void can_copy_filter_to_zfilter(const struct can_filter *filter, |
| struct zcan_filter *zfilter) |
| { |
| zfilter->id_type = (filter->can_id & BIT(31)) >> 31; |
| zfilter->rtr = (filter->can_id & BIT(30)) >> 30; |
| zfilter->id = filter->can_id & BIT_MASK(29); |
| zfilter->rtr_mask = (filter->can_mask & BIT(30)) >> 30; |
| zfilter->id_mask = filter->can_mask & BIT_MASK(29); |
| } |
| |
| /** |
| * @brief Translate a @a zcan_filter struct to a @a can_filter struct. |
| * |
| * @param zfilter Pointer to zcan_filter struct. |
| * @param filter Pointer to can_filter struct. |
| */ |
| static inline void can_copy_zfilter_to_filter(const struct zcan_filter *zfilter, |
| struct can_filter *filter) |
| { |
| filter->can_id = (zfilter->id_type << 31) | |
| (zfilter->rtr << 30) | zfilter->id; |
| filter->can_mask = (zfilter->rtr_mask << 30) | |
| (zfilter->id_type << 31) | zfilter->id_mask; |
| } |
| |
| /** @} */ |
| |
| /** |
| * @cond INTERNAL_HIDDEN |
| * Deprecated APIs |
| */ |
| |
| /** |
| * @name CAN specific error codes |
| * |
| * The `CAN_TX_*` error codes are used for CAN specific error return codes from |
| * @a can_send() and for `error_flags` values in @a can_tx_callback_t(). |
| * |
| * `CAN_NO_FREE_FILTER` is returned by `can_add_rx_*()` if no free filters are |
| * available. `CAN_TIMEOUT` indicates that @a can_recover() timed out. |
| * |
| * @deprecated Use the corresponding errno definitions instead. |
| * |
| * @{ |
| */ |
| |
| /** Transmitted successfully. */ |
| #define CAN_TX_OK (0) __DEPRECATED_MACRO |
| /** General transmit error. */ |
| #define CAN_TX_ERR (-EIO) __DEPRECATED_MACRO |
| /** Bus arbitration lost during transmission. */ |
| #define CAN_TX_ARB_LOST (-EBUSY) __DEPRECATED_MACRO |
| /** CAN controller is in bus off state. */ |
| #define CAN_TX_BUS_OFF (-ENETDOWN) __DEPRECATED_MACRO |
| /** Unknown error. */ |
| #define CAN_TX_UNKNOWN (CAN_TX_ERR) __DEPRECATED_MACRO |
| /** Invalid parameter. */ |
| #define CAN_TX_EINVAL (-EINVAL) __DEPRECATED_MACRO |
| /** No free filters available. */ |
| #define CAN_NO_FREE_FILTER (-ENOSPC) __DEPRECATED_MACRO |
| /** Operation timed out. */ |
| #define CAN_TIMEOUT (-EAGAIN) __DEPRECATED_MACRO |
| |
| /** @} */ |
| |
| /** |
| * @brief Configure operation of a host controller. |
| * |
| * @deprecated Use @a can_set_bitrate() and @a can_set_mode() instead. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param mode Operation mode. |
| * @param bitrate bus-speed in Baud/s. |
| * |
| * @retval 0 If successful. |
| * @retval -EIO General input/output error, failed to configure device. |
| */ |
| __deprecated static inline int can_configure(const struct device *dev, enum can_mode mode, |
| uint32_t bitrate) |
| { |
| int err; |
| |
| if (bitrate > 0) { |
| err = can_set_bitrate(dev, bitrate, bitrate); |
| if (err != 0) { |
| return err; |
| } |
| } |
| |
| return can_set_mode(dev, mode); |
| } |
| |
| /** |
| * Allow including drivers/can.h even if CONFIG_CAN is not selected. |
| */ |
| #ifndef CONFIG_CAN_WORKQ_FRAMES_BUF_CNT |
| #define CONFIG_CAN_WORKQ_FRAMES_BUF_CNT 4 |
| #endif |
| |
| /** |
| * @brief CAN frame buffer structure |
| * |
| * Used internally by @a zcan_work struct |
| */ |
| struct can_frame_buffer { |
| struct zcan_frame buf[CONFIG_CAN_WORKQ_FRAMES_BUF_CNT]; |
| uint16_t head; |
| uint16_t tail; |
| }; |
| |
| /** |
| * @brief CAN work structure |
| * |
| * Used to attach a work queue to a filter. |
| */ |
| struct zcan_work { |
| struct k_work work_item; |
| struct k_work_q *work_queue; |
| struct can_frame_buffer buf; |
| can_rx_callback_t cb; |
| void *cb_arg; |
| }; |
| |
| /** |
| * @brief Attach a CAN work queue with a given CAN filter |
| * |
| * Attach a work queue to CAN identifiers specified by a filter. Whenever a |
| * frame matching the filter is received by the CAN controller, the frame is |
| * pushed to the buffer of the @a zcan_work structure and the work element is |
| * put in the workqueue. |
| * |
| * If a frame matches more than one attached filter, the priority of the match |
| * is hardware dependent. |
| * |
| * The same CAN work queue can be attached to more than one filter. |
| * |
| * @see @a can_remove_rx_filter() |
| * |
| * @note The work queue must be initialized before and the caller must have |
| * appropriate permissions on it. |
| * |
| * @deprecated Use @a can_add_rx_filter_msgq() along with @a |
| * k_work_poll_submit() instead. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param work_q Pointer to the already initialized @a zcan_work queue. |
| * @param work Pointer to a @a zcan_work structure, which will be initialized. |
| * @param callback This function is called by the work queue whenever a frame |
| * matching the filter is received. |
| * @param user_data User data to pass to callback function. |
| * @param filter Pointer to a @a zcan_filter structure defining the filter. |
| * |
| * @retval filter_id on success. |
| * @retval -ENOSPC if there are no free filters. |
| */ |
| __deprecated int can_attach_workq(const struct device *dev, struct k_work_q *work_q, |
| struct zcan_work *work, can_rx_callback_t callback, |
| void *user_data, const struct zcan_filter *filter); |
| |
| /** |
| * @deprecated Use can_add_rx_filter() instead. |
| */ |
| __deprecated static inline int can_attach_isr(const struct device *dev, can_rx_callback_t isr, |
| void *user_data, const struct zcan_filter *filter) |
| { |
| return can_add_rx_filter(dev, isr, user_data, filter); |
| } |
| |
| /** |
| * @deprecated Use CAN_MSGQ_DEFINE() instead. |
| */ |
| #define CAN_DEFINE_MSGQ(name, size) CAN_MSGQ_DEFINE(name, size) __DEPRECATED_MACRO |
| |
| /** |
| * @deprecated Use can_add_rx_filter_msgq() instead. |
| */ |
| __deprecated static inline int can_attach_msgq(const struct device *dev, struct k_msgq *msg_q, |
| const struct zcan_filter *filter) |
| { |
| return can_add_rx_filter_msgq(dev, msg_q, filter); |
| } |
| |
| /** |
| * @deprecated Use can_remove_rx_filter() instead. |
| */ |
| __deprecated static inline void can_detach(const struct device *dev, int filter_id) |
| { |
| can_remove_rx_filter(dev, filter_id); |
| } |
| |
| /** |
| * @deprecated Use can_set_state_change_callback() instead. |
| */ |
| __deprecated static inline void can_register_state_change_isr(const struct device *dev, |
| can_state_change_callback_t isr) |
| { |
| can_set_state_change_callback(dev, isr, NULL); |
| } |
| |
| /** |
| * @brief Wrapper function for writing data to the CAN bus. |
| * |
| * Simple wrapper function for @a can_send() without the need for filling in a |
| * @a zcan_frame struct. This function blocks until the data is sent or a |
| * timeout occurs. |
| * |
| * By default, the CAN controller will automatically retry transmission in case |
| * of lost bus arbitration or missing acknowledge. Some CAN controllers support |
| * disabling automatic retransmissions ("one-shot" mode) via a devicetree |
| * property. |
| * |
| * @deprecated Use @a can_send() instead. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param data Pointer to the data to write. |
| * @param length Number of bytes to write (max. 8). |
| * @param id CAN identifier used for writing. |
| * @param rtr Write as data frame or Remote Transmission Request (RTR) frame. |
| * @param timeout Timeout waiting for an empty TX mailbox or ``K_FOREVER``. |
| * |
| * @retval 0 if successful. |
| * @retval -EINVAL if an invalid parameter was passed to the function. |
| * @retval -ENETDOWN if the CAN controller is in bus-off state. |
| * @retval -EBUSY if CAN bus arbitration was lost (only applicable if automatic |
| * retransmissions are disabled). |
| * @retval -EIO if a general transmit error occurred (e.g. missing ACK if |
| * automatic retransmissions are disabled). |
| * @retval -EAGAIN on timeout. |
| */ |
| __deprecated static inline int can_write(const struct device *dev, const uint8_t *data, |
| uint8_t length, uint32_t id, enum can_rtr rtr, |
| k_timeout_t timeout) |
| { |
| struct zcan_frame frame; |
| |
| if (length > 8) { |
| return -EINVAL; |
| } |
| |
| frame.id = id; |
| |
| if (id > CAN_MAX_STD_ID) { |
| frame.id_type = CAN_EXTENDED_IDENTIFIER; |
| } else { |
| frame.id_type = CAN_STANDARD_IDENTIFIER; |
| } |
| |
| frame.dlc = length; |
| frame.rtr = rtr; |
| memcpy(frame.data, data, length); |
| |
| return can_send(dev, &frame, timeout, NULL, NULL); |
| } |
| |
| /** @endcond */ |
| |
| /** |
| * @} |
| */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #include <syscalls/can.h> |
| |
| #endif /* ZEPHYR_INCLUDE_DRIVERS_CAN_H_ */ |