瀏覽代碼

[Components] driver usb vcom fix error for console (#1160)

* [Components] driver usb vcom fix error for console
Aubr.Cool 7 年之前
父節點
當前提交
537943ed6f
共有 1 個文件被更改,包括 193 次插入77 次删除
  1. 193 77
      components/drivers/usb/usbdevice/class/cdc_vcom.c

+ 193 - 77
components/drivers/usb/usbdevice/class/cdc_vcom.c

@@ -37,26 +37,41 @@
 #ifdef RT_USB_DEVICE_CDC
 
 #define TX_TIMEOUT              1000
-#define CDC_RX_BUFSIZE          2048
+#define CDC_RX_BUFSIZE          128
 #define CDC_MAX_PACKET_SIZE     64
 #define VCOM_DEVICE             "vcom"
 
-#define VCOM_TASK_STK_SIZE      2048
+#ifdef RT_VCOM_TASK_STK_SIZE
+#define VCOM_TASK_STK_SIZE      RT_VCOM_TASK_STK_SIZE
+#else /*!RT_VCOM_TASK_STK_SIZE*/
+#define VCOM_TASK_STK_SIZE      512
+#endif /*RT_VCOM_TASK_STK_SIZE*/
 
-//#define VCOM_TX_USE_DMA
+#ifdef RT_VCOM_TX_USE_DMA
+#define VCOM_TX_USE_DMA
+#endif /*RT_VCOM_TASK_STK_SIZE*/
+
+#ifdef RT_VCOM_SERNO
+#define _SER_NO RT_VCOM_SERNO
+#else /*!RT_VCOM_SERNO*/
+#define _SER_NO  "32021919830108"
+#endif /*RT_VCOM_SERNO*/
+
+#ifdef RT_VCOM_SER_LEN
+#define __SER_NO_LEN RT_VCOM_SER_LEN
+#else /*!RT_VCOM_SER_LEN*/
+#define __SER_NO_LEN rt_strlen("32021919830108")
+#endif /*RT_VCOM_SER_LEN*/
 
 ALIGN(RT_ALIGN_SIZE)
 static rt_uint8_t vcom_thread_stack[VCOM_TASK_STK_SIZE];
 static struct rt_thread vcom_thread;
-#define VCOM_MQ_MSG_SZ  16
-#define VCOM_MQ_MAX_MSG 4
-/* internal of the message queue: every message is associated with a pointer,
- * so in order to recveive VCOM_MQ_MAX_MSG messages, we have to allocate more
- * than VCOM_MQ_MSG_SZ*VCOM_MQ_MAX_MSG memery. */
-static rt_uint8_t vcom_tx_thread_mq_pool[(VCOM_MQ_MSG_SZ+sizeof(void*))*VCOM_MQ_MAX_MSG];
-static struct rt_messagequeue vcom_tx_thread_mq;
 static struct ucdc_line_coding line_coding;
 
+#define CDC_TX_BUFSIZE    1024
+
+#define CDC_TX_HAS_DATE   0x01
+
 struct vcom
 {
     struct rt_serial_device     serial;
@@ -67,7 +82,10 @@ struct vcom
     rt_bool_t in_sending;
     struct rt_completion wait;
     rt_uint8_t rx_rbp[CDC_RX_BUFSIZE];    
-    struct rt_ringbuffer rx_ringbuffer;   
+    struct rt_ringbuffer rx_ringbuffer;
+    rt_uint8_t tx_rbp[CDC_TX_BUFSIZE];
+    struct rt_ringbuffer tx_ringbuffer;
+    struct rt_event  tx_event;
 };
 
 struct vcom_tx_msg
@@ -191,12 +209,17 @@ const static struct ucdc_data_descriptor _data_desc =
     0x00,
 };
 
+static char serno[_SER_NO_LEN + 1] = {'\0',};
+RT_WEAK  rt_err_t vcom_get_stored_serno(char *serno, int size)
+{
+    return RT_ERROR;
+}
 const static char* _ustring[] =
 {
     "Language",
     "RT-Thread Team.",
     "RTT Virtual Serial",
-    "32021919830108",
+    serno,
     "Configuration",
     "Interface",
 };
@@ -233,7 +256,6 @@ static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
     RT_ASSERT(func != RT_NULL);
 
     RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_in_handler %d\n", size));
