diff options
| author | RyanCW <[email protected]> | 2025-08-16 11:51:57 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-16 11:51:57 +0800 |
| commit | e0243e87c0230f2afcdce3e1070755f78dfee9c7 (patch) | |
| tree | e1aff5d61d6231fee568b371fcb9a1864e93bdd8 /components/drivers | |
| parent | 329cffd77e203ab73f098188b0ec02b6ef6af0ed (diff) | |
[component][drivers][serial_v2] 优化serial_v2 (#10603)
* [bsp][stm32][drv_usart_v2] uart_isr不再使用链式调用,RXNE内循环读空,一些细节优化
* [componnents][drivers][serial_v2] 增加获取config接口,使用rt_tick_get_delta替代内部的时间绕回判断,写满丢弃策略rx接收数据错乱修复,clang-tidy和cppcheck审查优化
* [utest][drivers][serial_v2] 测试例程进行优化
* [bsp][stm32][drv_usart_v2] 撤回DMAMUX1修改
* [componnents][drivers][serial_v2] read和write不再返回-RT_ETIMEOUT改为已发送或读取的字节数,细节优化
* [utest][drivers][serial_v2] 增加单独的timeout测试,减少测试中的硬延时
* [utest][drivers][serial_v2] 漏提交的posix下标志位
* [utest][drivers][serial_v2] 优化测试例程
* [bsp][stm32][drv_usart_v2] transmit返回错误值,RXNE增加超时逻辑
* [componnents][drivers][serial_v2] 增加transmit错误处理,增加超时退出机制显式的避免死循环
* [componnents][drivers][serial_v2] 适配serial_v2和posix非libc标准库下的console和shell
Diffstat (limited to 'components/drivers')
| -rw-r--r-- | components/drivers/include/drivers/dev_serial_v2.h | 6 | ||||
| -rw-r--r-- | components/drivers/serial/dev_serial_v2.c | 403 |
2 files changed, 236 insertions, 173 deletions
diff --git a/components/drivers/include/drivers/dev_serial_v2.h b/components/drivers/include/drivers/dev_serial_v2.h index 5360b011e3..b987bc4543 100644 --- a/components/drivers/include/drivers/dev_serial_v2.h +++ b/components/drivers/include/drivers/dev_serial_v2.h @@ -210,6 +210,7 @@ #define RT_SERIAL_CTRL_RX_FLUSH 0x45 /* clear rx buffer. Discard all data */ #define RT_SERIAL_CTRL_TX_FLUSH 0x46 /* clear tx buffer. Blocking and wait for the send buffer data to be sent. not supported in poll mode */ #define RT_SERIAL_CTRL_GET_UNREAD_BYTES_COUNT 0x47 /* get unread bytes count. not supported in poll mode */ +#define RT_SERIAL_CTRL_GET_CONFIG 0x48 /* get serial config */ #define RT_SERIAL_ERR_OVERRUN 0x01 #define RT_SERIAL_ERR_FRAMING 0x02 @@ -336,7 +337,12 @@ struct rt_serial_device #ifdef RT_USING_SERIAL_BYPASS struct rt_serial_bypass* bypass; #endif + struct rt_device_notify rx_notify; + +#ifdef RT_USING_POSIX_STDIO + rt_bool_t is_posix_mode; +#endif }; /** diff --git a/components/drivers/serial/dev_serial_v2.c b/components/drivers/serial/dev_serial_v2.c index dc09da1f69..2a526c809a 100644 --- a/components/drivers/serial/dev_serial_v2.c +++ b/components/drivers/serial/dev_serial_v2.c @@ -61,9 +61,10 @@ static rt_err_t serial_fops_rx_ind(rt_device_t dev, rt_size_t size) /* fops for serial */ static int serial_fops_open(struct dfs_file *fd) { - rt_err_t ret = 0; - rt_uint16_t flags = 0; - rt_device_t device; + rt_err_t ret = 0; + rt_uint16_t flags = 0; + rt_device_t device; + struct rt_serial_device *serial; device = (rt_device_t)fd->vnode->data; RT_ASSERT(device != RT_NULL); @@ -89,8 +90,14 @@ static int serial_fops_open(struct dfs_file *fd) if ((fd->flags & O_ACCMODE) != O_WRONLY) rt_device_set_rx_indicate(device, serial_fops_rx_ind); + + rt_device_close(device); ret = rt_device_open(device, flags | RT_SERIAL_RX_BLOCKING | RT_SERIAL_TX_BLOCKING); - if (ret == RT_EOK) return 0; + if (ret == RT_EOK) + { + serial = (struct rt_serial_device *)device; + serial->is_posix_mode = RT_TRUE; + } return ret; } @@ -125,6 +132,8 @@ static int serial_fops_ioctl(struct dfs_file *fd, int cmd, void *args) fd->flags &= ~mask; fd->flags |= flags; break; + default: + break; } return rt_device_control(device, cmd, args); @@ -204,13 +213,10 @@ static ssize_t serial_fops_write(struct dfs_file *fd, const void *buf, size_t co static int serial_fops_flush(struct dfs_file *fd) { - rt_device_t device; - struct rt_serial_device *serial; - + rt_device_t device; device = (rt_device_t)fd->vnode->data; RT_ASSERT(device != RT_NULL); - serial = (struct rt_serial_device *)device; rt_device_control(device, RT_SERIAL_CTRL_TX_FLUSH, (void *)RT_NULL); rt_device_control(device, RT_SERIAL_CTRL_RX_FLUSH, (void *)RT_NULL); @@ -379,8 +385,8 @@ rt_ssize_t _serial_poll_rx(struct rt_device *dev, int getc_element; /* Gets one byte of data received */ rt_uint8_t *getc_buffer; /* Pointer to the receive data buffer */ - if (size == 0) return 0; RT_ASSERT(dev != RT_NULL && buffer != RT_NULL); + if (size == 0) return 0; serial = (struct rt_serial_device *)dev; getc_buffer = (rt_uint8_t *)buffer; @@ -389,7 +395,7 @@ rt_ssize_t _serial_poll_rx(struct rt_device *dev, while (size) { getc_element = serial->ops->getc(serial); - if (getc_element == -1) break; + if (getc_element < 0) break; *getc_buffer = getc_element; @@ -424,6 +430,7 @@ rt_ssize_t _serial_poll_tx(struct rt_device *dev, struct rt_serial_device *serial; rt_size_t putc_size; rt_uint8_t *putc_buffer; /* Pointer to the transmit data buffer */ + int putc_result; if (size == 0) return 0; RT_ASSERT(dev != RT_NULL && buffer != RT_NULL); @@ -441,7 +448,8 @@ rt_ssize_t _serial_poll_tx(struct rt_device *dev, if (*putc_buffer == '\n') serial->ops->putc(serial, '\r'); } - serial->ops->putc(serial, *putc_buffer); + putc_result = serial->ops->putc(serial, *putc_buffer); + if (putc_result < 0) break; ++putc_buffer; --size; @@ -461,7 +469,7 @@ rt_ssize_t _serial_poll_tx(struct rt_device *dev, * @param pos Empty parameter. * @param buffer Receive data buffer. * @param size Receive data buffer length. - * @return Returns the actual length of data received. If a timeout occurs in blocking mode, it returns -RT_ETIMEOUT. + * @return Returns the actual length of data received. */ static rt_ssize_t _serial_fifo_rx(struct rt_device *dev, rt_off_t pos, @@ -482,15 +490,15 @@ static rt_ssize_t _serial_fifo_rx(struct rt_device *dev, if (dev->open_flag & RT_SERIAL_RX_BLOCKING) { rt_size_t data_len; - rt_tick_t now_tick; + rt_tick_t delta_tick; rt_size_t rx_bufsz_third = serial->config.rx_bufsz / 2; rt_int32_t base_rx_timeout = rt_atomic_load(&rx_fifo->rx_timeout); - rt_int32_t rx_timeout = base_rx_timeout; + rt_int32_t rx_timeout_left = base_rx_timeout; rt_tick_t begin_tick = rt_tick_get(); while (1) { - if (rx_timeout != RT_WAITING_NO) + if (rx_timeout_left != RT_WAITING_NO) { level = rt_spin_lock_irqsave(&serial->spinlock); data_len = rt_ringbuffer_data_len(&rx_fifo->rb); @@ -512,26 +520,24 @@ static rt_ssize_t _serial_fifo_rx(struct rt_device *dev, level = RT_SERIAL_FIFO_LOCK(&serial->spinlock); recv_size += rt_ringbuffer_get(&rx_fifo->rb, (rt_uint8_t *)buffer + recv_size, size - recv_size); RT_SERIAL_FIFO_UNLOCK(&serial->spinlock, level); - if (recv_size == size || rx_timeout == RT_WAITING_NO) + if (recv_size == size || rx_timeout_left == RT_WAITING_NO) { break; } - rt_completion_wait(&rx_fifo->rx_cpt, rx_timeout); - if (rx_timeout != RT_WAITING_FOREVER) + rt_completion_wait(&rx_fifo->rx_cpt, rx_timeout_left); + if (rx_timeout_left != RT_WAITING_FOREVER) { - now_tick = rt_tick_get(); - if (now_tick - begin_tick >= base_rx_timeout) + delta_tick = rt_tick_get_delta(begin_tick); + if (delta_tick >= base_rx_timeout) { - return -RT_ETIMEOUT; - } - else - { - if (now_tick > begin_tick) - rx_timeout = base_rx_timeout - (now_tick - begin_tick); - else - rx_timeout = begin_tick + base_rx_timeout - now_tick + 1; + level = RT_SERIAL_FIFO_LOCK(&serial->spinlock); + recv_size += rt_ringbuffer_get(&rx_fifo->rb, (rt_uint8_t *)buffer + recv_size, size - recv_size); + RT_SERIAL_FIFO_UNLOCK(&serial->spinlock, level); + return recv_size; } + + rx_timeout_left = base_rx_timeout - delta_tick; } } } @@ -554,7 +560,7 @@ static rt_ssize_t _serial_fifo_rx(struct rt_device *dev, * @param pos Empty parameter. * @param buffer Transmit data buffer. * @param size Transmit data buffer length. - * @return Returns the actual length of data transmitted. If a timeout occurs, it returns -RT_ETIMEOUT. + * @return Returns the actual length of data transmitted. */ static rt_ssize_t _serial_fifo_tx_blocking_nbuf(struct rt_device *dev, rt_off_t pos, @@ -594,28 +600,29 @@ static rt_ssize_t _serial_fifo_tx_blocking_nbuf(struct rt_device *dev, (rt_uint8_t *)buffer, size, RT_SERIAL_TX_BLOCKING); + if (send_size <= 0) + { + return 0; + } if (rt_atomic_load(&tx_fifo->tx_timeout) == RT_WAITING_NO) { - return send_size; + /* The implementation of POSIX nonblock mode is to set tx_timeout to RT_WAITING_NO */ +#ifdef RT_USING_POSIX_STDIO + if (serial->is_posix_mode) + return send_size; +#endif + return 0; } /* Waiting for the transmission to complete */ ret = rt_completion_wait(&tx_fifo->tx_cpt, rt_atomic_load(&tx_fifo->tx_timeout)); if (ret != RT_EOK) { - if (ret == -RT_ETIMEOUT) - { - return ret; - } - else - { - return 0; - } + /* Cannot get the number of bytes sent under DMA, so returns 0 directly */ + return 0; } - /* Inactive tx mode flag */ - rt_atomic_flag_clear(&tx_fifo->activated); return send_size; } @@ -626,7 +633,7 @@ static rt_ssize_t _serial_fifo_tx_blocking_nbuf(struct rt_device *dev, * @param pos Empty parameter. * @param buffer Transmit data buffer. * @param size Transmit data buffer length. - * @return Returns the final length of data transmitted. If not all data can be sent within the timeout period, returns -RT_ETIMEOUT. + * @return Returns the final length of data transmitted. */ static rt_ssize_t _serial_fifo_tx_blocking_buf(struct rt_device *dev, rt_off_t pos, @@ -657,11 +664,13 @@ static rt_ssize_t _serial_fifo_tx_blocking_buf(struct rt_device *dev, return 0; } - rt_tick_t now_tick; + rt_tick_t delta_tick; rt_int32_t base_tx_timeout = rt_atomic_load(&tx_fifo->tx_timeout); - rt_int32_t tx_timeout = base_tx_timeout; + rt_int32_t tx_timeout_left = base_tx_timeout; rt_tick_t begin_tick = rt_tick_get(); rt_size_t send_size = 0; + rt_size_t rb_size; + rt_ssize_t transmit_size; while (send_size != size) { @@ -671,6 +680,7 @@ static rt_ssize_t _serial_fifo_tx_blocking_buf(struct rt_device *dev, tx_fifo->put_size = rt_ringbuffer_put(&tx_fifo->rb, (rt_uint8_t *)buffer + send_size, size - send_size); + rb_size = rt_ringbuffer_data_len(&tx_fifo->rb); RT_SERIAL_FIFO_UNLOCK(&serial->spinlock, level); /* clear tx_cpt flag */ @@ -679,39 +689,44 @@ static rt_ssize_t _serial_fifo_tx_blocking_buf(struct rt_device *dev, /* Call the transmit interface for transmission again */ /* Note that in interrupt mode, buffer and tx_fifo->put_size * are inactive parameters */ - serial->ops->transmit(serial, - (rt_uint8_t *)buffer + send_size, - tx_fifo->put_size, - RT_SERIAL_TX_BLOCKING); - - send_size += tx_fifo->put_size; + transmit_size = serial->ops->transmit(serial, + (rt_uint8_t *)buffer + send_size, + tx_fifo->put_size, + RT_SERIAL_TX_BLOCKING); + if (transmit_size <= 0) + { + return send_size; + } - if (tx_timeout == RT_WAITING_NO) + if (tx_timeout_left == RT_WAITING_NO) { + /* The implementation of POSIX nonblock mode is to set tx_timeout to RT_WAITING_NO */ +#ifdef RT_USING_POSIX_STDIO + if (serial->is_posix_mode) + send_size += tx_fifo->put_size; +#endif break; } /* Waiting for the transmission to complete */ - rt_completion_wait(&tx_fifo->tx_cpt, tx_timeout); - if (tx_timeout != RT_WAITING_FOREVER) + rt_completion_wait(&tx_fifo->tx_cpt, tx_timeout_left); + if (tx_timeout_left != RT_WAITING_FOREVER) { - now_tick = rt_tick_get(); - if (now_tick - begin_tick >= base_tx_timeout) - { - return -RT_ETIMEOUT; - } - else + delta_tick = rt_tick_get_delta(begin_tick); + if (delta_tick >= base_tx_timeout) { - if (now_tick > begin_tick) - tx_timeout = base_tx_timeout - (now_tick - begin_tick); - else - tx_timeout = begin_tick + base_tx_timeout - now_tick + 1; + level = RT_SERIAL_FIFO_LOCK(&serial->spinlock); + send_size += rb_size - rt_ringbuffer_data_len(&tx_fifo->rb); + RT_SERIAL_FIFO_UNLOCK(&serial->spinlock, level); + return send_size; } + + tx_timeout_left = base_tx_timeout - delta_tick; } + + send_size += tx_fifo->put_size; } - /* Finally Inactivate the tx->fifo */ - rt_atomic_flag_clear(&tx_fifo->activated); return send_size; } @@ -734,7 +749,8 @@ static rt_ssize_t _serial_fifo_tx_nonblocking(struct rt_device *dev, struct rt_serial_tx_fifo *tx_fifo; rt_uint8_t *put_ptr; rt_base_t level; - rt_size_t send_size = 0; + rt_size_t send_size; + rt_ssize_t transmit_size; if (size == 0) return 0; RT_ASSERT(dev != RT_NULL && buffer != RT_NULL); @@ -761,10 +777,14 @@ static rt_ssize_t _serial_fifo_tx_nonblocking(struct rt_device *dev, /* Call the transmit interface for transmission again */ /* Note that in interrupt mode, put_ptr and tx_fifo->put_size * are inactive parameters */ - serial->ops->transmit(serial, - put_ptr, - tx_fifo->put_size, - RT_SERIAL_TX_NON_BLOCKING); + transmit_size = serial->ops->transmit(serial, + put_ptr, + tx_fifo->put_size, + RT_SERIAL_TX_NON_BLOCKING); + if (transmit_size <= 0) + { + return 0; + } /* In tx_nonblocking mode, there is no need to call rt_completion_wait() APIs to wait * for the rt_current_thread to resume */ return send_size; @@ -794,7 +814,8 @@ static rt_err_t rt_serial_tx_enable(struct rt_device *dev, rt_uint16_t tx_oflag) { struct rt_serial_device *serial; - struct rt_serial_tx_fifo *tx_fifo = RT_NULL; + struct rt_serial_tx_fifo *tx_fifo = RT_NULL; + rt_err_t control_result = RT_EOK; RT_ASSERT(dev != RT_NULL); serial = (struct rt_serial_device *)dev; @@ -824,11 +845,16 @@ static rt_err_t rt_serial_tx_enable(struct rt_device *dev, { /* When using RT_SERIAL_TX_BLOCKING, it is necessary to determine * whether serial device needs to use buffer */ - rt_err_t optmode; /* The operating mode used by serial device */ /* Call the Control() API to get the operating mode */ - optmode = serial->ops->control(serial, - RT_DEVICE_CHECK_OPTMODE, - (void *)RT_DEVICE_FLAG_TX_BLOCKING); + control_result = serial->ops->control(serial, + RT_DEVICE_CHECK_OPTMODE, + (void *)RT_DEVICE_FLAG_TX_BLOCKING); + if (control_result < 0) + { + return control_result; + } + + rt_err_t optmode = control_result; if (optmode == RT_SERIAL_TX_BLOCKING_BUFFER) { /* If use RT_SERIAL_TX_BLOCKING_BUFFER, the ringbuffer is initialized */ @@ -844,7 +870,7 @@ static rt_err_t rt_serial_tx_enable(struct rt_device *dev, dev->write = _serial_fifo_tx_blocking_buf; #endif } - else + else if (optmode == RT_SERIAL_TX_BLOCKING_NO_BUFFER) { /* If not use RT_SERIAL_TX_BLOCKING_BUFFER, * the control() API is called to configure the serial device */ @@ -860,9 +886,17 @@ static rt_err_t rt_serial_tx_enable(struct rt_device *dev, #endif /* Call the control() API to configure the serial device by RT_SERIAL_TX_BLOCKING*/ - serial->ops->control(serial, - RT_DEVICE_CTRL_CONFIG, - (void *)RT_SERIAL_TX_BLOCKING); + control_result = serial->ops->control(serial, + RT_DEVICE_CTRL_CONFIG, + (void *)RT_SERIAL_TX_BLOCKING); + if (control_result < 0) + { + goto __exit; + } + } + else + { + return -RT_EIO; } rt_atomic_flag_clear(&tx_fifo->activated); tx_fifo->put_size = 0; @@ -897,11 +931,12 @@ static rt_err_t rt_serial_tx_enable(struct rt_device *dev, dev->open_flag |= RT_SERIAL_TX_NON_BLOCKING; /* Call the control() API to configure the serial device by RT_SERIAL_TX_NON_BLOCKING*/ - serial->ops->control(serial, - RT_DEVICE_CTRL_CONFIG, - (void *)RT_SERIAL_TX_NON_BLOCKING); + control_result = serial->ops->control(serial, + RT_DEVICE_CTRL_CONFIG, + (void *)RT_SERIAL_TX_NON_BLOCKING); - return RT_EOK; +__exit: + return control_result; } @@ -974,11 +1009,7 @@ static rt_err_t rt_serial_rx_enable(struct rt_device *dev, { dev->open_flag |= RT_SERIAL_RX_NON_BLOCKING; /* Call the control() API to configure the serial device by RT_SERIAL_RX_NON_BLOCKING*/ - serial->ops->control(serial, - RT_DEVICE_CTRL_CONFIG, - (void *)RT_SERIAL_RX_NON_BLOCKING); - - return RT_EOK; + return serial->ops->control(serial, RT_DEVICE_CTRL_CONFIG, (void *)RT_SERIAL_RX_NON_BLOCKING); } /* When using RT_SERIAL_RX_BLOCKING, rt_completion_init() and rx_cpt_index are initialized */ @@ -988,11 +1019,7 @@ static rt_err_t rt_serial_rx_enable(struct rt_device *dev, rt_completion_init(&rx_fifo->rx_cpt); dev->open_flag |= RT_SERIAL_RX_BLOCKING; /* Call the control() API to configure the serial device by RT_SERIAL_RX_BLOCKING*/ - serial->ops->control(serial, - RT_DEVICE_CTRL_CONFIG, - (void *)RT_SERIAL_RX_BLOCKING); - - return RT_EOK; + return serial->ops->control(serial, RT_DEVICE_CTRL_CONFIG, (void *)RT_SERIAL_RX_BLOCKING); } /** @@ -1016,23 +1043,27 @@ static rt_err_t rt_serial_rx_disable(struct rt_device *dev, if (serial->serial_rx == RT_NULL) return RT_EOK; + rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; + RT_ASSERT(rx_fifo != RT_NULL); + if (rx_oflag == RT_SERIAL_RX_NON_BLOCKING) { dev->open_flag &= ~RT_SERIAL_RX_NON_BLOCKING; + /* disable ignore return value */ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_SERIAL_RX_NON_BLOCKING); } else { + rt_completion_done(&rx_fifo->rx_cpt); dev->open_flag &= ~RT_SERIAL_RX_BLOCKING; + /* disable ignore return value */ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_SERIAL_RX_BLOCKING); } - rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; - RT_ASSERT(rx_fifo != RT_NULL); rt_free(rx_fifo); serial->serial_rx = RT_NULL; @@ -1066,7 +1097,7 @@ static rt_err_t rt_serial_tx_disable(struct rt_device *dev, if (tx_oflag == RT_SERIAL_TX_NON_BLOCKING) { dev->open_flag &= ~RT_SERIAL_TX_NON_BLOCKING; - + /* disable ignore return value */ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_SERIAL_TX_NON_BLOCKING); @@ -1075,6 +1106,7 @@ static rt_err_t rt_serial_tx_disable(struct rt_device *dev, { rt_completion_done(&tx_fifo->tx_cpt); dev->open_flag &= ~RT_SERIAL_TX_BLOCKING; + /* disable ignore return value */ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_SERIAL_TX_BLOCKING); @@ -1112,6 +1144,36 @@ static rt_err_t rt_serial_init(struct rt_device *dev) } /** + * @brief Close the serial device. + * @param dev The pointer of device driver structure + * @return Return the status of the operation. + */ +static rt_err_t rt_serial_close(struct rt_device *dev) +{ + struct rt_serial_device *serial; + + RT_ASSERT(dev != RT_NULL); + serial = (struct rt_serial_device *)dev; + + /* Disable serial receive mode. */ + rt_serial_rx_disable(dev, dev->open_flag & (RT_SERIAL_RX_BLOCKING | RT_SERIAL_RX_NON_BLOCKING)); + /* Disable serial tranmit mode. */ + rt_serial_tx_disable(dev, dev->open_flag & (RT_SERIAL_TX_BLOCKING | RT_SERIAL_TX_NON_BLOCKING)); + + /* Clear the callback function */ + serial->parent.rx_indicate = RT_NULL; + serial->parent.tx_complete = RT_NULL; + + rt_memset(&serial->rx_notify, RT_NULL, sizeof(struct rt_device_notify)); + + /* Call the control() API to close the serial device. disable ignore return value */ + serial->ops->control(serial, RT_DEVICE_CTRL_CLOSE, RT_NULL); + dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED; + + return RT_EOK; +} + +/** * @brief Open the serial device. * @param dev The pointer of device driver structure * @param oflag The flag of that the serial port opens. @@ -1120,19 +1182,12 @@ static rt_err_t rt_serial_init(struct rt_device *dev) static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) { struct rt_serial_device *serial; + rt_err_t result = RT_EOK; RT_ASSERT(dev != RT_NULL); serial = (struct rt_serial_device *)dev; - /* Check that the device has been turned on */ - if ((dev->open_flag) & (15 << 12)) - { - LOG_D("(%s) serial device has already been opened, it will run in its original configuration", dev->parent.name); - return RT_EOK; - } - - LOG_D("open serial device: 0x%08x with open flag: 0x%04x", - dev, oflag); + LOG_D("open serial device: 0x%08x with open flag: 0x%04x", dev, oflag); /* By default, the receive mode of a serial devide is RT_SERIAL_RX_NON_BLOCKING */ if ((oflag & RT_SERIAL_RX_BLOCKING) == RT_SERIAL_RX_BLOCKING) @@ -1152,48 +1207,31 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) /* initialize the Rx structure according to open flag */ if (serial->serial_rx == RT_NULL) - rt_serial_rx_enable(dev, dev->open_flag & (RT_SERIAL_RX_BLOCKING | RT_SERIAL_RX_NON_BLOCKING)); + { + result = rt_serial_rx_enable(dev, dev->open_flag & (RT_SERIAL_RX_BLOCKING | RT_SERIAL_RX_NON_BLOCKING)); + if (result != RT_EOK) + { + rt_serial_close(dev); + goto __exit; + } + } /* initialize the Tx structure according to open flag */ if (serial->serial_tx == RT_NULL) - rt_serial_tx_enable(dev, dev->open_flag & (RT_SERIAL_TX_BLOCKING | RT_SERIAL_TX_NON_BLOCKING)); + { + result = rt_serial_tx_enable(dev, dev->open_flag & (RT_SERIAL_TX_BLOCKING | RT_SERIAL_TX_NON_BLOCKING)); + if (result != RT_EOK) + { + rt_serial_close(dev); + goto __exit; + } + } - return RT_EOK; +__exit: + return result; } -/** - * @brief Close the serial device. - * @param dev The pointer of device driver structure - * @return Return the status of the operation. - */ -static rt_err_t rt_serial_close(struct rt_device *dev) -{ - struct rt_serial_device *serial; - - RT_ASSERT(dev != RT_NULL); - serial = (struct rt_serial_device *)dev; - - /* this device has more reference count */ - if (dev->ref_count > 1) return -RT_ERROR; - /* Disable serial receive mode. */ - rt_serial_rx_disable(dev, dev->open_flag & (RT_SERIAL_RX_BLOCKING | RT_SERIAL_RX_NON_BLOCKING)); - /* Disable serial tranmit mode. */ - rt_serial_tx_disable(dev, dev->open_flag & (RT_SERIAL_TX_BLOCKING | RT_SERIAL_TX_NON_BLOCKING)); - - /* Clear the callback function */ - serial->parent.rx_indicate = RT_NULL; - serial->parent.tx_complete = RT_NULL; - - rt_memset(&serial->rx_notify, RT_NULL, sizeof(struct rt_device_notify)); - - /* Call the control() API to close the serial device */ - serial->ops->control(serial, RT_DEVICE_CTRL_CLOSE, RT_NULL); - dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED; - - return RT_EOK; -} - static void _serial_rx_flush(struct rt_serial_device *serial) { rt_base_t level; @@ -1202,8 +1240,10 @@ static void _serial_rx_flush(struct rt_serial_device *serial) if (serial->config.rx_bufsz == 0) { - while (serial->ops->getc(serial) != -1) + rt_uint32_t rx_flush_limit = 0xFFFFFFF; + while (serial->ops->getc(serial) != -1 && rx_flush_limit > 0) { + rx_flush_limit--; } } else @@ -1235,7 +1275,6 @@ static void _serial_tx_flush(struct rt_serial_device *serial) if (rt_atomic_load(&tx_fifo->activated)) { rt_completion_wait(&tx_fifo->tx_cpt, RT_WAITING_FOREVER); - return; } } } @@ -1252,15 +1291,14 @@ static rt_err_t _serial_get_unread_bytes_count(struct rt_serial_device *serial, *unread_bytes = -1; return -RT_EPERM; } - else - { - rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; - RT_ASSERT(rx_fifo != RT_NULL); - level = RT_SERIAL_FIFO_LOCK(&serial->spinlock); - *unread_bytes = rt_ringbuffer_data_len(&rx_fifo->rb); - RT_SERIAL_FIFO_UNLOCK(&serial->spinlock, level); - } + rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + level = RT_SERIAL_FIFO_LOCK(&serial->spinlock); + *unread_bytes = rt_ringbuffer_data_len(&rx_fifo->rb); + RT_SERIAL_FIFO_UNLOCK(&serial->spinlock, level); + return RT_EOK; } @@ -1384,6 +1422,17 @@ static rt_err_t rt_serial_control(struct rt_device *dev, serial->ops->configure(serial, (struct serial_configure *)args); } break; + case RT_SERIAL_CTRL_GET_CONFIG: + if (args == RT_NULL) + { + ret = -RT_EINVAL; + } + else + { + struct serial_configure *pconfig = (struct serial_configure *)args; + *pconfig = serial->config; + } + break; case RT_DEVICE_CTRL_NOTIFY_SET: if (args == RT_NULL) { @@ -1402,7 +1451,7 @@ static rt_err_t rt_serial_control(struct rt_device *dev, } else { - *(rt_uint16_t *)args = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM; + *(rt_uint16_t *)args = RT_DEVICE_FLAG_RDWR | RT_SERIAL_RX_BLOCKING | RT_SERIAL_TX_BLOCKING | RT_DEVICE_FLAG_STREAM; } break; @@ -1944,21 +1993,17 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) #ifdef RT_SERIAL_BUF_STRATEGY_DROP rt_uint8_t *ptr; rt_size_t size; - rt_size_t space_len; + rt_size_t put_len; /* UART_IT_IDLE and dma isr */ level = rt_spin_lock_irqsave(&serial->spinlock); do { - space_len = rt_ringbuffer_space_len(&rx_fifo->rb); - if (space_len == 0) - break; - rt_serial_update_write_index(&rx_fifo->dma_ping_rb, rx_length); size = rt_ringbuffer_peek(&rx_fifo->dma_ping_rb, &ptr); - space_len -= rt_ringbuffer_put(&rx_fifo->rb, ptr, size); - if (space_len == 0) + put_len = rt_ringbuffer_put(&rx_fifo->rb, ptr, size); + if (put_len != size) break; size = rt_ringbuffer_peek(&rx_fifo->dma_ping_rb, &ptr); @@ -1973,9 +2018,10 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) rt_size_t size; /* UART_IT_IDLE and dma isr */ level = rt_spin_lock_irqsave(&serial->spinlock); - rt_serial_update_write_index(&rx_fifo->dma_ping_rb, rx_length); do { + rt_serial_update_write_index(&rx_fifo->dma_ping_rb, rx_length); + size = rt_ringbuffer_peek(&rx_fifo->dma_ping_rb, &ptr); rt_ringbuffer_put_force(&rx_fifo->rb, ptr, size); @@ -2022,8 +2068,9 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) /* Interrupt transmit event */ case RT_SERIAL_EVENT_TX_DONE: { struct rt_serial_tx_fifo *tx_fifo; - rt_size_t tx_length = 0; - tx_fifo = (struct rt_serial_tx_fifo *)serial->serial_tx; + rt_size_t tx_length; + rt_ssize_t transmit_size; + tx_fifo = (struct rt_serial_tx_fifo *)serial->serial_tx; RT_ASSERT(tx_fifo != RT_NULL); /* Get the length of the data from the ringbuffer */ @@ -2049,22 +2096,28 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) /* Call the transmit interface for transmission again */ /* Note that in interrupt mode, tx_fifo->buffer and tx_length * are inactive parameters */ - serial->ops->transmit(serial, - tx_fifo->rb.buffer_ptr, - tx_length, - serial->parent.open_flag & (RT_SERIAL_TX_BLOCKING | RT_SERIAL_TX_NON_BLOCKING)); + transmit_size = serial->ops->transmit(serial, + tx_fifo->rb.buffer_ptr, + tx_length, + serial->parent.open_flag & (RT_SERIAL_TX_BLOCKING | RT_SERIAL_TX_NON_BLOCKING)); + if (transmit_size <= 0) + { + rt_atomic_flag_clear(&tx_fifo->activated); + } break; } #ifdef RT_SERIAL_USING_DMA case RT_SERIAL_EVENT_TX_DMADONE: { struct rt_serial_tx_fifo *tx_fifo; - rt_size_t tx_length = 0; - tx_fifo = (struct rt_serial_tx_fifo *)serial->serial_tx; + rt_size_t tx_length; + rt_ssize_t transmit_size; + tx_fifo = (struct rt_serial_tx_fifo *)serial->serial_tx; RT_ASSERT(tx_fifo != RT_NULL); - if ((serial->parent.open_flag & RT_SERIAL_TX_BLOCKING) != RT_SERIAL_TX_BLOCKING || rt_ringbuffer_get_size(&tx_fifo->rb) != 0) + /* nonblock */ + if ((serial->parent.open_flag & RT_SERIAL_TX_BLOCKING) != RT_SERIAL_TX_BLOCKING) { - // 每次进来中断就说明之前的put_size已经被发送完毕了 + /* Each interruption upon entry indicates that the previous `put_size` has already been sent completely */ rt_serial_update_read_index(&tx_fifo->rb, tx_fifo->put_size); /* Get the length of the data from the ringbuffer */ @@ -2076,15 +2129,19 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) * then call the transmit interface for transmission again */ rt_atomic_flag_test_and_set(&tx_fifo->activated); - rt_uint8_t *put_ptr = RT_NULL; + rt_uint8_t *put_ptr; /* Get the linear length buffer from ringbuffer */ tx_fifo->put_size = rt_serial_get_linear_buffer(&tx_fifo->rb, &put_ptr); /* Call the transmit interface for transmission again */ - serial->ops->transmit(serial, - put_ptr, - tx_fifo->put_size, - RT_SERIAL_TX_NON_BLOCKING); + transmit_size = serial->ops->transmit(serial, + put_ptr, + tx_fifo->put_size, + RT_SERIAL_TX_NON_BLOCKING); + if (transmit_size <= 0) + { + rt_atomic_flag_clear(&tx_fifo->activated); + } break; } } |
