mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-26 17:55:30 +03:00
PICO: Adding VCP (CDC) support (#14106)
* PICO VCP * Beginning to work through tinyUSB * PICO: Additional VCP changes * Updates based on feedback from @ledvinap
This commit is contained in:
parent
0109f50909
commit
a7032d15f5
8 changed files with 796 additions and 24 deletions
208
src/platform/PICO/serial_usb_vcp_pico.c
Normal file
208
src/platform/PICO/serial_usb_vcp_pico.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* This file is part of Betaflight.
|
||||
*
|
||||
* Betaflight is free software. You can redistribute this software
|
||||
* and/or modify this software 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.
|
||||
*
|
||||
* Betaflight 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 this software.
|
||||
*
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef USE_VCP
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#include "common/utils.h"
|
||||
|
||||
#include "drivers/io.h"
|
||||
|
||||
#include "pg/usb.h"
|
||||
|
||||
#include "usb/usb_cdc.h"
|
||||
|
||||
#include "drivers/time.h"
|
||||
#include "drivers/serial.h"
|
||||
#include "drivers/serial_usb_vcp.h"
|
||||
|
||||
static vcpPort_t vcpPort = { 0 };
|
||||
|
||||
static void usbVcpSetBaudRate(serialPort_t *instance, uint32_t baudRate)
|
||||
{
|
||||
UNUSED(instance);
|
||||
UNUSED(baudRate);
|
||||
}
|
||||
|
||||
static void usbVcpSetMode(serialPort_t *instance, portMode_e mode)
|
||||
{
|
||||
UNUSED(instance);
|
||||
UNUSED(mode);
|
||||
}
|
||||
|
||||
static void usbVcpSetCtrlLineStateCb(serialPort_t *instance, void (*cb)(void *context, uint16_t ctrlLineState), void *context)
|
||||
{
|
||||
UNUSED(instance);
|
||||
UNUSED(cb);
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
static void usbVcpSetBaudRateCb(serialPort_t *instance, void (*cb)(serialPort_t *context, uint32_t baud), serialPort_t *context)
|
||||
{
|
||||
UNUSED(instance);
|
||||
UNUSED(cb);
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
static bool isUsbVcpTransmitBufferEmpty(const serialPort_t *instance)
|
||||
{
|
||||
UNUSED(instance);
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t usbVcpRxBytesAvailable(const serialPort_t *instance)
|
||||
{
|
||||
UNUSED(instance);
|
||||
return cdc_usb_bytes_available();
|
||||
}
|
||||
|
||||
static uint8_t usbVcpRead(serialPort_t *instance)
|
||||
{
|
||||
UNUSED(instance);
|
||||
|
||||
uint8_t buf[1];
|
||||
|
||||
while (true) {
|
||||
if (cdc_usb_read(buf, 1)) {
|
||||
return buf[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usbVcpWriteBuf(serialPort_t *instance, const void *data, int count)
|
||||
{
|
||||
UNUSED(instance);
|
||||
|
||||
if (!(cdc_usb_connected() && cdc_usb_configured())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *p = data;
|
||||
while (count > 0) {
|
||||
int txed = cdc_usb_write(p, count);
|
||||
|
||||
if (txed <= 0) {
|
||||
break;
|
||||
}
|
||||
count -= txed;
|
||||
p += txed;
|
||||
}
|
||||
}
|
||||
|
||||
static bool usbVcpFlush(vcpPort_t *port)
|
||||
{
|
||||
uint32_t count = port->txAt;
|
||||
port->txAt = 0;
|
||||
|
||||
if (count == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!cdc_usb_connected() || !cdc_usb_configured()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t *p = port->txBuf;
|
||||
while (count > 0) {
|
||||
int txed = cdc_usb_write(p, count);
|
||||
|
||||
if (txed <= 0) {
|
||||
break;
|
||||
}
|
||||
count -= txed;
|
||||
p += txed;
|
||||
}
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static uint32_t usbTxBytesFree(const serialPort_t *instance)
|
||||
{
|
||||
UNUSED(instance);
|
||||
return cdc_usb_tx_bytes_free();
|
||||
}
|
||||
|
||||
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 = usbVcpRxBytesAvailable,
|
||||
.serialTotalTxFree = usbTxBytesFree,
|
||||
.serialRead = usbVcpRead,
|
||||
.serialSetBaudRate = usbVcpSetBaudRate,
|
||||
.isSerialTransmitBufferEmpty = isUsbVcpTransmitBufferEmpty,
|
||||
.setMode = usbVcpSetMode,
|
||||
.setCtrlLineStateCb = usbVcpSetCtrlLineStateCb,
|
||||
.setBaudRateCb = usbVcpSetBaudRateCb,
|
||||
.writeBuf = usbVcpWriteBuf,
|
||||
.beginWrite = usbVcpBeginWrite,
|
||||
.endWrite = usbVcpEndWrite
|
||||
}
|
||||
};
|
||||
|
||||
serialPort_t *usbVcpOpen(void)
|
||||
{
|
||||
cdc_usb_init();
|
||||
|
||||
vcpPort_t *s = &vcpPort;
|
||||
s->port.vTable = usbVTable;
|
||||
return &s->port;
|
||||
}
|
||||
|
||||
uint32_t usbVcpGetBaudRate(serialPort_t *instance)
|
||||
{
|
||||
UNUSED(instance);
|
||||
return cdc_usb_baud_rate();
|
||||
}
|
||||
|
||||
uint8_t usbVcpIsConnected(void)
|
||||
{
|
||||
return cdc_usb_connected();
|
||||
}
|
||||
|
||||
#endif // USE_VCP
|
Loading…
Add table
Add a link
Reference in a new issue