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:
parent
23e682c310
commit
c2900de5c1
6 changed files with 204 additions and 129 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue