* @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 waitin
| 159 | * @return The number of bytes successfully sent. |
| 160 | */ |
| 161 | rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *data, int msgs) |
| 162 | { |
| 163 | int size; |
| 164 | struct rt_can_tx_fifo *tx_fifo; |
| 165 | |
| 166 | RT_ASSERT(can != RT_NULL); |
| 167 | |
| 168 | size = msgs; |
| 169 | tx_fifo = (struct rt_can_tx_fifo *) can->can_tx; |
| 170 | RT_ASSERT(tx_fifo != RT_NULL); |
| 171 | |
| 172 | while (msgs) |
| 173 | { |
| 174 | rt_base_t level; |
| 175 | rt_uint32_t no; |
| 176 | rt_uint32_t result; |
| 177 | struct rt_can_sndbxinx_list *tx_tosnd = RT_NULL; |
| 178 | |
| 179 | rt_sem_take(&(tx_fifo->sem), RT_WAITING_FOREVER); |
| 180 | level = rt_hw_local_irq_disable(); |
| 181 | tx_tosnd = rt_list_entry(tx_fifo->freelist.next, struct rt_can_sndbxinx_list, list); |
| 182 | RT_ASSERT(tx_tosnd != RT_NULL); |
| 183 | rt_list_remove(&tx_tosnd->list); |
| 184 | rt_hw_local_irq_enable(level); |
| 185 | |
| 186 | no = ((rt_ubase_t)tx_tosnd - (rt_ubase_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list); |
| 187 | tx_tosnd->result = RT_CAN_SND_RESULT_WAIT; |
| 188 | rt_completion_init(&tx_tosnd->completion); |
| 189 | if (can->ops->sendmsg(can, data, no) != RT_EOK) |
| 190 | { |
| 191 | /* send failed. */ |
| 192 | level = rt_hw_local_irq_disable(); |
| 193 | rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list); |
| 194 | rt_hw_local_irq_enable(level); |
| 195 | rt_sem_release(&(tx_fifo->sem)); |
| 196 | goto err_ret; |
| 197 | } |
| 198 | |
| 199 | can->status.sndchange |= 1<<no; |
| 200 | if (rt_completion_wait(&(tx_tosnd->completion), RT_CANSND_MSG_TIMEOUT) != RT_EOK) |
| 201 | { |
| 202 | level = rt_hw_local_irq_disable(); |
| 203 | rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list); |
| 204 | can->status.sndchange &= ~ (1<<no); |
| 205 | rt_hw_local_irq_enable(level); |
| 206 | rt_sem_release(&(tx_fifo->sem)); |
| 207 | goto err_ret; |
| 208 | } |
| 209 | |
| 210 | level = rt_hw_local_irq_disable(); |
| 211 | result = tx_tosnd->result; |
| 212 | if (!rt_list_isempty(&tx_tosnd->list)) |
| 213 | { |
| 214 | rt_list_remove(&tx_tosnd->list); |
| 215 | } |
| 216 | rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list); |
| 217 | rt_hw_local_irq_enable(level); |
| 218 | rt_sem_release(&(tx_fifo->sem)); |
no test coverage detected