1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * Taken from ST Cube library and heavily modified.  See below for original
5  * copyright header.
6  */
7 
8 /**
9   ******************************************************************************
10   * @file    USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c
11   * @author  MCD Application Team
12   * @version V1.0.1
13   * @date    26-February-2014
14   * @brief   Source file for USBD CDC interface
15   ******************************************************************************
16   * @attention
17   *
18   * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
19   *
20   * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
21   * You may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at:
23   *
24   *        http://www.st.com/software_license_agreement_liberty_v2
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   *
32   ******************************************************************************
33   */
34 
35 /* Includes ------------------------------------------------------------------*/
36 
37 #include <stdbool.h>
38 #include <stdint.h>
39 
40 #include "usbd_cdc_msc_hid.h"
41 #include "usbd_cdc_interface.h"
42 #include "pendsv.h"
43 
44 #include "py/obj.h"
45 #include "shared/runtime/interrupt_char.h"
46 #include "irq.h"
47 
48 #if MICROPY_HW_ENABLE_USB
49 
50 // CDC control commands
51 #define CDC_SEND_ENCAPSULATED_COMMAND               0x00
52 #define CDC_GET_ENCAPSULATED_RESPONSE               0x01
53 #define CDC_SET_COMM_FEATURE                        0x02
54 #define CDC_GET_COMM_FEATURE                        0x03
55 #define CDC_CLEAR_COMM_FEATURE                      0x04
56 #define CDC_SET_LINE_CODING                         0x20
57 #define CDC_GET_LINE_CODING                         0x21
58 #define CDC_SET_CONTROL_LINE_STATE                  0x22
59 #define CDC_SEND_BREAK                              0x23
60 
61 // Used to control the connect_state variable when USB host opens the serial port
62 static uint8_t usbd_cdc_connect_tx_timer;
63 
usbd_cdc_init(usbd_cdc_state_t * cdc_in)64 uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) {
65     usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t *)cdc_in;
66 
67     // Reset the CDC state due to a new USB host connection
68     // Note: we don't reset tx_buf_ptr_* in order to allow the output buffer to
69     // be filled (by usbd_cdc_tx_always) before the USB device is connected, and
70     // to retain transmit buffer state across multiple USB connections (they will
71     // be 0 at MCU reset since the variables live in the BSS).
72     cdc->rx_buf_put = 0;
73     cdc->rx_buf_get = 0;
74     cdc->rx_buf_full = false;
75     cdc->tx_need_empty_packet = 0;
76     cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED;
77     if (cdc->attached_to_repl) {
78         // Default behavior is non-blocking when attached to repl
79         cdc->flow &= ~USBD_CDC_FLOWCONTROL_CTS;
80     } else {
81         cdc->flow |= USBD_CDC_FLOWCONTROL_CTS;
82     }
83 
84     // Return the buffer to place the first USB OUT packet
85     return cdc->rx_packet_buf;
86 }
87 
usbd_cdc_deinit(usbd_cdc_state_t * cdc_in)88 void usbd_cdc_deinit(usbd_cdc_state_t *cdc_in) {
89     usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t *)cdc_in;
90     cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED;
91 }
92 
93 // Manage the CDC class requests
94 // cmd: command code
95 // pbuf: buffer containing command data (request parameters)
96 // length: number of data to be sent (in bytes)
97 // Returns USBD_OK if all operations are OK else USBD_FAIL
usbd_cdc_control(usbd_cdc_state_t * cdc_in,uint8_t cmd,uint8_t * pbuf,uint16_t length)98 int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t *pbuf, uint16_t length) {
99     usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t *)cdc_in;
100 
101     switch (cmd) {
102         case CDC_SEND_ENCAPSULATED_COMMAND:
103             /* Add your code here */
104             break;
105 
106         case CDC_GET_ENCAPSULATED_RESPONSE:
107             /* Add your code here */
108             break;
109 
110         case CDC_SET_COMM_FEATURE:
111             /* Add your code here */
112             break;
113 
114         case CDC_GET_COMM_FEATURE:
115             /* Add your code here */
116             break;
117 
118         case CDC_CLEAR_COMM_FEATURE:
119             /* Add your code here */
120             break;
121 
122         case CDC_SET_LINE_CODING:
123             #if 0
124             LineCoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) | \
125                 (pbuf[2] << 16) | (pbuf[3] << 24));
126             LineCoding.format = pbuf[4];
127             LineCoding.paritytype = pbuf[5];
128             LineCoding.datatype = pbuf[6];
129             /* Set the new configuration */
130             #endif
131             break;
132 
133         case CDC_GET_LINE_CODING:
134             /* Add your code here */
135             pbuf[0] = (uint8_t)(115200);
136             pbuf[1] = (uint8_t)(115200 >> 8);
137             pbuf[2] = (uint8_t)(115200 >> 16);
138             pbuf[3] = (uint8_t)(115200 >> 24);
139             pbuf[4] = 0; // stop bits (1)
140             pbuf[5] = 0; // parity (none)
141             pbuf[6] = 8; // number of bits (8)
142             break;
143 
144         case CDC_SET_CONTROL_LINE_STATE: {
145             // wValue, indicating the state, is passed in length (bit of a hack)
146             if (length & 1) {
147                 // The actual connection state is delayed to give the host a chance to
148                 // configure its serial port (in most cases to disable local echo)
149                 cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTING;
150                 usbd_cdc_connect_tx_timer = 8; // wait for 8 SOF IRQs
151                 #if !MICROPY_HW_USB_IS_MULTI_OTG
152                 USB->CNTR |= USB_CNTR_SOFM;
153                 #else
154                 PCD_HandleTypeDef *hpcd = cdc->base.usbd->pdev->pData;
155                 hpcd->Instance->GINTMSK |= USB_OTG_GINTMSK_SOFM;
156                 #endif
157             } else {
158                 cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED;
159             }
160             break;
161         }
162 
163         case CDC_SEND_BREAK:
164             /* Add your code here */
165             break;
166 
167         default:
168             break;
169     }
170 
171     return USBD_OK;
172 }
173 
usbd_cdc_tx_buffer_mask(uint16_t val)174 static inline uint16_t usbd_cdc_tx_buffer_mask(uint16_t val) {
175     return val & (MICROPY_HW_USB_CDC_TX_DATA_SIZE - 1);
176 }
177 
usbd_cdc_tx_buffer_size(usbd_cdc_itf_t * cdc)178 static inline uint16_t usbd_cdc_tx_buffer_size(usbd_cdc_itf_t *cdc) {
179     return cdc->tx_buf_ptr_in - cdc->tx_buf_ptr_out;
180 }
181 
usbd_cdc_tx_buffer_empty(usbd_cdc_itf_t * cdc)182 static inline bool usbd_cdc_tx_buffer_empty(usbd_cdc_itf_t *cdc) {
183     return cdc->tx_buf_ptr_out == cdc->tx_buf_ptr_in;
184 }
185 
usbd_cdc_tx_buffer_will_be_empty(usbd_cdc_itf_t * cdc)186 static inline bool usbd_cdc_tx_buffer_will_be_empty(usbd_cdc_itf_t *cdc) {
187     return cdc->tx_buf_ptr_out_next == cdc->tx_buf_ptr_in;
188 }
189 
usbd_cdc_tx_buffer_full(usbd_cdc_itf_t * cdc)190 static inline bool usbd_cdc_tx_buffer_full(usbd_cdc_itf_t *cdc) {
191     return usbd_cdc_tx_buffer_size(cdc) == MICROPY_HW_USB_CDC_TX_DATA_SIZE;
192 }
193 
usbd_cdc_tx_send_length(usbd_cdc_itf_t * cdc)194 static uint16_t usbd_cdc_tx_send_length(usbd_cdc_itf_t *cdc) {
195     uint16_t to_end = MICROPY_HW_USB_CDC_TX_DATA_SIZE - usbd_cdc_tx_buffer_mask(cdc->tx_buf_ptr_out);
196     return MIN(usbd_cdc_tx_buffer_size(cdc), to_end);
197 }
198 
usbd_cdc_tx_buffer_put(usbd_cdc_itf_t * cdc,uint8_t data,bool check_overflow)199 static void usbd_cdc_tx_buffer_put(usbd_cdc_itf_t *cdc, uint8_t data, bool check_overflow) {
200     cdc->tx_buf[usbd_cdc_tx_buffer_mask(cdc->tx_buf_ptr_in)] = data;
201     cdc->tx_buf_ptr_in++;
202     if (check_overflow && usbd_cdc_tx_buffer_size(cdc) > MICROPY_HW_USB_CDC_TX_DATA_SIZE) {
203         cdc->tx_buf_ptr_out++;
204         cdc->tx_buf_ptr_out_next = cdc->tx_buf_ptr_out;
205     }
206 }
207 
usbd_cdc_tx_buffer_getp(usbd_cdc_itf_t * cdc,uint16_t len)208 static uint8_t *usbd_cdc_tx_buffer_getp(usbd_cdc_itf_t *cdc, uint16_t len) {
209     cdc->tx_buf_ptr_out_next += len;
210     return &cdc->tx_buf[usbd_cdc_tx_buffer_mask(cdc->tx_buf_ptr_out)];
211 }
212 
213 // Called when the USB IN endpoint is ready to receive more data
214 // (cdc.base.tx_in_progress must be 0)
usbd_cdc_tx_ready(usbd_cdc_state_t * cdc_in)215 void usbd_cdc_tx_ready(usbd_cdc_state_t *cdc_in) {
216 
217     usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t *)cdc_in;
218     cdc->tx_buf_ptr_out = cdc->tx_buf_ptr_out_next;
219 
220     if (usbd_cdc_tx_buffer_empty(cdc) && !cdc->tx_need_empty_packet) {
221         // No outstanding data to send
222         return;
223     }
224     uint16_t len = usbd_cdc_tx_send_length(cdc);
225     // Should always succeed because cdc.base.tx_in_progress==0
226     USBD_CDC_TransmitPacket(&cdc->base, len, usbd_cdc_tx_buffer_getp(cdc, len));
227 
228 
229     // According to the USB specification, a packet size of 64 bytes (CDC_DATA_FS_MAX_PACKET_SIZE)
230     // gets held at the USB host until the next packet is sent.  This is because a
231     // packet of maximum size is considered to be part of a longer chunk of data, and
232     // the host waits for all data to arrive (ie, waits for a packet < max packet size).
233     // To flush a packet of exactly max packet size, we need to send a zero-size packet.
234     // See eg http://www.cypress.com/?id=4&rID=92719
235     cdc->tx_need_empty_packet = (len > 0 && len % usbd_cdc_max_packet(cdc->base.usbd->pdev) == 0 && usbd_cdc_tx_buffer_will_be_empty(cdc));
236 }
237 
238 // Attempt to queue data on the USB IN endpoint
usbd_cdc_try_tx(usbd_cdc_itf_t * cdc)239 static void usbd_cdc_try_tx(usbd_cdc_itf_t *cdc) {
240     uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
241     if (cdc == NULL || cdc->connect_state == USBD_CDC_CONNECT_STATE_DISCONNECTED) {
242         // CDC device is not connected to a host, so we are unable to send any data
243     } else if (cdc->base.tx_in_progress) {
244         // USB driver will call callback when ready
245     } else {
246         usbd_cdc_tx_ready(&cdc->base);
247     }
248     restore_irq_pri(basepri);
249 }
250 
HAL_PCD_SOFCallback(PCD_HandleTypeDef * hpcd)251 void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
252     if (usbd_cdc_connect_tx_timer > 0) {
253         --usbd_cdc_connect_tx_timer;
254     } else {
255         usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef *)hpcd->pData)->pClassData;
256         #if !MICROPY_HW_USB_IS_MULTI_OTG
257         USB->CNTR &= ~USB_CNTR_SOFM;
258         #else
259         hpcd->Instance->GINTMSK &= ~USB_OTG_GINTMSK_SOFM;
260         #endif
261         for (int i = 0; i < MICROPY_HW_USB_CDC_NUM; ++i) {
262             usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t *)usbd->cdc[i];
263             if (cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTING) {
264                 cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTED;
265                 usbd_cdc_try_tx(cdc);
266             }
267         }
268     }
269 }
270 
usbd_cdc_rx_buffer_full(usbd_cdc_itf_t * cdc)271 bool usbd_cdc_rx_buffer_full(usbd_cdc_itf_t *cdc) {
272     int get = cdc->rx_buf_get, put = cdc->rx_buf_put;
273     int remaining = (get - put) + (-((int)(get <= put)) & MICROPY_HW_USB_CDC_RX_DATA_SIZE);
274     return remaining < CDC_DATA_MAX_PACKET_SIZE + 1;
275 }
276 
usbd_cdc_rx_check_resume(usbd_cdc_itf_t * cdc)277 void usbd_cdc_rx_check_resume(usbd_cdc_itf_t *cdc) {
278     uint32_t irq_state = disable_irq();
279     if (cdc->rx_buf_full) {
280         if (!usbd_cdc_rx_buffer_full(cdc)) {
281             cdc->rx_buf_full = false;
282             enable_irq(irq_state);
283             USBD_CDC_ReceivePacket(&cdc->base, cdc->rx_packet_buf);
284             return;
285         }
286     }
287     enable_irq(irq_state);
288 }
289 
290 // Data received over USB OUT endpoint is processed here.
291 // len: number of bytes received into the buffer we passed to USBD_CDC_ReceivePacket
292 // Returns USBD_OK if all operations are OK else USBD_FAIL
usbd_cdc_receive(usbd_cdc_state_t * cdc_in,size_t len)293 int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) {
294     usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t *)cdc_in;
295 
296     // copy the incoming data into the circular buffer
297     for (const uint8_t *src = cdc->rx_packet_buf, *top = cdc->rx_packet_buf + len; src < top; ++src) {
298         if (cdc->attached_to_repl && *src == mp_interrupt_char) {
299             pendsv_kbd_intr();
300         } else {
301             uint16_t next_put = (cdc->rx_buf_put + 1) & (MICROPY_HW_USB_CDC_RX_DATA_SIZE - 1);
302             if (next_put == cdc->rx_buf_get) {
303                 // overflow, we just discard the rest of the chars
304                 break;
305             }
306             cdc->rx_user_buf[cdc->rx_buf_put] = *src;
307             cdc->rx_buf_put = next_put;
308         }
309     }
310 
311     usbd_cdc_rx_event_callback(cdc);
312 
313     if ((cdc->flow & USBD_CDC_FLOWCONTROL_RTS) && (usbd_cdc_rx_buffer_full(cdc))) {
314         cdc->rx_buf_full = true;
315         return USBD_BUSY;
316     } else {
317         // initiate next USB packet transfer
318         cdc->rx_buf_full = false;
319         return USBD_CDC_ReceivePacket(&cdc->base, cdc->rx_packet_buf);
320     }
321 }
322 
usbd_cdc_tx_half_empty(usbd_cdc_itf_t * cdc)323 int usbd_cdc_tx_half_empty(usbd_cdc_itf_t *cdc) {
324     int32_t tx_waiting = usbd_cdc_tx_buffer_size(cdc);
325     return tx_waiting <= MICROPY_HW_USB_CDC_TX_DATA_SIZE / 2;
326 }
327 
328 // Writes only the data that fits if flow & CTS, else writes all data
329 // Returns number of bytes actually written to the device
usbd_cdc_tx_flow(usbd_cdc_itf_t * cdc,const uint8_t * buf,uint32_t len)330 int usbd_cdc_tx_flow(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len) {
331     if (cdc->flow & USBD_CDC_FLOWCONTROL_CTS) {
332         // Only write as much as can fit in tx buffer
333         return usbd_cdc_tx(cdc, buf, len, 0);
334     } else {
335         // Never block, keep most recent data in rolling buffer
336         usbd_cdc_tx_always(cdc, buf, len);
337         return len;
338     }
339 }
340 
341 // timout in milliseconds.
342 // Returns number of bytes written to the device.
usbd_cdc_tx(usbd_cdc_itf_t * cdc,const uint8_t * buf,uint32_t len,uint32_t timeout)343 int usbd_cdc_tx(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len, uint32_t timeout) {
344     for (uint32_t i = 0; i < len; i++) {
345         // Wait until the device is connected and the buffer has space, with a given timeout
346         uint32_t start = HAL_GetTick();
347         while (cdc->connect_state == USBD_CDC_CONNECT_STATE_DISCONNECTED || usbd_cdc_tx_buffer_full(cdc)) {
348             usbd_cdc_try_tx(cdc);
349             // Wraparound of tick is taken care of by 2's complement arithmetic.
350             if (HAL_GetTick() - start >= timeout) {
351                 // timeout
352                 return i;
353             }
354             if (query_irq() == IRQ_STATE_DISABLED) {
355                 // IRQs disabled so buffer will never be drained; return immediately
356                 return i;
357             }
358             __WFI(); // enter sleep mode, waiting for interrupt
359         }
360 
361         // Write data to device buffer
362         usbd_cdc_tx_buffer_put(cdc, buf[i], false);
363     }
364 
365     usbd_cdc_try_tx(cdc);
366 
367     // Success, return number of bytes read
368     return len;
369 }
370 
371 // Always write all of the data to the device tx buffer, even if the
372 // device is not connected, or if the buffer is full.  Has a small timeout
373 // to wait for the buffer to be drained, in the case the device is connected.
usbd_cdc_tx_always(usbd_cdc_itf_t * cdc,const uint8_t * buf,uint32_t len)374 void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len) {
375     for (int i = 0; i < len; i++) {
376         // If the CDC device is not connected to the host then we don't have anyone to receive our data.
377         // The device may become connected in the future, so we should at least try to fill the buffer
378         // and hope that it doesn't overflow by the time the device connects.
379         // If the device is not connected then we should go ahead and fill the buffer straight away,
380         // ignoring overflow.  Otherwise, we should make sure that we have enough room in the buffer.
381         if (cdc->connect_state != USBD_CDC_CONNECT_STATE_DISCONNECTED) {
382             // If the buffer is full, wait until it gets drained, with a timeout of 500ms
383             // (wraparound of tick is taken care of by 2's complement arithmetic).
384             uint32_t start = HAL_GetTick();
385             while (usbd_cdc_tx_buffer_full(cdc) && HAL_GetTick() - start <= 500) {
386                 usbd_cdc_try_tx(cdc);
387                 if (cdc->base.usbd->pdev->dev_state == USBD_STATE_SUSPENDED) {
388                     // The USB is suspended so buffer will never be drained; exit loop
389                     break;
390                 }
391                 if (query_irq() == IRQ_STATE_DISABLED) {
392                     // IRQs disabled so buffer will never be drained; exit loop
393                     break;
394                 }
395                 __WFI(); // enter sleep mode, waiting for interrupt
396             }
397         }
398 
399         usbd_cdc_tx_buffer_put(cdc, buf[i], true);
400     }
401     usbd_cdc_try_tx(cdc);
402 }
403 
404 // Returns number of bytes in the rx buffer.
usbd_cdc_rx_num(usbd_cdc_itf_t * cdc)405 int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc) {
406     int32_t rx_waiting = (int32_t)cdc->rx_buf_put - (int32_t)cdc->rx_buf_get;
407     if (rx_waiting < 0) {
408         rx_waiting += MICROPY_HW_USB_CDC_RX_DATA_SIZE;
409     }
410     usbd_cdc_rx_check_resume(cdc);
411     return rx_waiting;
412 }
413 
414 // timout in milliseconds.
415 // Returns number of bytes read from the device.
usbd_cdc_rx(usbd_cdc_itf_t * cdc,uint8_t * buf,uint32_t len,uint32_t timeout)416 int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeout) {
417     // loop to read bytes
418     for (uint32_t i = 0; i < len; i++) {
419         // Wait until we have at least 1 byte to read
420         uint32_t start = HAL_GetTick();
421         while (cdc->rx_buf_put == cdc->rx_buf_get) {
422             // Wraparound of tick is taken care of by 2's complement arithmetic.
423             if (HAL_GetTick() - start >= timeout) {
424                 // timeout
425                 return i;
426             }
427             if (query_irq() == IRQ_STATE_DISABLED) {
428                 // IRQs disabled so buffer will never be filled; return immediately
429                 return i;
430             }
431             usbd_cdc_rx_check_resume(cdc);
432             __WFI(); // enter sleep mode, waiting for interrupt
433         }
434 
435         // Copy byte from device to user buffer
436         buf[i] = cdc->rx_user_buf[cdc->rx_buf_get];
437         cdc->rx_buf_get = (cdc->rx_buf_get + 1) & (MICROPY_HW_USB_CDC_RX_DATA_SIZE - 1);
438     }
439     usbd_cdc_rx_check_resume(cdc);
440 
441     // Success, return number of bytes read
442     return len;
443 }
444 
445 #endif
446