]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/protocol/arm_atsam/usb/udi_cdc.c
ffe3526db56793191a558f83f33e870301cc5073
[qmk_firmware.git] / tmk_core / protocol / arm_atsam / usb / udi_cdc.c
1 /**
2  * \file
3  *
4  * \brief USB Device Communication Device Class (CDC) interface.
5  *
6  * Copyright (c) 2009-2016 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 /*
44  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45  */
46
47 #include "samd51j18a.h"
48 #include "conf_usb.h"
49 #include "usb_protocol.h"
50 #include "usb_protocol_cdc.h"
51 #include "udd.h"
52 #include "udc.h"
53 #include "udi_cdc.h"
54 #include <string.h>
55 #include "udi_cdc_conf.h"
56 #include "udi_device_conf.h"
57 #include "stdarg.h"
58 #include "tmk_core/protocol/arm_atsam/clks.h"
59
60 #ifdef CDC
61
62 #ifdef UDI_CDC_LOW_RATE
63 #  ifdef USB_DEVICE_HS_SUPPORT
64 #    define UDI_CDC_TX_BUFFERS     (UDI_CDC_DATA_EPS_HS_SIZE)
65 #    define UDI_CDC_RX_BUFFERS     (UDI_CDC_DATA_EPS_HS_SIZE)
66 #  else
67 #    define UDI_CDC_TX_BUFFERS     (UDI_CDC_DATA_EPS_FS_SIZE)
68 #    define UDI_CDC_RX_BUFFERS     (UDI_CDC_DATA_EPS_FS_SIZE)
69 #  endif
70 #else
71 #  ifdef USB_DEVICE_HS_SUPPORT
72 #    define UDI_CDC_TX_BUFFERS     (UDI_CDC_DATA_EPS_HS_SIZE)
73 #    define UDI_CDC_RX_BUFFERS     (UDI_CDC_DATA_EPS_HS_SIZE)
74 #  else
75 #    define UDI_CDC_TX_BUFFERS     (5*UDI_CDC_DATA_EPS_FS_SIZE)
76 #    define UDI_CDC_RX_BUFFERS     (5*UDI_CDC_DATA_EPS_FS_SIZE)
77 #  endif
78 #endif
79
80 #ifndef UDI_CDC_TX_EMPTY_NOTIFY
81 #  define UDI_CDC_TX_EMPTY_NOTIFY(port)
82 #endif
83
84 /**
85  * \ingroup udi_cdc_group
86  * \defgroup udi_cdc_group_udc Interface with USB Device Core (UDC)
87  *
88  * Structures and functions required by UDC.
89  *
90  * @{
91  */
92 bool udi_cdc_comm_enable(void);
93 void udi_cdc_comm_disable(void);
94 bool udi_cdc_comm_setup(void);
95 bool udi_cdc_data_enable(void);
96 void udi_cdc_data_disable(void);
97 bool udi_cdc_data_setup(void);
98 uint8_t udi_cdc_getsetting(void);
99 void udi_cdc_data_sof_notify(void);
100 UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm = {
101     .enable = udi_cdc_comm_enable,
102     .disable = udi_cdc_comm_disable,
103     .setup = udi_cdc_comm_setup,
104     .getsetting = udi_cdc_getsetting,
105     .sof_notify = NULL
106 };
107 UDC_DESC_STORAGE udi_api_t udi_api_cdc_data = {
108     .enable = udi_cdc_data_enable,
109     .disable = udi_cdc_data_disable,
110     .setup = udi_cdc_data_setup,
111     .getsetting = udi_cdc_getsetting,
112     .sof_notify = udi_cdc_data_sof_notify,
113 };
114 //@}
115
116 /**
117  * \ingroup udi_cdc_group
118  * \defgroup udi_cdc_group_internal Implementation of UDI CDC
119  *
120  * Class internal implementation
121  * @{
122  */
123
124 /**
125  * \name Internal routines
126  */
127 //@{
128
129 /**
130  * \name Routines to control serial line
131  */
132 //@{
133
134 /**
135  * \brief Returns the port number corresponding at current setup request
136  *
137  * \return port number
138  */
139 static uint8_t udi_cdc_setup_to_port(void);
140
141 /**
142  * \brief Sends line coding to application
143  *
144  * Called after SETUP request when line coding data is received.
145  */
146 static void udi_cdc_line_coding_received(void);
147
148 /**
149  * \brief Records new state
150  *
151  * \param port       Communication port number to manage
152  * \param b_set      State is enabled if true, else disabled
153  * \param bit_mask   Field to process (see CDC_SERIAL_STATE_ defines)
154  */
155 static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask);
156
157 /**
158  * \brief Check and eventually notify the USB host of new state
159  *
160  * \param port       Communication port number to manage
161  * \param ep         Port communication endpoint
162  */
163 static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep);
164
165 /**
166  * \brief Ack sent of serial state message
167  * Callback called after serial state message sent
168  *
169  * \param status     UDD_EP_TRANSFER_OK, if transfer finished
170  * \param status     UDD_EP_TRANSFER_ABORT, if transfer aborted
171  * \param n          number of data transfered
172  */
173 static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
174
175 //@}
176
177 /**
178  * \name Routines to process data transfer
179  */
180 //@{
181
182 /**
183  * \brief Enable the reception of data from the USB host
184  *
185  * The value udi_cdc_rx_trans_sel indicate the RX buffer to fill.
186  *
187  * \param port       Communication port number to manage
188  *
189  * \return \c 1 if function was successfully done, otherwise \c 0.
190  */
191 static bool udi_cdc_rx_start(uint8_t port);
192
193 /**
194  * \brief Update rx buffer management with a new data
195  * Callback called after data reception on USB line
196  *
197  * \param status     UDD_EP_TRANSFER_OK, if transfer finish
198  * \param status     UDD_EP_TRANSFER_ABORT, if transfer aborted
199  * \param n          number of data received
200  */
201 static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
202
203 /**
204  * \brief Ack sent of tx buffer
205  * Callback called after data transfer on USB line
206  *
207  * \param status     UDD_EP_TRANSFER_OK, if transfer finished
208  * \param status     UDD_EP_TRANSFER_ABORT, if transfer aborted
209  * \param n          number of data transfered
210  */
211 static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
212
213 /**
214  * \brief Send buffer on line or wait a SOF event
215  *
216  * \param port       Communication port number to manage
217  */
218 static void udi_cdc_tx_send(uint8_t port);
219
220 //@}
221
222 //@}
223
224 /**
225  * \name Information about configuration of communication line
226  */
227 //@{
228 COMPILER_WORD_ALIGNED
229 static usb_cdc_line_coding_t udi_cdc_line_coding[UDI_CDC_PORT_NB];
230 static bool udi_cdc_serial_state_msg_ongoing[UDI_CDC_PORT_NB];
231 static volatile le16_t udi_cdc_state[UDI_CDC_PORT_NB];
232 COMPILER_WORD_ALIGNED static usb_cdc_notify_serial_state_t uid_cdc_state_msg[UDI_CDC_PORT_NB];
233
234 //! Status of CDC COMM interfaces
235 static volatile uint8_t udi_cdc_nb_comm_enabled = 0;
236 //@}
237
238 /**
239  * \name Variables to manage RX/TX transfer requests
240  * Two buffers for each sense are used to optimize the speed.
241  */
242 //@{
243
244 //! Status of CDC DATA interfaces
245 static volatile uint8_t udi_cdc_nb_data_enabled = 0;
246 static volatile bool udi_cdc_data_running = false;
247 //! Buffer to receive data
248 COMPILER_WORD_ALIGNED static uint8_t udi_cdc_rx_buf[UDI_CDC_PORT_NB][2][UDI_CDC_RX_BUFFERS];
249 //! Data available in RX buffers
250 static volatile uint16_t udi_cdc_rx_buf_nb[UDI_CDC_PORT_NB][2];
251 //! Give the current RX buffer used (rx0 if 0, rx1 if 1)
252 static volatile uint8_t udi_cdc_rx_buf_sel[UDI_CDC_PORT_NB];
253 //! Read position in current RX buffer
254 static volatile uint16_t udi_cdc_rx_pos[UDI_CDC_PORT_NB];
255 //! Signal a transfer on-going
256 static volatile bool udi_cdc_rx_trans_ongoing[UDI_CDC_PORT_NB];
257
258 //! Define a transfer halted
259 #define  UDI_CDC_TRANS_HALTED    2
260
261 //! Buffer to send data
262 COMPILER_WORD_ALIGNED static uint8_t udi_cdc_tx_buf[UDI_CDC_PORT_NB][2][UDI_CDC_TX_BUFFERS];
263 //! Data available in TX buffers
264 static uint16_t udi_cdc_tx_buf_nb[UDI_CDC_PORT_NB][2];
265 //! Give current TX buffer used (tx0 if 0, tx1 if 1)
266 static volatile uint8_t udi_cdc_tx_buf_sel[UDI_CDC_PORT_NB];
267 //! Value of SOF during last TX transfer
268 static uint16_t udi_cdc_tx_sof_num[UDI_CDC_PORT_NB];
269 //! Signal a transfer on-going
270 static volatile bool udi_cdc_tx_trans_ongoing[UDI_CDC_PORT_NB];
271 //! Signal that both buffer content data to send
272 static volatile bool udi_cdc_tx_both_buf_to_send[UDI_CDC_PORT_NB];
273
274 //@}
275
276 bool udi_cdc_comm_enable(void)
277 {
278     uint8_t port;
279     uint8_t iface_comm_num;
280
281 //#if UDI_CDC_PORT_NB == 1 // To optimize code
282     port = 0;
283     udi_cdc_nb_comm_enabled = 0;
284 //#else
285 //    if (udi_cdc_nb_comm_enabled > UDI_CDC_PORT_NB) {
286 //        udi_cdc_nb_comm_enabled = 0;
287 //    }
288 //    port = udi_cdc_nb_comm_enabled;
289 //#endif
290
291     // Initialize control signal management
292     udi_cdc_state[port] = CPU_TO_LE16(0);
293
294     uid_cdc_state_msg[port].header.bmRequestType =
295             USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS |
296             USB_REQ_RECIP_INTERFACE;
297     uid_cdc_state_msg[port].header.bNotification = USB_REQ_CDC_NOTIFY_SERIAL_STATE;
298     uid_cdc_state_msg[port].header.wValue = LE16(0);
299
300     /*
301     switch (port) {
302     #define UDI_CDC_PORT_TO_IFACE_COMM(index, unused) \
303         case index: \
304             iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_##index; \
305             break;
306         MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_IFACE_COMM, ~)
307     #undef UDI_CDC_PORT_TO_IFACE_COMM
308         default:
309             iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_0;
310             break;
311         }
312     */
313     iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_0;
314
315     uid_cdc_state_msg[port].header.wIndex = LE16(iface_comm_num);
316     uid_cdc_state_msg[port].header.wLength = LE16(2);
317     uid_cdc_state_msg[port].value = CPU_TO_LE16(0);
318
319     udi_cdc_line_coding[port].dwDTERate = CPU_TO_LE32(UDI_CDC_DEFAULT_RATE);
320     udi_cdc_line_coding[port].bCharFormat = UDI_CDC_DEFAULT_STOPBITS;
321     udi_cdc_line_coding[port].bParityType = UDI_CDC_DEFAULT_PARITY;
322     udi_cdc_line_coding[port].bDataBits = UDI_CDC_DEFAULT_DATABITS;
323     // Call application callback
324     // to initialize memories or indicate that interface is enabled
325 #if 0
326     UDI_CDC_SET_CODING_EXT(port,(&udi_cdc_line_coding[port]));
327     if (!UDI_CDC_ENABLE_EXT(port)) {
328         return false;
329     }
330 #endif
331     udi_cdc_nb_comm_enabled++;
332     return true;
333 }
334
335 bool udi_cdc_data_enable(void)
336 {
337     uint8_t port;
338
339 //#if UDI_CDC_PORT_NB == 1 // To optimize code
340     port = 0;
341     udi_cdc_nb_data_enabled = 0;
342 //#else
343 //    if (udi_cdc_nb_data_enabled > UDI_CDC_PORT_NB) {
344 //        udi_cdc_nb_data_enabled = 0;
345 //    }
346 //    port = udi_cdc_nb_data_enabled;
347 //#endif
348
349     // Initialize TX management
350     udi_cdc_tx_trans_ongoing[port] = false;
351     udi_cdc_tx_both_buf_to_send[port] = false;
352     udi_cdc_tx_buf_sel[port] = 0;
353     udi_cdc_tx_buf_nb[port][0] = 0;
354     udi_cdc_tx_buf_nb[port][1] = 0;
355     udi_cdc_tx_sof_num[port] = 0;
356     udi_cdc_tx_send(port);
357
358     // Initialize RX management
359     udi_cdc_rx_trans_ongoing[port] = false;
360     udi_cdc_rx_buf_sel[port] = 0;
361     udi_cdc_rx_buf_nb[port][0] = 0;
362     udi_cdc_rx_buf_nb[port][1] = 0;
363     udi_cdc_rx_pos[port] = 0;
364     if (!udi_cdc_rx_start(port)) {
365         return false;
366     }
367     udi_cdc_nb_data_enabled++;
368     if (udi_cdc_nb_data_enabled == UDI_CDC_PORT_NB) {
369         udi_cdc_data_running = true;
370     }
371     return true;
372 }
373
374 void udi_cdc_comm_disable(void)
375 {
376     Assert(udi_cdc_nb_comm_enabled != 0);
377     udi_cdc_nb_comm_enabled--;
378 }
379
380 void udi_cdc_data_disable(void)
381 {
382 //  uint8_t port;
383
384     Assert(udi_cdc_nb_data_enabled != 0);
385     udi_cdc_nb_data_enabled--;
386 //  port = udi_cdc_nb_data_enabled;
387 //  UDI_CDC_DISABLE_EXT(port);
388     udi_cdc_data_running = false;
389 }
390
391 bool udi_cdc_comm_setup(void)
392 {
393     uint8_t port = udi_cdc_setup_to_port();
394
395     if (Udd_setup_is_in()) {
396         // GET Interface Requests
397         if (Udd_setup_type() == USB_REQ_TYPE_CLASS) {
398             // Requests Class Interface Get
399             switch (udd_g_ctrlreq.req.bRequest) {
400             case USB_REQ_CDC_GET_LINE_CODING:
401                 // Get configuration of CDC line
402                 if (sizeof(usb_cdc_line_coding_t) !=
403                         udd_g_ctrlreq.req.wLength)
404                     return false; // Error for USB host
405                 udd_g_ctrlreq.payload =
406                         (uint8_t *) &
407                         udi_cdc_line_coding[port];
408                 udd_g_ctrlreq.payload_size =
409                         sizeof(usb_cdc_line_coding_t);
410                 return true;
411             }
412         }
413     }
414     if (Udd_setup_is_out()) {
415         // SET Interface Requests
416         if (Udd_setup_type() == USB_REQ_TYPE_CLASS) {
417             // Requests Class Interface Set
418             switch (udd_g_ctrlreq.req.bRequest) {
419             case USB_REQ_CDC_SET_LINE_CODING:
420                 // Change configuration of CDC line
421                 if (sizeof(usb_cdc_line_coding_t) !=
422                         udd_g_ctrlreq.req.wLength)
423                     return false; // Error for USB host
424                 udd_g_ctrlreq.callback =
425                         udi_cdc_line_coding_received;
426                 udd_g_ctrlreq.payload =
427                         (uint8_t *) &
428                         udi_cdc_line_coding[port];
429                 udd_g_ctrlreq.payload_size =
430                         sizeof(usb_cdc_line_coding_t);
431                 return true;
432             case USB_REQ_CDC_SET_CONTROL_LINE_STATE:
433                 // According cdc spec 1.1 chapter 6.2.14
434 //              UDI_CDC_SET_DTR_EXT(port, (0 !=
435 //                      (udd_g_ctrlreq.req.wValue
436 //                       & CDC_CTRL_SIGNAL_DTE_PRESENT)));
437 //              UDI_CDC_SET_RTS_EXT(port, (0 !=
438 //                      (udd_g_ctrlreq.req.wValue
439 //                       & CDC_CTRL_SIGNAL_ACTIVATE_CARRIER)));
440                 return true;
441             }
442         }
443     }
444     return false;  // request Not supported
445 }
446
447 bool udi_cdc_data_setup(void)
448 {
449     return false;  // request Not supported
450 }
451
452 uint8_t udi_cdc_getsetting(void)
453 {
454     return 0;      // CDC don't have multiple alternate setting
455 }
456
457 void udi_cdc_data_sof_notify(void)
458 {
459     static uint8_t port_notify = 0;
460
461     // A call of udi_cdc_data_sof_notify() is done for each port
462     udi_cdc_tx_send(port_notify);
463     /*
464 #if UDI_CDC_PORT_NB != 1 // To optimize code
465     port_notify++;
466     if (port_notify >= UDI_CDC_PORT_NB) {
467         port_notify = 0;
468     }
469 #endif
470     */
471 }
472
473
474 //-------------------------------------------------
475 //------- Internal routines to control serial line
476
477 static uint8_t udi_cdc_setup_to_port(void)
478 {
479     uint8_t port;
480
481     /*
482     switch (udd_g_ctrlreq.req.wIndex & 0xFF) {
483 #define UDI_CDC_IFACE_COMM_TO_PORT(iface, unused) \
484     case UDI_CDC_COMM_IFACE_NUMBER_##iface: \
485         port = iface; \
486         break;
487     MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_IFACE_COMM_TO_PORT, ~)
488 #undef UDI_CDC_IFACE_COMM_TO_PORT
489     default:
490         port = 0;
491         break;
492     }
493     */
494     port = 0;
495
496     return port;
497 }
498
499 static void udi_cdc_line_coding_received(void)
500 {
501     uint8_t port = udi_cdc_setup_to_port();
502     UNUSED(port);
503
504 //  UDI_CDC_SET_CODING_EXT(port, (&udi_cdc_line_coding[port]));
505 }
506
507 static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask)
508 {
509     udd_ep_id_t ep_comm;
510     uint32_t irqflags;  //irqflags_t
511
512
513 //#if UDI_CDC_PORT_NB == 1 // To optimize code
514     port = 0;
515 //#endif
516
517     // Update state
518   irqflags = __get_PRIMASK();
519   __disable_irq();
520   __DMB();
521     if (b_set) {
522         udi_cdc_state[port] |= bit_mask;
523     } else {
524         udi_cdc_state[port] &= ~(unsigned)bit_mask;
525     }
526     __DMB();
527   __set_PRIMASK(irqflags);
528
529     /*
530     // Send it if possible and state changed
531     switch (port) {
532 #define UDI_CDC_PORT_TO_COMM_EP(index, unused) \
533     case index: \
534         ep_comm = UDI_CDC_COMM_EP_##index; \
535         break;
536     MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_COMM_EP, ~)
537 #undef UDI_CDC_PORT_TO_COMM_EP
538     default:
539         ep_comm = UDI_CDC_COMM_EP_0;
540         break;
541     }
542     */
543     ep_comm = UDI_CDC_COMM_EP_0;
544
545     udi_cdc_ctrl_state_notify(port, ep_comm);
546 }
547
548
549 static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep)
550 {
551 #if UDI_CDC_PORT_NB == 1 // To optimize code
552     port = 0;
553 #endif
554
555     // Send it if possible and state changed
556     if ((!udi_cdc_serial_state_msg_ongoing[port])
557             && (udi_cdc_state[port] != uid_cdc_state_msg[port].value)) {
558         // Fill notification message
559         uid_cdc_state_msg[port].value = udi_cdc_state[port];
560         // Send notification message
561         udi_cdc_serial_state_msg_ongoing[port] =
562                 udd_ep_run(ep,
563                 false,
564                 (uint8_t *) & uid_cdc_state_msg[port],
565                 sizeof(uid_cdc_state_msg[0]),
566                 udi_cdc_serial_state_msg_sent);
567     }
568 }
569
570
571 static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
572 {
573     uint8_t port;
574     UNUSED(n);
575     UNUSED(status);
576
577     /*
578     switch (ep) {
579 #define UDI_CDC_GET_PORT_FROM_COMM_EP(iface, unused) \
580     case UDI_CDC_COMM_EP_##iface: \
581         port = iface; \
582         break;
583     MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_GET_PORT_FROM_COMM_EP, ~)
584 #undef UDI_CDC_GET_PORT_FROM_COMM_EP
585     default:
586         port = 0;
587         break;
588     }
589     */
590     port = 0;
591
592     udi_cdc_serial_state_msg_ongoing[port] = false;
593
594     // For the irregular signals like break, the incoming ring signal,
595     // or the overrun error state, this will reset their values to zero
596     // and again will not send another notification until their state changes.
597     udi_cdc_state[port] &= ~(CDC_SERIAL_STATE_BREAK |
598             CDC_SERIAL_STATE_RING |
599             CDC_SERIAL_STATE_FRAMING |
600             CDC_SERIAL_STATE_PARITY | CDC_SERIAL_STATE_OVERRUN);
601     uid_cdc_state_msg[port].value &= ~(CDC_SERIAL_STATE_BREAK |
602             CDC_SERIAL_STATE_RING |
603             CDC_SERIAL_STATE_FRAMING |
604             CDC_SERIAL_STATE_PARITY | CDC_SERIAL_STATE_OVERRUN);
605     // Send it if possible and state changed
606     udi_cdc_ctrl_state_notify(port, ep);
607 }
608
609 //-------------------------------------------------
610 //------- Internal routines to process data transfer
611
612 static bool udi_cdc_rx_start(uint8_t port)
613 {
614     uint32_t irqflags;  //irqflags_t
615     uint8_t buf_sel_trans;
616     udd_ep_id_t ep;
617
618 //#if UDI_CDC_PORT_NB == 1 // To optimize code
619     port = 0;
620 //#endif
621
622     irqflags = __get_PRIMASK();
623   __disable_irq();
624   __DMB();
625     buf_sel_trans = udi_cdc_rx_buf_sel[port];
626     if (udi_cdc_rx_trans_ongoing[port] ||
627         (udi_cdc_rx_pos[port] < udi_cdc_rx_buf_nb[port][buf_sel_trans])) {
628         // Transfer already on-going or current buffer no empty
629       __DMB();
630     __set_PRIMASK(irqflags);
631         return false;
632     }
633
634     // Change current buffer
635     udi_cdc_rx_pos[port] = 0;
636     udi_cdc_rx_buf_sel[port] = (buf_sel_trans==0)?1:0;
637
638     // Start transfer on RX
639     udi_cdc_rx_trans_ongoing[port] = true;
640   __DMB();
641   __set_PRIMASK(irqflags);
642
643     if (udi_cdc_multi_is_rx_ready(port)) {
644 //      UDI_CDC_RX_NOTIFY(port);
645     }
646
647     /*
648     // Send the buffer with enable of short packet
649     switch (port) {
650 #define UDI_CDC_PORT_TO_DATA_EP_OUT(index, unused) \
651     case index: \
652         ep = UDI_CDC_DATA_EP_OUT_##index; \
653         break;
654     MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_OUT, ~)
655 #undef UDI_CDC_PORT_TO_DATA_EP_OUT
656     default:
657         ep = UDI_CDC_DATA_EP_OUT_0;
658         break;
659     }
660     */
661     ep = UDI_CDC_DATA_EP_OUT_0;
662
663     return udd_ep_run(ep,
664             true,
665             udi_cdc_rx_buf[port][buf_sel_trans],
666             UDI_CDC_RX_BUFFERS,
667             udi_cdc_data_received);
668 }
669
670 static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
671 {
672     uint8_t buf_sel_trans;
673     uint8_t port;
674
675     /*
676     switch (ep) {
677 #define UDI_CDC_DATA_EP_OUT_TO_PORT(index, unused) \
678     case UDI_CDC_DATA_EP_OUT_##index: \
679         port = index; \
680         break;
681     MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_OUT_TO_PORT, ~)
682 #undef UDI_CDC_DATA_EP_OUT_TO_PORT
683     default:
684         port = 0;
685         break;
686     }
687     */
688     port = 0;
689
690     if (UDD_EP_TRANSFER_OK != status) {
691         // Abort reception
692         return;
693     }
694
695     buf_sel_trans = (udi_cdc_rx_buf_sel[port]==0)?1:0;
696
697     if (!n) {
698         udd_ep_run( ep,
699                 true,
700                 udi_cdc_rx_buf[port][buf_sel_trans],
701                 UDI_CDC_RX_BUFFERS,
702                 udi_cdc_data_received);
703         return;
704     }
705
706     udi_cdc_rx_buf_nb[port][buf_sel_trans] = n;
707     udi_cdc_rx_trans_ongoing[port] = false;
708     udi_cdc_rx_start(port);
709 }
710
711 static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
712 {
713     uint8_t port;
714     UNUSED(n);
715
716     /*
717     switch (ep) {
718 #define UDI_CDC_DATA_EP_IN_TO_PORT(index, unused) \
719     case UDI_CDC_DATA_EP_IN_##index: \
720         port = index; \
721         break;
722     MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_IN_TO_PORT, ~)
723 #undef UDI_CDC_DATA_EP_IN_TO_PORT
724     default:
725         port = 0;
726         break;
727     }
728     */
729     port = 0;
730
731     if (UDD_EP_TRANSFER_OK != status) {
732         // Abort transfer
733         return;
734     }
735
736     udi_cdc_tx_buf_nb[port][(udi_cdc_tx_buf_sel[port]==0)?1:0] = 0;
737     udi_cdc_tx_both_buf_to_send[port] = false;
738     udi_cdc_tx_trans_ongoing[port] = false;
739
740     if (n != 0) {
741         UDI_CDC_TX_EMPTY_NOTIFY(port);
742     }
743
744     udi_cdc_tx_send(port);
745 }
746
747 static void udi_cdc_tx_send(uint8_t port)
748 {
749     uint32_t irqflags;  //irqflags_t
750     uint8_t buf_sel_trans;
751     bool b_short_packet;
752     udd_ep_id_t ep;
753     static uint16_t sof_zlp_counter = 0;
754
755 //#if UDI_CDC_PORT_NB == 1 // To optimize code
756     port = 0;
757 //#endif
758
759     if (udi_cdc_tx_trans_ongoing[port]) {
760         return; // Already on going or wait next SOF to send next data
761     }
762     if (udd_is_high_speed()) {
763         if (udi_cdc_tx_sof_num[port] == udd_get_micro_frame_number()) {
764             return; // Wait next SOF to send next data
765         }
766     }else{
767         if (udi_cdc_tx_sof_num[port] == udd_get_frame_number()) {
768             return; // Wait next SOF to send next data
769         }
770     }
771
772     irqflags = __get_PRIMASK();
773   __disable_irq();
774   __DMB();
775     buf_sel_trans = udi_cdc_tx_buf_sel[port];
776     if (udi_cdc_tx_buf_nb[port][buf_sel_trans] == 0) {
777         sof_zlp_counter++;
778         if (((!udd_is_high_speed()) && (sof_zlp_counter < 100))
779                 || (udd_is_high_speed() && (sof_zlp_counter < 800))) {
780       __DMB();
781     __set_PRIMASK(irqflags);
782             return;
783         }
784     }
785     sof_zlp_counter = 0;
786
787     if (!udi_cdc_tx_both_buf_to_send[port]) {
788         // Send current Buffer
789         // and switch the current buffer
790         udi_cdc_tx_buf_sel[port] = (buf_sel_trans==0)?1:0;
791     }else{
792         // Send the other Buffer
793         // and no switch the current buffer
794         buf_sel_trans = (buf_sel_trans==0)?1:0;
795     }
796     udi_cdc_tx_trans_ongoing[port] = true;
797   __DMB();
798   __set_PRIMASK(irqflags);
799
800     b_short_packet = (udi_cdc_tx_buf_nb[port][buf_sel_trans] != UDI_CDC_TX_BUFFERS);
801     if (b_short_packet) {
802         if (udd_is_high_speed()) {
803             udi_cdc_tx_sof_num[port] = udd_get_micro_frame_number();
804         }else{
805             udi_cdc_tx_sof_num[port] = udd_get_frame_number();
806         }
807     }else{
808         udi_cdc_tx_sof_num[port] = 0; // Force next transfer without wait SOF
809     }
810
811     /*
812     // Send the buffer with enable of short packet
813     switch (port) {
814 #define UDI_CDC_PORT_TO_DATA_EP_IN(index, unused) \
815     case index: \
816         ep = UDI_CDC_DATA_EP_IN_##index; \
817         break;
818     MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_IN, ~)
819 #undef UDI_CDC_PORT_TO_DATA_EP_IN
820     default:
821         ep = UDI_CDC_DATA_EP_IN_0;
822         break;
823     }
824     */
825     ep = UDI_CDC_DATA_EP_IN_0;
826
827     udd_ep_run( ep,
828             b_short_packet,
829             udi_cdc_tx_buf[port][buf_sel_trans],
830             udi_cdc_tx_buf_nb[port][buf_sel_trans],
831             udi_cdc_data_sent);
832 }
833
834 //---------------------------------------------
835 //------- Application interface
836
837 void udi_cdc_ctrl_signal_dcd(bool b_set)
838 {
839     udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DCD);
840 }
841
842 void udi_cdc_ctrl_signal_dsr(bool b_set)
843 {
844     udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DSR);
845 }
846
847 void udi_cdc_signal_framing_error(void)
848 {
849     udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_FRAMING);
850 }
851
852 void udi_cdc_signal_parity_error(void)
853 {
854     udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_PARITY);
855 }
856
857 void udi_cdc_signal_overrun(void)
858 {
859     udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_OVERRUN);
860 }
861
862 void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set)
863 {
864     udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DCD);
865 }
866
867 void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set)
868 {
869     udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DSR);
870 }
871
872 void udi_cdc_multi_signal_framing_error(uint8_t port)
873 {
874     udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_FRAMING);
875 }
876
877 void udi_cdc_multi_signal_parity_error(uint8_t port)
878 {
879     udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_PARITY);
880 }
881
882 void udi_cdc_multi_signal_overrun(uint8_t port)
883 {
884     udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_OVERRUN);
885 }
886
887 iram_size_t udi_cdc_multi_get_nb_received_data(uint8_t port)
888 {
889     uint32_t irqflags;  //irqflags_t
890     uint16_t pos;
891     iram_size_t nb_received;
892
893 //#if UDI_CDC_PORT_NB == 1 // To optimize code
894     port = 0;
895 //#endif
896
897     irqflags = __get_PRIMASK();
898   __disable_irq();
899   __DMB();
900     pos = udi_cdc_rx_pos[port];
901     nb_received = udi_cdc_rx_buf_nb[port][udi_cdc_rx_buf_sel[port]] - pos;
902     __DMB();
903   __set_PRIMASK(irqflags);
904     return nb_received;
905 }
906
907 iram_size_t udi_cdc_get_nb_received_data(void)
908 {
909     return udi_cdc_multi_get_nb_received_data(0);
910 }
911
912 bool udi_cdc_multi_is_rx_ready(uint8_t port)
913 {
914     return (udi_cdc_multi_get_nb_received_data(port) > 0);
915 }
916
917 bool udi_cdc_is_rx_ready(void)
918 {
919     return udi_cdc_multi_is_rx_ready(0);
920 }
921
922 int udi_cdc_multi_getc(uint8_t port)
923 {
924     uint32_t irqflags;  //irqflags_t
925     int rx_data = 0;
926     bool b_databit_9;
927     uint16_t pos;
928     uint8_t buf_sel;
929     bool again;
930
931 //#if UDI_CDC_PORT_NB == 1 // To optimize code
932     port = 0;
933 //#endif
934
935     b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits);
936
937 udi_cdc_getc_process_one_byte:
938     // Check available data
939     irqflags = __get_PRIMASK();
940   __disable_irq();
941   __DMB();
942     pos = udi_cdc_rx_pos[port];
943     buf_sel = udi_cdc_rx_buf_sel[port];
944     again = pos >= udi_cdc_rx_buf_nb[port][buf_sel];
945     __DMB();
946   __set_PRIMASK(irqflags);
947     while (again) {
948         if (!udi_cdc_data_running) {
949             return 0;
950         }
951         goto udi_cdc_getc_process_one_byte;
952     }
953
954     // Read data
955     rx_data |= udi_cdc_rx_buf[port][buf_sel][pos];
956     udi_cdc_rx_pos[port] = pos+1;
957
958     udi_cdc_rx_start(port);
959
960     if (b_databit_9) {
961         // Receive MSB
962         b_databit_9 = false;
963         rx_data = rx_data << 8;
964         goto udi_cdc_getc_process_one_byte;
965     }
966     return rx_data;
967 }
968
969 int udi_cdc_getc(void)
970 {
971     return udi_cdc_multi_getc(0);
972 }
973
974 iram_size_t udi_cdc_multi_read_buf(uint8_t port, void* buf, iram_size_t size)
975 {
976     uint32_t irqflags;  //irqflags_t
977     uint8_t *ptr_buf = (uint8_t *)buf;
978     iram_size_t copy_nb;
979     uint16_t pos;
980     uint8_t buf_sel;
981     bool again;
982
983 //#if UDI_CDC_PORT_NB == 1 // To optimize code
984     port = 0;
985 //#endif
986
987 udi_cdc_read_buf_loop_wait:
988     // Check available data
989     irqflags = __get_PRIMASK();
990   __disable_irq();
991   __DMB();  pos = udi_cdc_rx_pos[port];
992     buf_sel = udi_cdc_rx_buf_sel[port];
993     again = pos >= udi_cdc_rx_buf_nb[port][buf_sel];
994     __DMB();
995   __set_PRIMASK(irqflags);
996     while (again) {
997         if (!udi_cdc_data_running) {
998             return size;
999         }
1000         goto udi_cdc_read_buf_loop_wait;
1001     }
1002
1003     // Read data
1004     copy_nb = udi_cdc_rx_buf_nb[port][buf_sel] - pos;
1005     if (copy_nb>size) {
1006         copy_nb = size;
1007     }
1008     memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], copy_nb);
1009     udi_cdc_rx_pos[port] += copy_nb;
1010     ptr_buf += copy_nb;
1011     size -= copy_nb;
1012     udi_cdc_rx_start(port);
1013
1014     if (size) {
1015         goto udi_cdc_read_buf_loop_wait;
1016     }
1017     return 0;
1018 }
1019
1020 static iram_size_t udi_cdc_multi_read_no_polling(uint8_t port, void* buf, iram_size_t size)
1021 {
1022     uint8_t *ptr_buf = (uint8_t *)buf;
1023     iram_size_t nb_avail_data;
1024     uint16_t pos;
1025     uint8_t buf_sel;
1026     uint32_t irqflags;  //irqflags_t
1027
1028 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1029     port = 0;
1030 //#endif
1031
1032     //Data interface not started... exit
1033     if (!udi_cdc_data_running) {
1034         return 0;
1035     }
1036
1037     //Get number of available data
1038     // Check available data
1039     irqflags = __get_PRIMASK();
1040   __disable_irq();
1041   __DMB();
1042     pos = udi_cdc_rx_pos[port];
1043     buf_sel = udi_cdc_rx_buf_sel[port];
1044     nb_avail_data = udi_cdc_rx_buf_nb[port][buf_sel] - pos;
1045     __DMB();
1046   __set_PRIMASK(irqflags);
1047     //If the buffer contains less than the requested number of data,
1048     //adjust read size
1049     if(nb_avail_data<size) {
1050         size = nb_avail_data;
1051     }
1052     if(size>0) {
1053         memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], size);
1054     irqflags = __get_PRIMASK();
1055     __disable_irq();
1056     __DMB();
1057         udi_cdc_rx_pos[port] += size;
1058     __DMB();
1059     __set_PRIMASK(irqflags);
1060         ptr_buf += size;
1061         udi_cdc_rx_start(port);
1062     }
1063     return(nb_avail_data);
1064 }
1065
1066 iram_size_t udi_cdc_read_no_polling(void* buf, iram_size_t size)
1067 {
1068     return udi_cdc_multi_read_no_polling(0, buf, size);
1069 }
1070
1071 iram_size_t udi_cdc_read_buf(void* buf, iram_size_t size)
1072 {
1073     return udi_cdc_multi_read_buf(0, buf, size);
1074 }
1075
1076 iram_size_t udi_cdc_multi_get_free_tx_buffer(uint8_t port)
1077 {
1078     uint32_t irqflags;  //irqflags_t
1079     iram_size_t buf_sel_nb, retval;
1080     uint8_t buf_sel;
1081
1082 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1083     port = 0;
1084 //#endif
1085
1086     irqflags = __get_PRIMASK();
1087   __disable_irq();
1088   __DMB();
1089     buf_sel = udi_cdc_tx_buf_sel[port];
1090     buf_sel_nb = udi_cdc_tx_buf_nb[port][buf_sel];
1091     if (buf_sel_nb == UDI_CDC_TX_BUFFERS) {
1092         if ((!udi_cdc_tx_trans_ongoing[port])
1093             && (!udi_cdc_tx_both_buf_to_send[port])) {
1094             /* One buffer is full, but the other buffer is not used.
1095              * (not used = transfer on-going)
1096              * then move to the other buffer to store data */
1097             udi_cdc_tx_both_buf_to_send[port] = true;
1098             udi_cdc_tx_buf_sel[port] = (buf_sel == 0)? 1 : 0;
1099             buf_sel_nb = 0;
1100         }
1101     }
1102     retval = UDI_CDC_TX_BUFFERS - buf_sel_nb;
1103     __DMB();
1104   __set_PRIMASK(irqflags);
1105     return retval;
1106 }
1107
1108 iram_size_t udi_cdc_get_free_tx_buffer(void)
1109 {
1110     return udi_cdc_multi_get_free_tx_buffer(0);
1111 }
1112
1113 bool udi_cdc_multi_is_tx_ready(uint8_t port)
1114 {
1115     return (udi_cdc_multi_get_free_tx_buffer(port) != 0);
1116 }
1117
1118 bool udi_cdc_is_tx_ready(void)
1119 {
1120     return udi_cdc_multi_is_tx_ready(0);
1121 }
1122
1123 int udi_cdc_multi_putc(uint8_t port, int value)
1124 {
1125     uint32_t irqflags;  //irqflags_t
1126     bool b_databit_9;
1127     uint8_t buf_sel;
1128
1129 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1130     port = 0;
1131 //#endif
1132
1133     b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits);
1134
1135 udi_cdc_putc_process_one_byte:
1136     // Check available space
1137     if (!udi_cdc_multi_is_tx_ready(port)) {
1138         if (!udi_cdc_data_running) {
1139             return false;
1140         }
1141         goto udi_cdc_putc_process_one_byte;
1142     }
1143
1144     // Write value
1145     irqflags = __get_PRIMASK();
1146   __disable_irq();
1147   __DMB();
1148     buf_sel = udi_cdc_tx_buf_sel[port];
1149     udi_cdc_tx_buf[port][buf_sel][udi_cdc_tx_buf_nb[port][buf_sel]++] = value;
1150   __DMB();
1151   __set_PRIMASK(irqflags);
1152
1153     if (b_databit_9) {
1154         // Send MSB
1155         b_databit_9 = false;
1156         value = value >> 8;
1157         goto udi_cdc_putc_process_one_byte;
1158     }
1159     return true;
1160 }
1161
1162 int udi_cdc_putc(int value)
1163 {
1164     return udi_cdc_multi_putc(0, value);
1165 }
1166
1167 iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t size)
1168 {
1169     uint32_t irqflags;  //irqflags_t
1170     uint8_t buf_sel;
1171     uint16_t buf_nb;
1172     iram_size_t copy_nb;
1173     uint8_t *ptr_buf = (uint8_t *)buf;
1174
1175 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1176     port = 0;
1177 //#endif
1178
1179     if (9 == udi_cdc_line_coding[port].bDataBits) {
1180         size *=2;
1181     }
1182
1183     udi_cdc_write_buf_loop_wait:
1184
1185     // Check available space
1186     if (!udi_cdc_multi_is_tx_ready(port)) {
1187         if (!udi_cdc_data_running) {
1188             return size;
1189         }
1190         goto udi_cdc_write_buf_loop_wait;
1191     }
1192
1193     // Write values
1194     irqflags = __get_PRIMASK();
1195     __disable_irq();
1196     __DMB();
1197     buf_sel = udi_cdc_tx_buf_sel[port];
1198     buf_nb = udi_cdc_tx_buf_nb[port][buf_sel];
1199     copy_nb = UDI_CDC_TX_BUFFERS - buf_nb;
1200     if (copy_nb > size) {
1201         copy_nb = size;
1202     }
1203     memcpy(&udi_cdc_tx_buf[port][buf_sel][buf_nb], ptr_buf, copy_nb);
1204     udi_cdc_tx_buf_nb[port][buf_sel] = buf_nb + copy_nb;
1205     __DMB();
1206     __set_PRIMASK(irqflags);
1207
1208     // Update buffer pointer
1209     ptr_buf = ptr_buf + copy_nb;
1210     size -= copy_nb;
1211
1212     if (size) {
1213         goto udi_cdc_write_buf_loop_wait;
1214     }
1215
1216     return 0;
1217 }
1218
1219 iram_size_t udi_cdc_write_buf(const void* buf, iram_size_t size)
1220 {
1221     return udi_cdc_multi_write_buf(0, buf, size);
1222 }
1223
1224 #define MAX_PRINT 256
1225 #define CDC_SEND_INTERVAL 2
1226 uint32_t cdc_tx_send_time_next;
1227
1228 void CDC_send(void)
1229 {
1230     while (timer_read64() < cdc_tx_send_time_next);
1231     udi_cdc_tx_send(0);
1232     cdc_tx_send_time_next = timer_read64() + CDC_SEND_INTERVAL;
1233 }
1234
1235 uint32_t CDC_print(char *printbuf)
1236 {
1237     uint32_t count=0;
1238     char *buf = printbuf;
1239     char c;
1240
1241     if (timer_read64() < 5000) return 0;
1242
1243     while ((c = *buf++) != 0 && !(count >= MAX_PRINT))
1244     {
1245         count++;
1246         if (!udi_cdc_is_tx_ready()) return 0;
1247         udi_cdc_putc(c);
1248         if (count >= UDI_CDC_TX_BUFFERS)
1249         {
1250             count = 0;
1251             CDC_send();
1252         }
1253     }
1254     if (count)
1255     {
1256         CDC_send();
1257     }
1258     return 1;
1259 }
1260
1261 char printbuf[CDC_PRINTBUF_SIZE];
1262
1263 int CDC_printf(const char *_Format, ...)
1264 {
1265     va_list va; //Variable argument list variable
1266     int result;
1267
1268     va_start(va, _Format); //Initialize the variable argument list
1269     result = vsnprintf(printbuf, CDC_PRINTBUF_SIZE, _Format, va);
1270     va_end(va);
1271
1272     CDC_print(printbuf);
1273
1274     return result;
1275 }
1276
1277 //global "inbuf" if desired
1278 inbuf_t inbuf;
1279
1280 uint32_t CDC_input_buf(inbuf_t inbuf, uint32_t inbuf_size)
1281 {
1282     int RXChar;
1283     int entered = 0;
1284
1285     if (!udi_cdc_is_rx_ready()) return 0;
1286     udi_cdc_get_nb_received_data();
1287     RXChar =  udi_cdc_getc();
1288
1289     if (RXChar)
1290     {
1291         switch (RXChar)
1292         {
1293             case '\t':  //tab - repeat last
1294                 inbuf.count=inbuf.lastcount;
1295                 inbuf.buf[inbuf.count+1] = 0;
1296                 CDC_print(inbuf.buf);
1297                 break;
1298             case '\r':  //enter
1299                 inbuf.buf[inbuf.count]=0;
1300                 inbuf.lastcount = inbuf.count;
1301                 inbuf.count = 0;
1302                 entered = 1;
1303                 break;
1304             case '\b': //backspace
1305                 if (inbuf.count > 0) {
1306                     inbuf.count -= 1;
1307                     CDC_print("\b \b\0");
1308                 }
1309                 else
1310                     CDC_print("\a\0");
1311                 break;
1312         default:
1313             if ((RXChar >= 32) && (RXChar <= 126))
1314             {
1315                 if (inbuf.count < inbuf_size-1)
1316                 {
1317                     inbuf.buf[inbuf.count] = RXChar;
1318                     inbuf.buf[inbuf.count+1] = 0;
1319                     CDC_print(&inbuf.buf[inbuf.count]);
1320                     inbuf.count += 1;
1321                 }
1322                 else
1323                     CDC_print("\a\0");
1324             }
1325             break;
1326         }
1327         RXChar = 0;
1328     }
1329     return entered;
1330 }
1331
1332 uint32_t CDC_input()
1333 {
1334     return CDC_input_buf(inbuf, CDC_INBUF_SIZE);
1335 }
1336
1337 void CDC_init(void)
1338 {
1339     inbuf.count = 0;
1340     inbuf.lastcount = 0;
1341     printbuf[0] = 0;
1342     cdc_tx_send_time_next = timer_read64() + CDC_SEND_INTERVAL;
1343 }
1344
1345 #else //CDC line 62
1346
1347 char printbuf[CDC_PRINTBUF_SIZE];
1348
1349 void CDC_send(void)
1350 {
1351     return;
1352 }
1353
1354 uint32_t CDC_print(char *printbuf)
1355 {
1356     return 0;
1357 }
1358
1359 int CDC_printf(const char *_Format, ...)
1360 {
1361     return 0;
1362 }
1363
1364 inbuf_t inbuf;
1365
1366 uint32_t CDC_input(void)
1367 {
1368     return 0;
1369 }
1370
1371 void CDC_init(void)
1372 {
1373     inbuf.count = 0;
1374     inbuf.lastcount = 0;
1375     printbuf[0]=0;
1376 }
1377
1378 #endif //CDC line 62
1379
1380 //@}