serial: allow buffering to speed up USB virtual COM ports.
Add begin write and end write hints. If implemented by the serial driver, then the driver can buffer up data sent via serialWrite() and flush it when serialEndWrite() is called. Implemented at the buffer level as it requires the least change to how serial_msp and serial_cli are architected. Also tidy up the visibility in the VCP driver. Signed-off-by: Michael Hope <mlhx@google.com>
This commit is contained in:
parent
0e460c18b0
commit
195456f9ac
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -323,5 +323,7 @@ const struct serialPortVTable uartVTable[] = {
|
|||
isUartTransmitBufferEmpty,
|
||||
uartSetMode,
|
||||
.writeBuf = NULL,
|
||||
.beginWrite = NULL,
|
||||
.endWrite = NULL,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -455,6 +455,8 @@ static uint32_t read32(void)
|
|||
|
||||
static void headSerialResponse(uint8_t err, uint8_t responseBodySize)
|
||||
{
|
||||
serialBeginWrite(mspSerialPort);
|
||||
|
||||
serialize8('$');
|
||||
serialize8('M');
|
||||
serialize8(err ? '!' : '>');
|
||||
|
@ -476,6 +478,7 @@ static void headSerialError(uint8_t responseBodySize)
|
|||
static void tailSerialReply(void)
|
||||
{
|
||||
serialize8(currentPort->checksum);
|
||||
serialEndWrite(mspSerialPort);
|
||||
}
|
||||
|
||||
static void s_struct(uint8_t *cb, uint8_t siz)
|
||||
|
|
Loading…
Reference in New Issue