1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-14 11:59:58 +03:00

Adding CLI command pass through for MSP (#13940)

This commit is contained in:
J Blackman 2024-10-03 23:59:47 +10:00 committed by GitHub
parent 23e682c310
commit c2900de5c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 204 additions and 129 deletions

View file

@ -175,6 +175,8 @@ bool cliMode = false;
#include "cli.h" #include "cli.h"
static serialPort_t *cliPort = NULL; static serialPort_t *cliPort = NULL;
static bool cliInteractive = false;
static timeMs_t cliEntryTime = 0;
// Space required to set array parameters // Space required to set array parameters
#define CLI_IN_BUFFER_SIZE 256 #define CLI_IN_BUFFER_SIZE 256
@ -315,6 +317,7 @@ typedef enum dumpFlags_e {
BARE = (1 << 8), BARE = (1 << 8),
} dumpFlags_t; } dumpFlags_t;
static void cliExit(const bool reboot);
typedef bool printFn(dumpFlags_t dumpMask, bool equalsDefault, const char *format, ...); typedef bool printFn(dumpFlags_t dumpMask, bool equalsDefault, const char *format, ...);
typedef enum { typedef enum {
@ -330,6 +333,12 @@ typedef struct serialPassthroughPort_s {
serialPort_t *port; serialPort_t *port;
} serialPassthroughPort_t; } serialPassthroughPort_t;
static void cliClearInputBuffer(void)
{
memset(cliBuffer, 0, sizeof(cliBuffer));
bufferIndex = 0;
}
static void cliWriterFlushInternal(bufWriter_t *writer) static void cliWriterFlushInternal(bufWriter_t *writer)
{ {
if (writer) { if (writer) {
@ -3581,23 +3590,17 @@ static void cliBootloader(const char *cmdName, char *cmdline)
cliRebootEx(rebootTarget); cliRebootEx(rebootTarget);
} }
static void cliExit(const char *cmdName, char *cmdline) static void cliExitCmd(const char *cmdName, char *cmdline)
{ {
UNUSED(cmdName); UNUSED(cmdName);
UNUSED(cmdline);
const bool reboot = strcasecmp(cmdline, "noreboot") != 0;
if (reboot) {
cliPrintHashLine("leaving CLI mode, unsaved changes lost"); cliPrintHashLine("leaving CLI mode, unsaved changes lost");
cliWriterFlush(); } else {
cliPrintHashLine("leaving CLI mode, no reboot");
*cliBuffer = '\0';
bufferIndex = 0;
cliMode = false;
// incase a motor was left running during motortest, clear it here
mixerResetDisarmedMotors();
if (strcasecmp(cmdline, "noreboot") == 0) {
return;
} }
cliReboot(); cliExit(reboot);
} }
#ifdef USE_GPS #ifdef USE_GPS
@ -6516,7 +6519,7 @@ const clicmd_t cmdTable[] = {
#ifdef USE_ESCSERIAL #ifdef USE_ESCSERIAL
CLI_COMMAND_DEF("escprog", "passthrough esc to serial", "<mode [sk/bl/ki/cc]> <index>", cliEscPassthrough), CLI_COMMAND_DEF("escprog", "passthrough esc to serial", "<mode [sk/bl/ki/cc]> <index>", cliEscPassthrough),
#endif #endif
CLI_COMMAND_DEF("exit", "exit command line interface and reboot (default)", "[noreboot]", cliExit), CLI_COMMAND_DEF("exit", "exit command line interface and reboot (default)", "[noreboot]", cliExitCmd),
CLI_COMMAND_DEF("feature", "configure features", CLI_COMMAND_DEF("feature", "configure features",
"list\r\n" "list\r\n"
"\t<->[name]", cliFeature), "\t<->[name]", cliFeature),
@ -6662,8 +6665,10 @@ static void cliHelp(const char *cmdName, char *cmdline)
static void processCharacter(const char c) static void processCharacter(const char c)
{ {
if (bufferIndex && (c == '\n' || c == '\r')) { if (bufferIndex && (c == '\n' || c == '\r')) {
// enter pressed if (cliInteractive) {
// echo new line back to terminal
cliPrintLinefeed(); cliPrintLinefeed();
}
// Strip comment starting with # from line // Strip comment starting with # from line
char *p = cliBuffer; char *p = cliBuffer;
@ -6690,27 +6695,39 @@ static void processCharacter(const char c)
} }
if (cmd < cmdTable + ARRAYLEN(cmdTable)) { if (cmd < cmdTable + ARRAYLEN(cmdTable)) {
cmd->cliCommand(cmd->name, options); cmd->cliCommand(cmd->name, options);
} else {
cliPrintError("input", "UNKNOWN COMMAND, TRY 'HELP'");
}
bufferIndex = 0;
}
memset(cliBuffer, 0, sizeof(cliBuffer));
// 'exit' will reset this flag, so we don't need to print prompt again
if (!cliMode) { if (!cliMode) {
// cli session ended
return; return;
} }
} else {
if (cliInteractive) {
cliPrintError("input", "UNKNOWN COMMAND, TRY 'HELP'");
} else {
cliPrint("ERR_CMD_NA: ");
cliPrintLine(cliBuffer);
}
}
}
cliClearInputBuffer();
// prompt if in interactive mode
if (cliInteractive) {
cliPrompt(); cliPrompt();
}
} else if (bufferIndex < sizeof(cliBuffer) && c >= 32 && c <= 126) { } else if (bufferIndex < sizeof(cliBuffer) && c >= 32 && c <= 126) {
if (!bufferIndex && c == ' ') if (!bufferIndex && c == ' ') {
return; // Ignore leading spaces return; // Ignore leading spaces
}
cliBuffer[bufferIndex++] = c; cliBuffer[bufferIndex++] = c;
// echo the character if interactive
if (cliInteractive) {
cliWrite(c); cliWrite(c);
} }
} }
}
static void processCharacterInteractive(const char c) static void processCharacterInteractive(const char c)
{ {
@ -6753,7 +6770,7 @@ static void processCharacterInteractive(const char c)
for (; i < bufferIndex; i++) for (; i < bufferIndex; i++)
cliWrite(cliBuffer[i]); cliWrite(cliBuffer[i]);
} else if (!bufferIndex && c == 4) { // CTRL-D } else if (!bufferIndex && c == 4) { // CTRL-D
cliExit("", cliBuffer); cliExit(true);
return; return;
} else if (c == 12) { // NewPage / CTRL-L } else if (c == 12) { // NewPage / CTRL-L
// clear screen // clear screen
@ -6770,42 +6787,76 @@ static void processCharacterInteractive(const char c)
} }
} }
void cliProcess(void) bool cliProcess(void)
{ {
if (!cliWriter || !cliMode) { if (!cliWriter || !cliMode) {
return; return false;
} }
// Flush the buffer to get rid of any MSP data polls sent by configurator after CLI was invoked
cliWriterFlush();
while (serialRxBytesWaiting(cliPort)) { while (serialRxBytesWaiting(cliPort)) {
uint8_t c = serialRead(cliPort); uint8_t c = serialRead(cliPort);
if (cliInteractive) {
processCharacterInteractive(c); processCharacterInteractive(c);
} else {
// handle terminating flow control character
if (c == 0x3 || (cmp32(millis(), cliEntryTime) > 2000)) { // CTRL-C (ETX) or 2 seconds timeout
cliWrite(0x3); // send end of text, terminating flow control
cliExit(false);
return cliMode;
}
processCharacter(c);
}
}
cliWriterFlush();
return cliMode;
}
static void cliExit(const bool reboot)
{
cliWriterFlush();
waitForSerialPortToFinishTransmitting(cliPort);
cliClearInputBuffer();
cliMode = false;
cliInteractive = false;
// incase a motor was left running during motortest, clear it here
mixerResetDisarmedMotors();
if (reboot) {
cliReboot();
} }
} }
void cliEnter(serialPort_t *serialPort) void cliEnter(serialPort_t *serialPort, bool interactive)
{ {
cliMode = true; cliMode = true;
cliInteractive = interactive;
cliPort = serialPort; cliPort = serialPort;
cliEntryTime = millis();
cliClearInputBuffer();
if (interactive) {
setPrintfSerialPort(cliPort); setPrintfSerialPort(cliPort);
}
bufWriterInit(&cliWriterDesc, cliWriteBuffer, sizeof(cliWriteBuffer), (bufWrite_t)serialWriteBufShim, serialPort); bufWriterInit(&cliWriterDesc, cliWriteBuffer, sizeof(cliWriteBuffer), (bufWrite_t)serialWriteBufShim, serialPort);
cliErrorWriter = cliWriter = &cliWriterDesc; cliErrorWriter = cliWriter = &cliWriterDesc;
if (interactive) {
#ifndef MINIMAL_CLI #ifndef MINIMAL_CLI
cliPrintLine("\r\nEntering CLI Mode, type 'exit' to return, or 'help'"); cliPrintLine("\r\nEntering CLI Mode, type 'exit' to reboot, or 'help'");
#else #else
cliPrintLine("\r\nCLI"); cliPrintLine("\r\nCLI");
#endif #endif
// arming flag not released if exiting cli with no reboot for safety
setArmingDisabled(ARMING_DISABLED_CLI); setArmingDisabled(ARMING_DISABLED_CLI);
cliPrompt(); cliPrompt();
#ifdef USE_CLI_BATCH #ifdef USE_CLI_BATCH
resetCommandBatch(); resetCommandBatch();
#endif #endif
} else {
cliWrite(0x2); // send start of text, initiating flow control
}
} }
#endif // USE_CLI #endif // USE_CLI

View file

@ -24,9 +24,9 @@
extern bool cliMode; extern bool cliMode;
void cliProcess(void); bool cliProcess(void);
struct serialPort_s; struct serialPort_s;
void cliEnter(struct serialPort_s *serialPort); void cliEnter(struct serialPort_s *serialPort, bool interactive);
#ifdef USE_CLI_DEBUG_PRINT #ifdef USE_CLI_DEBUG_PRINT
void cliPrint(const char *str); void cliPrint(const char *str);

View file

@ -125,6 +125,7 @@ void serialWriteBuf(serialPort_t *instance, const uint8_t *data, int count)
serialWriteBufNoFlush(instance, data, count); serialWriteBufNoFlush(instance, data, count);
serialEndWrite(instance); serialEndWrite(instance);
} }
void serialWriteBufShim(void *instance, const uint8_t *data, int count) void serialWriteBufShim(void *instance, const uint8_t *data, int count)
{ {
serialWriteBuf((serialPort_t *)instance, data, count); serialWriteBuf((serialPort_t *)instance, data, count);

View file

@ -138,13 +138,6 @@ static void taskHandleSerial(timeUs_t currentTimeUs)
DEBUG_SET(DEBUG_USB, 1, usbVcpIsConnected()); DEBUG_SET(DEBUG_USB, 1, usbVcpIsConnected());
#endif #endif
#ifdef USE_CLI
// in cli mode, all serial stuff goes to here. enter cli mode by sending #
if (cliMode) {
cliProcess();
return;
}
#endif
bool evaluateMspData = ARMING_FLAG(ARMED) ? MSP_SKIP_NON_MSP_DATA : MSP_EVALUATE_NON_MSP_DATA; bool evaluateMspData = ARMING_FLAG(ARMED) ? MSP_SKIP_NON_MSP_DATA : MSP_EVALUATE_NON_MSP_DATA;
mspSerialProcess(evaluateMspData, mspFcProcessCommand, mspFcProcessReply); mspSerialProcess(evaluateMspData, mspFcProcessCommand, mspFcProcessReply);
} }

View file

@ -120,39 +120,32 @@ void mspSerialReleaseSharedTelemetryPorts(void)
} }
#endif #endif
static bool mspSerialProcessReceivedData(mspPort_t *mspPort, uint8_t c) static void mspSerialProcessReceivedPacketData(mspPort_t *mspPort, uint8_t c)
{ {
switch (mspPort->c_state) { switch (mspPort->packetState) {
default: default:
case MSP_IDLE: // Waiting for '$' character case MSP_IDLE:
if (c == '$') {
mspPort->c_state = MSP_HEADER_START;
} else {
return false;
}
break;
case MSP_HEADER_START: // Waiting for 'M' (MSPv1 / MSPv2_over_v1) or 'X' (MSPv2 native) case MSP_HEADER_START: // Waiting for 'M' (MSPv1 / MSPv2_over_v1) or 'X' (MSPv2 native)
mspPort->offset = 0; mspPort->offset = 0;
mspPort->checksum1 = 0; mspPort->checksum1 = 0;
mspPort->checksum2 = 0; mspPort->checksum2 = 0;
switch (c) { switch (c) {
case 'M': case 'M':
mspPort->c_state = MSP_HEADER_M; mspPort->packetState = MSP_HEADER_M;
mspPort->mspVersion = MSP_V1; mspPort->mspVersion = MSP_V1;
break; break;
case 'X': case 'X':
mspPort->c_state = MSP_HEADER_X; mspPort->packetState = MSP_HEADER_X;
mspPort->mspVersion = MSP_V2_NATIVE; mspPort->mspVersion = MSP_V2_NATIVE;
break; break;
default: default:
mspPort->c_state = MSP_IDLE; mspPort->packetState = MSP_IDLE;
break; break;
} }
break; break;
case MSP_HEADER_M: // Waiting for '<' / '>' case MSP_HEADER_M: // Waiting for '<' / '>'
mspPort->c_state = MSP_HEADER_V1; mspPort->packetState = MSP_HEADER_V1;
switch (c) { switch (c) {
case '<': case '<':
mspPort->packetType = MSP_PACKET_COMMAND; mspPort->packetType = MSP_PACKET_COMMAND;
@ -161,13 +154,13 @@ static bool mspSerialProcessReceivedData(mspPort_t *mspPort, uint8_t c)
mspPort->packetType = MSP_PACKET_REPLY; mspPort->packetType = MSP_PACKET_REPLY;
break; break;
default: default:
mspPort->c_state = MSP_IDLE; mspPort->packetState = MSP_IDLE;
break; break;
} }
break; break;
case MSP_HEADER_X: case MSP_HEADER_X:
mspPort->c_state = MSP_HEADER_V2_NATIVE; mspPort->packetState = MSP_HEADER_V2_NATIVE;
switch (c) { switch (c) {
case '<': case '<':
mspPort->packetType = MSP_PACKET_COMMAND; mspPort->packetType = MSP_PACKET_COMMAND;
@ -176,7 +169,7 @@ static bool mspSerialProcessReceivedData(mspPort_t *mspPort, uint8_t c)
mspPort->packetType = MSP_PACKET_REPLY; mspPort->packetType = MSP_PACKET_REPLY;
break; break;
default: default:
mspPort->c_state = MSP_IDLE; mspPort->packetState = MSP_IDLE;
break; break;
} }
break; break;
@ -188,22 +181,22 @@ static bool mspSerialProcessReceivedData(mspPort_t *mspPort, uint8_t c)
mspHeaderV1_t * hdr = (mspHeaderV1_t *)&mspPort->inBuf[0]; mspHeaderV1_t * hdr = (mspHeaderV1_t *)&mspPort->inBuf[0];
// Check incoming buffer size limit // Check incoming buffer size limit
if (hdr->size > MSP_PORT_INBUF_SIZE) { if (hdr->size > MSP_PORT_INBUF_SIZE) {
mspPort->c_state = MSP_IDLE; mspPort->packetState = MSP_IDLE;
} }
else if (hdr->cmd == MSP_V2_FRAME_ID) { else if (hdr->cmd == MSP_V2_FRAME_ID) {
// MSPv1 payload must be big enough to hold V2 header + extra checksum // MSPv1 payload must be big enough to hold V2 header + extra checksum
if (hdr->size >= sizeof(mspHeaderV2_t) + 1) { if (hdr->size >= sizeof(mspHeaderV2_t) + 1) {
mspPort->mspVersion = MSP_V2_OVER_V1; mspPort->mspVersion = MSP_V2_OVER_V1;
mspPort->c_state = MSP_HEADER_V2_OVER_V1; mspPort->packetState = MSP_HEADER_V2_OVER_V1;
} else { } else {
mspPort->c_state = MSP_IDLE; mspPort->packetState = MSP_IDLE;
} }
} else { } else {
mspPort->dataSize = hdr->size; mspPort->dataSize = hdr->size;
mspPort->cmdMSP = hdr->cmd; mspPort->cmdMSP = hdr->cmd;
mspPort->cmdFlags = 0; mspPort->cmdFlags = 0;
mspPort->offset = 0; // re-use buffer mspPort->offset = 0; // re-use buffer
mspPort->c_state = mspPort->dataSize > 0 ? MSP_PAYLOAD_V1 : MSP_CHECKSUM_V1; // If no payload - jump to checksum byte mspPort->packetState = mspPort->dataSize > 0 ? MSP_PAYLOAD_V1 : MSP_CHECKSUM_V1; // If no payload - jump to checksum byte
} }
} }
break; break;
@ -212,15 +205,15 @@ static bool mspSerialProcessReceivedData(mspPort_t *mspPort, uint8_t c)
mspPort->inBuf[mspPort->offset++] = c; mspPort->inBuf[mspPort->offset++] = c;
mspPort->checksum1 ^= c; mspPort->checksum1 ^= c;
if (mspPort->offset == mspPort->dataSize) { if (mspPort->offset == mspPort->dataSize) {
mspPort->c_state = MSP_CHECKSUM_V1; mspPort->packetState = MSP_CHECKSUM_V1;
} }
break; break;
case MSP_CHECKSUM_V1: case MSP_CHECKSUM_V1:
if (mspPort->checksum1 == c) { if (mspPort->checksum1 == c) {
mspPort->c_state = MSP_COMMAND_RECEIVED; mspPort->packetState = MSP_COMMAND_RECEIVED;
} else { } else {
mspPort->c_state = MSP_IDLE; mspPort->packetState = MSP_IDLE;
} }
break; break;
@ -231,13 +224,13 @@ static bool mspSerialProcessReceivedData(mspPort_t *mspPort, uint8_t c)
if (mspPort->offset == (sizeof(mspHeaderV2_t) + sizeof(mspHeaderV1_t))) { if (mspPort->offset == (sizeof(mspHeaderV2_t) + sizeof(mspHeaderV1_t))) {
mspHeaderV2_t * hdrv2 = (mspHeaderV2_t *)&mspPort->inBuf[sizeof(mspHeaderV1_t)]; mspHeaderV2_t * hdrv2 = (mspHeaderV2_t *)&mspPort->inBuf[sizeof(mspHeaderV1_t)];
if (hdrv2->size > MSP_PORT_INBUF_SIZE) { if (hdrv2->size > MSP_PORT_INBUF_SIZE) {
mspPort->c_state = MSP_IDLE; mspPort->packetState = MSP_IDLE;
} else { } else {
mspPort->dataSize = hdrv2->size; mspPort->dataSize = hdrv2->size;
mspPort->cmdMSP = hdrv2->cmd; mspPort->cmdMSP = hdrv2->cmd;
mspPort->cmdFlags = hdrv2->flags; mspPort->cmdFlags = hdrv2->flags;
mspPort->offset = 0; // re-use buffer mspPort->offset = 0; // re-use buffer
mspPort->c_state = mspPort->dataSize > 0 ? MSP_PAYLOAD_V2_OVER_V1 : MSP_CHECKSUM_V2_OVER_V1; mspPort->packetState = mspPort->dataSize > 0 ? MSP_PAYLOAD_V2_OVER_V1 : MSP_CHECKSUM_V2_OVER_V1;
} }
} }
break; break;
@ -248,16 +241,16 @@ static bool mspSerialProcessReceivedData(mspPort_t *mspPort, uint8_t c)
mspPort->inBuf[mspPort->offset++] = c; mspPort->inBuf[mspPort->offset++] = c;
if (mspPort->offset == mspPort->dataSize) { if (mspPort->offset == mspPort->dataSize) {
mspPort->c_state = MSP_CHECKSUM_V2_OVER_V1; mspPort->packetState = MSP_CHECKSUM_V2_OVER_V1;
} }
break; break;
case MSP_CHECKSUM_V2_OVER_V1: case MSP_CHECKSUM_V2_OVER_V1:
mspPort->checksum1 ^= c; mspPort->checksum1 ^= c;
if (mspPort->checksum2 == c) { if (mspPort->checksum2 == c) {
mspPort->c_state = MSP_CHECKSUM_V1; // Checksum 2 correct - verify v1 checksum mspPort->packetState = MSP_CHECKSUM_V1; // Checksum 2 correct - verify v1 checksum
} else { } else {
mspPort->c_state = MSP_IDLE; mspPort->packetState = MSP_IDLE;
} }
break; break;
@ -270,7 +263,7 @@ static bool mspSerialProcessReceivedData(mspPort_t *mspPort, uint8_t c)
mspPort->cmdMSP = hdrv2->cmd; mspPort->cmdMSP = hdrv2->cmd;
mspPort->cmdFlags = hdrv2->flags; mspPort->cmdFlags = hdrv2->flags;
mspPort->offset = 0; // re-use buffer mspPort->offset = 0; // re-use buffer
mspPort->c_state = mspPort->dataSize > 0 ? MSP_PAYLOAD_V2_NATIVE : MSP_CHECKSUM_V2_NATIVE; mspPort->packetState = mspPort->dataSize > 0 ? MSP_PAYLOAD_V2_NATIVE : MSP_CHECKSUM_V2_NATIVE;
} }
break; break;
@ -279,20 +272,18 @@ static bool mspSerialProcessReceivedData(mspPort_t *mspPort, uint8_t c)
mspPort->inBuf[mspPort->offset++] = c; mspPort->inBuf[mspPort->offset++] = c;
if (mspPort->offset == mspPort->dataSize) { if (mspPort->offset == mspPort->dataSize) {
mspPort->c_state = MSP_CHECKSUM_V2_NATIVE; mspPort->packetState = MSP_CHECKSUM_V2_NATIVE;
} }
break; break;
case MSP_CHECKSUM_V2_NATIVE: case MSP_CHECKSUM_V2_NATIVE:
if (mspPort->checksum2 == c) { if (mspPort->checksum2 == c) {
mspPort->c_state = MSP_COMMAND_RECEIVED; mspPort->packetState = MSP_COMMAND_RECEIVED;
} else { } else {
mspPort->c_state = MSP_IDLE; mspPort->packetState = MSP_IDLE;
} }
break; break;
} }
return true;
} }
static uint8_t mspSerialChecksumBuf(uint8_t checksum, const uint8_t *data, int len) static uint8_t mspSerialChecksumBuf(uint8_t checksum, const uint8_t *data, int len)
@ -445,39 +436,29 @@ static mspPostProcessFnPtr mspSerialProcessReceivedCommand(mspPort_t *msp, mspPr
return mspPostProcessFn; return mspPostProcessFn;
} }
static void mspEvaluateNonMspData(mspPort_t * mspPort, uint8_t receivedChar)
{
if (receivedChar == serialConfig()->reboot_character) {
mspPort->pendingRequest = MSP_PENDING_BOOTLOADER_ROM;
#ifdef USE_CLI
} else if (receivedChar == '#') {
mspPort->pendingRequest = MSP_PENDING_CLI;
#endif
}
}
static void mspProcessPendingRequest(mspPort_t * mspPort) static void mspProcessPendingRequest(mspPort_t * mspPort)
{ {
// If no request is pending or 100ms guard time has not elapsed - do nothing // If no request is pending or 100ms guard time has not elapsed - do nothing
if ((mspPort->pendingRequest == MSP_PENDING_NONE) || (millis() - mspPort->lastActivityMs < 100)) { if ((mspPort->pendingRequest == MSP_PENDING_NONE) || (cmp32(millis(), mspPort->lastActivityMs) < 100)) {
return; return;
} }
switch(mspPort->pendingRequest) { switch(mspPort->pendingRequest) {
case MSP_PENDING_BOOTLOADER_ROM: case MSP_PENDING_BOOTLOADER_ROM:
systemResetToBootloader(BOOTLOADER_REQUEST_ROM); systemResetToBootloader(BOOTLOADER_REQUEST_ROM);
break; break;
#if defined(USE_FLASH_BOOT_LOADER) #if defined(USE_FLASH_BOOT_LOADER)
case MSP_PENDING_BOOTLOADER_FLASH: case MSP_PENDING_BOOTLOADER_FLASH:
systemResetToBootloader(BOOTLOADER_REQUEST_FLASH); systemResetToBootloader(BOOTLOADER_REQUEST_FLASH);
break; break;
#endif #endif
#ifdef USE_CLI #ifdef USE_CLI
case MSP_PENDING_CLI: case MSP_PENDING_CLI:
mspPort->pendingRequest = MSP_PENDING_NONE; mspPort->pendingRequest = MSP_PENDING_NONE;
cliEnter(mspPort->port); mspPort->portState = PORT_CLI_ACTIVE;
cliEnter(mspPort->port, true);
break; break;
#endif #endif
@ -498,8 +479,38 @@ static void mspSerialProcessReceivedReply(mspPort_t *msp, mspProcessReplyFnPtr m
}; };
mspProcessReplyFn(&reply); mspProcessReplyFn(&reply);
}
msp->c_state = MSP_IDLE; void mspProcessPacket(mspPort_t *mspPort, mspProcessCommandFnPtr mspProcessCommandFn, mspProcessReplyFnPtr mspProcessReplyFn)
{
mspPostProcessFnPtr mspPostProcessFn = NULL;
while (serialRxBytesWaiting(mspPort->port)) {
const uint8_t c = serialRead(mspPort->port);
mspSerialProcessReceivedPacketData(mspPort, c);
if (mspPort->packetState == MSP_COMMAND_RECEIVED) {
if (mspPort->packetType == MSP_PACKET_COMMAND) {
mspPostProcessFn = mspSerialProcessReceivedCommand(mspPort, mspProcessCommandFn);
} else if (mspPort->packetType == MSP_PACKET_REPLY) {
mspSerialProcessReceivedReply(mspPort, mspProcessReplyFn);
}
// process one command at a time so as not to block
mspPort->packetState = MSP_IDLE;
}
if (mspPort->packetState == MSP_IDLE) {
mspPort->portState = PORT_IDLE;
break;
}
}
if (mspPostProcessFn) {
waitForSerialPortToFinishTransmitting(mspPort->port);
mspPostProcessFn(mspPort->port);
}
} }
/* /*
@ -515,39 +526,50 @@ void mspSerialProcess(mspEvaluateNonMspData_e evaluateNonMspData, mspProcessComm
continue; continue;
} }
mspPostProcessFnPtr mspPostProcessFn = NULL; // whilst port is idle, poll incoming until portState changes or no more bytes
while (mspPort->portState == PORT_IDLE && serialRxBytesWaiting(mspPort->port)) {
if (serialRxBytesWaiting(mspPort->port)) {
// There are bytes incoming - abort pending request // There are bytes incoming - abort pending request
mspPort->lastActivityMs = millis(); mspPort->lastActivityMs = millis();
mspPort->pendingRequest = MSP_PENDING_NONE; mspPort->pendingRequest = MSP_PENDING_NONE;
while (serialRxBytesWaiting(mspPort->port)) {
const uint8_t c = serialRead(mspPort->port); const uint8_t c = serialRead(mspPort->port);
const bool consumed = mspSerialProcessReceivedData(mspPort, c); if (c == '$') {
mspPort->portState = PORT_MSP_PACKET;
if (!consumed && evaluateNonMspData == MSP_EVALUATE_NON_MSP_DATA) { mspPort->packetState = MSP_HEADER_START;
mspEvaluateNonMspData(mspPort, c); } else if (evaluateNonMspData == MSP_EVALUATE_NON_MSP_DATA) {
// evaluate the non-MSP data
if (c == serialConfig()->reboot_character) {
mspPort->pendingRequest = MSP_PENDING_BOOTLOADER_ROM;
#ifdef USE_CLI
} else if (c == '#') {
mspPort->pendingRequest = MSP_PENDING_CLI;
} else if (c == 0x2) {
mspPort->portState = PORT_CLI_CMD;
cliEnter(mspPort->port, false);
#endif
} }
if (mspPort->c_state == MSP_COMMAND_RECEIVED) {
if (mspPort->packetType == MSP_PACKET_COMMAND) {
mspPostProcessFn = mspSerialProcessReceivedCommand(mspPort, mspProcessCommandFn);
} else if (mspPort->packetType == MSP_PACKET_REPLY) {
mspSerialProcessReceivedReply(mspPort, mspProcessReplyFn);
}
mspPort->c_state = MSP_IDLE;
break; // process one command at a time so as not to block.
} }
} }
if (mspPostProcessFn) { switch (mspPort->portState) {
waitForSerialPortToFinishTransmitting(mspPort->port); case PORT_IDLE:
mspPostProcessFn(mspPort->port);
}
} else {
mspProcessPendingRequest(mspPort); mspProcessPendingRequest(mspPort);
break;
case PORT_MSP_PACKET:
mspProcessPacket(mspPort, mspProcessCommandFn, mspProcessReplyFn);
break;
#ifdef USE_CLI
case PORT_CLI_ACTIVE:
case PORT_CLI_CMD:
if (!cliProcess()) {
mspPort->portState = PORT_IDLE;
}
break;
#endif
default:
break;
} }
} }
} }
@ -585,7 +607,8 @@ int mspSerialPush(serialPortIdentifier_e port, uint8_t cmd, uint8_t *data, int d
#ifndef USE_MSP_PUSH_OVER_VCP #ifndef USE_MSP_PUSH_OVER_VCP
|| mspPort->port->identifier == SERIAL_PORT_USB_VCP || mspPort->port->identifier == SERIAL_PORT_USB_VCP
#endif #endif
|| (port != SERIAL_PORT_ALL && mspPort->port->identifier != port)) { || (port != SERIAL_PORT_ALL && mspPort->port->identifier != port)
|| mspPort->portState == PORT_CLI_CMD || mspPort->portState == PORT_CLI_ACTIVE) {
continue; continue;
} }
@ -601,7 +624,6 @@ int mspSerialPush(serialPortIdentifier_e port, uint8_t cmd, uint8_t *data, int d
return ret; // return the number of bytes written return ret; // return the number of bytes written
} }
uint32_t mspSerialTxBytesFree(void) uint32_t mspSerialTxBytesFree(void)
{ {
uint32_t ret = UINT32_MAX; uint32_t ret = UINT32_MAX;

View file

@ -29,6 +29,13 @@
// Each MSP port requires state and a receive buffer, revisit this default if someone needs more than 3 MSP ports. // Each MSP port requires state and a receive buffer, revisit this default if someone needs more than 3 MSP ports.
#define MAX_MSP_PORT_COUNT 3 #define MAX_MSP_PORT_COUNT 3
typedef enum {
PORT_IDLE,
PORT_MSP_PACKET,
PORT_CLI_ACTIVE,
PORT_CLI_CMD
} mspPortState_e;
typedef enum { typedef enum {
MSP_IDLE, MSP_IDLE,
MSP_HEADER_START, MSP_HEADER_START,
@ -48,7 +55,7 @@ typedef enum {
MSP_CHECKSUM_V2_NATIVE, MSP_CHECKSUM_V2_NATIVE,
MSP_COMMAND_RECEIVED MSP_COMMAND_RECEIVED
} mspState_e; } mspPacketState_e;
typedef enum { typedef enum {
MSP_PACKET_COMMAND, MSP_PACKET_COMMAND,
@ -100,7 +107,8 @@ typedef struct mspPort_s {
struct serialPort_s *port; // null when port unused. struct serialPort_s *port; // null when port unused.
timeMs_t lastActivityMs; timeMs_t lastActivityMs;
mspPendingSystemRequest_e pendingRequest; mspPendingSystemRequest_e pendingRequest;
mspState_e c_state; mspPortState_e portState;
mspPacketState_e packetState;
mspPacketType_e packetType; mspPacketType_e packetType;
uint8_t inBuf[MSP_PORT_INBUF_SIZE]; uint8_t inBuf[MSP_PORT_INBUF_SIZE];
uint16_t cmdMSP; uint16_t cmdMSP;