diff --git a/include/drivers/can.h b/include/drivers/can.h index ca3fd42a3a4..e0252a129ae 100644 --- a/include/drivers/can.h +++ b/include/drivers/can.h @@ -1,10 +1,5 @@ -/** - * @file - * - * @brief Public APIs for the CAN drivers. - */ - /* + * Copyright (c) 2021 Vestas Wind Systems A/S * Copyright (c) 2018 Alexander Wachter * * SPDX-License-Identifier: Apache-2.0 @@ -13,13 +8,6 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_CAN_H_ #define ZEPHYR_INCLUDE_DRIVERS_CAN_H_ -/** - * @brief CAN Interface - * @defgroup can_interface CAN Interface - * @ingroup io_interfaces - * @{ - */ - #include #include #include @@ -29,192 +17,185 @@ extern "C" { #endif -#define CAN_EX_ID (1 << 31) -#define CAN_MAX_STD_ID (0x7FF) -#define CAN_STD_ID_MASK CAN_MAX_STD_ID -#define CAN_EXT_ID_MASK (0x1FFFFFFF) -#define CAN_MAX_DLC (8) -#define CANFD_MAX_DLC CONFIG_CANFD_MAX_DLC +/** + * @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 8 +#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 - 8) * 4 +#define CAN_MAX_DLEN (CONFIG_CANFD_MAX_DLC + (CONFIG_CANFD_MAX_DLC - 8U) * 4U) #elif CONFIG_CANFD_MAX_DLC == 13 -#define CAN_MAX_DLEN 32 +#define CAN_MAX_DLEN 32U #elif CONFIG_CANFD_MAX_DLC == 14 -#define CAN_MAX_DLEN 48 +#define CAN_MAX_DLEN 48U #elif CONFIG_CANFD_MAX_DLC == 15 -#define CAN_MAX_DLEN 64 +#define CAN_MAX_DLEN 64U #endif #endif /* CONFIG_CANFD_MAX_DLC */ -/* CAN_TX_* are the error flags from tx_callback and send.*/ -/** send successfully */ -#define CAN_TX_OK (0) -/** general send error */ -#define CAN_TX_ERR (-2) -/** bus arbitration lost during sending */ -#define CAN_TX_ARB_LOST (-3) -/** controller is in bus off state */ -#define CAN_TX_BUS_OFF (-4) -/** unexpected error */ -#define CAN_TX_UNKNOWN (-5) +/** + * 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 +/** @endcond */ -/** invalid parameter */ -#define CAN_TX_EINVAL (-22) +/** @} */ -/** attach_* failed because there is no unused filter left*/ +/** + * @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_attach_*()` if no free filters are + * available. `CAN_TIMEOUT` indicates that @a can_recover() timed out. + * + * @{ + */ + +/** Transmitted successfully. */ +#define CAN_TX_OK (0) +/** General transmit error. */ +#define CAN_TX_ERR (-2) +/** Bus arbitration lost during transmission. */ +#define CAN_TX_ARB_LOST (-3) +/** CAN controller is in bus off state. */ +#define CAN_TX_BUS_OFF (-4) +/** Unknown error. */ +#define CAN_TX_UNKNOWN (-5) +/** Invalid parameter. */ +#define CAN_TX_EINVAL (-22) +/** No free filters available. */ #define CAN_NO_FREE_FILTER (-1) +/** Operation timed out. */ +#define CAN_TIMEOUT (-1) -/** operation timed out*/ -#define CAN_TIMEOUT (-1) - -/** - * @brief Statically define and initialize a can message queue. - * - * The message queue's ring buffer contains space for @a size messages. - * - * @param name Name of the message queue. - * @param size Number of can messages. - */ -#define CAN_DEFINE_MSGQ(name, size) \ - K_MSGQ_DEFINE(name, sizeof(struct zcan_frame), size, 4) - -/** - * @brief Define if the message has a standard (11bit) or extended (29bit) - * identifier - */ -enum can_ide { - CAN_STANDARD_IDENTIFIER, - CAN_EXTENDED_IDENTIFIER -}; - -/** - * @brief Defines if the message is a data or remote frame - */ -enum can_rtr { - CAN_DATAFRAME, - CAN_REMOTEREQUEST -}; +/** @} */ /** * @brief Defines the mode of the CAN controller */ enum can_mode { - /*Normal mode*/ + /* Normal mode. */ CAN_NORMAL_MODE, - /*Controller is not allowed to send dominant bits*/ + /* Controller is not allowed to send dominant bits. */ CAN_SILENT_MODE, - /*Controller is in loopback mode (receive own messages)*/ + /* Controller is in loopback mode (receives own frames). */ CAN_LOOPBACK_MODE, - /*Combination of loopback and silent*/ + /* Combination of loopback and silent modes. */ CAN_SILENT_LOOPBACK_MODE }; /** - * @brief Defines the possible states of the CAN bus + * @brief Defines the state of the CAN bus */ enum can_state { + /** Error-active state. */ CAN_ERROR_ACTIVE, + /** Error-passive state. */ CAN_ERROR_PASSIVE, + /** Bus-off state. */ CAN_BUS_OFF, + /** Bus state unknown. */ CAN_BUS_UNKNOWN }; /** - * Controller Area Network Identifier structure for Linux compatibility. - * - * The fields in this type are: - * - * +------+--------------------------------------------------------------+ - * | 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) | - * +------+--------------------------------------------------------------+ + * @brief Defines if the CAN frame has a standard (11-bit) or extended (29-bit) + * CAN identifier */ -typedef uint32_t canid_t; - -/** - * @brief CAN frame structure that is compatible with Linux. This is mainly - * used by Socket CAN code. - * - * @details Used to pass CAN messages from userspace to the socket CAN and vice - * versa. - */ -struct can_frame { - /** 32 bit CAN_ID + EFF/RTR/ERR flags */ - canid_t can_id; - - /** The length of the message */ - uint8_t can_dlc; - - /** @cond INTERNAL_HIDDEN */ - uint8_t pad; /* padding */ - uint8_t res0; /* reserved / padding */ - uint8_t res1; /* reserved / padding */ - /** @endcond */ - - /** The message data */ - uint8_t data[CAN_MAX_DLEN]; +enum can_ide { + /** Standard (11-bit) CAN identifier. */ + CAN_STANDARD_IDENTIFIER, + /** Extended (29-bit) CAN identifier. */ + CAN_EXTENDED_IDENTIFIER }; /** - * @brief CAN filter that is compatible with Linux. This is mainly used by - * Socket CAN code. - * - * @details A filter matches, when "received_can_id & mask == can_id & mask" + * @brief Defines if the CAN frame is a data frame or a Remote Transmission Request (RTR) frame */ -struct can_filter { - canid_t can_id; - canid_t can_mask; +enum can_rtr { + /** Data frame. */ + CAN_DATAFRAME, + /** Remote Transmission Request (RTR) frame. */ + CAN_REMOTEREQUEST }; /** - * @brief CAN message structure - * - * Used to pass can messages from userspace to the driver and - * from driver to userspace + * @brief CAN frame structure */ struct zcan_frame { - /** Message identifier*/ + /** Standard (11-bit) or extended (29-bit) CAN identifier. */ uint32_t id : 29; - /** Frame is in the CAN-FD frame format */ + /** Frame is in the CAN-FD frame format if set to true. */ uint32_t fd : 1; - /** Set the message to a transmission request instead of data frame - * use can_rtr enum for assignment - */ + /** Remote Transmission Request (RTR) flag. Use @a can_rtr enum for assignment. */ uint32_t rtr : 1; - /** Indicates the identifier type (standard or extended) - * use can_ide enum for assignment - */ + /** CAN identifier type (standard or extended). Use @a can_ide enum for assignment. */ uint32_t id_type : 1; - /** The length of the message (max. 8) in byte */ + /** Data Length Code (DLC) indicating data length in bytes. */ uint8_t dlc; - /** Baud Rate Switch. Frame transfer with different timing during - * the data phase. Only valid for CAN-FD - */ + /** Baud Rate Switch (BRS). Only valid for CAN-FD. */ uint8_t brs : 1; - /** Reserved for future flags */ - uint8_t res : 7; -#if defined(CONFIG_CAN_RX_TIMESTAMP) - /** Timer value of the CAN free-running timer. - * The timer is incremented every bit time and captured at the start - * of frame bit (SOF). + /** @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 */ + uint8_t res0; /* reserved/padding. */ + uint8_t res1; /* reserved/padding. */ /** @endcond */ #endif /** The frame payload data. */ @@ -226,156 +207,127 @@ struct zcan_frame { /** * @brief CAN filter structure - * - * Used to pass can identifier filter information to the driver. - * rtr_mask and *_id_mask are used to mask bits of the RTR and id fields. - * If the mask bit is 0, the value of the corresponding bit in the id or rtr - * field don't care for the filter matching. - * */ struct zcan_filter { - /** target state of the identifier */ + /** CAN identifier to match. */ uint32_t id : 29; + /** @cond INTERNAL_HIDDEN */ uint32_t res0 : 1; - /** target state of the RTR bit */ + /** @endcond */ + /** Match data frame or Remote Transmission Request (RTR) frame. */ uint32_t rtr : 1; - /** Indicates the identifier type (standard or extended) - * use can_ide enum for assignment - */ + /** Standard or extended CAN identifier. Use @a can_ide enum for assignment. */ uint32_t id_type : 1; - /** identifier mask*/ - uint32_t id_mask : 29; + /** 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; - /** RTR bit mask */ + /** @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 bus error count structure - * - * Used to pass the bus error counters to userspace + * @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; }; -/** SWJ value to indicate that the SJW should not be changed */ -#define CAN_SJW_NO_CHANGE 0 - /** - * @brief CAN bus timings + * @brief CAN bus timing structure * - * Used to pass bus timing values to the config and bitrate calculator function. + * 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. - * prop_seg and phase_seg1 affect the sampling-point in the same way and some + * 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 tq + * always has a length of 1 time quantum (see below). * - * +---------+----------+------------+------------+ - * |sync_seg | prop_seg | phase_seg1 | phase_seg2 | - * +---------+----------+------------+------------+ - * ^ - * Sampling-Point + * @code{.unparsed} * - * 1 tq (time quantum) 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 resynchronization jump width (SJW) defines the amount of time quantum - * the sample point can be moved. - * The sample point is moved when resynchronization is needed. + * +---------+----------+------------+------------+ + * |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*/ + /** Synchronisation jump width. */ uint16_t sjw; - /** Propagation Segment */ + /** Propagation segment. */ uint16_t prop_seg; - /** Phase Segment 1 */ + /** Phase segment 1. */ uint16_t phase_seg1; - /** Phase Segment 2 */ + /** Phase segment 2. */ uint16_t phase_seg2; - /** Prescaler value */ + /** Prescaler value. */ uint16_t prescaler; }; -/** - * @cond INTERNAL_HIDDEN - * - * For internal use only, skip these in public documentation. - */ - /** * @typedef can_tx_callback_t - * @brief Define the application callback handler function signature + * @brief Defines the application callback handler function signature * - * @param error_flags status of the performed send operation - * @param arg argument that was passed when the message was sent + * @param error_flags Status of the performed send operation. + * @param user_data User data provided when the frame was sent. */ -typedef void (*can_tx_callback_t)(uint32_t error_flags, void *arg); +typedef void (*can_tx_callback_t)(uint32_t error_flags, void *user_data); /** * @typedef can_rx_callback_t - * @brief Define the application callback handler function signature - * for receiving. + * @brief Defines the application callback handler function signature for receiving. * - * @param msg received message - * @param arg argument that was passed when the filter was attached + * @param frame Received frame. + * @param user_data User data provided when the filter was attached. */ -typedef void (*can_rx_callback_t)(struct zcan_frame *msg, void *arg); +typedef void (*can_rx_callback_t)(struct zcan_frame *frame, void *user_data); /** * @typedef can_state_change_isr_t - * @brief Defines the state change isr handler function signature + * @brief Defines the state change Interrupt Service Routine (ISR) handler function signature * - * @param state state of the node - * @param err_cnt struct with the error counter values + * @param state State of the CAN controller. + * @param err_cnt CAN controller error counter values. */ -typedef void(*can_state_change_isr_t)(enum can_state state, - struct can_bus_err_cnt err_cnt); +typedef void (*can_state_change_isr_t)(enum can_state state, struct can_bus_err_cnt err_cnt); -typedef int (*can_set_timing_t)(const struct device *dev, - const struct can_timing *timing, - const struct can_timing *timing_data); +/** + * @cond INTERNAL_HIDDEN + * + * For internal driver use only, skip these in public documentation. + */ -typedef int (*can_set_mode_t)(const struct device *dev, enum can_mode mode); - -typedef int (*can_send_t)(const struct device *dev, - const struct zcan_frame *msg, - k_timeout_t timeout, can_tx_callback_t callback_isr, - void *callback_arg); - - -typedef int (*can_attach_msgq_t)(const struct device *dev, - struct k_msgq *msg_q, - const struct zcan_filter *filter); - -typedef int (*can_attach_isr_t)(const struct device *dev, - can_rx_callback_t isr, - void *callback_arg, - const struct zcan_filter *filter); - -typedef void (*can_detach_t)(const struct device *dev, int filter_id); - -typedef int (*can_recover_t)(const struct device *dev, k_timeout_t timeout); - -typedef enum can_state (*can_get_state_t)(const struct device *dev, - struct can_bus_err_cnt *err_cnt); - -typedef void(*can_register_state_change_isr_t)(const struct device *dev, - can_state_change_isr_t isr); - -typedef int (*can_get_core_clock_t)(const struct device *dev, uint32_t *rate); - -typedef int (*can_get_max_filters_t)(const struct device *dev, - enum can_ide id_type); - -#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; @@ -395,15 +347,95 @@ struct zcan_work { void *cb_arg; }; +/** + * @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_isr, + void *user_data); + +/** + * @typedef can_attach_isr_t + * @brief Callback API upon attaching an RX filter ISR + * See @a can_attach_isr() for argument description + */ +typedef int (*can_attach_isr_t)(const struct device *dev, + can_rx_callback_t isr, + void *user_data, + const struct zcan_filter *filter); + +/** + * @typedef can_detach_t + * @brief Callback API upon detaching an RX filter + * See @a can_detach() for argument description + */ +typedef void (*can_detach_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 get the CAN controller state + * See @a can_get_state() for argument description + */ +typedef enum can_state (*can_get_state_t)(const struct device *dev, + struct can_bus_err_cnt *err_cnt); + +/** + * @typedef can_register_state_change_isr_t + * @brief Callback API upon registering a state change ISR + * See @a can_register_state_change_isr() for argument description + */ +typedef void(*can_register_state_change_isr_t)(const struct device *dev, + can_state_change_isr_t isr); + +/** + * @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_attach_isr_t attach_isr; can_detach_t detach; -#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY +#if !defined(CONFIG_CAN_AUTO_BUS_OFF_RECOVERY) || defined(__DOXYGEN__) can_recover_t recover; -#endif +#endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ can_get_state_t get_state; can_register_state_change_isr_t register_state_change_isr; can_get_core_clock_t get_core_clock; @@ -412,378 +444,126 @@ __subsystem struct can_driver_api { struct can_timing timing_min; /* Max values for the timing registers */ struct can_timing timing_max; -#ifdef CONFIG_CAN_FD_MODE +#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 +#endif /* CONFIG_CAN_FD_MODE */ }; +/** @endcond */ + /** - * @endcond + * @name CAN controller configuration + * + * @{ */ /** - * @brief Convert the DLC to the number of bytes + * @brief Get the CAN core clock rate * - * This function converts a the Data Length Code to the number of bytes. - * - * @param dlc The Data Length Code - * - * @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 a number of bytes to the DLC - * - * This function converts a number of bytes to the Data Length Code - * - * @param num_bytes The number of bytes - * - * @retval The 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; -} - -/** - * @brief Perform data transfer to CAN bus. - * - * This routine provides a generic interface to perform data transfer - * to the CAN bus. Use can_write() for simple write. - * - * @param dev Pointer to the device structure for the driver instance. - * @param msg Message to transfer. - * @param timeout Waiting for empty tx mailbox timeout or K_FOREVER. - * @param callback_isr Is called when message was sent or a transmission error - * occurred. If NULL, this function is blocking until - * message is sent. This must be NULL if called from user - * mode. - * @param callback_arg This will be passed whenever the isr is called. - * - * @retval 0 If successful. - * @retval CAN_TX_* on failure. - */ -__syscall int can_send(const struct device *dev, const struct zcan_frame *msg, - k_timeout_t timeout, can_tx_callback_t callback_isr, - void *callback_arg); - -static inline int z_impl_can_send(const struct device *dev, - const struct zcan_frame *msg, - k_timeout_t timeout, - can_tx_callback_t callback_isr, - void *callback_arg) -{ - const struct can_driver_api *api = - (const struct can_driver_api *)dev->api; - - return api->send(dev, msg, timeout, callback_isr, callback_arg); -} - -/* - * Derived CAN APIs -- all implemented in terms of can_send() - */ - -/** - * @brief Write a set amount of data to the CAN bus. - * - * This routine writes a set amount of data synchronously. + * 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 data Data to send. - * @param length Number of bytes to write (max. 8). - * @param id Identifier of the can message. - * @param rtr Send remote transmission request or data frame - * @param timeout Waiting for empty tx mailbox timeout or K_FOREVER + * @param[out] rate CAN core clock rate in Hz. * - * @retval 0 If successful. - * @retval -EIO General input / output error. - * @retval -EINVAL if length > 8. - */ -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 msg; - - if (length > 8) { - return -EINVAL; - } - - msg.id = id; - - if (id > CAN_MAX_STD_ID) { - msg.id_type = CAN_EXTENDED_IDENTIFIER; - } else { - msg.id_type = CAN_STANDARD_IDENTIFIER; - } - - msg.dlc = length; - msg.rtr = rtr; - memcpy(msg.data, data, length); - - return can_send(dev, &msg, timeout, NULL, NULL); -} - -/** - * @brief Attach a CAN work queue to a single or group of identifiers. - * - * This routine attaches a work queue to identifiers specified by a filter. - * Whenever the filter matches, the message is pushed to the buffer - * of the zcan_work structure and the work element is put to the workqueue. - * If a message passes more than one filter the priority of the match - * is hardware dependent. - * A CAN work queue can be attached to more than one filter. - * The work queue must be initialized before and the caller must have - * appropriate permissions on it. - * - * @param dev Pointer to the device structure for the driver instance. - * @param work_q Pointer to the already initialized work queue. - * @param work Pointer to a zcan_work. The work will be initialized. - * @param callback This function is called by workq whenever a message arrives. - * @param callback_arg Is passed to the callback when called. - * @param filter Pointer to a zcan_filter structure defining the id - * filtering. - * - * @retval filter_id on success. - * @retval CAN_NO_FREE_FILTER if there is no filter left. - */ -int can_attach_workq(const struct device *dev, struct k_work_q *work_q, - struct zcan_work *work, - can_rx_callback_t callback, void *callback_arg, - const struct zcan_filter *filter); - -/** - * @brief Attach a message queue to a single or group of identifiers. - * - * This routine attaches a message queue to identifiers specified by - * a filter. Whenever the filter matches, the message is pushed to the queue - * If a message passes more than one filter the priority of the match - * is hardware dependent. - * A message queue can be attached to more than one filter. - * The message queue must me initialized before, and the caller must have - * appropriate permissions on it. - * - * @param dev Pointer to the device structure for the driver instance. - * @param msg_q Pointer to the already initialized message queue. - * @param filter Pointer to a zcan_filter structure defining the id - * filtering. - * - * @retval filter_id on success. - * @retval CAN_NO_FREE_FILTER if there is no filter left. - */ -__syscall int can_attach_msgq(const struct device *dev, struct k_msgq *msg_q, - const struct zcan_filter *filter); - -/** - * @brief Attach an isr callback function to a single or group of identifiers. - * - * This routine attaches an isr callback to identifiers specified by - * a filter. Whenever the filter matches, the callback function is called - * with isr context. - * If a message passes more than one filter the priority of the match - * is hardware dependent. - * A callback function can be attached to more than one filter. - * - * @param dev Pointer to the device structure for the driver instance. - * @param isr Callback function pointer. - * @param callback_arg This will be passed whenever the isr is called. - * @param filter Pointer to a zcan_filter structure defining the id - * filtering. - * - * @retval filter_id on success. - * @retval CAN_NO_FREE_FILTER if there is no filter left. - */ -static inline int can_attach_isr(const struct device *dev, - can_rx_callback_t isr, - void *callback_arg, - const struct zcan_filter *filter) -{ - const struct can_driver_api *api = - (const struct can_driver_api *)dev->api; - - return api->attach_isr(dev, isr, callback_arg, filter); -} - -/** - * @brief Detach an isr or message queue from the identifier filtering. - * - * This routine detaches an isr callback or message queue from the identifier - * filtering. - * - * @param dev Pointer to the device structure for the driver instance. - * @param filter_id filter id returned by can_attach_isr or can_attach_msgq. - * - * @retval none - */ -__syscall void can_detach(const struct device *dev, int filter_id); - -static inline void z_impl_can_detach(const struct device *dev, int filter_id) -{ - const struct can_driver_api *api = - (const struct can_driver_api *)dev->api; - - return api->detach(dev, filter_id); -} - -/** - * @brief Read the core clock value - * - * Returns the core clock value. One time quantum is 1/core clock. - * - * @param dev Pointer to the device structure for the driver instance. - * @param[out] rate controller clock rate - * - * @retval 0 on success - * @retval negative on error + * @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) +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; + const struct can_driver_api *api = (const struct can_driver_api *)dev->api; return api->get_core_clock(dev, rate); } -/** - * @brief Retrieve maximum number of filters - * - * @param dev Pointer to the device structure for the driver instance. - * @param id_type CAN identifier type (standard or extended) - * - * @retval Number of maximum concurrent filters - * @retval -EIO General input / output error, failed to query device - * @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); -} - /** * @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 given for the, - * give parameters, -EINVAL is returned. - * The sample_pnt does not always match perfectly. The algorithm tries to find - * the best match possible. + * 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 res Result is written into the can_timing struct provided. - * @param bitrate Target bitrate in bits/s + * @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 Positive sample point error on success - * @retval -EINVAL if there is no solution for the desired values - * @retval -EIO if core_clock is not available + * @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); -#ifdef CONFIG_CAN_FD_MODE +#if defined(CONFIG_CAN_FD_MODE) || defined(__DOXYGEN__) /** * @brief Calculate timing parameters for the data phase * - * Same as can_calc_timing but with the max and min values from 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 res Result is written into the can_timing struct provided. + * @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 data phase in permille of the entire bit time. + * @param sample_pnt Sampling point for the data phase in permille of the entire bit time. * - * @retval Positive sample point error on success - * @retval -EINVAL if there is no solution for the desired values - * @retval -EIO if core_clock is not available + * @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 +#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. - * sjw, prop_seg, phase_seg1 and phase_seg2 must be given. - * The returned bitrate error is reminder of the devision of the clockrate by + * 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 bitrate error - * @retval negative on error + * @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); -/** - * @brief Set the controller to the given 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. +/** Synchronization Jump Width (SJW) value to indicate that the SJW should not + * be changed by the timing calculation. */ -__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); -} +#define CAN_SJW_NO_CHANGE 0 /** - * @brief Configure timing of a host controller. + * @brief Configure the bus timing of a CAN controller. * * If the sjw equals CAN_SJW_NO_CHANGE, the sjw parameter is not changed. * - * The second parameter timing_data is only relevant for CAN-FD. - * If the controller does not support CAN-FD or the FD mode is not enabled, - * this parameter is ignored. + * @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) + * @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. + * @retval -EIO General input/output error, failed to configure device. */ __syscall int can_set_timing(const struct device *dev, const struct can_timing *timing, @@ -793,27 +573,45 @@ 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; + const struct can_driver_api *api = (const struct can_driver_api *)dev->api; return api->set_timing(dev, timing, timing_data); } /** - * @brief Set the bitrate of the CAN controller + * @brief Set the CAN controller to the given operation mode * - * The second parameter bitrate_data is only relevant for CAN-FD. - * If the controller does not support CAN-FD or the FD mode is not enabled, - * this parameter is ignored. - * The sample point is set to the CiA DS 301 reccommended value of 87.5% - * - * @param dev Pointer to the device structure for the driver instance. - * @param bitrate Desired arbitration phase bitrate - * @param bitrate_data Desired data phase bitrate + * @param dev Pointer to the device structure for the driver instance. + * @param mode Operation mode. * * @retval 0 If successful. - * @retval -EINVAL bitrate cannot be reached. - * @retval -EIO General input / output error, failed to set bitrate. + * @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, @@ -841,26 +639,31 @@ static inline int can_set_bitrate(const struct device *dev, timing_data.sjw = CAN_SJW_NO_CHANGE; return can_set_timing(dev, &timing, &timing_data); -#else +#else /* CONFIG_CAN_FD_MODE */ return can_set_timing(dev, &timing, NULL); -#endif /* CONFIG_CAN_FD_MODE */ +#endif /* !CONFIG_CAN_FD_MODE */ } /** * @brief Configure operation of a host controller. * + * @warning This function is 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 + * @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. + * @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) { - int err = can_set_bitrate(dev, bitrate, bitrate); + err = can_set_bitrate(dev, bitrate, bitrate); if (err != 0) { return err; } @@ -869,25 +672,263 @@ __deprecated static inline int can_configure(const struct device *dev, enum can_ return can_set_mode(dev, mode); } +/** @} */ + /** - * @brief Get current state + * @name Transmitting CAN frames * - * Returns the actual state of the CAN controller. + * @{ + */ + +/** + * @brief Transmit a CAN frame on the CAN bus + * + * Transmit a CAN fram on the CAN bus with optional timeout and completion + * callback function. + * + * @see can_write() for a simplified API wrapper. + * + * @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 CAN_TX_* on failure. + */ +__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); +} + +/** + * @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. * * @param dev Pointer to the device structure for the driver instance. - * @param err_cnt Pointer to the err_cnt destination structure or NULL. + * @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 -EIO General input/output error. + * @retval -EINVAL if length > 8. + * @retval CAN_TX_* on failure. + */ +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); +} + +/** @} */ + +/** + * @name Receiving CAN frames + * + * @{ + */ + +/** + * @brief Attach a callback function with a given CAN filter + * + * Attach a callback to CAN identifiers specified by a filter. Whenever a 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 attached to more than one filter. + * + * @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 CAN_NO_FREE_FILTER if there are no free filters. + */ +static inline int can_attach_isr(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->attach_isr(dev, callback, user_data, filter); +} + +/** + * @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. + * + * @note The work queue must be initialized before and the caller must have + * appropriate permissions on it. + * + * @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 CAN_NO_FREE_FILTER if there are no free filters. + */ +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); + +/** + * @brief Statically define and initialize a CAN RX message queue. + * + * The message queue's ring buffer contains space for @a size CAN frames. + * + * @param name Name of the message queue. + * @param size Number of CAN frames. + */ +#define CAN_DEFINE_MSGQ(name, size) \ + K_MSGQ_DEFINE(name, sizeof(struct zcan_frame), size, 4) + +/** + * @brief Attach a message queue with a given filter + * + * Attach a message 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 message queue. + * + * If a frame matches more than one attached filter, the priority of the match + * is hardware dependent. + * + * A message queue can be attached to more than one filter. + * + * @note The message queue must me initialized before, and the caller must have + * appropriate permissions on it. + * + * @param dev Pointer to the device structure for the driver instance. + * @param msg_q 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 CAN_NO_FREE_FILTER if there are no free filters. + */ +__syscall int can_attach_msgq(const struct device *dev, struct k_msgq *msg_q, + const struct zcan_filter *filter); + +/** + * @brief Detach an ISR, CAN work queue, or CAN message queue RX filter + * + * This routine detaches an CAN RX filter based on the filter ID returned by @a + * can_attach_isr(), @a can_attach_workq(), or @a can_attach_msgq(). + * + * @param dev Pointer to the device structure for the driver instance. + * @param filter_id Filter ID + */ +__syscall void can_detach(const struct device *dev, int filter_id); + +static inline void z_impl_can_detach(const struct device *dev, int filter_id) +{ + const struct can_driver_api *api = (const struct can_driver_api *)dev->api; + + return api->detach(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] err_cnt Pointer to the err_cnt destination structure or NULL. * * @retval state */ __syscall enum can_state can_get_state(const struct device *dev, struct can_bus_err_cnt *err_cnt); -static inline -enum can_state z_impl_can_get_state(const struct device *dev, - struct can_bus_err_cnt *err_cnt) +static inline enum can_state z_impl_can_get_state(const struct device *dev, + struct can_bus_err_cnt *err_cnt) { - const struct can_driver_api *api = - (const struct can_driver_api *)dev->api; + const struct can_driver_api *api = (const struct can_driver_api *)dev->api; return api->get_state(dev, err_cnt); } @@ -897,55 +938,161 @@ enum can_state z_impl_can_get_state(const struct device *dev, * * 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. + * @param timeout Timeout for waiting for the recovery or ``K_FOREVER``. * * @retval 0 on success. * @retval CAN_TIMEOUT on timeout. */ -#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY +#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) +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; + const struct can_driver_api *api = (const struct can_driver_api *)dev->api; return api->recover(dev, timeout); } -#else +#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) +static inline int z_impl_can_recover(const struct device *dev, k_timeout_t timeout) { return 0; } -#endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ +#endif /* !CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ /** - * @brief Register an ISR callback for state change interrupt + * @brief Register an ISR callback for the CAN controller state change interrupt * - * Only one callback can be registered per controller. - * Calling this function again, overrides the previous call. + * 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 isr Pointer to ISR + * @param isr ISR callback function. */ -static inline -void can_register_state_change_isr(const struct device *dev, - can_state_change_isr_t isr) +static inline void can_register_state_change_isr(const struct device *dev, + can_state_change_isr_t isr) { - const struct can_driver_api *api = - (const struct can_driver_api *)dev->api; + const struct can_driver_api *api = (const struct can_driver_api *)dev->api; return api->register_state_change_isr(dev, isr); } +/** @} */ + /** - * @brief Converter that translates between can_frame and zcan_frame structs. + * @name CAN utility functions * - * @param frame Pointer to can_frame struct. + * @{ + */ + +/** + * @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, @@ -959,30 +1106,27 @@ static inline void can_copy_frame_to_zframe(const struct can_frame *frame, } /** - * @brief Converter that translates between zcan_frame and can_frame structs. + * @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. + * @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_id = (zframe->id_type << 31) | (zframe->rtr << 30) | zframe->id; frame->can_dlc = zframe->dlc; memcpy(frame->data, zframe->data, sizeof(frame->data)); } /** - * @brief Converter that translates between can_filter and zcan_frame_filter - * structs. + * @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_frame_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) +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; @@ -992,15 +1136,13 @@ void can_copy_filter_to_zfilter(const struct can_filter *filter, } /** - * @brief Converter that translates between zcan_filter and can_filter - * structs. + * @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. + * @param filter Pointer to can_filter struct. */ -static inline -void can_copy_zfilter_to_filter(const struct zcan_filter *zfilter, - struct can_filter *filter) +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; @@ -1008,12 +1150,16 @@ void can_copy_zfilter_to_filter(const struct zcan_filter *zfilter, (zfilter->id_type << 31) | zfilter->id_mask; } -#ifdef __cplusplus -} -#endif +/** @} */ + /** * @} */ + +#ifdef __cplusplus +} +#endif + #include #endif /* ZEPHYR_INCLUDE_DRIVERS_CAN_H_ */