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/can | |
| 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/can')
| -rw-r--r-- | components/drivers/can/Kconfig | 69 | ||||
| -rw-r--r-- | components/drivers/can/dev_can.c | 335 |
2 files changed, 338 insertions, 66 deletions
diff --git a/components/drivers/can/Kconfig b/components/drivers/can/Kconfig index c762a46d6b..ccb4348db2 100644 --- a/components/drivers/can/Kconfig +++ b/components/drivers/can/Kconfig @@ -1,31 +1,76 @@ config RT_USING_CAN bool "Using CAN device drivers" default n + help + Enable this option to include the CAN device driver framework. if RT_USING_CAN + config RT_CAN_USING_HDR - bool "Enable CAN hardware filter" + bool "Enable CAN hardware filter support" default n - + help + If your CAN controller supports hardware filtering, and you want to + use the framework to configure these filters, enable this option. + config RT_CAN_USING_CANFD - bool "Enable CANFD support" + bool "Enable CAN-FD support" default n - + help + Enable this to support CAN with Flexible Data-Rate. This will + increase the size of the rt_can_msg structure. + config RT_CANMSG_BOX_SZ - int "CAN message box size" + int "Software RX message box size (in messages)" default 16 help - Set the size of the CAN message box. - + This sets the capacity of the software buffer (FIFO) for incoming + CAN messages. It defines how many messages can be buffered by the + driver before the application must read them. + config RT_CANSND_BOX_NUM - int "Number of CAN send queues" + int "Number of mailboxes for blocking send" default 1 help - Set the number of CAN send queues. - + This sets the number of concurrent blocking send operations that + can be in flight. It is typically matched to the number of + hardware transmission mailboxes on the CAN controller. + config RT_CANSND_MSG_TIMEOUT - int "CAN send message timeout" + int "Timeout for blocking send (in OS ticks)" default 100 help - Set the timeout for CAN send messages. + This sets the default time a thread will wait for a hardware + mailbox to become available when sending in blocking mode. + + config RT_CAN_NB_TX_FIFO_SIZE + int "Non-blocking send buffer size (in bytes)" + default 256 + help + This defines the size of the software ring buffer used for + non-blocking and ISR-based transmissions. When the hardware + mailboxes are full, outgoing messages are temporarily stored + in this buffer. + + To calculate a suitable size, use: + (number of messages to buffer) * sizeof(struct rt_can_msg). + For standard CAN, sizeof(struct rt_can_msg) is typically 16 bytes. + The default of 256 bytes can buffer 16 standard CAN messages. + If using CAN-FD, you will need to increase this size significantly. + + config RT_CAN_MALLOC_NB_TX_BUFFER + bool "Dynamically allocate the non-blocking send buffer" + depends on RT_USING_HEAP + default n + help + If this option is enabled (y), the non-blocking send buffer will + be allocated from the system heap at runtime when the CAN device + is opened (using rt_malloc). This saves static RAM but requires + a heap to be available. + + If this option is disabled (n), the buffer will be allocated + as a static array within the rt_can_device structure. This + consumes static RAM but guarantees the memory is always available + and avoids heap fragmentation. + endif
\ No newline at end of file diff --git a/components/drivers/can/dev_can.c b/components/drivers/can/dev_can.c index 8f70a1ddfb..73aee2f094 100644 --- a/components/drivers/can/dev_can.c +++ b/components/drivers/can/dev_can.c @@ -7,6 +7,7 @@ * Date Author Notes * 2015-05-14 [email protected] 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. */ #include <rthw.h> @@ -40,8 +41,19 @@ static rt_err_t rt_can_init(struct rt_device *dev) return result; } -/* - * can interrupt routines +/** + * @internal + * @brief Handles reading messages from the software RX FIFO into a user buffer. + * + * This function is called by the public `rt_can_read()` API when the device + * is opened with interrupt-driven reception enabled. It safely transfers + * messages from the internal `uselist` to the user-provided buffer. + * + * @param[in] can A pointer to the CAN device. + * @param[out] data A pointer to the destination buffer for the received messages. + * @param[in] msgs The total size in bytes of the destination buffer. + * + * @return The number of bytes actually read from the FIFO. */ rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *data, rt_ssize_t msgs) { @@ -63,7 +75,7 @@ rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *d struct rt_can_msg_list *listmsg = RT_NULL; /* disable interrupt */ - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); #ifdef RT_CAN_USING_HDR hdr = data->hdr_index; @@ -97,22 +109,22 @@ rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *d else { /* no data, enable interrupt and break out */ - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); break; } } /* enable interrupt */ - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); if (listmsg != RT_NULL) { rt_memcpy(data, &listmsg->data, sizeof(struct rt_can_msg)); - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); rt_list_insert_before(&rx_fifo->freelist, &listmsg->list); rx_fifo->freenumbers++; RT_ASSERT(rx_fifo->freenumbers <= can->config.msgboxsz); - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); listmsg = RT_NULL; } @@ -127,6 +139,25 @@ rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *d return (size - msgs); } +/** + * @internal + * @brief Handles the blocking (synchronous) transmission of CAN messages. + * + * This function is the core of the blocking send mechanism. It iterates through + * a buffer of messages to be sent. For each message, it: + * 1. Acquires a hardware mailbox resource using a semaphore. + * 2. Submits the message to the low-level driver for transmission. + * 3. Blocks the calling thread by waiting on a completion object. + * 4. Is woken up by the TX complete ISR (`rt_hw_can_isr`) when the transmission is finished. + * + * @note This function will block the calling thread and must not be called from an ISR. + * + * @param[in] can A pointer to the CAN device. + * @param[in] data A pointer to the source buffer of messages to be sent. + * @param[in] msgs The total size in bytes of the source buffer. + * + * @return The number of bytes successfully sent. + */ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *data, int msgs) { int size; @@ -146,11 +177,11 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da struct rt_can_sndbxinx_list *tx_tosnd = RT_NULL; rt_sem_take(&(tx_fifo->sem), RT_WAITING_FOREVER); - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); tx_tosnd = rt_list_entry(tx_fifo->freelist.next, struct rt_can_sndbxinx_list, list); RT_ASSERT(tx_tosnd != RT_NULL); rt_list_remove(&tx_tosnd->list); - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); no = ((rt_ubase_t)tx_tosnd - (rt_ubase_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list); tx_tosnd->result = RT_CAN_SND_RESULT_WAIT; @@ -158,9 +189,9 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da if (can->ops->sendmsg(can, data, no) != RT_EOK) { /* send failed. */ - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list); - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); rt_sem_release(&(tx_fifo->sem)); goto err_ret; } @@ -168,29 +199,29 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da can->status.sndchange |= 1<<no; if (rt_completion_wait(&(tx_tosnd->completion), RT_CANSND_MSG_TIMEOUT) != RT_EOK) { - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list); can->status.sndchange &= ~ (1<<no); - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); rt_sem_release(&(tx_fifo->sem)); goto err_ret; } - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); result = tx_tosnd->result; if (!rt_list_isempty(&tx_tosnd->list)) { rt_list_remove(&tx_tosnd->list); } rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list); - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); rt_sem_release(&(tx_fifo->sem)); if (result == RT_CAN_SND_RESULT_OK) { - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); can->status.sndpkg++; - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); data ++; msgs -= sizeof(struct rt_can_msg); @@ -199,9 +230,9 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da else { err_ret: - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); can->status.dropedsndpkg++; - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); break; } } @@ -209,6 +240,20 @@ err_ret: return (size - msgs); } +/** + * @internal + * @brief Handles blocking transmission in "private mode". + * + * This is a specialized version of `_can_int_tx` where the target hardware mailbox + * for each message is specified by the user in the `priv` field of the `rt_can_msg` + * structure, rather than being acquired dynamically from a pool. + * + * @param[in] can A pointer to the CAN device. + * @param[in] data A pointer to the source buffer of messages. + * @param[in] msgs The total size in bytes of the source buffer. + * + * @return The number of bytes successfully sent. + */ rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_msg *data, int msgs) { int size; @@ -230,16 +275,16 @@ rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_ms break; } - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); if ((tx_fifo->buffer[no].result != RT_CAN_SND_RESULT_OK)) { - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER); continue; } tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_WAIT; - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); if (can->ops->sendmsg(can, data, no) != RT_EOK) { @@ -255,18 +300,18 @@ rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_ms result = tx_fifo->buffer[no].result; if (result == RT_CAN_SND_RESULT_OK) { - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); can->status.sndpkg++; - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); data ++; msgs -= sizeof(struct rt_can_msg); if (!msgs) break; } else { - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); can->status.dropedsndpkg++; - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); break; } } @@ -274,6 +319,76 @@ rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_ms return (size - msgs); } +/** + * @internal + * @brief Internal implementation of non-blocking CAN transmission. + * + * This function iterates through a buffer of CAN messages and attempts to send each one + * using a non-blocking strategy. It first tries to send directly via hardware (fast path). + * If the hardware is busy, it enqueues the message into a software ring buffer (slow path). + * This function is thread-safe and ISR-safe due to the use of critical sections for + * accessing the shared ring buffer. + * + * @param[in] can A pointer to the CAN device. + * @param[in] pmsg A pointer to the buffer of `rt_can_msg` structures. + * @param[in] size The total size of the buffer in bytes. + * + * @return The number of bytes successfully sent or enqueued for later transmission. + */ +static rt_ssize_t _can_nonblocking_tx(struct rt_can_device *can, const struct rt_can_msg *pmsg, rt_size_t size) +{ + rt_ssize_t sent_size = 0; + rt_base_t level; + + if (can->ops->sendmsg_nonblocking == RT_NULL) + { + return -RT_EINVAL; + } + + while (sent_size < size) + { + if (can->ops->sendmsg_nonblocking(can, pmsg) == RT_EOK) + { + pmsg++; + sent_size += sizeof(struct rt_can_msg); + continue; + } + + level = rt_hw_local_irq_disable(); + if (rt_ringbuffer_space_len(&can->nb_tx_rb) >= sizeof(struct rt_can_msg)) + { + rt_ringbuffer_put(&can->nb_tx_rb, (rt_uint8_t *)pmsg, sizeof(struct rt_can_msg)); + rt_hw_local_irq_enable(level); + + pmsg++; + sent_size += sizeof(struct rt_can_msg); + } + else + { + /* Buffer is full, cannot process this message or subsequent ones. */ + can->status.dropedsndpkg += (size - sent_size) / sizeof(struct rt_can_msg); + rt_hw_local_irq_enable(level); + break; + } + } + + return sent_size; +} + +/** + * @internal + * @brief Opens the CAN device and initializes its resources. + * + * This function is called when `rt_device_open()` is invoked on a CAN device. + * It allocates and initializes software FIFOs for reception and transmission, + * sets up semaphores for the blocking send mechanism, configures the non-blocking + * send buffer, and starts the periodic status timer. + * + * @param[in] dev A pointer to the device to be opened. + * @param[in] oflag The open flags, e.g., `RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX`. + * + * @return `RT_EOK` on successful opening, or an error code on failure. + */ static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag) { struct rt_can_device *can; @@ -369,6 +484,12 @@ static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag) } #endif +#ifdef RT_CAN_MALLOC_NB_TX_BUFFER + can->nb_tx_rb_pool = (rt_uint8_t *)rt_malloc(RT_CAN_NB_TX_FIFO_SIZE); + RT_ASSERT(can->nb_tx_rb_pool != RT_NULL); +#endif /* RT_CAN_MALLOC_NB_TX_BUFFER */ + rt_ringbuffer_init(&can->nb_tx_rb, can->nb_tx_rb_pool, RT_CAN_NB_TX_FIFO_SIZE); + if (!can->timerinitflag) { can->timerinitflag = 1; @@ -397,6 +518,14 @@ static rt_err_t rt_can_close(struct rt_device *dev) return RT_EOK; } +#ifdef RT_CAN_MALLOC_NB_TX_BUFFER + if (can->nb_tx_rb_pool) + { + rt_free(can->nb_tx_rb_pool); + can->nb_tx_rb_pool = RT_NULL; + } +#endif + if (can->timerinitflag) { can->timerinitflag = 0; @@ -461,7 +590,7 @@ static rt_ssize_t rt_can_read(struct rt_device *dev, struct rt_can_device *can; RT_ASSERT(dev != RT_NULL); - if (size == 0) return 0; + if (size == 0) return -RT_EINVAL; can = (struct rt_can_device *)dev; @@ -470,22 +599,64 @@ static rt_ssize_t rt_can_read(struct rt_device *dev, return _can_int_rx(can, buffer, size); } - return 0; + return -RT_ENOSYS; } +/** + * @brief Write data to the CAN device. + * + * This function serves as the unified entry point for sending CAN messages. + * It intelligently routes the request to either a blocking or non-blocking + * transmission function based on: + * 1. The calling context (thread or ISR). + * 2. A user-specified flag (`nonblocking`) in the message structure. + * + * @param[in] dev A pointer to the device object. + * @param[in] pos This parameter is ignored for CAN devices. + * @param[in] buffer A pointer to the buffer containing one or more `rt_can_msg` structures. + * @param[in] size The total size of the buffer in bytes. Must be a multiple of `sizeof(struct rt_can_msg)`. + * + * @return The number of bytes successfully written. For non-blocking sends, this means + * the data was either sent directly or enqueued in the buffer. + */ static rt_ssize_t rt_can_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size) { struct rt_can_device *can; + const struct rt_can_msg *pmsg; RT_ASSERT(dev != RT_NULL); - if (size == 0) return 0; + RT_ASSERT(buffer != RT_NULL); + + if (size == 0) return -RT_EINVAL; + + /* Ensure size is a multiple of the message size for buffer operations */ + if (size % sizeof(struct rt_can_msg) != 0) + { + return -RT_EINVAL; + } can = (struct rt_can_device *)dev; + pmsg = (const struct rt_can_msg *)buffer; + + if(dev->ref_count == 0) + { + return -RT_ENOSYS; + } - if ((dev->open_flag & RT_DEVICE_FLAG_INT_TX) && (dev->ref_count > 0)) + /* + * Routing to the non-blocking send scenario: + * 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) + { + return _can_nonblocking_tx(can, pmsg, size); + } + + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) { if (can->config.privmode) { @@ -496,7 +667,7 @@ static rt_ssize_t rt_can_write(struct rt_device *dev, return _can_int_tx(can, buffer, size); } } - return 0; + return -RT_ENOSYS; } static rt_err_t rt_can_control(struct rt_device *dev, @@ -542,7 +713,7 @@ static rt_err_t rt_can_control(struct rt_device *dev, { for (i = 0; i < can->config.sndboxnumber; i++) { - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); if(rt_list_isempty(&tx_fifo->buffer[i].list)) { rt_sem_release(&(tx_fifo->sem)); @@ -551,7 +722,7 @@ static rt_err_t rt_can_control(struct rt_device *dev, { rt_list_remove(&tx_fifo->buffer[i].list); } - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); } } @@ -559,12 +730,12 @@ static rt_err_t rt_can_control(struct rt_device *dev, { for (i = 0; i < can->config.sndboxnumber; i++) { - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); if (tx_fifo->buffer[i].result == RT_CAN_SND_RESULT_OK) { rt_list_insert_before(&tx_fifo->freelist, &tx_fifo->buffer[i].list); } - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); } } } @@ -603,18 +774,18 @@ static rt_err_t rt_can_control(struct rt_device *dev, continue; } - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); if (!can->hdr[pitem->hdr_bank].connected) { - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); rt_memcpy(&can->hdr[pitem->hdr_bank].filter, pitem, sizeof(struct rt_can_filter_item)); - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); can->hdr[pitem->hdr_bank].connected = 1; can->hdr[pitem->hdr_bank].msgs = 0; rt_list_init(&can->hdr[pitem->hdr_bank].list); } - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); count--; pitem++; @@ -630,7 +801,7 @@ static rt_err_t rt_can_control(struct rt_device *dev, pitem++; continue; } - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); if (can->hdr[pitem->hdr_bank].connected) { @@ -640,13 +811,13 @@ static rt_err_t rt_can_control(struct rt_device *dev, { rt_list_remove(can->hdr[pitem->hdr_bank].list.next); } - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); rt_memset(&can->hdr[pitem->hdr_bank].filter, 0, sizeof(struct rt_can_filter_item)); } else { - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); } count--; pitem++; @@ -675,8 +846,17 @@ static rt_err_t rt_can_control(struct rt_device *dev, return res; } -/* - * can timer +/** + * @internal + * @brief Periodic timer callback for the CAN device. + * + * This function is executed periodically by a system timer. Its main purposes are: + * 1. To query the current status of the CAN controller (e.g., error counters, bus state). + * 2. To invoke a user-registered status indicator callback, if any. + * 3. To call a user-registered bus hook function for periodic tasks, if any. + * + * @param[in] arg The argument passed to the callback, which is a pointer to the `rt_can_device`. + * @return void */ static void cantimeout(void *arg) { @@ -740,6 +920,10 @@ rt_err_t rt_hw_can_register(struct rt_can_device *can, can->bus_hook = RT_NULL; #endif /*RT_CAN_USING_BUS_HOOK*/ +#ifdef RT_CAN_MALLOC_NB_TX_BUFFER + can->nb_tx_rb_pool = RT_NULL; +#endif + #ifdef RT_USING_DEVICE_OPS device->ops = &can_device_ops; #else @@ -770,6 +954,17 @@ rt_err_t rt_hw_can_register(struct rt_can_device *can, } /* ISR for can interrupt */ +/** + * @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. + * @return void + */ void rt_hw_can_isr(struct rt_can_device *can, int event) { switch (event & 0xff) @@ -777,9 +972,9 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) case RT_CAN_EVENT_RXOF_IND: { rt_base_t level; - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); can->status.dropedrcvpkg++; - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); } case RT_CAN_EVENT_RX_IND: { @@ -803,7 +998,7 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) if (ch == -1) break; /* disable interrupt */ - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); can->status.rcvpkg++; can->status.rcvchange = 1; if (!rt_list_isempty(&rx_fifo->freelist)) @@ -836,12 +1031,12 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) #endif } /* enable interrupt */ - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); if (listmsg != RT_NULL) { rt_memcpy(&listmsg->data, &tmpmsg, sizeof(struct rt_can_msg)); - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); rt_list_insert_before(&rx_fifo->uselist, &listmsg->list); #ifdef RT_CAN_USING_HDR hdr = tmpmsg.hdr_index; @@ -857,7 +1052,7 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) } #endif - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); } /* invoke callback */ @@ -867,9 +1062,9 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) rt_size_t rx_length; RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0); - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); rx_length = can->hdr[hdr].msgs * sizeof(struct rt_can_msg); - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); if (rx_length) { can->hdr[hdr].filter.ind(&can->parent, can->hdr[hdr].filter.args, hdr, rx_length); @@ -882,10 +1077,10 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) { rt_size_t rx_length; - level = rt_hw_interrupt_disable(); + level = rt_hw_local_irq_disable(); /* get rx length */ rx_length = rt_list_len(&rx_fifo->uselist)* sizeof(struct rt_can_msg); - rt_hw_interrupt_enable(level); + rt_hw_local_irq_enable(level); if (rx_length) { @@ -904,6 +1099,7 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) no = event >> 8; tx_fifo = (struct rt_can_tx_fifo *) can->can_tx; RT_ASSERT(tx_fifo != RT_NULL); + if (can->status.sndchange&(1<<no)) { if ((event & 0xff) == RT_CAN_EVENT_TX_DONE) @@ -916,6 +1112,37 @@ void rt_hw_can_isr(struct rt_can_device *can, int event) } rt_completion_done(&(tx_fifo->buffer[no].completion)); } + + if (can->ops->sendmsg_nonblocking != RT_NULL) + { + while (RT_TRUE) + { + struct rt_can_msg msg_to_send; + rt_base_t level; + rt_bool_t msg_was_present = RT_FALSE; + + level = rt_hw_local_irq_disable(); + if (rt_ringbuffer_data_len(&can->nb_tx_rb) >= sizeof(struct rt_can_msg)) + { + rt_ringbuffer_get(&can->nb_tx_rb, (rt_uint8_t *)&msg_to_send, sizeof(struct rt_can_msg)); + msg_was_present = RT_TRUE; + } + rt_hw_local_irq_enable(level); + + if (!msg_was_present) + { + break; + } + + if (can->ops->sendmsg_nonblocking(can, &msg_to_send) != RT_EOK) + { + level = rt_hw_local_irq_disable(); + rt_ringbuffer_put_force(&can->nb_tx_rb, (rt_uint8_t *)&msg_to_send, sizeof(struct rt_can_msg)); + rt_hw_local_irq_enable(level); + break; + } + } + } break; } } |