-    rt_kprintf("%s size = %d\n",__func__,size);
     data = (struct vcom*)func->user_data;
     if ((size != 0) && (size % CDC_MAX_PACKET_SIZE == 0))
     {
@@ -286,7 +308,7 @@ static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
 
     data->ep_out->request.buffer = data->ep_out->buffer;
     data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
-    data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;    
+    data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
     rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
 
     return RT_EOK;
@@ -442,7 +464,7 @@ static rt_err_t _function_enable(ufunction_t func)
     data->ep_out->request.buffer = data->ep_out->buffer;
     data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
     
-    data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;    
+    data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
     rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
     
     return RT_EOK;
@@ -522,6 +544,14 @@ ufunction_t rt_usbd_function_cdc_create(udevice_t device)
     /* parameter check */
     RT_ASSERT(device != RT_NULL);
 
+    extern rt_err_t vcom_get_stored_serno(char *serno, int size);
+
+    rt_memset(serno, 0, _SER_NO_LEN + 1);
+    if(vcom_get_stored_serno(serno, _SER_NO_LEN) != RT_EOK)
+    {
+        rt_memset(serno, 0, _SER_NO_LEN + 1);
+        rt_memcpy(serno, _SER_NO, rt_strlen(_SER_NO));
+    }
     /* set usb device string description */
     rt_usbd_device_set_string(device, _ustring);
     
@@ -636,113 +666,205 @@ static int _vcom_getc(struct rt_serial_device *serial)
 
     return result;
 }
-
-#ifdef VCOM_TX_USE_DMA
-static rt_size_t _vcom_tx(struct rt_serial_device *serial, const char *buf, rt_size_t size,int direction)
+static rt_size_t _vcom_tx(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size,int direction)
 {
-    static struct vcom_tx_msg msg;
+    rt_uint32_t level;
+
+    struct ufunction *func;
+    struct vcom *data;
+
+    func = (struct ufunction*)serial->parent.user_data;
+    data = (struct vcom*)func->user_data;
+    rt_uint32_t baksize = size;
+    rt_size_t ptr = 0;
+    int empty = 0;
+    rt_uint8_t crlf[2] = {'\r', '\n',};
 
     RT_ASSERT(serial != RT_NULL);
     RT_ASSERT(buf != RT_NULL);
 
-    rt_kprintf("%s\n",__func__);
-
-    msg.buf     = buf;
-    msg.serial  = serial;
-    msg.size    = size;
+    RT_DEBUG_LOG(RT_DEBUG_USB, ("%s\n",__func__));
 
-    if (rt_mq_send(&vcom_tx_thread_mq, (void*)&msg, sizeof(struct vcom_tx_msg)) != RT_EOK)
+    if (data->connected)
     {
-        rt_kprintf("vcom send msg fail\n");
-        return 0;
-    }
+        size = 0;
+        if((serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
+        {
+            empty = 0;
+            while(ptr < baksize)
+            {
+                while(ptr < baksize && buf[ptr] != '\n')
+                {
+                    ptr++;
+                }
+                if(ptr < baksize)
+                {
+                    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);
+                    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;
+                    }
+                    if(size == ptr)
+                    {
+                        empty = 1;
+                        break;
+                    }
+                    ptr++;
+                }
+                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)
+        {
+            rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
+        }
+    }
     return size;
 }
