diff options
| author | wdfk-prog <[email protected]> | 2025-09-27 09:42:02 +0800 |
|---|---|---|
| committer | R b b666 <[email protected]> | 2025-09-28 11:17:21 +0800 |
| commit | 11156de0de6bea4eb9090d162152caf2b352b232 (patch) | |
| tree | e0d564de7da98d2a8b2b9b068dd8c0dbcb82423c /components/drivers/include | |
| parent | ed574f693f512fbbeff994d494e36952e0659f07 (diff) | |
feat[can]: Implement non-blocking send mechanism and enhance CAN driver functionality
- Added support for non-blocking mode CAN message sending, including software ring buffer management and dynamic memory allocation options.
- Improved related comments and error handling.
- Updated example code to demonstrate the usage of both blocking and non-blocking sending modes, and corrected some structure field naming and macro definitions.
Diffstat (limited to 'components/drivers/include')
| -rw-r--r-- | components/drivers/include/drivers/dev_can.h | 547 |
1 files changed, 355 insertions, 192 deletions
diff --git a/components/drivers/include/drivers/dev_can.h b/components/drivers/include/drivers/dev_can.h index 81ea0927ed..922ddcbb53 100644 --- a/components/drivers/include/drivers/dev_can.h +++ b/components/drivers/include/drivers/dev_can.h @@ -8,12 +8,14 @@ * 2015-05-14 [email protected] first version * 2015-07-06 Bernard remove RT_CAN_USING_LED. * 2022-05-08 hpmicro add CANFD support, fixed typos + * 2025-09-20 wdfk_prog Added non-blocking send mechanism APIs and data structures. */ #ifndef __DEV_CAN_H_ #define __DEV_CAN_H_ #include <rtthread.h> +#include <rtdevice.h> #ifndef RT_CANMSG_BOX_SZ #define RT_CANMSG_BOX_SZ 16 @@ -71,77 +73,88 @@ enum CANBAUD * @brief CAN driver api * @ingroup group_device_driver * - * <b>Example</b> + * <b>Example: Demonstrating CAN RX, Filters, and Blocking/Non-Blocking TX</b> * @code {.c} * #include <rtthread.h> - * #include "rtdevice.h" + * #include <rtdevice.h> * - * #define CAN_DEV_NAME "can1" // CAN 设备名称 + * #define CAN_DEV_NAME "can1" // The name of the CAN device * - * static struct rt_semaphore rx_sem; // 用于接收消息的信号量 - * static rt_device_t can_dev; // CAN 设备句柄 + * static rt_device_t can_dev; // CAN device handle + * static struct rt_semaphore rx_sem; // Semaphore for message reception * - * // 接收数据回调函数 - * static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size) + * // Callback function for CAN reception + * static rt_err_t can_rx_callback(rt_device_t dev, rt_size_t size) * { - * // CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 + * // The CAN interrupt calls this callback when data is received. + * // Release the semaphore to notify the receiving thread. * rt_sem_release(&rx_sem); - * * return RT_EOK; * } * * static void can_rx_thread(void *parameter) * { - * int i; * rt_err_t res; - * struct rt_can_msg rxmsg = {0}; + * struct rt_can_msg rx_msg = {0}; * - * // 设置接收回调函数 - * rt_device_set_rx_indicate(can_dev, can_rx_call); + * // Set the receive callback function + * rt_device_set_rx_indicate(can_dev, can_rx_callback); * * #ifdef RT_CAN_USING_HDR - * struct rt_can_filter_item items[5] = + * // Example of configuring multiple hardware filters + * struct rt_can_filter_item items[] = * { - * RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), // std,match ID:0x100~0x1ff,hdr 为 - 1,设置默认过滤表 - * RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), // std,match ID:0x300~0x3ff,hdr 为 - 1 - * RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7ff, RT_NULL, RT_NULL), // std,match ID:0x211,hdr 为 - 1 - * RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL), // std,match ID:0x486,hdr 为 - 1 - * {0x555, 0, 0, 0, 0x7ff, 7,} // std,match ID:0x555,hdr 为 7,指定设置 7 号过滤表 + * // Filter 1: Match standard frames with IDs from 0x100 to 0x1FF. hdr_index will be -1. + * RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), + * // Filter 2: Match standard frames with IDs from 0x300 to 0x3FF. hdr_index will be -1. + * RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), + * // Filter 3: Exactly match standard frame with ID 0x211. hdr_index will be -1. + * RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7FF, RT_NULL, RT_NULL), + * // Filter 4: Exactly match standard frame with ID 0x486 using a helper macro. hdr_index will be -1. + * RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL), + * // Filter 5: Exactly match standard frame with ID 0x555 and explicitly assign it to filter bank #7. + * // This uses direct struct initialization: {id, ide, rtr, mode, mask, hdr_bank}. + * {0x555, 0, 0, 0, 0x7FF, 7} * }; - * struct rt_can_filter_config cfg = {5, 1, items}; // 一共有 5 个过滤表 - * // 设置硬件过滤表 + * // Create the filter configuration structure with 5 active filters. + * struct rt_can_filter_config cfg = {sizeof(items)/sizeof(items[0]), 1, items}; + * // Set the hardware filters for the CAN device. * res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg); * RT_ASSERT(res == RT_EOK); * #endif - * res = RT_TRUE; - * res = rt_device_control(can_dev, RT_CAN_CMD_START, &res); + * + * // Some drivers might require an explicit start command. + * // This is driver-specific. + * rt_uint32_t cmd_arg = 1; // Argument to enable the controller + * res = rt_device_control(can_dev, RT_CAN_CMD_START, &cmd_arg); + * RT_ASSERT(res == RT_EOK); + * * while (1) * { - * // hdr 值为 - 1,表示直接从 uselist 链表读取数据 - * rxmsg.hdr = -1; - * // 阻塞等待接收信号量 + * // Block and wait for the semaphore, which is released by the receive callback. * rt_sem_take(&rx_sem, RT_WAITING_FOREVER); - * // 从 CAN 读取一帧数据 - * rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg)); - * // 打印数据 ID 及内容 - * rt_kprintf("ID:%x", rxmsg.id); - * for (i = 0; i < 8; i++) + * + * // Read one frame of data from the CAN device's general message queue. + * rx_msg.hdr_index = -1; + * rt_device_read(can_dev, 0, &rx_msg, sizeof(rx_msg)); + * + * // Print the received message's ID and data. + * rt_kprintf("Received a message. ID: 0x%x, Data: ", rx_msg.id); + * for (int i = 0; i < rx_msg.len; i++) * { - * rt_kprintf("%2x", rxmsg.data[i]); + * rt_kprintf("%02x ", rx_msg.data[i]); * } - * * rt_kprintf("\n"); * } * } * * int can_sample(int argc, char *argv[]) * { - * struct rt_can_msg msg = {0}; * rt_err_t res; - * rt_size_t size; * rt_thread_t thread; * char can_name[RT_NAME_MAX]; * + * // Allow specifying the CAN device name from the command line, e.g., "can_sample can2" * if (argc == 2) * { * rt_strncpy(can_name, argv[1], RT_NAME_MAX); @@ -150,21 +163,23 @@ enum CANBAUD * { * rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX); * } - * // 查找 CAN 设备 + * + * // Find the CAN device by name * can_dev = rt_device_find(can_name); * if (!can_dev) * { - * rt_kprintf("find %s failed!\n", can_name); + * rt_kprintf("find device %s failed!\n", can_name); * return -RT_ERROR; * } * - * // 初始化 CAN 接收信号量 + * // Initialize the receive semaphore * rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO); * - * // 以中断接收及发送方式打开 CAN 设备 + * // Open the CAN device in interrupt-driven TX/RX mode * res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX); * RT_ASSERT(res == RT_EOK); - * // 创建数据接收线程 + * + * // Create and start the data receiving thread * thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10); * if (thread != RT_NULL) * { @@ -173,36 +188,61 @@ enum CANBAUD * else * { * rt_kprintf("create can_rx thread failed!\n"); + * return -RT_ERROR; * } * - * msg.id = 0x78; // ID 为 0x78 - * msg.ide = RT_CAN_STDID; // 标准格式 - * msg.rtr = RT_CAN_DTR; // 数据帧 - * msg.len = 8; // 数据长度为 8 - * // 待发送的 8 字节数据 - * msg.data[0] = 0x00; - * msg.data[1] = 0x11; - * msg.data[2] = 0x22; - * msg.data[3] = 0x33; - * msg.data[4] = 0x44; - * msg.data[5] = 0x55; - * msg.data[6] = 0x66; - * msg.data[7] = 0x77; - * // 发送一帧 CAN 数据 - * size = rt_device_write(can_dev, 0, &msg, sizeof(msg)); - * if (size == 0) + * rt_kprintf("CAN device %s opened successfully.\n", can_name); + * + * // --- Demonstrate Blocking Send --- + * struct rt_can_msg blocking_msg = {0}; + * blocking_msg.id = 0x78; + * blocking_msg.ide = RT_CAN_STDID; + * blocking_msg.rtr = RT_CAN_DTR; + * blocking_msg.len = 8; + * // The `nonblocking` flag is 0 by default for blocking mode. + * for(int i = 0; i < 8; i++) blocking_msg.data[i] = i; + * + * rt_kprintf("Attempting to send a message in BLOCKING mode...\n"); + * if (rt_device_write(can_dev, 0, &blocking_msg, sizeof(blocking_msg)) == sizeof(blocking_msg)) + * { + * rt_kprintf("Blocking message sent successfully.\n"); + * } + * else + * { + * rt_kprintf("Blocking message send failed.\n"); + * } + * + * rt_thread_mdelay(100); // Wait a moment for clarity in the log + * + * // --- Demonstrate Non-Blocking Send --- + * struct rt_can_msg nonblocking_msg = {0}; + * nonblocking_msg.id = 0x79; + * nonblocking_msg.ide = RT_CAN_STDID; + * nonblocking_msg.rtr = RT_CAN_DTR; + * nonblocking_msg.len = 4; + * nonblocking_msg.data[0] = 0xDE; + * nonblocking_msg.data[1] = 0xAD; + * nonblocking_msg.data[2] = 0xBE; + * nonblocking_msg.data[3] = 0xEF; + * nonblocking_msg.nonblocking = 1; // <-- Key: Set the non-blocking flag + * + * rt_kprintf("Attempting to send a message in NON-BLOCKING mode...\n"); + * if (rt_device_write(can_dev, 0, &nonblocking_msg, sizeof(nonblocking_msg)) == sizeof(nonblocking_msg)) * { - * rt_kprintf("can dev write data failed!\n"); + * rt_kprintf("Non-blocking message was accepted (sent or enqueued).\n"); + * } + * else + * { + * rt_kprintf("Non-blocking send failed (buffer was full).\n"); * } * * return res; * } - * // 导出到 msh 命令列表中 - * MSH_CMD_EXPORT(can_sample, can device sample); + * // Export the function to the MSH command line + * MSH_CMD_EXPORT(can_sample, can device usage example); * @endcode */ - /*! * @addtogroup group_drivers_can * @{ @@ -211,27 +251,46 @@ enum CANBAUD #define CAN_RX_FIFO1 (0x00000001U) /*!< CAN receive FIFO 1 */ /** - * @brief CAN filter item + * @brief CAN filter item structure */ struct rt_can_filter_item { - rt_uint32_t id : 29; - rt_uint32_t ide : 1; - rt_uint32_t rtr : 1; - rt_uint32_t mode : 1; - rt_uint32_t mask; - rt_int32_t hdr_bank;/*Should be defined as:rx.FilterBank,which should be changed to rt_int32_t hdr_bank*/ - rt_uint32_t rxfifo;/*Add a configuration item that CAN_RX_FIFO0/CAN_RX_FIFO1*/ + rt_uint32_t id : 29; /**< The CAN ID to be filtered. */ + rt_uint32_t ide : 1; /**< Identifier type. 0 for Standard ID, 1 for Extended ID. */ + rt_uint32_t rtr : 1; /**< Frame type. 0 for Data Frame, 1 for Remote Frame. */ + rt_uint32_t mode : 1; /**< Filter mode. 0 for Mask Mode, 1 for List Mode. */ + rt_uint32_t mask; /**< The filter mask. In Mask Mode, a '1' bit means the corresponding ID bit must match. */ + rt_int32_t hdr_bank; /**< The specific hardware filter bank index to use. A value of -1 allows the driver to auto-assign. */ + rt_uint32_t rxfifo; /**< The target RX FIFO for matched messages (CAN_RX_FIFO0 or CAN_RX_FIFO1). */ #ifdef RT_CAN_USING_HDR + /** + * @brief Callback function for a specific filter. + * @param[in] dev The CAN device that triggered the callback. + * @param[in] args User-provided arguments. + * @param[in] hdr The hardware filter index that matched the message. + * @param[in] size The size of the received data in bytes. + * @return The operation status. + */ rt_err_t (*ind)(rt_device_t dev, void *args , rt_int32_t hdr, rt_size_t size); - void *args; + void *args; /**< User arguments for the indication callback. */ #endif /*RT_CAN_USING_HDR*/ }; - +/** + * @def RT_CAN_FILTER_ITEM_INIT + * @brief A helper macro to initialize a `rt_can_filter_item` structure for Mask Mode. + * + * @param[in] _id The CAN ID for the filter. + * @param[in] _ide Identifier type (0 for Standard, 1 for Extended). + * @param[in] _rtr Frame type (0 for Data, 1 for Remote). + * @param[in] _mode Filter mode (0 for Mask, 1 for List). + * @param[in] _mask The mask to be applied. + * @param[in] _ind Optional callback function (can be RT_NULL). + * @param[in] _args Optional arguments for the callback (can be RT_NULL). + */ #ifdef RT_CAN_USING_HDR #define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,ind,args) \ - {(id), (ide), (rtr), (mode),(mask), -1, CAN_RX_FIFO0,(ind), (args)}/*0:CAN_RX_FIFO0*/ + {(id), (ide), (rtr), (mode),(mask), -1, CAN_RX_FIFO0,(ind), (args)} #define RT_CAN_FILTER_STD_INIT(id,ind,args) \ RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,ind,args) #define RT_CAN_FILTER_EXT_INIT(id,ind,args) \ @@ -245,9 +304,8 @@ struct rt_can_filter_item #define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,ind,args) \ RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,ind,args) #else - #define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask) \ - {(id), (ide), (rtr), (mode), (mask), -1, CAN_RX_FIFO0 }/*0:CAN_RX_FIFO0*/ + {(id), (ide), (rtr), (mode), (mask), -1, CAN_RX_FIFO0 } #define RT_CAN_FILTER_STD_INIT(id) \ RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF) #define RT_CAN_FILTER_EXT_INIT(id) \ @@ -264,65 +322,65 @@ struct rt_can_filter_item /** - * @brief CAN filter configuration + * @brief CAN hardware filter configuration structure. + * This structure is passed to the driver via `rt_device_control` with the `RT_CAN_CMD_SET_FILTER` command. */ struct rt_can_filter_config { - rt_uint32_t count; - rt_uint32_t actived; - struct rt_can_filter_item *items; + rt_uint32_t count; /**< The number of filter items in the `items` array. */ + rt_uint32_t actived; /**< A flag to activate (1) or deactivate (0) the filters. */ + struct rt_can_filter_item *items; /**< A pointer to an array of filter items. */ }; /** - * @brief CAN timing configuration + * @brief CAN bit-timing parameters structure. */ struct rt_can_bit_timing { - rt_uint16_t prescaler; /* Pre-scaler */ - rt_uint16_t num_seg1; /* Bit Timing Segment 1, in terms of Tq */ - rt_uint16_t num_seg2; /* Bit Timing Segment 2, in terms of Tq */ - rt_uint8_t num_sjw; /* Synchronization Jump Width, in terms of Tq */ - rt_uint8_t num_sspoff; /* Secondary Sample Point Offset, in terms of Tq */ + rt_uint16_t prescaler; /**< Baud rate prescaler. */ + rt_uint16_t num_seg1; /**< Bit Timing Segment 1, in terms of Time Quanta (Tq). */ + rt_uint16_t num_seg2; /**< Bit Timing Segment 2, in terms of Time Quanta (Tq). */ + rt_uint8_t num_sjw; /**< Synchronization Jump Width, in terms of Time Quanta (Tq). */ + rt_uint8_t num_sspoff; /**< Secondary Sample Point Offset, in terms of Time Quanta (Tq) for CAN-FD. */ }; /** - * @brief CAN bit timing configuration list - * @note - * items[0] always for CAN2.0/CANFD Arbitration Phase - * items[1] always for CANFD (if it exists) + * @brief CAN bit timing configuration list structure. + * @note items[0] is for CAN 2.0 / CAN-FD Arbitration Phase. + * items[1] is for CAN-FD Data Phase (if applicable). */ struct rt_can_bit_timing_config { - rt_uint32_t count; - struct rt_can_bit_timing *items; + rt_uint32_t count; /**< The number of bit-timing configurations (typically 1 for CAN, 2 for CAN-FD). */ + struct rt_can_bit_timing *items; /**< A pointer to an array of bit-timing structures. */ }; /** - * @brief CAN configuration + * @brief CAN device configuration structure. */ struct can_configure { - rt_uint32_t baud_rate; - rt_uint32_t msgboxsz; - rt_uint32_t sndboxnumber; - rt_uint32_t mode : 8; - rt_uint32_t privmode : 8; - rt_uint32_t reserved : 16; - rt_uint32_t ticks; + rt_uint32_t baud_rate; /**< The baud rate for the arbitration phase (e.g., CAN500kBaud). */ + rt_uint32_t msgboxsz; /**< The size of the software receive buffer (in number of messages). */ + rt_uint32_t sndboxnumber; /**< The number of hardware mailboxes used for blocking send operations. */ + rt_uint32_t mode : 8; /**< The CAN operation mode (e.g., RT_CAN_MODE_NORMAL, RT_CAN_MODE_LOOPBACK). */ + rt_uint32_t privmode : 8; /**< Private mode flag. If set, the `priv` field of `rt_can_msg` specifies the hardware mailbox. */ + rt_uint32_t reserved : 16; /**< Reserved for future use. */ + rt_uint32_t ticks; /**< The period in OS ticks for the status-checking timer. */ #ifdef RT_CAN_USING_HDR - rt_uint32_t maxhdr; + rt_uint32_t maxhdr; /**< The maximum number of hardware filters supported by the controller. */ #endif #ifdef RT_CAN_USING_CANFD - rt_uint32_t baud_rate_fd; /* CANFD data bit rate*/ - rt_uint32_t use_bit_timing: 8; /* Use the bit timing for CAN timing configuration */ - rt_uint32_t enable_canfd : 8; /* Enable CAN-FD mode */ - rt_uint32_t reserved1 : 16; + rt_uint32_t baud_rate_fd; /**< The baud rate for the CAN-FD data phase. */ + rt_uint32_t use_bit_timing: 8; /**< A flag to indicate that `can_timing` and `canfd_timing` should be used instead of `baud_rate`. */ + rt_uint32_t enable_canfd : 8; /**< A flag to enable CAN-FD functionality. */ + rt_uint32_t reserved1 : 16; /**< Reserved for future use. */ /* The below fields take effect only if use_bit_timing is non-zero */ - struct rt_can_bit_timing can_timing; /* CAN bit-timing /CANFD bit-timing for arbitration phase */ - struct rt_can_bit_timing canfd_timing; /* CANFD bit-timing for datat phase */ + struct rt_can_bit_timing can_timing; /**< Custom bit-timing for the arbitration phase. */ + struct rt_can_bit_timing canfd_timing; /**< Custom bit-timing for the data phase. */ #endif }; @@ -368,66 +426,130 @@ enum RT_CAN_BUS_ERR }; /** - * @brief CAN status + * @brief CAN device status and error statistics structure. */ struct rt_can_status { - rt_uint32_t rcverrcnt; - rt_uint32_t snderrcnt; - rt_uint32_t errcode; - rt_uint32_t rcvpkg; - rt_uint32_t dropedrcvpkg; - rt_uint32_t sndpkg; - rt_uint32_t dropedsndpkg; - rt_uint32_t bitpaderrcnt; - rt_uint32_t formaterrcnt; - rt_uint32_t ackerrcnt; - rt_uint32_t biterrcnt; - rt_uint32_t crcerrcnt; - rt_uint32_t rcvchange; - rt_uint32_t sndchange; - rt_uint32_t lasterrtype; + rt_uint32_t rcverrcnt; /**< Receive Error Counter (REC). */ + rt_uint32_t snderrcnt; /**< Transmit Error Counter (TEC). */ + rt_uint32_t errcode; /**< The current bus error code (see `enum RT_CAN_BUS_ERR`). */ + rt_uint32_t rcvpkg; /**< Total number of successfully received packages. */ + rt_uint32_t dropedrcvpkg; /**< Number of received packages dropped due to full buffers. */ + rt_uint32_t sndpkg; /**< Total number of successfully sent packages. */ + rt_uint32_t dropedsndpkg; /**< Number of sent packages dropped due to full buffers or errors. */ + rt_uint32_t bitpaderrcnt; /**< Bit stuffing error count. */ + rt_uint32_t formaterrcnt; /**< Format error count. */ + rt_uint32_t ackerrcnt; /**< Acknowledgment error count. */ + rt_uint32_t biterrcnt; /**< Bit error (recessive/dominant) count. */ + rt_uint32_t crcerrcnt; /**< CRC error count. */ + rt_uint32_t rcvchange; /**< A flag indicating that the RX buffer status has changed. */ + rt_uint32_t sndchange; /**< A bitmask indicating which TX mailboxes have changed status. */ + rt_uint32_t lasterrtype; /**< The type of the last error that occurred. */ }; #ifdef RT_CAN_USING_HDR +/** + * @brief CAN hardware filter list entry. + * @internal + */ struct rt_can_hdr { - rt_uint32_t connected; - rt_uint32_t msgs; - struct rt_can_filter_item filter; - struct rt_list_node list; + rt_uint32_t connected; /**< Flag indicating if the filter is connected to a specific list. */ + rt_uint32_t msgs; /**< The number of messages currently buffered for this filter. */ + struct rt_can_filter_item filter; /**< A copy of the filter configuration item. */ + struct rt_list_node list; /**< The list head for messages matched by this filter. */ }; #endif struct rt_can_device; -typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device *, void *); +/** + * @brief Typedef for the CAN status indication callback function. + * @param[in] can A pointer to the CAN device. + * @param[in] args User-provided arguments. + * @return The operation status. + */ +typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device *can, void *args); +/** + * @brief Structure to hold the status indication callback and its arguments. + */ typedef struct rt_can_status_ind_type { - rt_canstatus_ind ind; - void *args; + rt_canstatus_ind ind; /**< Pointer to the status indication callback function. */ + void *args; /**< Pointer to user arguments for the callback. */ } *rt_can_status_ind_type_t; -typedef void (*rt_can_bus_hook)(struct rt_can_device *); + +/** + * @brief Typedef for the periodic bus hook function. + * @param[in] can A pointer to the CAN device. + * @return void + */ +typedef void (*rt_can_bus_hook)(struct rt_can_device *can); + +/** + * @brief The CAN message structure. + */ +struct rt_can_msg +{ + rt_uint32_t id : 29; /**< CAN ID (Standard or Extended). */ + rt_uint32_t ide : 1; /**< Identifier type: 0=Standard ID, 1=Extended ID. */ + rt_uint32_t rtr : 1; /**< Frame type: 0=Data Frame, 1=Remote Frame. */ + rt_uint32_t rsv : 1; /**< Reserved bit. */ + rt_uint32_t len : 8; /**< Data Length Code (DLC) from 0 to 8. */ + rt_uint32_t priv : 8; /**< Private data, used to specify the hardware mailbox in private mode. */ + rt_int32_t hdr_index : 8; /**< For received messages, the index of the hardware filter that matched the message. */ +#ifdef RT_CAN_USING_CANFD + rt_uint32_t fd_frame : 1; /**< CAN-FD frame indicator. */ + rt_uint32_t brs : 1; /**< Bit-rate switching indicator for CAN-FD. */ + rt_uint32_t rxfifo : 2; /**< The RX FIFO where the message was received. */ + rt_uint32_t reserved : 3; +#else + rt_uint32_t rxfifo : 2; /**< The RX FIFO where the message was received. */ + rt_uint32_t reserved : 5; +#endif + rt_uint32_t nonblocking : 1; /**< Send mode: 0=Blocking (default), 1=Non-blocking. */ +#ifdef RT_CAN_USING_CANFD + rt_uint8_t data[64]; /**< CAN-FD message payload (up to 64 bytes). */ +#else + rt_uint8_t data[8]; /**< CAN message payload (up to 8 bytes). */ +#endif +}; +typedef struct rt_can_msg *rt_can_msg_t; + +#ifndef RT_CAN_NB_TX_FIFO_SIZE +#define RT_CAN_NB_TX_FIFO_SIZE (RT_CANMSG_BOX_SZ * sizeof(struct rt_can_msg)) +#endif + +/** + * @brief The core CAN device structure. + */ struct rt_can_device { - struct rt_device parent; + struct rt_device parent; /**< Inherits from the base RT-Thread device structure. */ - const struct rt_can_ops *ops; - struct can_configure config; - struct rt_can_status status; + const struct rt_can_ops *ops; /**< A pointer to the low-level driver operations. */ + struct can_configure config; /**< The current configuration of the CAN device. */ + struct rt_can_status status; /**< The current status and error statistics of the CAN device. */ - rt_uint32_t timerinitflag; - struct rt_timer timer; + rt_uint32_t timerinitflag; /**< A flag to indicate if the status timer has been initialized. */ + struct rt_timer timer; /**< A timer for periodically checking the CAN bus status. */ - struct rt_can_status_ind_type status_indicate; + struct rt_can_status_ind_type status_indicate; /**< The user-registered status indication callback. */ #ifdef RT_CAN_USING_HDR - struct rt_can_hdr *hdr; + struct rt_can_hdr *hdr; /**< A pointer to an array of hardware filter list entries. */ #endif #ifdef RT_CAN_USING_BUS_HOOK - rt_can_bus_hook bus_hook; + rt_can_bus_hook bus_hook; /**< The user-registered periodic bus hook function. */ #endif /*RT_CAN_USING_BUS_HOOK*/ - struct rt_mutex lock; - void *can_rx; - void *can_tx; + struct rt_mutex lock; /**< A mutex for thread-safe access to the device. */ + void *can_rx; /**< A pointer to the software receive FIFO structure (`rt_can_rx_fifo`). */ + void *can_tx; /**< A pointer to the software transmit FIFO structure (`rt_can_tx_fifo`). */ + + struct rt_ringbuffer nb_tx_rb; /**< The ring buffer for non-blocking transmissions. */ +#ifdef RT_CAN_MALLOC_NB_TX_BUFFER + rt_uint8_t *nb_tx_rb_pool; /**< A pointer to the dynamically allocated pool for the non-blocking TX ring buffer. */ +#else + rt_uint8_t nb_tx_rb_pool[RT_CAN_NB_TX_FIFO_SIZE]; /**< The statically allocated pool for the non-blocking TX ring buffer. */ +#endif /* RT_CAN_MALLOC_NB_TX_BUFFER */ }; typedef struct rt_can_device *rt_can_t; @@ -438,49 +560,30 @@ typedef struct rt_can_device *rt_can_t; typedef struct rt_can_status *rt_can_status_t; -struct rt_can_msg -{ - rt_uint32_t id : 29; - rt_uint32_t ide : 1; - rt_uint32_t rtr : 1; - rt_uint32_t rsv : 1; - rt_uint32_t len : 8; - rt_uint32_t priv : 8; - rt_int32_t hdr_index : 8;/*Should be defined as:rx.FilterMatchIndex,which should be changed to rt_int32_t hdr_index : 8*/ -#ifdef RT_CAN_USING_CANFD - rt_uint32_t fd_frame : 1; - rt_uint32_t brs : 1; - rt_uint32_t rxfifo : 2;/*Redefined to return :CAN RX FIFO0/CAN RX FIFO1*/ - rt_uint32_t reserved : 4; -#else - rt_uint32_t rxfifo : 2;/*Redefined to return :CAN RX FIFO0/CAN RX FIFO1*/ - rt_uint32_t reserved : 6; -#endif -#ifdef RT_CAN_USING_CANFD - rt_uint8_t data[64]; -#else - rt_uint8_t data[8]; -#endif -}; -typedef struct rt_can_msg *rt_can_msg_t; - +/** + * @internal + * @brief List node for a single CAN message in a software FIFO. + */ struct rt_can_msg_list { - struct rt_list_node list; + struct rt_list_node list; /**< List node to link into a free/used list. */ #ifdef RT_CAN_USING_HDR - struct rt_list_node hdrlist; - struct rt_can_hdr *owner; + struct rt_list_node hdrlist; /**< List node to link into a specific hardware filter's list. */ + struct rt_can_hdr *owner; /**< Pointer to the hardware filter that owns this message. */ #endif - struct rt_can_msg data; + struct rt_can_msg data; /**< The actual CAN message data. */ }; +/** + * @internal + * @brief Software receive FIFO structure. + */ struct rt_can_rx_fifo { - /* software fifo */ - struct rt_can_msg_list *buffer; - rt_uint32_t freenumbers; - struct rt_list_node freelist; - struct rt_list_node uselist; + struct rt_can_msg_list *buffer; /**< A pointer to the buffer pool of message list nodes. */ + rt_uint32_t freenumbers; /**< The number of free nodes in the buffer pool. */ + struct rt_list_node freelist; /**< The list of free message nodes. */ + struct rt_list_node uselist; /**< The list of used message nodes (containing received messages). */ }; #define RT_CAN_SND_RESULT_OK 0 @@ -493,40 +596,94 @@ struct rt_can_rx_fifo #define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */ #define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */ +/** + * @internal + * @brief List node for a blocking send operation, corresponding to one hardware mailbox. + */ struct rt_can_sndbxinx_list { - struct rt_list_node list; - struct rt_completion completion; - rt_uint32_t result; + struct rt_list_node list; /**< List node to link into the free list. */ + struct rt_completion completion;/**< A completion object to block the sending thread. */ + rt_uint32_t result; /**< The result of the transmission (OK, ERR, WAIT). */ }; +/** + * @internal + * @brief Software transmit FIFO structure for blocking sends. + */ struct rt_can_tx_fifo { - struct rt_can_sndbxinx_list *buffer; - struct rt_semaphore sem; - struct rt_list_node freelist; + struct rt_can_sndbxinx_list *buffer; /**< A pointer to the buffer of sendbox nodes. */ + struct rt_semaphore sem; /**< A counting semaphore representing available hardware mailboxes. */ + struct rt_list_node freelist; /**< The list of free sendbox nodes. */ }; /** - * @brief CAN operators + * @brief The CAN device driver operations structure. + * + * This structure contains pointers to the low-level functions that implement the CAN functionality. + * It must be provided when registering a CAN device. */ struct rt_can_ops { + /** + * @brief Configures the CAN controller with the specified settings. + * @param[in] can A pointer to the CAN device structure. + * @param[in] cfg A pointer to the configuration structure. + * @return `RT_EOK` on success, or a negative error code on failure. + */ rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg); + /** + * @brief Sends control commands to the CAN device. + * @param[in] can A pointer to the CAN device structure. + * @param[in] cmd The control command (e.g., RT_CAN_CMD_SET_FILTER). + * @param[in] arg A pointer to the arguments for the command. + * @return `RT_EOK` on success, or a negative error code on failure. + */ rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg); + /** + * @brief Low-level blocking function to send a CAN message. + * @param[in] can A pointer to the CAN device structure. + * @param[in] buf A pointer to the `rt_can_msg` to be sent. + * @param[in] boxno The hardware mailbox number to use for transmission. + * @return The number of bytes sent on success, or a negative error code on failure. + */ rt_ssize_t (*sendmsg)(struct rt_can_device *can, const void *buf, rt_uint32_t boxno); - rt_ssize_t (*recvmsg)(struct rt_can_device *can, void *buf, rt_uint32_t boxno); + /** + * @brief Low-level function to receive a CAN message. + * @param[in,out] can A pointer to the CAN device structure. + * @param[out] buf A pointer to the buffer to store the received `rt_can_msg`. + * @param[in] fifo The hardware FIFO number to read from. + * @return The number of bytes received on success, or a negative error code on failure. + */ + rt_ssize_t (*recvmsg)(struct rt_can_device *can, void *buf, rt_uint32_t fifo); + /** + * @brief Low-level, hardware-specific function to send a CAN message non-blockingly. + * + * This function attempts to place a message into a hardware transmission mailbox + * and returns immediately without waiting for the transmission to complete. + * + * @param[in] can A pointer to the CAN device structure. + * @param[in] buf A pointer to the `rt_can_msg` to be sent. + * + * @return + * - `RT_EOK` if the message was successfully accepted by the hardware. + * - `-RT_EBUSY` if all hardware mailboxes are currently full. + * - Other negative error codes for different failures. + */ + rt_ssize_t (*sendmsg_nonblocking)(struct rt_can_device *can, const void *buf); }; /** - * @brief Register a CAN device to device list + * @brief This function registers a CAN device with the device framework. * - * @param can the CAN device object - * @param name the name of CAN device - * @param ops the CAN device operators - * @param data the private data of CAN device + * @param[in] can A pointer to the CAN device object to be registered. + * @param[in] name The name that the device will be registered with. + * @param[in] ops A pointer to the structure containing the low-level CAN driver operations. + * @param[in] data A pointer to a user-defined data structure, which can be accessed + * via `can->parent.user_data`. * - * @return the error code, RT_EOK on successfully + * @return `RT_EOK` on successful registration, or a negative error code on failure. */ rt_err_t rt_hw_can_register(struct rt_can_device *can, const char *name, @@ -534,10 +691,16 @@ rt_err_t rt_hw_can_register(struct rt_can_device *can, void *data); /** - * @brief CAN interrupt service routine + * @brief The framework-level ISR handler for CAN devices. + * + * This function is called by the low-level BSP ISR and acts as the central + * dispatcher for all CAN-related interrupt events. It handles both receive + * events and transmission-complete events. + * + * @param[in] can A pointer to the CAN device structure. + * @param[in] event The interrupt event mask, indicating the cause of the interrupt. * - * @param can the CAN device - * @param event the event mask + * @return void */ void rt_hw_can_isr(struct rt_can_device *can, int event); |
