瀏覽代碼

Merge pull request #2310 from weety/dev

Fixed data loss issue when USB CDC serial works in dma transmission m…
Bernard Xiong 6 年之前
父節點
當前提交
f182626681
共有 1 個文件被更改,包括 48 次插入48 次删除
  1. 48 48
      components/drivers/usb/usbdevice/class/cdc_vcom.c

+ 48 - 48
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)
+        else
         {
-            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)
-        {
-            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);
             }
         }