feat(usbh_serial): Use Ping-Pong Buffer to Decrease Packet Loss
This commit is contained in:
@@ -165,27 +165,43 @@ static void usbh_serial_callback(void *arg, int nbytes)
|
|||||||
struct usbh_serial *serial = (struct usbh_serial *)arg;
|
struct usbh_serial *serial = (struct usbh_serial *)arg;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nbytes >= serial->driver->ignore_rx_header) {
|
if (nbytes < 0) {
|
||||||
usbh_serial_ringbuffer_write(&serial->rx_rb,
|
if (nbytes != -USB_ERR_SHUTDOWN) {
|
||||||
&serial->iobuffer[USBH_SERIAL_RX_NOCACHE_OFFSET + serial->driver->ignore_rx_header],
|
USB_LOG_ERR("serial transfer error: %d\n", nbytes);
|
||||||
(nbytes - serial->driver->ignore_rx_header));
|
}
|
||||||
|
serial->rx_errorcode = nbytes;
|
||||||
|
usb_osal_sem_give(serial->rx_complete_sem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbytes >= serial->driver->ignore_rx_header) {
|
||||||
/* resubmit the read urb */
|
/* resubmit the read urb */
|
||||||
usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[USBH_SERIAL_RX_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
|
usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX_NOCACHE_OFFSET : USBH_SERIAL_RX2_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
|
||||||
0, usbh_serial_callback, serial);
|
0, usbh_serial_callback, serial);
|
||||||
ret = usbh_submit_urb(&serial->bulkin_urb);
|
ret = usbh_submit_urb(&serial->bulkin_urb);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
USB_LOG_ERR("serial submit failed: %d\n", ret);
|
USB_LOG_ERR("serial submit failed: %d\n", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usbh_serial_ringbuffer_write(&serial->rx_rb,
|
||||||
|
&serial->iobuffer[(serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header],
|
||||||
|
(nbytes - serial->driver->ignore_rx_header));
|
||||||
|
|
||||||
if (serial->rx_complete_callback) {
|
if (serial->rx_complete_callback) {
|
||||||
serial->rx_complete_callback(serial, nbytes - serial->driver->ignore_rx_header);
|
serial->rx_complete_callback(serial, nbytes - serial->driver->ignore_rx_header);
|
||||||
}
|
}
|
||||||
|
serial->rx_buf_index ^= 1;
|
||||||
serial->rx_errorcode = 0;
|
serial->rx_errorcode = 0;
|
||||||
usb_osal_sem_give(serial->rx_complete_sem);
|
usb_osal_sem_give(serial->rx_complete_sem);
|
||||||
} else {
|
} else {
|
||||||
serial->rx_errorcode = nbytes;
|
serial->rx_errorcode = nbytes;
|
||||||
usb_osal_sem_give(serial->rx_complete_sem);
|
usb_osal_sem_give(serial->rx_complete_sem);
|
||||||
|
usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
|
||||||
|
0, usbh_serial_callback, serial);
|
||||||
|
ret = usbh_submit_urb(&serial->bulkin_urb);
|
||||||
|
if (ret < 0) {
|
||||||
|
USB_LOG_ERR("serial resubmit short packet failed: %d\n", ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,7 +455,8 @@ int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg)
|
|||||||
|
|
||||||
usbh_serial_ringbuffer_reset(&serial->rx_rb);
|
usbh_serial_ringbuffer_reset(&serial->rx_rb);
|
||||||
usb_osal_sem_reset(serial->rx_complete_sem);
|
usb_osal_sem_reset(serial->rx_complete_sem);
|
||||||
usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[USBH_SERIAL_RX_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
|
serial->rx_buf_index = 0;
|
||||||
|
usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
|
||||||
0, usbh_serial_callback, serial);
|
0, usbh_serial_callback, serial);
|
||||||
ret = usbh_submit_urb(&serial->bulkin_urb);
|
ret = usbh_submit_urb(&serial->bulkin_urb);
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#define USBH_SERIAL_INT_NOCACHE_OFFSET USB_ALIGN_UP(USBH_SERIAL_CTRL_NOCACHE_SIZE, CONFIG_USB_ALIGN_SIZE)
|
#define USBH_SERIAL_INT_NOCACHE_OFFSET USB_ALIGN_UP(USBH_SERIAL_CTRL_NOCACHE_SIZE, CONFIG_USB_ALIGN_SIZE)
|
||||||
#define USBH_SERIAL_RX_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_INT_NOCACHE_OFFSET + USBH_SERIAL_INT_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)
|
#define USBH_SERIAL_RX_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_INT_NOCACHE_OFFSET + USBH_SERIAL_INT_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)
|
||||||
#define USBH_SERIAL_RX_NOCACHE_SIZE 512
|
#define USBH_SERIAL_RX_NOCACHE_SIZE 512
|
||||||
|
#define USBH_SERIAL_RX2_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_RX_NOCACHE_OFFSET + USBH_SERIAL_RX_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)
|
||||||
|
#define USBH_SERIAL_RX2_NOCACHE_SIZE 512
|
||||||
|
|
||||||
#define USBH_SERIAL_DATABITS_5 5
|
#define USBH_SERIAL_DATABITS_5 5
|
||||||
#define USBH_SERIAL_DATABITS_6 6
|
#define USBH_SERIAL_DATABITS_6 6
|
||||||
@@ -52,7 +54,7 @@
|
|||||||
#define USBH_SERIAL_O_RDWR 0x0002 /* open for reading and writing */
|
#define USBH_SERIAL_O_RDWR 0x0002 /* open for reading and writing */
|
||||||
|
|
||||||
#define USBH_SERIAL_O_ACCMODE 0x0003 /* mask for above modes, from 4.4BSD https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/include/sys/fcntl.h */
|
#define USBH_SERIAL_O_ACCMODE 0x0003 /* mask for above modes, from 4.4BSD https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/include/sys/fcntl.h */
|
||||||
#define USBH_SERIAL_O_NONBLOCK 0x0004 /* non blocking I/O, from BSD apple https://opensource.apple.com/source/xnu/xnu-1228.0.2/bsd/sys/fcntl.h */
|
#define USBH_SERIAL_O_NONBLOCK 0x0004 /* non-blocking I/O, from BSD apple https://opensource.apple.com/source/xnu/xnu-1228.0.2/bsd/sys/fcntl.h */
|
||||||
|
|
||||||
#define USBH_SERIAL_CMD_SET_ATTR 0
|
#define USBH_SERIAL_CMD_SET_ATTR 0
|
||||||
#define USBH_SERIAL_CMD_GET_ATTR 1
|
#define USBH_SERIAL_CMD_GET_ATTR 1
|
||||||
@@ -144,6 +146,7 @@ struct usbh_serial {
|
|||||||
usbh_serial_ringbuf_t rx_rb;
|
usbh_serial_ringbuf_t rx_rb;
|
||||||
uint8_t rx_rb_pool[CONFIG_USBHOST_SERIAL_RX_SIZE];
|
uint8_t rx_rb_pool[CONFIG_USBHOST_SERIAL_RX_SIZE];
|
||||||
usb_osal_sem_t rx_complete_sem;
|
usb_osal_sem_t rx_complete_sem;
|
||||||
|
uint8_t rx_buf_index;
|
||||||
int rx_errorcode;
|
int rx_errorcode;
|
||||||
usbh_serial_rx_complete_callback_t rx_complete_callback;
|
usbh_serial_rx_complete_callback_t rx_complete_callback;
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_TEST_USBH_SERIAL
|
#if CONFIG_TEST_USBH_SERIAL
|
||||||
#define SERIAL_TEST_LEN (2 * 1024)
|
#define SERIAL_TEST_LEN (1 * 1024)
|
||||||
|
|
||||||
|
#if SERIAL_TEST_LEN >= CONFIG_USBHOST_SERIAL_RX_SIZE
|
||||||
|
#error SERIAL_TEST_LEN is larger than CONFIG_USBHOST_SERIAL_RX_SIZE, please reduce SERIAL_TEST_LEN or increase CONFIG_USBHOST_SERIAL_RX_SIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
volatile uint32_t serial_tx_bytes = 0;
|
volatile uint32_t serial_tx_bytes = 0;
|
||||||
volatile uint32_t serial_rx_bytes = 0;
|
volatile uint32_t serial_rx_bytes = 0;
|
||||||
@@ -94,7 +98,7 @@ static void usbh_serial_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
|||||||
for (uint8_t j = 0; j < 6; j++) {
|
for (uint8_t j = 0; j < 6; j++) {
|
||||||
uint32_t start_time = (uint32_t)xTaskGetTickCount();
|
uint32_t start_time = (uint32_t)xTaskGetTickCount();
|
||||||
for (uint32_t i = 0; i < TEST_COUNT; i++) {
|
for (uint32_t i = 0; i < TEST_COUNT; i++) {
|
||||||
usbh_serial_write(serialize, serial_speed_buffer, test_len[j]);
|
usbh_serial_write(serial, serial_speed_buffer, test_len[j]);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
USB_LOG_RAW("bulk out error,ret:%d\r\n", ret);
|
USB_LOG_RAW("bulk out error,ret:%d\r\n", ret);
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -105,6 +109,7 @@ static void usbh_serial_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
|||||||
uint32_t time_ms = xTaskGetTickCount() - start_time;
|
uint32_t time_ms = xTaskGetTickCount() - start_time;
|
||||||
USB_LOG_RAW("per packet len:%d, out speed:%f MB/S\r\n", (unsigned int)test_len[j], (test_len[j] * TEST_COUNT / 1024 / 1024) * 1000 / ((float)time_ms));
|
USB_LOG_RAW("per packet len:%d, out speed:%f MB/S\r\n", (unsigned int)test_len[j], (test_len[j] * TEST_COUNT / 1024 / 1024) * 1000 / ((float)time_ms));
|
||||||
}
|
}
|
||||||
|
goto delete_with_close;
|
||||||
#endif
|
#endif
|
||||||
memset(serial_tx_buffer, 0xA5, sizeof(serial_tx_buffer));
|
memset(serial_tx_buffer, 0xA5, sizeof(serial_tx_buffer));
|
||||||
USB_LOG_RAW("start serial loopback test, len: %d\r\n", SERIAL_TEST_LEN);
|
USB_LOG_RAW("start serial loopback test, len: %d\r\n", SERIAL_TEST_LEN);
|
||||||
@@ -118,7 +123,6 @@ static void usbh_serial_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
|||||||
goto delete_with_close;
|
goto delete_with_close;
|
||||||
} else {
|
} else {
|
||||||
serial_tx_bytes += ret;
|
serial_tx_bytes += ret;
|
||||||
usb_osal_msleep(10); // 11.52 Byte/ms at 115200bps --> 64Byte/5.5ms
|
|
||||||
|
|
||||||
if (serial_tx_bytes == SERIAL_TEST_LEN) {
|
if (serial_tx_bytes == SERIAL_TEST_LEN) {
|
||||||
USB_LOG_RAW("send over\r\n");
|
USB_LOG_RAW("send over\r\n");
|
||||||
@@ -130,7 +134,7 @@ static void usbh_serial_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
|||||||
volatile uint32_t wait_timeout = 0;
|
volatile uint32_t wait_timeout = 0;
|
||||||
serial_rx_bytes = 0;
|
serial_rx_bytes = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = usbh_serial_read(serial, &serial_rx_data[serial_rx_bytes], SERIAL_TEST_LEN);
|
ret = usbh_serial_read(serial, &serial_rx_data[serial_rx_bytes], SERIAL_TEST_LEN - serial_rx_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
USB_LOG_RAW("serial read error, ret:%d\r\n", ret);
|
USB_LOG_RAW("serial read error, ret:%d\r\n", ret);
|
||||||
goto delete_with_close;
|
goto delete_with_close;
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ usbh_serial_control
|
|||||||
usbh_serial_write
|
usbh_serial_write
|
||||||
""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
``usbh_serial_write`` 向串口写数据。 **串口设备如果是 USB2TTL 类型,必须按照波特率发送,否则会丢包**
|
``usbh_serial_write`` 向串口写数据。
|
||||||
|
|
||||||
.. code-block:: C
|
.. code-block:: C
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ usbh_serial_write
|
|||||||
usbh_serial_read
|
usbh_serial_read
|
||||||
""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
``usbh_serial_read`` 从串口读数据。 **如果没有设置波特率,不允许使用该 API**。
|
``usbh_serial_read`` 从串口读数据。 **如果没有设置波特率,不允许使用该 API,设置波特率后,内部会开启 rx 接收并将数据写入 ringbuf **。
|
||||||
|
|
||||||
.. code-block:: C
|
.. code-block:: C
|
||||||
|
|
||||||
@@ -244,7 +244,7 @@ usbh_serial_cdc_write_async
|
|||||||
usbh_serial_cdc_read_async
|
usbh_serial_cdc_read_async
|
||||||
""""""""""""""""""""""""""""""""""""
|
""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
``usbh_serial_cdc_read_async`` 异步从串口读数据。 **如果设置了波特率,不允许使用该 API**。
|
``usbh_serial_cdc_read_async`` 异步从串口读数据。 **如果设置了波特率,不允许使用该 API,设置波特率后,内部会开启 rx 接收并将数据写入 ringbuf **。
|
||||||
|
|
||||||
.. code-block:: C
|
.. code-block:: C
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ Serial 框架当前支持 cdc acm, ftdi, cp210x, ch34x, pl2303,gsm 驱动。
|
|||||||
goto delete_with_close;
|
goto delete_with_close;
|
||||||
} else {
|
} else {
|
||||||
serial_tx_bytes += ret;
|
serial_tx_bytes += ret;
|
||||||
usb_osal_msleep(10); // 11.52 Byte/ms at 115200bps --> 64Byte/5.5ms
|
|
||||||
|
|
||||||
if (serial_tx_bytes == SERIAL_TEST_LEN) {
|
if (serial_tx_bytes == SERIAL_TEST_LEN) {
|
||||||
USB_LOG_RAW("send over\r\n");
|
USB_LOG_RAW("send over\r\n");
|
||||||
@@ -55,7 +54,7 @@ Serial 框架当前支持 cdc acm, ftdi, cp210x, ch34x, pl2303,gsm 驱动。
|
|||||||
volatile uint32_t wait_timeout = 0;
|
volatile uint32_t wait_timeout = 0;
|
||||||
serial_rx_bytes = 0;
|
serial_rx_bytes = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = usbh_serial_read(serial, &serial_rx_data[serial_rx_bytes], SERIAL_TEST_LEN);
|
ret = usbh_serial_read(serial, &serial_rx_data[serial_rx_bytes], SERIAL_TEST_LEN - serial_rx_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
USB_LOG_RAW("serial read error, ret:%d\r\n", ret);
|
USB_LOG_RAW("serial read error, ret:%d\r\n", ret);
|
||||||
goto delete_with_close;
|
goto delete_with_close;
|
||||||
@@ -86,11 +85,12 @@ Serial 框架当前支持 cdc acm, ftdi, cp210x, ch34x, pl2303,gsm 驱动。
|
|||||||
|
|
||||||
usbh_serial_close(serial);
|
usbh_serial_close(serial);
|
||||||
|
|
||||||
|
.. note:: 需要注意,例程中使用的是比较简单的先发送后读取的方式,因此发送的总长度不可以超过 CONFIG_USBHOST_SERIAL_RX_SIZE,正常使用 TX/RX 请分开进行。
|
||||||
|
|
||||||
用户需要考虑以下三种场景:
|
用户需要考虑以下三种场景:
|
||||||
|
|
||||||
- USB2TTL 设备 + 启用了波特率,这种情况下需要使用 `usbh_serial_write` 和 `usbh_serial_read` 进行收发数据, **并且需要根据波特率控制发送频率,防止对端丢包**;
|
- USB2TTL 设备 + 启用了波特率,这种情况下需要使用 `usbh_serial_write` 和 `usbh_serial_read` 进行收发数据, **并且 read 操作需要及时,防止 ringbuf 数据溢出而丢包**;
|
||||||
|
|
||||||
- 纯 USB 设备 + 未启动波特率,这种情况下可以使用 `usbh_serial_cdc_write_async` 和 `usbh_serial_cdc_read_async` 进行异步收发数据,阻塞则用 `usbh_serial_write` 并且不需要控制发送频率。不可以使用 `usbh_serial_read`。
|
- 纯 USB 设备 + 未启动波特率,这种情况下可以使用 `usbh_serial_cdc_write_async` 和 `usbh_serial_cdc_read_async` 进行异步收发数据。阻塞则可以用 `usbh_serial_write` ,不可以使用 `usbh_serial_read`。
|
||||||
|
|
||||||
- 纯 USB 设备 + 启动波特率,同 1,但是速率打折扣。不可以使用 `usbh_serial_cdc_write_async` 和 `usbh_serial_cdc_read_async`。如果是 GSM 设备需要使用第一种。
|
- 纯 USB 设备 + 启动波特率,同 1,但是速率打折扣(因为多了一层 ringbuf)。此时也不可以使用 `usbh_serial_cdc_write_async` 和 `usbh_serial_cdc_read_async`。 **如果是 GSM 设备请使用第一种场景**。
|
||||||
Reference in New Issue
Block a user