/* Vcom Tx Thread */
static void vcom_tx_thread_entry(void* parameter)
{
    struct vcom_tx_msg msg;

    while (1)
    {
        if (rt_mq_recv(&vcom_tx_thread_mq, (void*)&msg,
                        sizeof(struct vcom_tx_msg), RT_WAITING_FOREVER) == RT_EOK)
        {
            struct ufunction *func;
            struct vcom *data;

            func = (struct ufunction*)msg.serial->parent.user_data;
            data = (struct vcom*)func->user_data;
            if (!data->connected)
            {
                continue;
            }
                    
            rt_completion_init(&data->wait);

            data->ep_in->request.buffer = (void*)msg.buf;
            data->ep_in->request.size = msg.size;
            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");
            }      
        }
    }
}
int res_check(int argc, char** argv)
{
    struct rt_completion done;
    rt_completion_init(&done);

    rt_kprintf("Resource checking program!\n");
    startup_checking(&done);
    rt_completion_wait(&done, RT_WAITING_FOREVER);
    rt_kprintf("\nChecking resource files done!!\n");
    
    return 0;
}
/**
 * This function will handle cdc_set_line_coding request.
 *
 * @param device the usb device object.
 * @param setup the setup request.
 *
 * @return RT_EOK on successful.
 */
static rt_err_t _cdc_set_line_coding(udevice_t device, ureq_t setup)
{
    struct ucdc_line_coding data;   
    rt_err_t ret;

    RT_ASSERT(device != RT_NULL);
    RT_ASSERT(setup != RT_NULL);

    rt_completion_init(&device->dcd->completion);
 
    dcd_ep_read(device->dcd, 0, (void*)&data, setup->length);

    ret = rt_completion_wait(&device->dcd->completion, 100);
    if(ret != RT_EOK)
    {
        rt_kprintf("_cdc_set_line_coding timeout\n");
    }
     
    return RT_EOK;
}
static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
{
    struct rt_serial_device *serial;

    RT_ASSERT(dev != RT_NULL);
    serial = (struct rt_serial_device *)dev;

    /* check device flag with the open flag */
    if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX)) 
        return -RT_EIO;
    if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
        return -RT_EIO;
    if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX))
        return -RT_EIO;
    if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX))
        return -RT_EIO;

    /* get open flags */
    dev->open_flag = oflag & 0xff;
    
    /* initialize the Rx/Tx structure according to open flag */
    if (serial->serial_rx == RT_NULL)
    {
        if (oflag & RT_DEVICE_FLAG_DMA_RX)
        {
            struct rt_serial_rx_dma* rx_dma;

            rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma));
            RT_ASSERT(rx_dma != RT_NULL);
            rx_dma->activated = RT_FALSE;

            serial->serial_rx = rx_dma;
            dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
        }
        else if (oflag & RT_DEVICE_FLAG_INT_RX)
        {
            struct rt_serial_rx_fifo* rx_fifo;

            rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) + 
                serial->config.bufsz);
            RT_ASSERT(rx_fifo != RT_NULL);
            rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
            rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
            rx_fifo->put_index = 0;
            rx_fifo->get_index = 0;

            serial->serial_rx = rx_fifo;
            dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
            /* configure low level device */
            serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
        }
        else
        {
            serial->serial_rx = RT_NULL;
        }
    }

    if (serial->serial_tx == RT_NULL)
    {
        if (oflag & RT_DEVICE_FLAG_DMA_TX)
        {
            struct rt_serial_tx_dma* tx_dma;

            tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
            RT_ASSERT(tx_dma != RT_NULL);
            tx_dma->activated = RT_FALSE;
            
            rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
            serial->serial_tx = tx_dma;

            dev->open_flag |= RT_DEVICE_FLAG_DMA_TX;
        }
        else if (oflag & RT_DEVICE_FLAG_INT_TX)
        {
            struct rt_serial_tx_fifo *tx_fifo;

            tx_fifo = (struct rt_serial_tx_fifo*) rt_malloc(sizeof(struct rt_serial_tx_fifo));
            RT_ASSERT(tx_fifo != RT_NULL);

            rt_completion_init(&(tx_fifo->completion));
            serial->serial_tx = tx_fifo;

            dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
            /* configure low level device */
            serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
        }
        else
        {
            serial->serial_tx = RT_NULL;
        }
    }

    return RT_EOK;
}