mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-24 16:55:36 +03:00
205 lines
4.4 KiB
C
205 lines
4.4 KiB
C
/*
|
|
* This file is part of Cleanflight.
|
|
*
|
|
* Cleanflight is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Cleanflight is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#include "platform.h"
|
|
|
|
#include "build_config.h"
|
|
#include "common/utils.h"
|
|
#include "drivers/io.h"
|
|
|
|
#include "usb_core.h"
|
|
#ifdef STM32F4
|
|
#include "usbd_cdc_vcp.h"
|
|
#else
|
|
#include "usb_init.h"
|
|
#include "hw_config.h"
|
|
#endif
|
|
|
|
#include "drivers/system.h"
|
|
|
|
#include "serial.h"
|
|
#include "serial_usb_vcp.h"
|
|
|
|
|
|
#define USB_TIMEOUT 50
|
|
|
|
static vcpPort_t vcpPort;
|
|
|
|
static void usbVcpSetBaudRate(serialPort_t *instance, uint32_t baudRate)
|
|
{
|
|
UNUSED(instance);
|
|
UNUSED(baudRate);
|
|
|
|
// TODO implement
|
|
}
|
|
|
|
static void usbVcpSetMode(serialPort_t *instance, portMode_t mode)
|
|
{
|
|
UNUSED(instance);
|
|
UNUSED(mode);
|
|
|
|
// TODO implement
|
|
}
|
|
|
|
static bool isUsbVcpTransmitBufferEmpty(serialPort_t *instance)
|
|
{
|
|
UNUSED(instance);
|
|
return true;
|
|
}
|
|
|
|
static uint32_t usbVcpAvailable(serialPort_t *instance)
|
|
{
|
|
UNUSED(instance);
|
|
|
|
return receiveLength;
|
|
}
|
|
|
|
static uint8_t usbVcpRead(serialPort_t *instance)
|
|
{
|
|
UNUSED(instance);
|
|
|
|
uint8_t buf[1];
|
|
|
|
uint32_t rxed = 0;
|
|
|
|
while (rxed < 1) {
|
|
rxed += CDC_Receive_DATA((uint8_t*)buf + rxed, 1 - rxed);
|
|
}
|
|
|
|
return buf[0];
|
|
}
|
|
|
|
static void usbVcpWriteBuf(serialPort_t *instance, void *data, int count)
|
|
{
|
|
UNUSED(instance);
|
|
|
|
|
|
if (!(usbIsConnected() && usbIsConfigured())) {
|
|
return;
|
|
}
|
|
|
|
uint32_t start = millis();
|
|
for (uint8_t *p = data; count > 0; ) {
|
|
uint32_t txed = CDC_Send_DATA(p, count);
|
|
count -= txed;
|
|
p += txed;
|
|
|
|
if (millis() - start > USB_TIMEOUT) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool usbVcpFlush(vcpPort_t *port)
|
|
{
|
|
uint8_t count = port->txAt;
|
|
port->txAt = 0;
|
|
|
|
if (count == 0) {
|
|
return true;
|
|
}
|
|
|
|
if (!usbIsConnected() || !usbIsConfigured()) {
|
|
return false;
|
|
}
|
|
|
|
uint32_t txed;
|
|
uint32_t start = millis();
|
|
|
|
do {
|
|
txed = CDC_Send_DATA(port->txBuf, count);
|
|
} while (txed != count && (millis() - start < USB_TIMEOUT));
|
|
|
|
return txed == count;
|
|
}
|
|
|
|
static void usbVcpWrite(serialPort_t *instance, uint8_t c)
|
|
{
|
|
vcpPort_t *port = container_of(instance, vcpPort_t, port);
|
|
|
|
port->txBuf[port->txAt++] = c;
|
|
if (!port->buffering || port->txAt >= ARRAYLEN(port->txBuf)) {
|
|
usbVcpFlush(port);
|
|
}
|
|
}
|
|
|
|
static void usbVcpBeginWrite(serialPort_t *instance)
|
|
{
|
|
vcpPort_t *port = container_of(instance, vcpPort_t, port);
|
|
port->buffering = true;
|
|
}
|
|
|
|
uint8_t usbTxBytesFree()
|
|
{
|
|
// Because we block upon transmit and don't buffer bytes, our "buffer" capacity is effectively unlimited.
|
|
return 255;
|
|
}
|
|
|
|
static void usbVcpEndWrite(serialPort_t *instance)
|
|
{
|
|
vcpPort_t *port = container_of(instance, vcpPort_t, port);
|
|
port->buffering = false;
|
|
usbVcpFlush(port);
|
|
}
|
|
|
|
static const struct serialPortVTable usbVTable[] = {
|
|
{
|
|
.serialWrite = usbVcpWrite,
|
|
.serialTotalRxWaiting = usbVcpAvailable,
|
|
.serialTotalTxFree = usbTxBytesFree,
|
|
.serialRead = usbVcpRead,
|
|
.serialSetBaudRate = usbVcpSetBaudRate,
|
|
.isSerialTransmitBufferEmpty = isUsbVcpTransmitBufferEmpty,
|
|
.setMode = usbVcpSetMode,
|
|
.beginWrite = usbVcpBeginWrite,
|
|
.endWrite = usbVcpEndWrite,
|
|
.writeBuf = usbVcpWriteBuf
|
|
}
|
|
};
|
|
|
|
serialPort_t *usbVcpOpen(void)
|
|
{
|
|
vcpPort_t *s;
|
|
|
|
#ifdef STM32F4
|
|
IOInit(IOGetByTag(IO_TAG(PA11)), OWNER_USB, RESOURCE_IO);
|
|
IOInit(IOGetByTag(IO_TAG(PA12)), OWNER_USB, RESOURCE_IO);
|
|
USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_CDC_cb, &USR_cb);
|
|
#else
|
|
Set_System();
|
|
Set_USBClock();
|
|
USB_Interrupts_Config();
|
|
USB_Init();
|
|
#endif
|
|
|
|
s = &vcpPort;
|
|
s->port.vTable = usbVTable;
|
|
|
|
return (serialPort_t *)s;
|
|
}
|
|
|
|
uint32_t usbVcpGetBaudRate(serialPort_t *instance)
|
|
{
|
|
UNUSED(instance);
|
|
|
|
return CDC_BaudRate();
|
|
}
|