11/*
2- * Copyright (c) 2016 Thomas Roell. All rights reserved.
2+ * Copyright (c) 2016-2017 Thomas Roell. All rights reserved.
33 *
44 * Permission is hereby granted, free of charge, to any person obtaining a copy
55 * of this software and associated documentation files (the "Software"), to
3232
3333#if defined(USBCON)
3434
35- /* STM32L4x5/STM32L4x6 have USB_OTG_FS with a multi-packet FIFO. However
36- * to avoid sending ZLP packets, the CDC_TX_PACKET_SIZE is one byte
37- * less than the maximum FIFO size in terms of 64 byte packets.
38- */
39- #define CDC_TX_PACKET_SIZE (((USBD_CDC_FIFO_SIZE + 63 ) & ~63 ) -1 )
35+ #define CDC_TX_PACKET_SIZE 128
36+ #define CDC_TX_PACKET_SMALL 64
4037
4138stm32l4_usbd_cdc_t stm32l4_usbd_cdc;
4239
40+ extern int (*stm32l4_stdio_put)(char , FILE*);
41+
42+ static int serialusb_stdio_put (char data, FILE *fp)
43+ {
44+ return Serial.write (&data, 1 );
45+ }
46+
4347CDC::CDC (struct _stm32l4_usbd_cdc_t *usbd_cdc, bool serialEvent)
4448{
4549 _usbd_cdc = usbd_cdc;
4650
47- _rx_read = 0 ;
48- _rx_write = 0 ;
49- _rx_count = 0 ;
5051 _tx_read = 0 ;
5152 _tx_write = 0 ;
5253 _tx_count = 0 ;
5354 _tx_size = 0 ;
5455
5556 _tx_data2 = NULL ;
5657 _tx_size2 = 0 ;
58+
59+ _tx_timeout = 0 ;
5760
5861 _completionCallback = NULL ;
5962 _receiveCallback = NULL ;
@@ -75,24 +78,36 @@ void CDC::begin(unsigned long baudrate, uint16_t config)
7578 /* If USBD_CDC has already been enabled/initialized by STDIO, just add the notify.
7679 */
7780 if (_usbd_cdc->state == USBD_CDC_STATE_INIT) {
78- stm32l4_usbd_cdc_enable (_usbd_cdc, 0 , CDC::_event_callback, (void *)this , (USBD_CDC_EVENT_RECEIVE | USBD_CDC_EVENT_TRANSMIT));
81+ stm32l4_usbd_cdc_enable (_usbd_cdc, &_rx_data[0 ], sizeof (_rx_data), 0 , CDC::_event_callback, (void *)this , (USBD_CDC_EVENT_RECEIVE | USBD_CDC_EVENT_TRANSMIT));
82+
83+ if (stm32l4_stdio_put == NULL ) {
84+ stm32l4_stdio_put = serialusb_stdio_put;
85+ }
7986 } else {
8087 flush ();
8188
8289 stm32l4_usbd_cdc_notify (_usbd_cdc, CDC::_event_callback, (void *)this , (USBD_CDC_EVENT_RECEIVE | USBD_CDC_EVENT_TRANSMIT));
8390 }
91+
92+ USBD_SOFCallback (CDC::_sof_callback, (void *)this );
8493}
8594
8695void CDC::end ()
8796{
8897 flush ();
8998
99+ USBD_SOFCallback (NULL , NULL );
100+
101+ if (stm32l4_stdio_put == serialusb_stdio_put) {
102+ stm32l4_stdio_put = NULL ;
103+ }
104+
90105 stm32l4_usbd_cdc_disable (_usbd_cdc);
91106}
92107
93108int CDC::available ()
94109{
95- return _rx_count ;
110+ return stm32l4_usbd_cdc_count (_usbd_cdc) ;
96111}
97112
98113int CDC::availableForWrite (void )
@@ -110,67 +125,25 @@ int CDC::availableForWrite(void)
110125
111126int CDC::peek ()
112127{
113- if (_rx_count == 0 ) {
114- return -1 ;
115- }
116-
117- return _rx_data[_rx_read];
128+ return stm32l4_usbd_cdc_peek (_usbd_cdc);
118129}
119130
120131int CDC::read ()
121132{
122- unsigned int rx_read;
123133 uint8_t data;
124134
125- if (_rx_count == 0 ) {
135+ if (! stm32l4_usbd_cdc_count (_usbd_cdc) ) {
126136 return -1 ;
127137 }
128138
129- rx_read = _rx_read ;
139+ stm32l4_usbd_cdc_receive (_usbd_cdc, &data, 1 ) ;
130140
131- data = _rx_data[rx_read];
132-
133- _rx_read = (unsigned int )(rx_read + 1 ) & (CDC_RX_BUFFER_SIZE -1 );
134-
135- armv7m_atomic_sub (&_rx_count, 1 );
136-
137141 return data;
138142}
139143
140144size_t CDC::read (uint8_t *buffer, size_t size)
141145{
142- unsigned int rx_read, rx_count;
143- size_t count;
144-
145- count = 0 ;
146-
147- while (count < size) {
148-
149- rx_count = _rx_count;
150-
151- if (rx_count == 0 ) {
152- break ;
153- }
154-
155- rx_read = _rx_read;
156-
157- if (rx_count > (CDC_RX_BUFFER_SIZE - rx_read)) {
158- rx_count = (CDC_RX_BUFFER_SIZE - rx_read);
159- }
160-
161- if (rx_count > (size - count)) {
162- rx_count = (size - count);
163- }
164-
165- memcpy (&buffer[count], &_rx_data[rx_read], rx_count);
166- count += rx_count;
167-
168- _rx_read = (rx_read + rx_count) & (CDC_RX_BUFFER_SIZE -1 );
169-
170- armv7m_atomic_sub (&_rx_count, rx_count);
171- }
172-
173- return count;
146+ return stm32l4_usbd_cdc_receive (_usbd_cdc, buffer, size);
174147}
175148
176149void CDC::flush ()
@@ -276,7 +249,7 @@ size_t CDC::write(const uint8_t *buffer, size_t size)
276249 tx_size = _tx_count;
277250 tx_read = _tx_read;
278251
279- if (tx_size) {
252+ if (tx_size >= CDC_TX_PACKET_SMALL ) {
280253 if (tx_size > (CDC_TX_BUFFER_SIZE - tx_read)) {
281254 tx_size = (CDC_TX_BUFFER_SIZE - tx_read);
282255 }
@@ -350,46 +323,18 @@ void CDC::onReceive(void(*callback)(void))
350323
351324void CDC::EventCallback (uint32_t events)
352325{
353- unsigned int rx_write, rx_count, rx_size, count;
354326 unsigned int tx_read, tx_size;
355- bool empty;
356-
357- if (events & USBD_CDC_EVENT_RECEIVE) {
358- empty = (_rx_count == 0 );
359-
360- count = 0 ;
361-
362- do {
363- rx_size = 0 ;
364- rx_count = CDC_RX_BUFFER_SIZE - _rx_count;
365-
366- if (rx_count == 0 ) {
367- break ;
368- }
369-
370- rx_write = _rx_write;
371-
372- if (rx_count > (CDC_RX_BUFFER_SIZE - rx_write)) {
373- rx_count = (CDC_RX_BUFFER_SIZE - rx_write);
374- }
375-
376- rx_size = stm32l4_usbd_cdc_receive (_usbd_cdc, &_rx_data[rx_write], rx_count);
377-
378- _rx_write = (rx_write + rx_size) & (CDC_RX_BUFFER_SIZE -1 );
379-
380- armv7m_atomic_add (&_rx_count, rx_size);
381-
382- count += rx_size;
383-
384- } while (rx_size);
385327
386- if (empty && count && _receiveCallback) {
328+ if (events & USBD_CDC_EVENT_RECEIVE) {
329+ if (_receiveCallback) {
387330 armv7m_pendsv_enqueue ((armv7m_pendsv_routine_t )_receiveCallback, NULL , 0 );
388331 }
389332 }
390333
391334 if (events & USBD_CDC_EVENT_TRANSMIT) {
392335
336+ _tx_timeout = 0 ;
337+
393338 tx_size = _tx_size;
394339
395340 if (tx_size != 0 ) {
@@ -437,11 +382,45 @@ void CDC::EventCallback(uint32_t events)
437382 }
438383}
439384
385+ void CDC::SOFCallback ()
386+ {
387+ unsigned int tx_read, tx_size;
388+
389+ if (_tx_count && !_tx_size && !_tx_size2)
390+ {
391+ _tx_timeout++;
392+
393+ // Small packets get only send after 8ms latency
394+ if (_tx_timeout >= 8 )
395+ {
396+ tx_size = _tx_count;
397+ tx_read = _tx_read;
398+
399+ if (tx_size > (CDC_TX_BUFFER_SIZE - tx_read)) {
400+ tx_size = (CDC_TX_BUFFER_SIZE - tx_read);
401+ }
402+
403+ if (tx_size > CDC_TX_PACKET_SIZE) {
404+ tx_size = CDC_TX_PACKET_SIZE;
405+ }
406+
407+ _tx_size = tx_size;
408+
409+ stm32l4_usbd_cdc_transmit (_usbd_cdc, &_tx_data[tx_read], tx_size);
410+ }
411+ }
412+ }
413+
440414void CDC::_event_callback (void *context, uint32_t events)
441415{
442416 reinterpret_cast <class CDC *>(context)->EventCallback (events);
443417}
444418
419+ void CDC::_sof_callback (void *context)
420+ {
421+ reinterpret_cast <class CDC *>(context)->SOFCallback ();
422+ }
423+
445424CDC::operator bool ()
446425{
447426 return stm32l4_usbd_cdc_connected (_usbd_cdc);
0 commit comments