diff --git a/src/main/drivers/serial.c b/src/main/drivers/serial.c
index a7f464f40..cacfd1dd4 100644
--- a/src/main/drivers/serial.c
+++ b/src/main/drivers/serial.c
@@ -85,3 +85,15 @@ void serialWriteBufShim(void *instance, void *data, int count)
{
serialWriteBuf((serialPort_t *)instance, data, count);
}
+
+void serialBeginWrite(serialPort_t *instance)
+{
+ if (instance->vTable->beginWrite)
+ instance->vTable->beginWrite(instance);
+}
+
+void serialEndWrite(serialPort_t *instance)
+{
+ if (instance->vTable->endWrite)
+ instance->vTable->endWrite(instance);
+}
diff --git a/src/main/drivers/serial.h b/src/main/drivers/serial.h
index 4ef3d0483..773aaa74a 100644
--- a/src/main/drivers/serial.h
+++ b/src/main/drivers/serial.h
@@ -75,6 +75,9 @@ struct serialPortVTable {
void (*setMode)(serialPort_t *instance, portMode_t mode);
void (*writeBuf)(serialPort_t *instance, void *data, int count);
+ // Optional functions used to buffer large writes.
+ void (*beginWrite)(serialPort_t *instance);
+ void (*endWrite)(serialPort_t *instance);
};
void serialWrite(serialPort_t *instance, uint8_t ch);
@@ -90,3 +93,5 @@ uint32_t serialGetBaudRate(serialPort_t *instance);
// A shim that adapts the bufWriter API to the serialWriteBuf() API.
void serialWriteBufShim(void *instance, void *data, int count);
+void serialBeginWrite(serialPort_t *instance);
+void serialEndWrite(serialPort_t *instance);
diff --git a/src/main/drivers/serial_uart.c b/src/main/drivers/serial_uart.c
index 486271a83..b524f70f7 100644
--- a/src/main/drivers/serial_uart.c
+++ b/src/main/drivers/serial_uart.c
@@ -323,5 +323,7 @@ const struct serialPortVTable uartVTable[] = {
isUartTransmitBufferEmpty,
uartSetMode,
.writeBuf = NULL,
+ .beginWrite = NULL,
+ .endWrite = NULL,
}
};
diff --git a/src/main/drivers/serial_usb_vcp.c b/src/main/drivers/serial_usb_vcp.c
index 29f689074..ed1e50de1 100644
--- a/src/main/drivers/serial_usb_vcp.c
+++ b/src/main/drivers/serial_usb_vcp.c
@@ -23,6 +23,7 @@
#include "platform.h"
#include "build_config.h"
+#include "common/utils.h"
#include "usb_core.h"
#include "usb_init.h"
@@ -103,9 +104,42 @@ static void usbVcpWriteBuf(serialPort_t *instance, void *data, int count)
}
}
+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)
{
- usbVcpWriteBuf(instance, &c, sizeof(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() {
@@ -113,7 +147,27 @@ uint8_t usbTxBytesFree() {
return 255;
}
-const struct serialPortVTable usbVTable[] = { { usbVcpWrite, usbVcpAvailable, usbTxBytesFree, usbVcpRead, usbVcpSetBaudRate, isUsbVcpTransmitBufferEmpty, usbVcpSetMode, .writeBuf = usbVcpWriteBuf } };
+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)
{
diff --git a/src/main/drivers/serial_usb_vcp.h b/src/main/drivers/serial_usb_vcp.h
index 94081586d..068073c2f 100644
--- a/src/main/drivers/serial_usb_vcp.h
+++ b/src/main/drivers/serial_usb_vcp.h
@@ -21,6 +21,12 @@
typedef struct {
serialPort_t port;
+
+ // Buffer used during bulk writes.
+ uint8_t txBuf[20];
+ uint8_t txAt;
+ // Set if the port is in bulk write mode and can buffer.
+ bool buffering;
} vcpPort_t;
serialPort_t *usbVcpOpen(void);
diff --git a/src/main/io/serial_cli.c b/src/main/io/serial_cli.c
deleted file mode 100644
index 424979e67..000000000
--- a/src/main/io/serial_cli.c
+++ /dev/null
@@ -1,2496 +0,0 @@
-/*
- * 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 .
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "platform.h"
-#include "scheduler.h"
-#include "version.h"
-
-#include "build_config.h"
-
-#include "common/axis.h"
-#include "common/maths.h"
-#include "common/color.h"
-#include "common/typeconversion.h"
-
-#include "drivers/system.h"
-
-#include "drivers/sensor.h"
-#include "drivers/accgyro.h"
-#include "drivers/compass.h"
-
-#include "drivers/serial.h"
-#include "drivers/bus_i2c.h"
-#include "drivers/gpio.h"
-#include "drivers/timer.h"
-#include "drivers/pwm_rx.h"
-
-
-#include "io/escservo.h"
-#include "io/gps.h"
-#include "io/gimbal.h"
-#include "io/rc_controls.h"
-#include "io/serial.h"
-#include "io/ledstrip.h"
-#include "io/flashfs.h"
-#include "io/beeper.h"
-
-#include "rx/rx.h"
-#include "rx/spektrum.h"
-
-#include "sensors/battery.h"
-#include "sensors/boardalignment.h"
-#include "sensors/sensors.h"
-#include "sensors/acceleration.h"
-#include "sensors/gyro.h"
-#include "sensors/compass.h"
-#include "sensors/barometer.h"
-
-#include "flight/pid.h"
-#include "flight/imu.h"
-#include "flight/mixer.h"
-#include "flight/navigation.h"
-#include "flight/failsafe.h"
-
-#include "telemetry/telemetry.h"
-#include "telemetry/frsky.h"
-
-#include "config/runtime_config.h"
-#include "config/config.h"
-#include "config/config_profile.h"
-#include "config/config_master.h"
-
-#include "common/printf.h"
-
-#include "serial_cli.h"
-
-// FIXME remove this for targets that don't need a CLI. Perhaps use a no-op macro when USE_CLI is not enabled
-// signal that we're in cli mode
-uint8_t cliMode = 0;
-
-#ifdef USE_CLI
-
-extern uint16_t cycleTime; // FIXME dependency on mw.c
-
-void gpsEnablePassthrough(serialPort_t *gpsPassthroughPort);
-
-static serialPort_t *cliPort;
-
-static void cliAux(char *cmdline);
-static void cliRxFail(char *cmdline);
-static void cliAdjustmentRange(char *cmdline);
-static void cliMotorMix(char *cmdline);
-static void cliDefaults(char *cmdline);
-static void cliDump(char *cmdLine);
-static void cliExit(char *cmdline);
-static void cliFeature(char *cmdline);
-static void cliMotor(char *cmdline);
-static void cliPlaySound(char *cmdline);
-static void cliProfile(char *cmdline);
-static void cliRateProfile(char *cmdline);
-static void cliReboot(void);
-static void cliSave(char *cmdline);
-static void cliSerial(char *cmdline);
-
-#ifdef USE_SERVOS
-static void cliServo(char *cmdline);
-static void cliServoMix(char *cmdline);
-#endif
-
-static void cliSet(char *cmdline);
-static void cliGet(char *cmdline);
-static void cliStatus(char *cmdline);
-#ifndef SKIP_TASK_STATISTICS
-static void cliTasks(char *cmdline);
-#endif
-static void cliVersion(char *cmdline);
-static void cliRxRange(char *cmdline);
-
-#ifdef GPS
-static void cliGpsPassthrough(char *cmdline);
-#endif
-
-static void cliHelp(char *cmdline);
-static void cliMap(char *cmdline);
-
-#ifdef LED_STRIP
-static void cliLed(char *cmdline);
-static void cliColor(char *cmdline);
-#endif
-
-#ifndef USE_QUAD_MIXER_ONLY
-static void cliMixer(char *cmdline);
-#endif
-
-#ifdef USE_FLASHFS
-static void cliFlashInfo(char *cmdline);
-static void cliFlashErase(char *cmdline);
-#ifdef USE_FLASH_TOOLS
-static void cliFlashWrite(char *cmdline);
-static void cliFlashRead(char *cmdline);
-#endif
-#endif
-
-// buffer
-static char cliBuffer[48];
-static uint32_t bufferIndex = 0;
-
-#ifndef USE_QUAD_MIXER_ONLY
-// sync this with mixerMode_e
-static const char * const mixerNames[] = {
- "TRI", "QUADP", "QUADX", "BI",
- "GIMBAL", "Y6", "HEX6",
- "FLYING_WING", "Y4", "HEX6X", "OCTOX8", "OCTOFLATP", "OCTOFLATX",
- "AIRPLANE", "HELI_120_CCPM", "HELI_90_DEG", "VTAIL4",
- "HEX6H", "PPM_TO_SERVO", "DUALCOPTER", "SINGLECOPTER",
- "ATAIL4", "CUSTOM", "CUSTOMAIRPLANE", "CUSTOMTRI", "QUADX1234", NULL
-};
-#endif
-
-// sync this with features_e
-static const char * const featureNames[] = {
- "RX_PPM", "VBAT", "INFLIGHT_ACC_CAL", "RX_SERIAL", "MOTOR_STOP",
- "SERVO_TILT", "SOFTSERIAL", "GPS", "FAILSAFE",
- "SONAR", "TELEMETRY", "CURRENT_METER", "3D", "RX_PARALLEL_PWM",
- "RX_MSP", "RSSI_ADC", "LED_STRIP", "DISPLAY", "ONESHOT125",
- "BLACKBOX", "CHANNEL_FORWARDING", NULL
-};
-
-// sync this with rxFailsafeChannelMode_e
-static const char rxFailsafeModeCharacters[] = "ahs";
-
-static const rxFailsafeChannelMode_e rxFailsafeModesTable[RX_FAILSAFE_TYPE_COUNT][RX_FAILSAFE_MODE_COUNT] = {
- { RX_FAILSAFE_MODE_AUTO, RX_FAILSAFE_MODE_HOLD, RX_FAILSAFE_MODE_INVALID },
- { RX_FAILSAFE_MODE_INVALID, RX_FAILSAFE_MODE_HOLD, RX_FAILSAFE_MODE_SET }
-};
-
-#ifndef CJMCU
-// sync this with sensors_e
-static const char * const sensorTypeNames[] = {
- "GYRO", "ACC", "BARO", "MAG", "SONAR", "GPS", "GPS+MAG", NULL
-};
-
-#define SENSOR_NAMES_MASK (SENSOR_GYRO | SENSOR_ACC | SENSOR_BARO | SENSOR_MAG)
-
-static const char * const sensorHardwareNames[4][11] = {
- { "", "None", "MPU6050", "L3G4200D", "MPU3050", "L3GD20", "MPU6000", "MPU6500", "FAKE", NULL },
- { "", "None", "ADXL345", "MPU6050", "MMA845x", "BMA280", "LSM303DLHC", "MPU6000", "MPU6500", "FAKE", NULL },
- { "", "None", "BMP085", "MS5611", "BMP280", NULL },
- { "", "None", "HMC5883", "AK8975", "AK8963", NULL }
-};
-#endif
-
-typedef struct {
- const char *name;
-#ifndef SKIP_CLI_COMMAND_HELP
- const char *description;
- const char *args;
-#endif
- void (*func)(char *cmdline);
-} clicmd_t;
-
-#ifndef SKIP_CLI_COMMAND_HELP
-#define CLI_COMMAND_DEF(name, description, args, method) \
-{ \
- name , \
- description , \
- args , \
- method \
-}
-#else
-#define CLI_COMMAND_DEF(name, description, args, method) \
-{ \
- name, \
- method \
-}
-#endif
-
-// should be sorted a..z for bsearch()
-const clicmd_t cmdTable[] = {
- CLI_COMMAND_DEF("adjrange", "configure adjustment ranges", NULL, cliAdjustmentRange),
- CLI_COMMAND_DEF("aux", "configure modes", NULL, cliAux),
-#ifdef LED_STRIP
- CLI_COMMAND_DEF("color", "configure colors", NULL, cliColor),
-#endif
- CLI_COMMAND_DEF("defaults", "reset to defaults and reboot", NULL, cliDefaults),
- CLI_COMMAND_DEF("dump", "dump configuration",
- "[master|profile]", cliDump),
- CLI_COMMAND_DEF("exit", NULL, NULL, cliExit),
- CLI_COMMAND_DEF("feature", "configure features",
- "list\r\n"
- "\t<+|->[name]", cliFeature),
-#ifdef USE_FLASHFS
- CLI_COMMAND_DEF("flash_erase", "erase flash chip", NULL, cliFlashErase),
- CLI_COMMAND_DEF("flash_info", "show flash chip info", NULL, cliFlashInfo),
-#ifdef USE_FLASH_TOOLS
- CLI_COMMAND_DEF("flash_read", NULL, " ", cliFlashRead),
- CLI_COMMAND_DEF("flash_write", NULL, " ", cliFlashWrite),
-#endif
-#endif
- CLI_COMMAND_DEF("get", "get variable value",
- "[name]", cliGet),
-#ifdef GPS
- CLI_COMMAND_DEF("gpspassthrough", "passthrough gps to serial", NULL, cliGpsPassthrough),
-#endif
- CLI_COMMAND_DEF("help", NULL, NULL, cliHelp),
-#ifdef LED_STRIP
- CLI_COMMAND_DEF("led", "configure leds", NULL, cliLed),
-#endif
- CLI_COMMAND_DEF("map", "configure rc channel order",
- "[