Fixed data loss issue when USB CDC serial works in dma transmission mode.
This commit is contained in:
parent
48aa297560
commit
5293175998
|
@ -63,6 +63,7 @@ static struct ucdc_line_coding line_coding;
|
||||||
#define CDC_BULKIN_MAXSIZE (CDC_TX_BUFSIZE / 8)
|
#define CDC_BULKIN_MAXSIZE (CDC_TX_BUFSIZE / 8)
|
||||||
|
|
||||||
#define CDC_TX_HAS_DATE 0x01
|
#define CDC_TX_HAS_DATE 0x01
|
||||||
|
#define CDC_TX_HAS_SPACE 0x02
|
||||||
|
|
||||||
struct vcom
|
struct vcom
|
||||||
{
|
{
|
||||||
|
@ -693,23 +694,48 @@ static int _vcom_getc(struct rt_serial_device *serial)
|
||||||
|
|
||||||
return result;
|
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_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 ufunction *func;
|
||||||
struct vcom *data;
|
struct vcom *data;
|
||||||
rt_uint32_t baksize;
|
rt_uint32_t send_size = 0;
|
||||||
rt_size_t ptr = 0;
|
rt_size_t ptr = 0;
|
||||||
int empty = 0;
|
|
||||||
rt_uint8_t crlf[2] = {'\r', '\n',};
|
rt_uint8_t crlf[2] = {'\r', '\n',};
|
||||||
|
|
||||||
func = (struct ufunction*)serial->parent.user_data;
|
func = (struct ufunction*)serial->parent.user_data;
|
||||||
data = (struct vcom*)func->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(serial != RT_NULL);
|
||||||
RT_ASSERT(buf != 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)
|
if (data->connected)
|
||||||
{
|
{
|
||||||
size = 0;
|
|
||||||
if((serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
|
if((serial->parent.open_flag & RT_DEVICE_FLAG_STREAM))
|
||||||
{
|
{
|
||||||
empty = 0;
|
while(send_size < size)
|
||||||
while(ptr < baksize)
|
|
||||||
{
|
{
|
||||||
while(ptr < baksize && buf[ptr] != '\n')
|
while(ptr < size && buf[ptr] != '\n')
|
||||||
{
|
{
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
if(ptr < baksize)
|
if(ptr < size)
|
||||||
{
|
{
|
||||||
level = rt_hw_interrupt_disable();
|
send_size += _vcom_rb_block_put(data, (const rt_uint8_t *)&buf[send_size], ptr - send_size);
|
||||||
size += rt_ringbuffer_put_force(&data->tx_ringbuffer, (const rt_uint8_t *)&buf[size], ptr - size);
|
_vcom_rb_block_put(data, crlf, 2);
|
||||||
rt_hw_interrupt_enable(level);
|
send_size++;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
else if (ptr == size)
|
||||||
|
{
|
||||||
|
send_size += _vcom_rb_block_put(data, (const rt_uint8_t *)&buf[send_size], ptr - send_size);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if(size < baksize && !empty)
|
|
||||||
{
|
{
|
||||||
level = rt_hw_interrupt_disable();
|
while (send_size < size)
|
||||||
size += rt_ringbuffer_put_force(&data->tx_ringbuffer, (rt_uint8_t *)&buf[size], baksize - size);
|
{
|
||||||
rt_hw_interrupt_enable(level);
|
send_size += _vcom_rb_block_put(data, (rt_uint8_t *)&buf[send_size], size - send_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(size)
|
|
||||||
{
|
|
||||||
rt_event_send(&data->tx_event, CDC_TX_HAS_DATE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -902,6 +901,7 @@ static void vcom_tx_thread_entry(void* parameter)
|
||||||
#else
|
#else
|
||||||
rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
|
rt_hw_serial_isr(&data->serial,RT_SERIAL_EVENT_TX_DMADONE);
|
||||||
#endif
|
#endif
|
||||||
|
rt_event_send(&data->tx_event, CDC_TX_HAS_SPACE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue