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 void usbVcpSetOptions(serialPort_t
*instance
, portOptions_t options
)
78 static bool isUsbVcpTransmitBufferEmpty(const serialPort_t
*instance
)
84 static uint32_t usbVcpAvailable(const serialPort_t
*instance
)
88 return CDC_Receive_BytesAvailable();
91 static uint8_t usbVcpRead(serialPort_t
*instance
)
98 if (CDC_Receive_DATA(buf
, 1))
103 static bool usbVcpIsConnected(const serialPort_t
*instance
)
106 return usbIsConnected() && usbIsConfigured();
109 static void usbVcpWriteBuf(serialPort_t
*instance
, const void *data
, int count
)
113 if (!usbVcpIsConnected(instance
)) {
117 uint32_t start
= millis();
118 const uint8_t *p
= data
;
120 uint32_t txed
= CDC_Send_DATA(p
, count
);
124 if (millis() - start
> USB_TIMEOUT
) {
130 static bool usbVcpFlush(vcpPort_t
*port
)
132 uint32_t count
= port
->txAt
;
139 if (!usbIsConnected() || !usbIsConfigured()) {
143 uint32_t start
= millis();
144 uint8_t *p
= port
->txBuf
;
146 uint32_t txed
= CDC_Send_DATA(p
, count
);
150 if (millis() - start
> USB_TIMEOUT
) {
157 static void usbVcpWrite(serialPort_t
*instance
, uint8_t c
)
159 vcpPort_t
*port
= container_of(instance
, vcpPort_t
, port
);
161 port
->txBuf
[port
->txAt
++] = c
;
162 if (!port
->buffering
|| port
->txAt
>= ARRAYLEN(port
->txBuf
)) {
167 static void usbVcpBeginWrite(serialPort_t
*instance
)
169 vcpPort_t
*port
= container_of(instance
, vcpPort_t
, port
);
170 port
->buffering
= true;
173 static uint32_t usbTxBytesFree(const serialPort_t
*instance
)
176 return CDC_Send_FreeBytes();
179 static void usbVcpEndWrite(serialPort_t
*instance
)
181 vcpPort_t
*port
= container_of(instance
, vcpPort_t
, port
);
182 port
->buffering
= false;
186 static const struct serialPortVTable usbVTable
[] = {
188 .serialWrite
= usbVcpWrite
,
189 .serialTotalRxWaiting
= usbVcpAvailable
,
190 .serialTotalTxFree
= usbTxBytesFree
,
191 .serialRead
= usbVcpRead
,
192 .serialSetBaudRate
= usbVcpSetBaudRate
,
193 .isSerialTransmitBufferEmpty
= isUsbVcpTransmitBufferEmpty
,
194 .setMode
= usbVcpSetMode
,
195 .setOptions
= usbVcpSetOptions
,
196 .isConnected
= usbVcpIsConnected
,
197 .writeBuf
= usbVcpWriteBuf
,
198 .beginWrite
= usbVcpBeginWrite
,
199 .endWrite
= usbVcpEndWrite
,
204 void usbVcpInitHardware(void)
207 usbGenerateDisconnectPulse();
209 IOInit(IOGetByTag(IO_TAG(PA11
)), OWNER_USB
, RESOURCE_INPUT
, 0);
210 IOInit(IOGetByTag(IO_TAG(PA12
)), OWNER_USB
, RESOURCE_OUTPUT
, 0);
211 USBD_Init(&USB_OTG_dev
, USB_OTG_FS_CORE_ID
, &USR_desc
, &USBD_CDC_cb
, &USR_cb
);
212 #elif defined(STM32F7) || defined(STM32H7)
213 usbGenerateDisconnectPulse();
215 IOInit(IOGetByTag(IO_TAG(PA11
)), OWNER_USB
, RESOURCE_INPUT
, 0);
216 IOInit(IOGetByTag(IO_TAG(PA12
)), OWNER_USB
, RESOURCE_OUTPUT
, 0);
217 /* Init Device Library */
218 USBD_Init(&USBD_Device
, &VCP_Desc
, 0);
220 /* Add Supported Class */
221 USBD_RegisterClass(&USBD_Device
, USBD_CDC_CLASS
);
223 /* Add CDC Interface Class */
224 USBD_CDC_RegisterInterface(&USBD_Device
, &USBD_CDC_fops
);
226 /* Start Device Process */
227 USBD_Start(&USBD_Device
);
230 HAL_PWREx_EnableUSBVoltageDetector();
231 delay(100); // Cold boot failures observed without this, even when USB cable is not connected
237 USB_Interrupts_Config();
242 serialPort_t
*usbVcpOpen(void)
247 s
->port
.vTable
= usbVTable
;
249 return (serialPort_t
*)s
;
252 uint32_t usbVcpGetBaudRate(serialPort_t
*instance
)
256 return CDC_BaudRate();