-#else
 static int _vcom_putc(struct rt_serial_device *serial, char c)
 {
-    static struct vcom_tx_msg msg;
+    rt_uint32_t level;
+    struct ufunction *func;
+    struct vcom *data;
+
+    func = (struct ufunction*)serial->parent.user_data;
+    data = (struct vcom*)func->user_data;
 
     RT_ASSERT(serial != RT_NULL);
 
-    msg.buf     = (void *)((rt_uint32_t)c);
-    msg.serial  = serial;
-    msg.size    = 1;
-    if (rt_mq_send(&vcom_tx_thread_mq, (void*)&msg, sizeof(struct vcom_tx_msg)) != RT_EOK)
+    if (data->connected)
     {
-//        rt_kprintf("vcom send msg fail\n");
-        return -1;
+        if(c == '\n' && (serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
+        {
+            level = rt_hw_interrupt_disable();
+            rt_ringbuffer_putchar_force(&data->tx_ringbuffer, '\r');
+            rt_hw_interrupt_enable(level);
+            rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
+        }
+        level = rt_hw_interrupt_disable();
+        rt_ringbuffer_putchar_force(&data->tx_ringbuffer, c);
+        rt_hw_interrupt_enable(level);
+        rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
     }
 
     return 1;
 }
-#endif
 
 static const struct rt_uart_ops usb_vcom_ops =
 {
     _vcom_configure,
     _vcom_control,
-#ifndef VCOM_TX_USE_DMA
     _vcom_putc,
     _vcom_getc,
-    RT_NULL
-#else
-    RT_NULL,
-    _vcom_getc,
     _vcom_tx
-#endif
-
 };
 
 /* Vcom Tx Thread */
 static void vcom_tx_thread_entry(void* parameter)
 {
-    struct vcom_tx_msg msg;
-    rt_uint8_t  ch;
+    rt_uint32_t level;
+    rt_uint32_t res;
+    struct ufunction *func = (struct ufunction *)parameter;
+    struct vcom *data = (struct vcom*)func->user_data;
+    rt_uint8_t ch[64];
+
     while (1)
     {
-        if (rt_mq_recv(&vcom_tx_thread_mq, (void*)&msg, sizeof(struct vcom_tx_msg), RT_WAITING_FOREVER) == RT_EOK)
+        if
+        (
+            (rt_event_recv(&data->tx_event, CDC_TX_HAS_DATE,
+                    RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+                    RT_WAITING_FOREVER, &res) != RT_EOK) ||
+                                 (!(res & CDC_TX_HAS_DATE))
+        )
         {
-            struct ufunction *func;
-            struct vcom *data;
-
-            func = (struct ufunction*)msg.serial->parent.user_data;
-            data = (struct vcom*)func->user_data;
+            continue;
+        }
+        if(!res & CDC_TX_HAS_DATE)
+        {
+            continue;
+        }
+        while(rt_ringbuffer_data_len(&data->tx_ringbuffer))
+        {
+            level = rt_hw_interrupt_disable();
+            res = rt_ringbuffer_get(&data->tx_ringbuffer, ch, 64);
+            rt_hw_interrupt_enable(level);
 
+            if(!res)
+            {
+                continue;
+            }
             if (!data->connected)
             {
+                if(data->serial.parent.open_flag &
+#ifndef VCOM_TX_USE_DMA
+                         RT_DEVICE_FLAG_INT_TX
+#else
+                         RT_DEVICE_FLAG_DMA_TX
+#endif
+                )
+                {
                 /* drop msg */
 #ifndef VCOM_TX_USE_DMA
-                rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DONE);
+                    rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DONE);
 #else
-                rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
+                    rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
 #endif
+                }
                 continue;
             }
-                    
             rt_completion_init(&data->wait);
-#ifndef VCOM_TX_USE_DMA
-            ch = (rt_uint8_t)((rt_uint32_t)msg.buf);
-            data->ep_in->request.buffer     = (rt_uint8_t*)&ch;
-#else
-            data->ep_in->request.buffer     = (rt_uint8_t*)msg.buf;
-#endif
-            data->ep_in->request.size       = msg.size;
+            data->ep_in->request.buffer     = ch;
+            data->ep_in->request.size       = res;
+
             data->ep_in->request.req_type   = UIO_REQUEST_WRITE;
 
             rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
-            
+
             if (rt_completion_wait(&data->wait, TX_TIMEOUT) != RT_EOK)
             {
-                rt_kprintf("vcom tx timeout\n");
+                RT_DEBUG_LOG(RT_DEBUG_USB, ("vcom tx timeout\n"));
             }
+            if(data->serial.parent.open_flag &
 #ifndef VCOM_TX_USE_DMA
-            rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DONE);
+                         RT_DEVICE_FLAG_INT_TX
 #else
-            rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
+                         RT_DEVICE_FLAG_DMA_TX
 #endif
+            )
+            {
+#ifndef VCOM_TX_USE_DMA
+                rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DONE);
+#else
+                rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
+#endif
+            }
         }
+
     }
 }
 
@@ -754,6 +876,9 @@ static void rt_usb_vcom_init(struct ufunction *func)
     
     /* initialize ring buffer */
     rt_ringbuffer_init(&data->rx_ringbuffer, data->rx_rbp, CDC_RX_BUFSIZE);
+    rt_ringbuffer_init(&data->tx_ringbuffer, data->tx_rbp, CDC_TX_BUFSIZE);
+
+    rt_event_init(&data->tx_event, "vom", RT_IPC_FLAG_FIFO);
 
     config.baud_rate    = BAUD_RATE_115200;
     config.data_bits    = DATA_BITS_8;
@@ -776,20 +901,11 @@ static void rt_usb_vcom_init(struct ufunction *func)
 #endif
                           func);
 
-    /* create an vcom message queue */
-    rt_mq_init(&vcom_tx_thread_mq,
-               "vcomq",
-               vcom_tx_thread_mq_pool,
-               VCOM_MQ_MSG_SZ,
-               sizeof(vcom_tx_thread_mq_pool),
-               RT_IPC_FLAG_FIFO);
-
-
     /* init usb device thread */
     rt_thread_init(&vcom_thread, "vcom",
-                   vcom_tx_thread_entry, RT_NULL,
+                   vcom_tx_thread_entry, func,
                    vcom_thread_stack, VCOM_TASK_STK_SIZE,
-                   8, 20);
+                   16, 20);
     result = rt_thread_startup(&vcom_thread);
     RT_ASSERT(result == RT_EOK);       
 }