2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
25 #include "build/build_config.h"
27 #include "common/utils.h"
28 #include "drivers/io.h"
32 #include "usbd_cdc_vcp.h"
34 #elif defined(STM32F7) || defined(STM32H7)
35 #include "vcp_hal/usbd_cdc_interface.h"
37 USBD_HandleTypeDef USBD_Device
;
41 #include "hw_config.h"
44 #include "drivers/time.h"
47 #include "serial_usb_vcp.h"
50 #define USB_TIMEOUT 50
52 static vcpPort_t vcpPort
;
54 static void usbVcpSetBaudRate(serialPort_t
*instance
, uint32_t baudRate
)
62 static void usbVcpSetMode(serialPort_t
*instance
, portMode_t mode
)
70 static bool isUsbVcpTransmitBufferEmpty(const serialPort_t
*instance
)
76 static uint32_t usbVcpAvailable(const serialPort_t
*instance
)
80 return CDC_Receive_BytesAvailable();
83 static uint8_t usbVcpRead(serialPort_t
*instance
)
90 if (CDC_Receive_DATA(buf
, 1))
95 static bool usbVcpIsConnected(const serialPort_t
*instance
)
98 return usbIsConnected() && usbIsConfigured();
101 static void usbVcpWriteBuf(serialPort_t
*instance
, const void *data
, int count
)
105 if (!usbVcpIsConnected(instance
)) {
109 uint32_t start
= millis();
110 const uint8_t *p
= data
;
112 uint32_t txed
= CDC_Send_DATA(p
, count
);
116 if (millis() - start
> USB_TIMEOUT
) {
122 static bool usbVcpFlush(vcpPort_t
*port
)
124 uint32_t count
= port
->txAt
;
131 if (!usbIsConnected() || !usbIsConfigured()) {
135 uint32_t start
= millis();
136 uint8_t *p
= port
->txBuf
;
138 uint32_t txed
= CDC_Send_DATA(p
, count
);
142 if (millis() - start
> USB_TIMEOUT
) {
149 static void usbVcpWrite(serialPort_t
*instance
, uint8_t c
)
151 vcpPort_t
*port
= container_of(instance
, vcpPort_t
, port
);
153 port
->txBuf
[port
->txAt
++] = c
;
154 if (!port
->buffering
|| port
->txAt
>= ARRAYLEN(port
->txBuf
)) {
159 static void usbVcpBeginWrite(serialPort_t
*instance
)
161 vcpPort_t
*port
= container_of(instance
, vcpPort_t
, port
);
162 port
->buffering
= true;
165 static uint32_t usbTxBytesFree(const serialPort_t
*instance
)
168 return CDC_Send_FreeBytes();
171 static void usbVcpEndWrite(serialPort_t
*instance
)
173 vcpPort_t
*port
= container_of(instance
, vcpPort_t
, port
);
174 port
->buffering
= false;
178 static const struct serialPortVTable usbVTable
[] = {
180 .serialWrite
= usbVcpWrite
,
181 .serialTotalRxWaiting
= usbVcpAvailable
,
182 .serialTotalTxFree
= usbTxBytesFree
,
183 .serialRead
= usbVcpRead
,
184 .serialSetBaudRate
= usbVcpSetBaudRate
,
185 .isSerialTransmitBufferEmpty
= isUsbVcpTransmitBufferEmpty
,
186 .setMode
= usbVcpSetMode
,
187 .isConnected
= usbVcpIsConnected
,
188 .writeBuf
= usbVcpWriteBuf
,
189 .beginWrite
= usbVcpBeginWrite
,
190 .endWrite
= usbVcpEndWrite
,
195 void usbVcpInitHardware(void)
198 usbGenerateDisconnectPulse();
200 IOInit(IOGetByTag(IO_TAG(PA11
)), OWNER_USB
, RESOURCE_INPUT
, 0);
201 IOInit(IOGetByTag(IO_TAG(PA12
)), OWNER_USB
, RESOURCE_OUTPUT
, 0);
202 USBD_Init(&USB_OTG_dev
, USB_OTG_FS_CORE_ID
, &USR_desc
, &USBD_CDC_cb
, &USR_cb
);
203 #elif defined(STM32F7) || defined(STM32H7)
204 usbGenerateDisconnectPulse();
206 IOInit(IOGetByTag(IO_TAG(PA11
)), OWNER_USB
, RESOURCE_INPUT
, 0);
207 IOInit(IOGetByTag(IO_TAG(PA12
)), OWNER_USB
, RESOURCE_OUTPUT
, 0);
208 /* Init Device Library */
209 USBD_Init(&USBD_Device
, &VCP_Desc
, 0);
211 /* Add Supported Class */
212 USBD_RegisterClass(&USBD_Device
, USBD_CDC_CLASS
);
214 /* Add CDC Interface Class */
215 USBD_CDC_RegisterInterface(&USBD_Device
, &USBD_CDC_fops
);
217 /* Start Device Process */
218 USBD_Start(&USBD_Device
);
221 HAL_PWREx_EnableUSBVoltageDetector();
222 delay(100); // Cold boot failures observed without this, even when USB cable is not connected
228 USB_Interrupts_Config();
233 serialPort_t
*usbVcpOpen(void)
238 s
->port
.vTable
= usbVTable
;
240 return (serialPort_t
*)s
;
243 uint32_t usbVcpGetBaudRate(serialPort_t
*instance
)
247 return CDC_BaudRate();