4 * \brief USB Device Communication Device Class (CDC) interface.
6 * Copyright (c) 2009-2016 Atmel Corporation. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
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.
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.
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
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.
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
47 #include "samd51j18a.h"
49 #include "usb_protocol.h"
50 #include "usb_protocol_cdc.h"
55 #include "udi_cdc_conf.h"
56 #include "udi_device_conf.h"
58 #include "tmk_core/protocol/arm_atsam/clks.h"
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)
67 # define UDI_CDC_TX_BUFFERS (UDI_CDC_DATA_EPS_FS_SIZE)
68 # define UDI_CDC_RX_BUFFERS (UDI_CDC_DATA_EPS_FS_SIZE)
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)
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)
80 #ifndef UDI_CDC_TX_EMPTY_NOTIFY
81 # define UDI_CDC_TX_EMPTY_NOTIFY(port)
85 * \ingroup udi_cdc_group
86 * \defgroup udi_cdc_group_udc Interface with USB Device Core (UDC)
88 * Structures and functions required by UDC.
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,
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,
117 * \ingroup udi_cdc_group
118 * \defgroup udi_cdc_group_internal Implementation of UDI CDC
120 * Class internal implementation
125 * \name Internal routines
130 * \name Routines to control serial line
135 * \brief Returns the port number corresponding at current setup request
137 * \return port number
139 static uint8_t udi_cdc_setup_to_port(void);
142 * \brief Sends line coding to application
144 * Called after SETUP request when line coding data is received.
146 static void udi_cdc_line_coding_received(void);
149 * \brief Records new state
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)
155 static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask);
158 * \brief Check and eventually notify the USB host of new state
160 * \param port Communication port number to manage
161 * \param ep Port communication endpoint
163 static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep);
166 * \brief Ack sent of serial state message
167 * Callback called after serial state message sent
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
173 static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
178 * \name Routines to process data transfer
183 * \brief Enable the reception of data from the USB host
185 * The value udi_cdc_rx_trans_sel indicate the RX buffer to fill.
187 * \param port Communication port number to manage
189 * \return \c 1 if function was successfully done, otherwise \c 0.
191 static bool udi_cdc_rx_start(uint8_t port);
194 * \brief Update rx buffer management with a new data
195 * Callback called after data reception on USB line
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
201 static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
204 * \brief Ack sent of tx buffer
205 * Callback called after data transfer on USB line
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
211 static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
214 * \brief Send buffer on line or wait a SOF event
216 * \param port Communication port number to manage
218 static void udi_cdc_tx_send(uint8_t port);
225 * \name Information about configuration of communication line
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];
234 //! Status of CDC COMM interfaces
235 static volatile uint8_t udi_cdc_nb_comm_enabled = 0;
239 * \name Variables to manage RX/TX transfer requests
240 * Two buffers for each sense are used to optimize the speed.
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];
258 //! Define a transfer halted
259 #define UDI_CDC_TRANS_HALTED 2
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];
276 bool udi_cdc_comm_enable(void)
279 uint8_t iface_comm_num;
281 //#if UDI_CDC_PORT_NB == 1 // To optimize code
283 udi_cdc_nb_comm_enabled = 0;
285 // if (udi_cdc_nb_comm_enabled > UDI_CDC_PORT_NB) {
286 // udi_cdc_nb_comm_enabled = 0;
288 // port = udi_cdc_nb_comm_enabled;
291 // Initialize control signal management
292 udi_cdc_state[port] = CPU_TO_LE16(0);
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);
302 #define UDI_CDC_PORT_TO_IFACE_COMM(index, unused) \
304 iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_##index; \
306 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_IFACE_COMM, ~)
307 #undef UDI_CDC_PORT_TO_IFACE_COMM
309 iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_0;
313 iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_0;
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);
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
326 UDI_CDC_SET_CODING_EXT(port,(&udi_cdc_line_coding[port]));
327 if (!UDI_CDC_ENABLE_EXT(port)) {
331 udi_cdc_nb_comm_enabled++;
335 bool udi_cdc_data_enable(void)
339 //#if UDI_CDC_PORT_NB == 1 // To optimize code
341 udi_cdc_nb_data_enabled = 0;
343 // if (udi_cdc_nb_data_enabled > UDI_CDC_PORT_NB) {
344 // udi_cdc_nb_data_enabled = 0;
346 // port = udi_cdc_nb_data_enabled;
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);
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)) {
367 udi_cdc_nb_data_enabled++;
368 if (udi_cdc_nb_data_enabled == UDI_CDC_PORT_NB) {
369 udi_cdc_data_running = true;
374 void udi_cdc_comm_disable(void)
376 Assert(udi_cdc_nb_comm_enabled != 0);
377 udi_cdc_nb_comm_enabled--;
380 void udi_cdc_data_disable(void)
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;
391 bool udi_cdc_comm_setup(void)
393 uint8_t port = udi_cdc_setup_to_port();
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 =
407 udi_cdc_line_coding[port];
408 udd_g_ctrlreq.payload_size =
409 sizeof(usb_cdc_line_coding_t);
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 =
428 udi_cdc_line_coding[port];
429 udd_g_ctrlreq.payload_size =
430 sizeof(usb_cdc_line_coding_t);
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)));
444 return false; // request Not supported
447 bool udi_cdc_data_setup(void)
449 return false; // request Not supported
452 uint8_t udi_cdc_getsetting(void)
454 return 0; // CDC don't have multiple alternate setting
457 void udi_cdc_data_sof_notify(void)
459 static uint8_t port_notify = 0;
461 // A call of udi_cdc_data_sof_notify() is done for each port
462 udi_cdc_tx_send(port_notify);
464 #if UDI_CDC_PORT_NB != 1 // To optimize code
466 if (port_notify >= UDI_CDC_PORT_NB) {
474 //-------------------------------------------------
475 //------- Internal routines to control serial line
477 static uint8_t udi_cdc_setup_to_port(void)
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: \
487 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_IFACE_COMM_TO_PORT, ~)
488 #undef UDI_CDC_IFACE_COMM_TO_PORT
499 static void udi_cdc_line_coding_received(void)
501 uint8_t port = udi_cdc_setup_to_port();
504 // UDI_CDC_SET_CODING_EXT(port, (&udi_cdc_line_coding[port]));
507 static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask)
510 uint32_t irqflags; //irqflags_t
513 //#if UDI_CDC_PORT_NB == 1 // To optimize code
518 irqflags = __get_PRIMASK();
522 udi_cdc_state[port] |= bit_mask;
524 udi_cdc_state[port] &= ~(unsigned)bit_mask;
527 __set_PRIMASK(irqflags);
530 // Send it if possible and state changed
532 #define UDI_CDC_PORT_TO_COMM_EP(index, unused) \
534 ep_comm = UDI_CDC_COMM_EP_##index; \
536 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_COMM_EP, ~)
537 #undef UDI_CDC_PORT_TO_COMM_EP
539 ep_comm = UDI_CDC_COMM_EP_0;
543 ep_comm = UDI_CDC_COMM_EP_0;
545 udi_cdc_ctrl_state_notify(port, ep_comm);
549 static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep)
551 #if UDI_CDC_PORT_NB == 1 // To optimize code
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] =
564 (uint8_t *) & uid_cdc_state_msg[port],
565 sizeof(uid_cdc_state_msg[0]),
566 udi_cdc_serial_state_msg_sent);
571 static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
579 #define UDI_CDC_GET_PORT_FROM_COMM_EP(iface, unused) \
580 case UDI_CDC_COMM_EP_##iface: \
583 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_GET_PORT_FROM_COMM_EP, ~)
584 #undef UDI_CDC_GET_PORT_FROM_COMM_EP
592 udi_cdc_serial_state_msg_ongoing[port] = false;
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);
609 //-------------------------------------------------
610 //------- Internal routines to process data transfer
612 static bool udi_cdc_rx_start(uint8_t port)
614 uint32_t irqflags; //irqflags_t
615 uint8_t buf_sel_trans;
618 //#if UDI_CDC_PORT_NB == 1 // To optimize code
622 irqflags = __get_PRIMASK();
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
630 __set_PRIMASK(irqflags);
634 // Change current buffer
635 udi_cdc_rx_pos[port] = 0;
636 udi_cdc_rx_buf_sel[port] = (buf_sel_trans==0)?1:0;
638 // Start transfer on RX
639 udi_cdc_rx_trans_ongoing[port] = true;
641 __set_PRIMASK(irqflags);
643 if (udi_cdc_multi_is_rx_ready(port)) {
644 // UDI_CDC_RX_NOTIFY(port);
648 // Send the buffer with enable of short packet
650 #define UDI_CDC_PORT_TO_DATA_EP_OUT(index, unused) \
652 ep = UDI_CDC_DATA_EP_OUT_##index; \
654 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_OUT, ~)
655 #undef UDI_CDC_PORT_TO_DATA_EP_OUT
657 ep = UDI_CDC_DATA_EP_OUT_0;
661 ep = UDI_CDC_DATA_EP_OUT_0;
663 return udd_ep_run(ep,
665 udi_cdc_rx_buf[port][buf_sel_trans],
667 udi_cdc_data_received);
670 static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
672 uint8_t buf_sel_trans;
677 #define UDI_CDC_DATA_EP_OUT_TO_PORT(index, unused) \
678 case UDI_CDC_DATA_EP_OUT_##index: \
681 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_OUT_TO_PORT, ~)
682 #undef UDI_CDC_DATA_EP_OUT_TO_PORT
690 if (UDD_EP_TRANSFER_OK != status) {
695 buf_sel_trans = (udi_cdc_rx_buf_sel[port]==0)?1:0;
700 udi_cdc_rx_buf[port][buf_sel_trans],
702 udi_cdc_data_received);
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);
711 static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
718 #define UDI_CDC_DATA_EP_IN_TO_PORT(index, unused) \
719 case UDI_CDC_DATA_EP_IN_##index: \
722 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_IN_TO_PORT, ~)
723 #undef UDI_CDC_DATA_EP_IN_TO_PORT
731 if (UDD_EP_TRANSFER_OK != status) {
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;
741 UDI_CDC_TX_EMPTY_NOTIFY(port);
744 udi_cdc_tx_send(port);
747 static void udi_cdc_tx_send(uint8_t port)
749 uint32_t irqflags; //irqflags_t
750 uint8_t buf_sel_trans;
753 static uint16_t sof_zlp_counter = 0;
755 //#if UDI_CDC_PORT_NB == 1 // To optimize code
759 if (udi_cdc_tx_trans_ongoing[port]) {
760 return; // Already on going or wait next SOF to send next data
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
767 if (udi_cdc_tx_sof_num[port] == udd_get_frame_number()) {
768 return; // Wait next SOF to send next data
772 irqflags = __get_PRIMASK();
775 buf_sel_trans = udi_cdc_tx_buf_sel[port];
776 if (udi_cdc_tx_buf_nb[port][buf_sel_trans] == 0) {
778 if (((!udd_is_high_speed()) && (sof_zlp_counter < 100))
779 || (udd_is_high_speed() && (sof_zlp_counter < 800))) {
781 __set_PRIMASK(irqflags);
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;
792 // Send the other Buffer
793 // and no switch the current buffer
794 buf_sel_trans = (buf_sel_trans==0)?1:0;
796 udi_cdc_tx_trans_ongoing[port] = true;
798 __set_PRIMASK(irqflags);
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();
805 udi_cdc_tx_sof_num[port] = udd_get_frame_number();
808 udi_cdc_tx_sof_num[port] = 0; // Force next transfer without wait SOF
812 // Send the buffer with enable of short packet
814 #define UDI_CDC_PORT_TO_DATA_EP_IN(index, unused) \
816 ep = UDI_CDC_DATA_EP_IN_##index; \
818 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_IN, ~)
819 #undef UDI_CDC_PORT_TO_DATA_EP_IN
821 ep = UDI_CDC_DATA_EP_IN_0;
825 ep = UDI_CDC_DATA_EP_IN_0;
829 udi_cdc_tx_buf[port][buf_sel_trans],
830 udi_cdc_tx_buf_nb[port][buf_sel_trans],
834 //---------------------------------------------
835 //------- Application interface
837 void udi_cdc_ctrl_signal_dcd(bool b_set)
839 udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DCD);
842 void udi_cdc_ctrl_signal_dsr(bool b_set)
844 udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DSR);
847 void udi_cdc_signal_framing_error(void)
849 udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_FRAMING);
852 void udi_cdc_signal_parity_error(void)
854 udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_PARITY);
857 void udi_cdc_signal_overrun(void)
859 udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_OVERRUN);
862 void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set)
864 udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DCD);
867 void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set)
869 udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DSR);
872 void udi_cdc_multi_signal_framing_error(uint8_t port)
874 udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_FRAMING);
877 void udi_cdc_multi_signal_parity_error(uint8_t port)
879 udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_PARITY);
882 void udi_cdc_multi_signal_overrun(uint8_t port)
884 udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_OVERRUN);
887 iram_size_t udi_cdc_multi_get_nb_received_data(uint8_t port)
889 uint32_t irqflags; //irqflags_t
891 iram_size_t nb_received;
893 //#if UDI_CDC_PORT_NB == 1 // To optimize code
897 irqflags = __get_PRIMASK();
900 pos = udi_cdc_rx_pos[port];
901 nb_received = udi_cdc_rx_buf_nb[port][udi_cdc_rx_buf_sel[port]] - pos;
903 __set_PRIMASK(irqflags);
907 iram_size_t udi_cdc_get_nb_received_data(void)
909 return udi_cdc_multi_get_nb_received_data(0);
912 bool udi_cdc_multi_is_rx_ready(uint8_t port)
914 return (udi_cdc_multi_get_nb_received_data(port) > 0);
917 bool udi_cdc_is_rx_ready(void)
919 return udi_cdc_multi_is_rx_ready(0);
922 int udi_cdc_multi_getc(uint8_t port)
924 uint32_t irqflags; //irqflags_t
931 //#if UDI_CDC_PORT_NB == 1 // To optimize code
935 b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits);
937 udi_cdc_getc_process_one_byte:
938 // Check available data
939 irqflags = __get_PRIMASK();
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];
946 __set_PRIMASK(irqflags);
948 if (!udi_cdc_data_running) {
951 goto udi_cdc_getc_process_one_byte;
955 rx_data |= udi_cdc_rx_buf[port][buf_sel][pos];
956 udi_cdc_rx_pos[port] = pos+1;
958 udi_cdc_rx_start(port);
963 rx_data = rx_data << 8;
964 goto udi_cdc_getc_process_one_byte;
969 int udi_cdc_getc(void)
971 return udi_cdc_multi_getc(0);
974 iram_size_t udi_cdc_multi_read_buf(uint8_t port, void* buf, iram_size_t size)
976 uint32_t irqflags; //irqflags_t
977 uint8_t *ptr_buf = (uint8_t *)buf;
983 //#if UDI_CDC_PORT_NB == 1 // To optimize code
987 udi_cdc_read_buf_loop_wait:
988 // Check available data
989 irqflags = __get_PRIMASK();
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];
995 __set_PRIMASK(irqflags);
997 if (!udi_cdc_data_running) {
1000 goto udi_cdc_read_buf_loop_wait;
1004 copy_nb = udi_cdc_rx_buf_nb[port][buf_sel] - pos;
1008 memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], copy_nb);
1009 udi_cdc_rx_pos[port] += copy_nb;
1012 udi_cdc_rx_start(port);
1015 goto udi_cdc_read_buf_loop_wait;
1020 static iram_size_t udi_cdc_multi_read_no_polling(uint8_t port, void* buf, iram_size_t size)
1022 uint8_t *ptr_buf = (uint8_t *)buf;
1023 iram_size_t nb_avail_data;
1026 uint32_t irqflags; //irqflags_t
1028 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1032 //Data interface not started... exit
1033 if (!udi_cdc_data_running) {
1037 //Get number of available data
1038 // Check available data
1039 irqflags = __get_PRIMASK();
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;
1046 __set_PRIMASK(irqflags);
1047 //If the buffer contains less than the requested number of data,
1049 if(nb_avail_data<size) {
1050 size = nb_avail_data;
1053 memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], size);
1054 irqflags = __get_PRIMASK();
1057 udi_cdc_rx_pos[port] += size;
1059 __set_PRIMASK(irqflags);
1061 udi_cdc_rx_start(port);
1063 return(nb_avail_data);
1066 iram_size_t udi_cdc_read_no_polling(void* buf, iram_size_t size)
1068 return udi_cdc_multi_read_no_polling(0, buf, size);
1071 iram_size_t udi_cdc_read_buf(void* buf, iram_size_t size)
1073 return udi_cdc_multi_read_buf(0, buf, size);
1076 iram_size_t udi_cdc_multi_get_free_tx_buffer(uint8_t port)
1078 uint32_t irqflags; //irqflags_t
1079 iram_size_t buf_sel_nb, retval;
1082 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1086 irqflags = __get_PRIMASK();
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;
1102 retval = UDI_CDC_TX_BUFFERS - buf_sel_nb;
1104 __set_PRIMASK(irqflags);
1108 iram_size_t udi_cdc_get_free_tx_buffer(void)
1110 return udi_cdc_multi_get_free_tx_buffer(0);
1113 bool udi_cdc_multi_is_tx_ready(uint8_t port)
1115 return (udi_cdc_multi_get_free_tx_buffer(port) != 0);
1118 bool udi_cdc_is_tx_ready(void)
1120 return udi_cdc_multi_is_tx_ready(0);
1123 int udi_cdc_multi_putc(uint8_t port, int value)
1125 uint32_t irqflags; //irqflags_t
1129 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1133 b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits);
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) {
1141 goto udi_cdc_putc_process_one_byte;
1145 irqflags = __get_PRIMASK();
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;
1151 __set_PRIMASK(irqflags);
1155 b_databit_9 = false;
1157 goto udi_cdc_putc_process_one_byte;
1162 int udi_cdc_putc(int value)
1164 return udi_cdc_multi_putc(0, value);
1167 iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t size)
1169 uint32_t irqflags; //irqflags_t
1172 iram_size_t copy_nb;
1173 uint8_t *ptr_buf = (uint8_t *)buf;
1175 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1179 if (9 == udi_cdc_line_coding[port].bDataBits) {
1183 udi_cdc_write_buf_loop_wait:
1185 // Check available space
1186 if (!udi_cdc_multi_is_tx_ready(port)) {
1187 if (!udi_cdc_data_running) {
1190 goto udi_cdc_write_buf_loop_wait;
1194 irqflags = __get_PRIMASK();
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) {
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;
1206 __set_PRIMASK(irqflags);
1208 // Update buffer pointer
1209 ptr_buf = ptr_buf + copy_nb;
1213 goto udi_cdc_write_buf_loop_wait;
1219 iram_size_t udi_cdc_write_buf(const void* buf, iram_size_t size)
1221 return udi_cdc_multi_write_buf(0, buf, size);
1224 #define MAX_PRINT 256
1225 #define CDC_SEND_INTERVAL 2
1226 uint32_t cdc_tx_send_time_next;
1230 while (CLK_get_ms() < cdc_tx_send_time_next);
1232 cdc_tx_send_time_next = CLK_get_ms() + CDC_SEND_INTERVAL;
1235 uint32_t CDC_print(char *printbuf)
1238 char *buf = printbuf;
1241 if (CLK_get_ms() < 5000) return 0;
1243 while ((c = *buf++) != 0 && !(count >= MAX_PRINT))
1246 if (!udi_cdc_is_tx_ready()) return 0;
1248 if (count >= UDI_CDC_TX_BUFFERS)
1261 char printbuf[CDC_PRINTBUF_SIZE];
1263 int dpf(const char *_Format, ...)
1265 va_list va; //Variable argument list variable
1268 va_start(va, _Format); //Initialize the variable argument list
1269 result = vsnprintf(printbuf, CDC_PRINTBUF_SIZE, _Format, va);
1272 CDC_print(printbuf);
1277 //global "inbuf" if desired
1280 uint32_t CDC_input_buf(inbuf_t inbuf, uint32_t inbuf_size)
1285 if (!udi_cdc_is_rx_ready()) return 0;
1286 udi_cdc_get_nb_received_data();
1287 RXChar = udi_cdc_getc();
1293 case '\t': //tab - repeat last
1294 inbuf.count=inbuf.lastcount;
1295 inbuf.buf[inbuf.count+1] = 0;
1296 CDC_print(inbuf.buf);
1299 inbuf.buf[inbuf.count]=0;
1300 inbuf.lastcount = inbuf.count;
1304 case '\b': //backspace
1305 if (inbuf.count > 0) {
1307 CDC_print("\b \b\0");
1313 if ((RXChar >= 32) && (RXChar <= 126))
1315 if (inbuf.count < inbuf_size-1)
1317 inbuf.buf[inbuf.count] = RXChar;
1318 inbuf.buf[inbuf.count+1] = 0;
1319 CDC_print(&inbuf.buf[inbuf.count]);
1332 uint32_t CDC_input()
1334 return CDC_input_buf(inbuf, CDC_INBUF_SIZE);
1340 inbuf.lastcount = 0;
1342 cdc_tx_send_time_next = CLK_get_ms() + CDC_SEND_INTERVAL;
1347 char printbuf[CDC_PRINTBUF_SIZE];
1354 uint32_t CDC_print(char *printbuf)
1359 int dpf(const char *_Format, ...)
1366 uint32_t CDC_input(void)
1374 inbuf.lastcount = 0;
1378 #endif //CDC line 62