diff --git a/components/drivers/can/dev_can.c b/components/drivers/can/dev_can.c index e0cf0db9b27..998ed0b942b 100644 --- a/components/drivers/can/dev_can.c +++ b/components/drivers/can/dev_can.c @@ -8,6 +8,7 @@ * 2015-05-14 aubrcool@qq.com first version * 2015-07-06 Bernard code cleanup and remove RT_CAN_USING_LED; * 2025-09-20 wdfk_prog Implemented non-blocking, ISR-safe send logic unified under rt_device_write. + * 2025-12-17 RCSN Support global send mode control, enable TX completion callback via RT_CAN_CMD_SET_SENDMODE */ #include @@ -652,7 +653,7 @@ static rt_ssize_t rt_can_write(struct rt_device *dev, * 1. Called from within an interrupt context. * 2. Called from a thread, but the user explicitly set the nonblocking flag on the first message. */ - if (rt_interrupt_get_nest() > 0 || pmsg->nonblocking) + if (rt_interrupt_get_nest() > 0 || pmsg->nonblocking || can->send_mode_nonblocking) { return _can_nonblocking_tx(can, pmsg, size); } @@ -1097,12 +1098,30 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) { struct rt_can_tx_fifo *tx_fifo; rt_uint32_t no; + struct rt_device *device; no = event >> 8; tx_fifo = (struct rt_can_tx_fifo *) can->can_tx; RT_ASSERT(tx_fifo != RT_NULL); - if (can->status.sndchange&(1<buffer[no].result + * - Wake up the blocked thread using rt_completion_done() + * - The blocked thread then checks the result and resumes execution + * + * Non-blocking sends are handled separately by the tx_complete callback + * (see the send_mode_nonblocking section below). + */ + if (can->status.sndchange & (1<buffer[no].result = RT_CAN_SND_RESULT_OK; @@ -1111,11 +1130,19 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) { tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_ERR; } + + /* Wake up the blocked thread waiting on this mailbox's completion */ rt_completion_done(&(tx_fifo->buffer[no].completion)); - } - - if (can->ops->sendmsg_nonblocking != RT_NULL) + } + else if (can->ops->sendmsg_nonblocking != RT_NULL) { + if (can->send_mode_nonblocking == 1) { + device = &(can->parent); + if (device->tx_complete != RT_NULL) + { + device->tx_complete(device, RT_NULL); + } + } while (RT_TRUE) { struct rt_can_msg msg_to_send; diff --git a/components/drivers/include/drivers/dev_can.h b/components/drivers/include/drivers/dev_can.h index 9bf0c162cbd..e62f02821e6 100644 --- a/components/drivers/include/drivers/dev_can.h +++ b/components/drivers/include/drivers/dev_can.h @@ -9,6 +9,7 @@ * 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. + * 2025-12-17 RCSN Added send_mode_nonblocking and RT_CAN_CMD_SET_SENDMODE for TX completion callback control */ #ifndef __DEV_CAN_H_ @@ -417,6 +418,7 @@ struct rt_can_ops; #define RT_CAN_CMD_SET_BAUD_FD 0x1B #define RT_CAN_CMD_SET_BITTIMING 0x1C #define RT_CAN_CMD_START 0x1D +#define RT_CAN_CMD_SET_SENDMODE 0x1E #define RT_DEVICE_CAN_INT_ERR 0x1000 @@ -563,6 +565,7 @@ struct rt_can_device #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 */ + rt_uint8_t send_mode_nonblocking; /**< Global send mode: 0=Blocking (default), 1=Non-blocking. */ }; typedef struct rt_can_device *rt_can_t;