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"
59 #include "tmk_core/protocol/arm_atsam/clks.h"
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)
68 # define UDI_CDC_TX_BUFFERS (UDI_CDC_DATA_EPS_FS_SIZE)
69 # define UDI_CDC_RX_BUFFERS (UDI_CDC_DATA_EPS_FS_SIZE)
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)
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)
81 #ifndef UDI_CDC_TX_EMPTY_NOTIFY
82 # define UDI_CDC_TX_EMPTY_NOTIFY(port)
86 * \ingroup udi_cdc_group
87 * \defgroup udi_cdc_group_udc Interface with USB Device Core (UDC)
89 * Structures and functions required by UDC.
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,
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,
118 * \ingroup udi_cdc_group
119 * \defgroup udi_cdc_group_internal Implementation of UDI CDC
121 * Class internal implementation
126 * \name Internal routines
131 * \name Routines to control serial line
136 * \brief Returns the port number corresponding at current setup request
138 * \return port number
140 static uint8_t udi_cdc_setup_to_port(void);
143 * \brief Sends line coding to application
145 * Called after SETUP request when line coding data is received.
147 static void udi_cdc_line_coding_received(void);
150 * \brief Records new state
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)
156 static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask);
159 * \brief Check and eventually notify the USB host of new state
161 * \param port Communication port number to manage
162 * \param ep Port communication endpoint
164 static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep);
167 * \brief Ack sent of serial state message
168 * Callback called after serial state message sent
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
174 static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
179 * \name Routines to process data transfer
184 * \brief Enable the reception of data from the USB host
186 * The value udi_cdc_rx_trans_sel indicate the RX buffer to fill.
188 * \param port Communication port number to manage
190 * \return \c 1 if function was successfully done, otherwise \c 0.
192 static bool udi_cdc_rx_start(uint8_t port);
195 * \brief Update rx buffer management with a new data
196 * Callback called after data reception on USB line
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
202 static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
205 * \brief Ack sent of tx buffer
206 * Callback called after data transfer on USB line
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
212 static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
215 * \brief Send buffer on line or wait a SOF event
217 * \param port Communication port number to manage
219 static void udi_cdc_tx_send(uint8_t port);
226 * \name Information about configuration of communication line
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];
235 //! Status of CDC COMM interfaces
236 static volatile uint8_t udi_cdc_nb_comm_enabled = 0;
240 * \name Variables to manage RX/TX transfer requests
241 * Two buffers for each sense are used to optimize the speed.
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];
259 //! Define a transfer halted
260 #define UDI_CDC_TRANS_HALTED 2
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];
277 bool udi_cdc_comm_enable(void)
280 uint8_t iface_comm_num;
282 //#if UDI_CDC_PORT_NB == 1 // To optimize code
284 udi_cdc_nb_comm_enabled = 0;
286 // if (udi_cdc_nb_comm_enabled > UDI_CDC_PORT_NB) {
287 // udi_cdc_nb_comm_enabled = 0;
289 // port = udi_cdc_nb_comm_enabled;
292 // Initialize control signal management
293 udi_cdc_state[port] = CPU_TO_LE16(0);
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);
303 #define UDI_CDC_PORT_TO_IFACE_COMM(index, unused) \
305 iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_##index; \
307 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_IFACE_COMM, ~)
308 #undef UDI_CDC_PORT_TO_IFACE_COMM
310 iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_0;
314 iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_0;
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);
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
327 UDI_CDC_SET_CODING_EXT(port,(&udi_cdc_line_coding[port]));
328 if (!UDI_CDC_ENABLE_EXT(port)) {
332 udi_cdc_nb_comm_enabled++;
336 bool udi_cdc_data_enable(void)
340 //#if UDI_CDC_PORT_NB == 1 // To optimize code
342 udi_cdc_nb_data_enabled = 0;
344 // if (udi_cdc_nb_data_enabled > UDI_CDC_PORT_NB) {
345 // udi_cdc_nb_data_enabled = 0;
347 // port = udi_cdc_nb_data_enabled;
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);
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)) {
368 udi_cdc_nb_data_enabled++;
369 if (udi_cdc_nb_data_enabled == UDI_CDC_PORT_NB) {
370 udi_cdc_data_running = true;
375 void udi_cdc_comm_disable(void)
377 Assert(udi_cdc_nb_comm_enabled != 0);
378 udi_cdc_nb_comm_enabled--;
381 void udi_cdc_data_disable(void)
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;
392 bool udi_cdc_comm_setup(void)
394 uint8_t port = udi_cdc_setup_to_port();
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 =
408 udi_cdc_line_coding[port];
409 udd_g_ctrlreq.payload_size =
410 sizeof(usb_cdc_line_coding_t);
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 =
429 udi_cdc_line_coding[port];
430 udd_g_ctrlreq.payload_size =
431 sizeof(usb_cdc_line_coding_t);
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)));
445 return false; // request Not supported
448 bool udi_cdc_data_setup(void)
450 return false; // request Not supported
453 uint8_t udi_cdc_getsetting(void)
455 return 0; // CDC don't have multiple alternate setting
458 void udi_cdc_data_sof_notify(void)
460 static uint8_t port_notify = 0;
462 // A call of udi_cdc_data_sof_notify() is done for each port
463 udi_cdc_tx_send(port_notify);
465 #if UDI_CDC_PORT_NB != 1 // To optimize code
467 if (port_notify >= UDI_CDC_PORT_NB) {
475 //-------------------------------------------------
476 //------- Internal routines to control serial line
478 static uint8_t udi_cdc_setup_to_port(void)
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: \
488 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_IFACE_COMM_TO_PORT, ~)
489 #undef UDI_CDC_IFACE_COMM_TO_PORT
500 static void udi_cdc_line_coding_received(void)
502 uint8_t port = udi_cdc_setup_to_port();
505 // UDI_CDC_SET_CODING_EXT(port, (&udi_cdc_line_coding[port]));
508 static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask)
511 uint32_t irqflags; //irqflags_t
514 //#if UDI_CDC_PORT_NB == 1 // To optimize code
519 irqflags = __get_PRIMASK();
523 udi_cdc_state[port] |= bit_mask;
525 udi_cdc_state[port] &= ~(unsigned)bit_mask;
528 __set_PRIMASK(irqflags);
531 // Send it if possible and state changed
533 #define UDI_CDC_PORT_TO_COMM_EP(index, unused) \
535 ep_comm = UDI_CDC_COMM_EP_##index; \
537 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_COMM_EP, ~)
538 #undef UDI_CDC_PORT_TO_COMM_EP
540 ep_comm = UDI_CDC_COMM_EP_0;
544 ep_comm = UDI_CDC_COMM_EP_0;
546 udi_cdc_ctrl_state_notify(port, ep_comm);
550 static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep)
552 #if UDI_CDC_PORT_NB == 1 // To optimize code
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] =
565 (uint8_t *) & uid_cdc_state_msg[port],
566 sizeof(uid_cdc_state_msg[0]),
567 udi_cdc_serial_state_msg_sent);
572 static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
580 #define UDI_CDC_GET_PORT_FROM_COMM_EP(iface, unused) \
581 case UDI_CDC_COMM_EP_##iface: \
584 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_GET_PORT_FROM_COMM_EP, ~)
585 #undef UDI_CDC_GET_PORT_FROM_COMM_EP
593 udi_cdc_serial_state_msg_ongoing[port] = false;
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);
610 //-------------------------------------------------
611 //------- Internal routines to process data transfer
613 static bool udi_cdc_rx_start(uint8_t port)
615 uint32_t irqflags; //irqflags_t
616 uint8_t buf_sel_trans;
619 //#if UDI_CDC_PORT_NB == 1 // To optimize code
623 irqflags = __get_PRIMASK();
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
631 __set_PRIMASK(irqflags);
635 // Change current buffer
636 udi_cdc_rx_pos[port] = 0;
637 udi_cdc_rx_buf_sel[port] = (buf_sel_trans==0)?1:0;
639 // Start transfer on RX
640 udi_cdc_rx_trans_ongoing[port] = true;
642 __set_PRIMASK(irqflags);
644 if (udi_cdc_multi_is_rx_ready(port)) {
645 // UDI_CDC_RX_NOTIFY(port);
649 // Send the buffer with enable of short packet
651 #define UDI_CDC_PORT_TO_DATA_EP_OUT(index, unused) \
653 ep = UDI_CDC_DATA_EP_OUT_##index; \
655 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_OUT, ~)
656 #undef UDI_CDC_PORT_TO_DATA_EP_OUT
658 ep = UDI_CDC_DATA_EP_OUT_0;
662 ep = UDI_CDC_DATA_EP_OUT_0;
664 return udd_ep_run(ep,
666 udi_cdc_rx_buf[port][buf_sel_trans],
668 udi_cdc_data_received);
671 static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
673 uint8_t buf_sel_trans;
678 #define UDI_CDC_DATA_EP_OUT_TO_PORT(index, unused) \
679 case UDI_CDC_DATA_EP_OUT_##index: \
682 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_OUT_TO_PORT, ~)
683 #undef UDI_CDC_DATA_EP_OUT_TO_PORT
691 if (UDD_EP_TRANSFER_OK != status) {
696 buf_sel_trans = (udi_cdc_rx_buf_sel[port]==0)?1:0;
701 udi_cdc_rx_buf[port][buf_sel_trans],
703 udi_cdc_data_received);
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);
712 static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
719 #define UDI_CDC_DATA_EP_IN_TO_PORT(index, unused) \
720 case UDI_CDC_DATA_EP_IN_##index: \
723 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_IN_TO_PORT, ~)
724 #undef UDI_CDC_DATA_EP_IN_TO_PORT
732 if (UDD_EP_TRANSFER_OK != status) {
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;
742 UDI_CDC_TX_EMPTY_NOTIFY(port);
745 udi_cdc_tx_send(port);
748 static void udi_cdc_tx_send(uint8_t port)
750 uint32_t irqflags; //irqflags_t
751 uint8_t buf_sel_trans;
754 static uint16_t sof_zlp_counter = 0;
756 //#if UDI_CDC_PORT_NB == 1 // To optimize code
760 if (udi_cdc_tx_trans_ongoing[port]) {
761 return; // Already on going or wait next SOF to send next data
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
768 if (udi_cdc_tx_sof_num[port] == udd_get_frame_number()) {
769 return; // Wait next SOF to send next data
773 irqflags = __get_PRIMASK();
776 buf_sel_trans = udi_cdc_tx_buf_sel[port];
777 if (udi_cdc_tx_buf_nb[port][buf_sel_trans] == 0) {
779 if (((!udd_is_high_speed()) && (sof_zlp_counter < 100))
780 || (udd_is_high_speed() && (sof_zlp_counter < 800))) {
782 __set_PRIMASK(irqflags);
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;
793 // Send the other Buffer
794 // and no switch the current buffer
795 buf_sel_trans = (buf_sel_trans==0)?1:0;
797 udi_cdc_tx_trans_ongoing[port] = true;
799 __set_PRIMASK(irqflags);
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();
806 udi_cdc_tx_sof_num[port] = udd_get_frame_number();
809 udi_cdc_tx_sof_num[port] = 0; // Force next transfer without wait SOF
813 // Send the buffer with enable of short packet
815 #define UDI_CDC_PORT_TO_DATA_EP_IN(index, unused) \
817 ep = UDI_CDC_DATA_EP_IN_##index; \
819 MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_IN, ~)
820 #undef UDI_CDC_PORT_TO_DATA_EP_IN
822 ep = UDI_CDC_DATA_EP_IN_0;
826 ep = UDI_CDC_DATA_EP_IN_0;
830 udi_cdc_tx_buf[port][buf_sel_trans],
831 udi_cdc_tx_buf_nb[port][buf_sel_trans],
835 //---------------------------------------------
836 //------- Application interface
838 void udi_cdc_ctrl_signal_dcd(bool b_set)
840 udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DCD);
843 void udi_cdc_ctrl_signal_dsr(bool b_set)
845 udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DSR);
848 void udi_cdc_signal_framing_error(void)
850 udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_FRAMING);
853 void udi_cdc_signal_parity_error(void)
855 udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_PARITY);
858 void udi_cdc_signal_overrun(void)
860 udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_OVERRUN);
863 void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set)
865 udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DCD);
868 void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set)
870 udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DSR);
873 void udi_cdc_multi_signal_framing_error(uint8_t port)
875 udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_FRAMING);
878 void udi_cdc_multi_signal_parity_error(uint8_t port)
880 udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_PARITY);
883 void udi_cdc_multi_signal_overrun(uint8_t port)
885 udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_OVERRUN);
888 iram_size_t udi_cdc_multi_get_nb_received_data(uint8_t port)
890 uint32_t irqflags; //irqflags_t
892 iram_size_t nb_received;
894 //#if UDI_CDC_PORT_NB == 1 // To optimize code
898 irqflags = __get_PRIMASK();
901 pos = udi_cdc_rx_pos[port];
902 nb_received = udi_cdc_rx_buf_nb[port][udi_cdc_rx_buf_sel[port]] - pos;
904 __set_PRIMASK(irqflags);
908 iram_size_t udi_cdc_get_nb_received_data(void)
910 return udi_cdc_multi_get_nb_received_data(0);
913 bool udi_cdc_multi_is_rx_ready(uint8_t port)
915 return (udi_cdc_multi_get_nb_received_data(port) > 0);
918 bool udi_cdc_is_rx_ready(void)
920 return udi_cdc_multi_is_rx_ready(0);
923 int udi_cdc_multi_getc(uint8_t port)
925 uint32_t irqflags; //irqflags_t
932 //#if UDI_CDC_PORT_NB == 1 // To optimize code
936 b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits);
938 udi_cdc_getc_process_one_byte:
939 // Check available data
940 irqflags = __get_PRIMASK();
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];
947 __set_PRIMASK(irqflags);
949 if (!udi_cdc_data_running) {
952 goto udi_cdc_getc_process_one_byte;
956 rx_data |= udi_cdc_rx_buf[port][buf_sel][pos];
957 udi_cdc_rx_pos[port] = pos+1;
959 udi_cdc_rx_start(port);
964 rx_data = rx_data << 8;
965 goto udi_cdc_getc_process_one_byte;
970 int udi_cdc_getc(void)
972 return udi_cdc_multi_getc(0);
975 iram_size_t udi_cdc_multi_read_buf(uint8_t port, void* buf, iram_size_t size)
977 uint32_t irqflags; //irqflags_t
978 uint8_t *ptr_buf = (uint8_t *)buf;
984 //#if UDI_CDC_PORT_NB == 1 // To optimize code
988 udi_cdc_read_buf_loop_wait:
989 // Check available data
990 irqflags = __get_PRIMASK();
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];
996 __set_PRIMASK(irqflags);
998 if (!udi_cdc_data_running) {
1001 goto udi_cdc_read_buf_loop_wait;
1005 copy_nb = udi_cdc_rx_buf_nb[port][buf_sel] - pos;
1009 memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], copy_nb);
1010 udi_cdc_rx_pos[port] += copy_nb;
1013 udi_cdc_rx_start(port);
1016 goto udi_cdc_read_buf_loop_wait;
1021 static iram_size_t udi_cdc_multi_read_no_polling(uint8_t port, void* buf, iram_size_t size)
1023 uint8_t *ptr_buf = (uint8_t *)buf;
1024 iram_size_t nb_avail_data;
1027 uint32_t irqflags; //irqflags_t
1029 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1033 //Data interface not started... exit
1034 if (!udi_cdc_data_running) {
1038 //Get number of available data
1039 // Check available data
1040 irqflags = __get_PRIMASK();
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;
1047 __set_PRIMASK(irqflags);
1048 //If the buffer contains less than the requested number of data,
1050 if(nb_avail_data<size) {
1051 size = nb_avail_data;
1054 memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], size);
1055 irqflags = __get_PRIMASK();
1058 udi_cdc_rx_pos[port] += size;
1060 __set_PRIMASK(irqflags);
1062 udi_cdc_rx_start(port);
1064 return(nb_avail_data);
1067 iram_size_t udi_cdc_read_no_polling(void* buf, iram_size_t size)
1069 return udi_cdc_multi_read_no_polling(0, buf, size);
1072 iram_size_t udi_cdc_read_buf(void* buf, iram_size_t size)
1074 return udi_cdc_multi_read_buf(0, buf, size);
1077 iram_size_t udi_cdc_multi_get_free_tx_buffer(uint8_t port)
1079 uint32_t irqflags; //irqflags_t
1080 iram_size_t buf_sel_nb, retval;
1083 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1087 irqflags = __get_PRIMASK();
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;
1103 retval = UDI_CDC_TX_BUFFERS - buf_sel_nb;
1105 __set_PRIMASK(irqflags);
1109 iram_size_t udi_cdc_get_free_tx_buffer(void)
1111 return udi_cdc_multi_get_free_tx_buffer(0);
1114 bool udi_cdc_multi_is_tx_ready(uint8_t port)
1116 return (udi_cdc_multi_get_free_tx_buffer(port) != 0);
1119 bool udi_cdc_is_tx_ready(void)
1121 return udi_cdc_multi_is_tx_ready(0);
1124 int udi_cdc_multi_putc(uint8_t port, int value)
1126 uint32_t irqflags; //irqflags_t
1130 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1134 b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits);
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) {
1142 goto udi_cdc_putc_process_one_byte;
1146 irqflags = __get_PRIMASK();
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;
1152 __set_PRIMASK(irqflags);
1156 b_databit_9 = false;
1158 goto udi_cdc_putc_process_one_byte;
1163 int udi_cdc_putc(int value)
1165 return udi_cdc_multi_putc(0, value);
1168 iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t size)
1170 uint32_t irqflags; //irqflags_t
1173 iram_size_t copy_nb;
1174 uint8_t *ptr_buf = (uint8_t *)buf;
1176 //#if UDI_CDC_PORT_NB == 1 // To optimize code
1180 if (9 == udi_cdc_line_coding[port].bDataBits) {
1184 udi_cdc_write_buf_loop_wait:
1186 // Check available space
1187 if (!udi_cdc_multi_is_tx_ready(port)) {
1188 if (!udi_cdc_data_running) {
1191 goto udi_cdc_write_buf_loop_wait;
1195 irqflags = __get_PRIMASK();
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) {
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;
1207 __set_PRIMASK(irqflags);
1209 // Update buffer pointer
1210 ptr_buf = ptr_buf + copy_nb;
1214 goto udi_cdc_write_buf_loop_wait;
1220 iram_size_t udi_cdc_write_buf(const void* buf, iram_size_t size)
1222 return udi_cdc_multi_write_buf(0, buf, size);
1225 #define MAX_PRINT 256
1226 #define CDC_SEND_INTERVAL 2
1227 uint32_t cdc_tx_send_time_next;
1231 while (CLK_get_ms() < cdc_tx_send_time_next);
1233 cdc_tx_send_time_next = CLK_get_ms() + CDC_SEND_INTERVAL;
1236 uint32_t CDC_print(char *printbuf)
1239 char *buf = printbuf;
1242 if (CLK_get_ms() < 5000) return 0;
1244 while ((c = *buf++) != 0 && !(count >= MAX_PRINT))
1247 if (!udi_cdc_is_tx_ready()) return 0;
1249 if (count >= UDI_CDC_TX_BUFFERS)
1263 char printbuf[CDC_PRINTBUF_SIZE];
1265 int dpf(const char *_Format, ...)
1267 va_list va; //Variable argument list variable
1270 va_start(va,_Format); //Initialize the variable argument list
1271 result = vspf(printbuf, _Format, va);
1274 CDC_print(printbuf);
1279 //global "inbuf" if desired
1282 uint32_t CDC_input_buf(inbuf_t inbuf, uint32_t inbuf_size)
1287 if (!udi_cdc_is_rx_ready()) return 0;
1288 udi_cdc_get_nb_received_data();
1289 RXChar = udi_cdc_getc();
1295 case '\t': //tab - repeat last
1296 inbuf.count=inbuf.lastcount;
1297 inbuf.buf[inbuf.count+1] = 0;
1298 CDC_print(inbuf.buf);
1301 inbuf.buf[inbuf.count]=0;
1302 inbuf.lastcount = inbuf.count;
1306 case '\b': //backspace
1307 if (inbuf.count > 0) {
1309 CDC_print("\b \b\0");
1315 if ((RXChar >= 32) && (RXChar <= 126))
1317 if (inbuf.count < inbuf_size-1)
1319 inbuf.buf[inbuf.count] = RXChar;
1320 inbuf.buf[inbuf.count+1] = 0;
1321 CDC_print(&inbuf.buf[inbuf.count]);
1334 uint32_t CDC_input()
1336 return CDC_input_buf(inbuf, CDC_INBUF_SIZE);
1342 inbuf.lastcount = 0;
1344 cdc_tx_send_time_next = CLK_get_ms() + CDC_SEND_INTERVAL;
1349 char printbuf[CDC_PRINTBUF_SIZE];
1356 uint32_t CDC_print(char *printbuf)
1361 int dpf(const char *_Format, ...)
1368 uint32_t CDC_input(void)
1376 inbuf.lastcount = 0;
1380 char printbuf[CDC_PRINTBUF_SIZE];
1382 #endif //CDC line 62