Merge pull request #10592 from iNavFlight/MrD_Update-parameter-description
[inav.git] / src / main / drivers / serial_usb_vcp.c
blob7fdbad2a114d3094a2f91d3081c7a26b617ab88c
1 /*
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/>.
18 #include <stdint.h>
19 #include <stdbool.h>
21 #include "platform.h"
23 #ifdef USE_VCP
25 #include "build/build_config.h"
27 #include "common/utils.h"
28 #include "drivers/io.h"
30 #if defined(STM32F4)
31 #include "usb_core.h"
32 #include "usbd_cdc_vcp.h"
33 #include "usb_io.h"
34 #elif defined(STM32F7) || defined(STM32H7)
35 #include "vcp_hal/usbd_cdc_interface.h"
36 #include "usb_io.h"
37 USBD_HandleTypeDef USBD_Device;
38 #else
39 #include "usb_core.h"
40 #include "usb_init.h"
41 #include "hw_config.h"
42 #endif
44 #include "drivers/time.h"
46 #include "serial.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)
56 UNUSED(instance);
57 UNUSED(baudRate);
59 // TODO implement
62 static void usbVcpSetMode(serialPort_t *instance, portMode_t mode)
64 UNUSED(instance);
65 UNUSED(mode);
67 // TODO implement
70 static void usbVcpSetOptions(serialPort_t *instance, portOptions_t options)
72 UNUSED(instance);
73 UNUSED(options);
75 // TODO implement
78 static bool isUsbVcpTransmitBufferEmpty(const serialPort_t *instance)
80 UNUSED(instance);
81 return true;
84 static uint32_t usbVcpAvailable(const serialPort_t *instance)
86 UNUSED(instance);
88 return CDC_Receive_BytesAvailable();
91 static uint8_t usbVcpRead(serialPort_t *instance)
93 UNUSED(instance);
95 uint8_t buf[1];
97 while (true) {
98 if (CDC_Receive_DATA(buf, 1))
99 return buf[0];
103 static bool usbVcpIsConnected(const serialPort_t *instance)
105 (void)instance;
106 return usbIsConnected() && usbIsConfigured();
109 static void usbVcpWriteBuf(serialPort_t *instance, const void *data, int count)
111 UNUSED(instance);
113 if (!usbVcpIsConnected(instance)) {
114 return;
117 uint32_t start = millis();
118 const uint8_t *p = data;
119 while (count > 0) {
120 uint32_t txed = CDC_Send_DATA(p, count);
121 count -= txed;
122 p += txed;
124 if (millis() - start > USB_TIMEOUT) {
125 break;
130 static bool usbVcpFlush(vcpPort_t *port)
132 uint32_t count = port->txAt;
133 port->txAt = 0;
135 if (count == 0) {
136 return true;
139 if (!usbIsConnected() || !usbIsConfigured()) {
140 return false;
143 uint32_t start = millis();
144 uint8_t *p = port->txBuf;
145 while (count > 0) {
146 uint32_t txed = CDC_Send_DATA(p, count);
147 count -= txed;
148 p += txed;
150 if (millis() - start > USB_TIMEOUT) {
151 break;
154 return count == 0;
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)) {
163 usbVcpFlush(port);
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)
175 UNUSED(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;
183 usbVcpFlush(port);
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,
200 .isIdle = NULL,
204 void usbVcpInitHardware(void)
206 #if defined(STM32F4)
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);
229 #ifdef STM32H7
230 HAL_PWREx_EnableUSBVoltageDetector();
231 delay(100); // Cold boot failures observed without this, even when USB cable is not connected
232 #endif
234 #else
235 Set_System();
236 Set_USBClock();
237 USB_Interrupts_Config();
238 USB_Init();
239 #endif
242 serialPort_t *usbVcpOpen(void)
244 vcpPort_t *s;
246 s = &vcpPort;
247 s->port.vTable = usbVTable;
249 return (serialPort_t *)s;
252 uint32_t usbVcpGetBaudRate(serialPort_t *instance)
254 UNUSED(instance);
256 return CDC_BaudRate();
259 #endif