summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorweety <[email protected]>2019-02-03 20:36:34 +0800
committerweety <[email protected]>2019-02-03 20:36:34 +0800
commit52931759987da58fe07388ab379327d51c9f569f (patch)
tree0f680a122214fe9cd45b82cbacb23d7a35418e66
parent48aa29756097f1b2512dbfec51672a9a23c42405 (diff)
Fixed data loss issue when USB CDC serial works in dma transmission mode.
-rw-r--r--components/drivers/usb/usbdevice/class/cdc_vcom.c96
1 files changed, 48 insertions, 48 deletions
diff --git a/components/drivers/usb/usbdevice/class/cdc_vcom.c b/components/drivers/usb/usbdevice/class/cdc_vcom.c
index 336cfcb152..b6044b37a7 100644
--- a/components/drivers/usb/usbdevice/class/cdc_vcom.c
+++ b/components/drivers/usb/usbdevice/class/cdc_vcom.c
@@ -63,6 +63,7 @@ static struct ucdc_line_coding line_coding;
#define CDC_BULKIN_MAXSIZE (CDC_TX_BUFSIZE / 8)
#define CDC_TX_HAS_DATE 0x01
+#define CDC_TX_HAS_SPACE 0x02
struct vcom
{
@@ -693,23 +694,48 @@ static int _vcom_getc(struct rt_serial_device *serial)
return result;
}
-static rt_size_t _vcom_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size,int direction)
+
+static rt_size_t _vcom_rb_block_put(struct vcom *data, const rt_uint8_t *buf, rt_size_t size)
{
rt_uint32_t level;
+ rt_size_t put_len = 0;
+ rt_size_t w_ptr = 0;
+ rt_uint32_t res;
+ rt_size_t remain_size = size;
+
+ while (remain_size)
+ {
+ level = rt_hw_interrupt_disable();
+ put_len = rt_ringbuffer_put(&data->tx_ringbuffer, (const rt_uint8_t *)&buf[w_ptr], remain_size);
+ rt_hw_interrupt_enable(level);
+ w_ptr += put_len;
+ remain_size -= put_len;
+ if (put_len == 0)
+ {
+ rt_event_recv(&data->tx_event, CDC_TX_HAS_SPACE,
+ RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+ VCOM_TX_TIMEOUT, &res);
+ }
+ else
+ {
+ rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
+ }
+ }
+
+ return size;
+}
+static rt_size_t _vcom_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size,int direction)
+{
struct ufunction *func;
struct vcom *data;
- rt_uint32_t baksize;
+ rt_uint32_t send_size = 0;
rt_size_t ptr = 0;
- int empty = 0;
rt_uint8_t crlf[2] = {'\r', '\n',};
func = (struct ufunction*)serial->parent.user_data;
data = (struct vcom*)func->user_data;
- size = (size >= CDC_BULKIN_MAXSIZE) ? CDC_BULKIN_MAXSIZE : size;
- baksize = size;
-
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(buf != RT_NULL);
@@ -717,64 +743,37 @@ static rt_size_t _vcom_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_s
if (data->connected)
{
- size = 0;
if((serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
{
- empty = 0;
- while(ptr < baksize)
+ while(send_size < size)
{
- while(ptr < baksize && buf[ptr] != '\n')
+ while(ptr < size && buf[ptr] != '\n')
{
ptr++;
}
- if(ptr < baksize)
+ if(ptr < size)
{
- level = rt_hw_interrupt_disable();
- size += rt_ringbuffer_put_force(&data->tx_ringbuffer, (const rt_uint8_t *)&buf[size], ptr - size);
- rt_hw_interrupt_enable(level);
-
- /* no data was be ignored */
- if(size == ptr)
- {
- level = rt_hw_interrupt_disable();
- if(rt_ringbuffer_space_len(&data->tx_ringbuffer) >= 2)
- {
- rt_ringbuffer_put_force(&data->tx_ringbuffer, crlf, 2);
- size++;
- }
- rt_hw_interrupt_enable(level);
- }
- else
- {
- empty = 1;
- break;
- }
-
- /* ring buffer is full */
- if(size == ptr)
- {
- empty = 1;
- break;
- }
+ send_size += _vcom_rb_block_put(data, (const rt_uint8_t *)&buf[send_size], ptr - send_size);
+ _vcom_rb_block_put(data, crlf, 2);
+ send_size++;
ptr++;
}
+ else if (ptr == size)
+ {
+ send_size += _vcom_rb_block_put(data, (const rt_uint8_t *)&buf[send_size], ptr - send_size);
+ }
else
{
break;
}
}
}
-
- if(size < baksize && !empty)
- {
- level = rt_hw_interrupt_disable();
- size += rt_ringbuffer_put_force(&data->tx_ringbuffer, (rt_uint8_t *)&buf[size], baksize - size);
- rt_hw_interrupt_enable(level);
- }
-
- if(size)
+ else
{
- rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
+ while (send_size < size)
+ {
+ send_size += _vcom_rb_block_put(data, (rt_uint8_t *)&buf[send_size], size - send_size);
+ }
}
}
else
@@ -902,6 +901,7 @@ static void vcom_tx_thread_entry(void* parameter)
#else
rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
#endif
+ rt_event_send(&data->tx_event, CDC_TX_HAS_SPACE);
}
}