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