mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-23 16:25:31 +03:00
Refactor serial port configuration, stage 1.
Tested and working: * multiple MSP ports at different baud rates. * cli on any MSP port. * GPS * gps passthough on currently active cli port. Example config used for testing: feature SOFTSERIAL feature GPS feature RX_PPM serial_port_1_functions = 1 serial_port_1_baudrate = 115200 serial_port_2_functions = 128 serial_port_2_baudrate = 115200 serial_port_3_functions = 1 serial_port_3_baudrate = 19200 serial_port_4_functions = 0 serial_port_4_baudrate = 0 Known broken: * Telemetry and shared serial ports * Telemetry when unarmed. Probably broken: * Blackbox on shared port. Untested. * Serial RX. * Blackbox.
This commit is contained in:
parent
519cc5f238
commit
5163bef0b2
31 changed files with 459 additions and 1247 deletions
|
@ -42,565 +42,141 @@
|
|||
#include "telemetry/telemetry.h"
|
||||
#endif
|
||||
|
||||
void updateSerialRxFunctionConstraint(functionConstraint_t *functionConstraintToUpdate);
|
||||
|
||||
void cliInit(serialConfig_t *serialConfig);
|
||||
|
||||
// this exists so the user can reference scenarios by a number in the CLI instead of an unuser-friendly bitmask.
|
||||
const serialPortFunctionScenario_e serialPortScenarios[SERIAL_PORT_SCENARIO_COUNT] = {
|
||||
SCENARIO_UNUSED,
|
||||
|
||||
// common scenarios in order of importance
|
||||
SCENARIO_MSP_CLI_TELEMETRY_GPS_PASTHROUGH,
|
||||
SCENARIO_GPS_ONLY,
|
||||
SCENARIO_SERIAL_RX_ONLY,
|
||||
SCENARIO_TELEMETRY_ONLY,
|
||||
|
||||
// other scenarios
|
||||
SCENARIO_MSP_CLI_GPS_PASTHROUGH,
|
||||
SCENARIO_CLI_ONLY,
|
||||
SCENARIO_GPS_PASSTHROUGH_ONLY,
|
||||
SCENARIO_MSP_ONLY,
|
||||
SCENARIO_SMARTPORT_TELEMETRY_ONLY,
|
||||
|
||||
SCENARIO_BLACKBOX_ONLY,
|
||||
SCENARIO_MSP_CLI_BLACKBOX_GPS_PASTHROUGH
|
||||
};
|
||||
|
||||
static serialConfig_t *serialConfig;
|
||||
static serialPort_t *serialPorts[SERIAL_PORT_COUNT];
|
||||
static serialPortUsage_t serialPortUsageList[SERIAL_PORT_COUNT];
|
||||
|
||||
#ifdef STM32F303xC
|
||||
static serialPortFunction_t serialPortFunctions[SERIAL_PORT_COUNT] = {
|
||||
serialPortIdentifier_e serialPortIdentifiers[SERIAL_PORT_COUNT] = {
|
||||
#ifdef USE_VCP
|
||||
{SERIAL_PORT_USB_VCP, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
SERIAL_PORT_USB_VCP,
|
||||
#endif
|
||||
#ifdef USE_USART1
|
||||
{SERIAL_PORT_USART1, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
SERIAL_PORT_USART1,
|
||||
#endif
|
||||
#ifdef USE_USART2
|
||||
{SERIAL_PORT_USART2, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
SERIAL_PORT_USART2,
|
||||
#endif
|
||||
#ifdef USE_USART3
|
||||
{SERIAL_PORT_USART3, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
SERIAL_PORT_USART3,
|
||||
#endif
|
||||
#ifdef USE_SOFTSERIAL1
|
||||
SERIAL_PORT_SOFTSERIAL1,
|
||||
#endif
|
||||
#ifdef USE_SOFTSERIAL2
|
||||
SERIAL_PORT_SOFTSERIAL2,
|
||||
#endif
|
||||
};
|
||||
|
||||
const serialPortConstraint_t serialPortConstraints[SERIAL_PORT_COUNT] = {
|
||||
#ifdef USE_VCP
|
||||
{SERIAL_PORT_USB_VCP, 9600, 115200, SPF_NONE },
|
||||
#endif
|
||||
#ifdef USE_USART1
|
||||
{SERIAL_PORT_USART1, 9600, 250000, SPF_SUPPORTS_SBUS_MODE | SPF_SUPPORTS_BIDIR_MODE},
|
||||
#endif
|
||||
#ifdef USE_USART2
|
||||
{SERIAL_PORT_USART2, 9600, 250000, SPF_SUPPORTS_CALLBACK | SPF_SUPPORTS_SBUS_MODE | SPF_SUPPORTS_BIDIR_MODE},
|
||||
#endif
|
||||
#ifdef USE_USART3
|
||||
{SERIAL_PORT_USART3, 9600, 250000, SPF_SUPPORTS_CALLBACK | SPF_SUPPORTS_SBUS_MODE | SPF_SUPPORTS_BIDIR_MODE},
|
||||
#endif
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#ifdef CC3D
|
||||
static serialPortFunction_t serialPortFunctions[SERIAL_PORT_COUNT] = {
|
||||
#ifdef USE_VCP
|
||||
{SERIAL_PORT_USB_VCP, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
#endif
|
||||
{SERIAL_PORT_USART1, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
{SERIAL_PORT_USART3, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
{SERIAL_PORT_SOFTSERIAL1, NULL, SCENARIO_UNUSED, FUNCTION_NONE}
|
||||
};
|
||||
|
||||
const serialPortConstraint_t serialPortConstraints[SERIAL_PORT_COUNT] = {
|
||||
#ifdef USE_VCP
|
||||
{SERIAL_PORT_USB_VCP, 9600, 115200, SPF_NONE },
|
||||
#endif
|
||||
{SERIAL_PORT_USART1, 9600, 250000, SPF_SUPPORTS_CALLBACK | SPF_SUPPORTS_SBUS_MODE | SPF_SUPPORTS_BIDIR_MODE},
|
||||
{SERIAL_PORT_USART3, 9600, 250000, SPF_SUPPORTS_CALLBACK | SPF_SUPPORTS_SBUS_MODE | SPF_SUPPORTS_BIDIR_MODE},
|
||||
{SERIAL_PORT_SOFTSERIAL1, 9600, 19200, SPF_SUPPORTS_CALLBACK | SPF_IS_SOFTWARE_INVERTABLE}
|
||||
};
|
||||
#else
|
||||
|
||||
static serialPortFunction_t serialPortFunctions[SERIAL_PORT_COUNT] = {
|
||||
{SERIAL_PORT_USART1, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
{SERIAL_PORT_USART2, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
#if (SERIAL_PORT_COUNT > 2)
|
||||
{SERIAL_PORT_SOFTSERIAL1, NULL, SCENARIO_UNUSED, FUNCTION_NONE},
|
||||
{SERIAL_PORT_SOFTSERIAL2, NULL, SCENARIO_UNUSED, FUNCTION_NONE}
|
||||
#endif
|
||||
};
|
||||
|
||||
const serialPortConstraint_t serialPortConstraints[SERIAL_PORT_COUNT] = {
|
||||
{SERIAL_PORT_USART1, 9600, 250000, SPF_SUPPORTS_SBUS_MODE | SPF_SUPPORTS_BIDIR_MODE},
|
||||
{SERIAL_PORT_USART2, 9600, 250000, SPF_SUPPORTS_CALLBACK | SPF_SUPPORTS_SBUS_MODE | SPF_SUPPORTS_BIDIR_MODE},
|
||||
#if (SERIAL_PORT_COUNT > 2)
|
||||
{SERIAL_PORT_SOFTSERIAL1, 9600, 19200, SPF_SUPPORTS_CALLBACK | SPF_IS_SOFTWARE_INVERTABLE},
|
||||
{SERIAL_PORT_SOFTSERIAL2, 9600, 19200, SPF_SUPPORTS_CALLBACK | SPF_IS_SOFTWARE_INVERTABLE}
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const functionConstraint_t functionConstraints[] = {
|
||||
{ FUNCTION_CLI, 9600, 115200, NO_AUTOBAUD, SPF_NONE },
|
||||
{ FUNCTION_GPS, 9600, 115200, AUTOBAUD, SPF_NONE },
|
||||
{ FUNCTION_GPS_PASSTHROUGH, 9600, 115200, NO_AUTOBAUD, SPF_NONE },
|
||||
{ FUNCTION_MSP, 9600, 115200, NO_AUTOBAUD, SPF_NONE },
|
||||
{ FUNCTION_SERIAL_RX, 9600, 250000, NO_AUTOBAUD, SPF_SUPPORTS_SBUS_MODE | SPF_SUPPORTS_CALLBACK },
|
||||
{ FUNCTION_TELEMETRY, 9600, 19200, NO_AUTOBAUD, SPF_NONE },
|
||||
{ FUNCTION_SMARTPORT_TELEMETRY, 57600, 57600, NO_AUTOBAUD, SPF_SUPPORTS_BIDIR_MODE },
|
||||
{ FUNCTION_BLACKBOX, 115200,115200, NO_AUTOBAUD, SPF_NONE }
|
||||
};
|
||||
|
||||
#define FUNCTION_CONSTRAINT_COUNT (sizeof(functionConstraints) / sizeof(functionConstraint_t))
|
||||
|
||||
typedef struct serialPortSearchResult_s {
|
||||
serialPortIndex_e portIndex;
|
||||
serialPortFunction_t *portFunction;
|
||||
const serialPortConstraint_t *portConstraint;
|
||||
const functionConstraint_t *functionConstraint;
|
||||
|
||||
// private
|
||||
uint8_t startSerialPortFunctionIndex; // used by findNextSerialPort
|
||||
} serialPortSearchResult_t;
|
||||
|
||||
static const serialPortFunctionList_t serialPortFunctionList = {
|
||||
SERIAL_PORT_COUNT,
|
||||
serialPortFunctions
|
||||
};
|
||||
|
||||
const serialPortFunctionList_t *getSerialPortFunctionList(void)
|
||||
{
|
||||
return &serialPortFunctionList;
|
||||
}
|
||||
|
||||
uint8_t lookupScenarioIndex(serialPortFunctionScenario_e scenario) {
|
||||
uint8_t index;
|
||||
for (index = 0; index < SERIAL_PORT_SCENARIO_COUNT; index++) {
|
||||
if (serialPortScenarios[index] == scenario) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static serialPortIndex_e lookupSerialPortIndexByIdentifier(serialPortIdentifier_e identifier)
|
||||
{
|
||||
serialPortIndex_e portIndex;
|
||||
for (portIndex = 0; portIndex < SERIAL_PORT_COUNT; portIndex++) {
|
||||
if (serialPortConstraints[portIndex].identifier == identifier) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return portIndex;
|
||||
}
|
||||
|
||||
#define IDENTIFIER_NOT_FOUND 0xFF
|
||||
|
||||
static uint8_t lookupSerialPortFunctionIndexByIdentifier(serialPortIdentifier_e identifier)
|
||||
static serialPortUsage_t *findSerialPortUsageByIdentifier(serialPortIdentifier_e identifier)
|
||||
{
|
||||
uint8_t index;
|
||||
for (index = 0; index < SERIAL_PORT_COUNT; index++) {
|
||||
if (serialPortFunctions[index].identifier == identifier) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return IDENTIFIER_NOT_FOUND;
|
||||
}
|
||||
|
||||
static const functionConstraint_t *findFunctionConstraint(serialPortFunction_e function)
|
||||
{
|
||||
const functionConstraint_t *functionConstraint = NULL;
|
||||
uint8_t functionConstraintIndex;
|
||||
|
||||
for (functionConstraintIndex = 0; functionConstraintIndex < FUNCTION_CONSTRAINT_COUNT; functionConstraintIndex++) {
|
||||
functionConstraint = &functionConstraints[functionConstraintIndex];
|
||||
if (functionConstraint->function == function) {
|
||||
return functionConstraint;
|
||||
serialPortUsage_t *candidate = &serialPortUsageList[index];
|
||||
if (candidate->identifier == identifier) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t countBits_uint32(uint32_t n) {
|
||||
uint8_t c; // c accumulates the total bits set in n
|
||||
for (c = 0; n; c++)
|
||||
n &= n - 1; // clear the least significant bit set
|
||||
return c;
|
||||
}
|
||||
static int serialPortFunctionMostSpecificFirstComparator(const void *aPtr, const void *bPtr)
|
||||
{
|
||||
serialPortFunction_t *a = (serialPortFunction_t *)aPtr;
|
||||
serialPortFunction_t *b = (serialPortFunction_t *)bPtr;
|
||||
|
||||
return countBits_uint32(a->scenario) - countBits_uint32(b->scenario);
|
||||
serialPortUsage_t *findSerialPortUsageByPort(serialPort_t *serialPort) {
|
||||
uint8_t index;
|
||||
for (index = 0; index < SERIAL_PORT_COUNT; index++) {
|
||||
serialPortUsage_t *candidate = &serialPortUsageList[index];
|
||||
if (candidate->serialPort == serialPort) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void sortSerialPortFunctions(serialPortFunction_t *serialPortFunctions, uint8_t elements)
|
||||
typedef struct findSerialPortConfigState_s {
|
||||
uint8_t lastIndex;
|
||||
} findSerialPortConfigState_t;
|
||||
|
||||
static findSerialPortConfigState_t findSerialPortConfigState;
|
||||
|
||||
serialPortConfig_t *findSerialPortConfig(serialPortFunction_e function)
|
||||
{
|
||||
serialPortFunction_t swap;
|
||||
memset(&findSerialPortConfigState, 0, sizeof(findSerialPortConfigState));
|
||||
|
||||
int index1;
|
||||
int index2;
|
||||
return findNextSerialPortConfig(function);
|
||||
}
|
||||
|
||||
// bubble-sort array (TODO - port selection can be implemented as repeated minimum search with bitmask marking used elements)
|
||||
for (index1 = 0; index1 < (elements - 1); index1++) {
|
||||
for (index2 = 0; index2 < elements - index1 - 1; index2++) {
|
||||
if(serialPortFunctionMostSpecificFirstComparator(&serialPortFunctions[index2], &serialPortFunctions[index2 + 1]) > 0) {
|
||||
swap = serialPortFunctions[index2];
|
||||
serialPortFunctions[index2] = serialPortFunctions[index2 + 1];
|
||||
serialPortFunctions[index2 + 1] = swap;
|
||||
serialPortConfig_t *findNextSerialPortConfig(serialPortFunction_e function)
|
||||
{
|
||||
while (findSerialPortConfigState.lastIndex < SERIAL_PORT_COUNT) {
|
||||
serialPortConfig_t *candidate = &serialConfig->portConfigs[findSerialPortConfigState.lastIndex++];
|
||||
|
||||
if (candidate->functionMask & function) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct findSharedSerialPortState_s {
|
||||
uint8_t lastIndex;
|
||||
} findSharedSerialPortState_t;
|
||||
|
||||
static findSharedSerialPortState_t findSharedSerialPortState;
|
||||
|
||||
serialPort_t *findSharedSerialPort(uint16_t functionMask, serialPortFunction_e sharedWithFunction)
|
||||
{
|
||||
memset(&findSharedSerialPortState, 0, sizeof(findSharedSerialPortState));
|
||||
|
||||
return findNextSharedSerialPort(functionMask, sharedWithFunction);
|
||||
}
|
||||
|
||||
serialPort_t *findNextSharedSerialPort(uint16_t functionMask, serialPortFunction_e sharedWithFunction)
|
||||
{
|
||||
while (findSharedSerialPortState.lastIndex < SERIAL_PORT_COUNT) {
|
||||
serialPortConfig_t *candidate = &serialConfig->portConfigs[findSharedSerialPortState.lastIndex++];
|
||||
|
||||
if ((candidate->functionMask & sharedWithFunction) && (candidate->functionMask & functionMask)) {
|
||||
serialPortUsage_t *serialPortUsage = findSerialPortUsageByIdentifier(candidate->identifier);
|
||||
if (!serialPortUsage) {
|
||||
continue;
|
||||
}
|
||||
return serialPortUsage->serialPort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serialPortSearchResult_t *findNextSerialPort(serialPortFunction_e function, const functionConstraint_t *functionConstraint, serialPortSearchResult_t *resultBuffer)
|
||||
{
|
||||
uint8_t serialPortFunctionIndex;
|
||||
serialPortFunction_t *serialPortFunction;
|
||||
for (serialPortFunctionIndex = resultBuffer->startSerialPortFunctionIndex; serialPortFunctionIndex < SERIAL_PORT_COUNT; serialPortFunctionIndex++) {
|
||||
serialPortFunction = &serialPortFunctions[serialPortFunctionIndex];
|
||||
|
||||
if (!(serialPortFunction->scenario & function)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t serialPortIndex = lookupSerialPortIndexByIdentifier(serialPortFunction->identifier);
|
||||
const serialPortConstraint_t *serialPortConstraint = &serialPortConstraints[serialPortIndex];
|
||||
|
||||
#if defined(CC3D)
|
||||
if (!feature(FEATURE_SOFTSERIAL) && (
|
||||
serialPortConstraint->identifier == SERIAL_PORT_SOFTSERIAL1)) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
#if defined(USE_SOFTSERIAL1) ||(defined(USE_SOFTSERIAL2))
|
||||
if (!feature(FEATURE_SOFTSERIAL) && (
|
||||
serialPortConstraint->identifier == SERIAL_PORT_SOFTSERIAL1 ||
|
||||
serialPortConstraint->identifier == SERIAL_PORT_SOFTSERIAL2
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#if (defined(NAZE) || defined(OLIMEXINO)) && defined(SONAR)
|
||||
if (feature(FEATURE_SONAR) && !feature(FEATURE_RX_PARALLEL_PWM) && (serialPortConstraint->identifier == SERIAL_PORT_SOFTSERIAL2)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if ((serialPortConstraint->feature & functionConstraint->requiredSerialPortFeatures) != functionConstraint->requiredSerialPortFeatures) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (functionConstraint->minBaudRate < serialPortConstraint->minBaudRate || functionConstraint->maxBaudRate > serialPortConstraint->maxBaudRate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
resultBuffer->portIndex = serialPortIndex;
|
||||
resultBuffer->portConstraint = serialPortConstraint;
|
||||
resultBuffer->portFunction = serialPortFunction;
|
||||
resultBuffer->functionConstraint = functionConstraint;
|
||||
|
||||
uint8_t nextStartIndex = serialPortFunctionIndex + 1;
|
||||
resultBuffer->startSerialPortFunctionIndex = nextStartIndex;
|
||||
|
||||
return resultBuffer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* since this method, and other methods that use it, use a single instance of
|
||||
* searchPortSearchResult be sure to copy the data out of it before it gets overwritten by another caller.
|
||||
* If this becomes a problem perhaps change the implementation to use a destination argument.
|
||||
*/
|
||||
static serialPortSearchResult_t *findSerialPort(serialPortFunction_e function, const functionConstraint_t *functionConstraint)
|
||||
{
|
||||
static serialPortSearchResult_t serialPortSearchResult;
|
||||
|
||||
memset(&serialPortSearchResult, 0, sizeof(serialPortSearchResult));
|
||||
|
||||
// FIXME this only needs to be done once, after the config has been loaded.
|
||||
sortSerialPortFunctions(serialPortFunctions, SERIAL_PORT_COUNT);
|
||||
|
||||
return findNextSerialPort(function, functionConstraint, &serialPortSearchResult);
|
||||
}
|
||||
|
||||
|
||||
static serialPortFunction_t *findSerialPortFunction(uint16_t functionMask)
|
||||
{
|
||||
serialPortIndex_e portIndex;
|
||||
|
||||
// find exact match first
|
||||
for (portIndex = 0; portIndex < SERIAL_PORT_COUNT; portIndex++) {
|
||||
serialPortFunction_t *serialPortFunction = &serialPortFunctions[portIndex];
|
||||
if (serialPortFunction->scenario == functionMask) {
|
||||
return serialPortFunction;
|
||||
}
|
||||
}
|
||||
|
||||
// find the first port that supports the function requested
|
||||
for (portIndex = 0; portIndex < SERIAL_PORT_COUNT; portIndex++) {
|
||||
serialPortFunction_t *serialPortFunction = &serialPortFunctions[portIndex];
|
||||
if (serialPortFunction->scenario & functionMask) {
|
||||
return serialPortFunction;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* find a serial port that is:
|
||||
* a) open
|
||||
* b) matches the function mask exactly, or if an exact match is not found the first port that supports the function
|
||||
*/
|
||||
serialPort_t *findOpenSerialPort(uint16_t functionMask)
|
||||
{
|
||||
serialPortFunction_t *function = findSerialPortFunction(functionMask);
|
||||
if (!function) {
|
||||
return NULL;
|
||||
}
|
||||
return function->port;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static serialPortFunction_t * findSerialPortFunctionByPort(serialPort_t *port)
|
||||
{
|
||||
serialPortFunction_t *serialPortFunction;
|
||||
uint8_t functionIndex;
|
||||
|
||||
for (functionIndex = 0; functionIndex < SERIAL_PORT_COUNT; functionIndex++) {
|
||||
serialPortFunction = &serialPortFunctions[functionIndex];
|
||||
if (serialPortFunction->port == port) {
|
||||
return serialPortFunction;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void beginSerialPortFunction(serialPort_t *port, serialPortFunction_e function)
|
||||
{
|
||||
serialPortFunction_t *serialPortFunction = findSerialPortFunctionByPort(port);
|
||||
|
||||
serialPortFunction->currentFunction = function;
|
||||
}
|
||||
|
||||
void endSerialPortFunction(serialPort_t *port, serialPortFunction_e function)
|
||||
{
|
||||
UNUSED(function);
|
||||
serialPortFunction_t *serialPortFunction = findSerialPortFunctionByPort(port);
|
||||
|
||||
serialPortFunction->currentFunction = FUNCTION_NONE;
|
||||
serialPortFunction->port = NULL;
|
||||
}
|
||||
|
||||
functionConstraint_t *getConfiguredFunctionConstraint(serialPortFunction_e function)
|
||||
{
|
||||
static functionConstraint_t configuredFunctionConstraint;
|
||||
const functionConstraint_t *functionConstraint;
|
||||
|
||||
functionConstraint = findFunctionConstraint(function);
|
||||
if (!functionConstraint) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(&configuredFunctionConstraint, functionConstraint, sizeof(functionConstraint_t));
|
||||
|
||||
switch(function) {
|
||||
case FUNCTION_MSP:
|
||||
configuredFunctionConstraint.maxBaudRate = serialConfig->msp_baudrate;
|
||||
break;
|
||||
|
||||
case FUNCTION_CLI:
|
||||
configuredFunctionConstraint.minBaudRate = serialConfig->cli_baudrate;
|
||||
configuredFunctionConstraint.maxBaudRate = configuredFunctionConstraint.minBaudRate;
|
||||
break;
|
||||
|
||||
case FUNCTION_GPS_PASSTHROUGH:
|
||||
configuredFunctionConstraint.minBaudRate = serialConfig->gps_passthrough_baudrate;
|
||||
configuredFunctionConstraint.maxBaudRate = configuredFunctionConstraint.minBaudRate;
|
||||
break;
|
||||
|
||||
#ifdef TELEMETRY
|
||||
case FUNCTION_TELEMETRY:
|
||||
case FUNCTION_SMARTPORT_TELEMETRY:
|
||||
configuredFunctionConstraint.minBaudRate = getTelemetryProviderBaudRate();
|
||||
configuredFunctionConstraint.maxBaudRate = configuredFunctionConstraint.minBaudRate;
|
||||
break;
|
||||
#endif
|
||||
#ifdef SERIAL_RX
|
||||
case FUNCTION_SERIAL_RX:
|
||||
updateSerialRxFunctionConstraint(&configuredFunctionConstraint);
|
||||
break;
|
||||
#endif
|
||||
case FUNCTION_GPS:
|
||||
configuredFunctionConstraint.maxBaudRate = serialConfig->gps_baudrate;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return &configuredFunctionConstraint;
|
||||
}
|
||||
|
||||
bool isSerialConfigValid(serialConfig_t *serialConfigToCheck)
|
||||
{
|
||||
serialPortSearchResult_t *searchResult;
|
||||
functionConstraint_t *functionConstraint;
|
||||
|
||||
serialConfig = serialConfigToCheck;
|
||||
|
||||
functionConstraint = getConfiguredFunctionConstraint(FUNCTION_MSP);
|
||||
searchResult = findSerialPort(FUNCTION_MSP, functionConstraint);
|
||||
if (!searchResult) {
|
||||
return false;
|
||||
}
|
||||
|
||||
functionConstraint = getConfiguredFunctionConstraint(FUNCTION_CLI);
|
||||
searchResult = findSerialPort(FUNCTION_CLI, functionConstraint);
|
||||
if (!searchResult) {
|
||||
return false;
|
||||
}
|
||||
|
||||
functionConstraint = getConfiguredFunctionConstraint(FUNCTION_GPS);
|
||||
searchResult = findSerialPort(FUNCTION_GPS, functionConstraint);
|
||||
if (feature(FEATURE_GPS) && !searchResult) {
|
||||
return false;
|
||||
}
|
||||
|
||||
functionConstraint = getConfiguredFunctionConstraint(FUNCTION_SERIAL_RX);
|
||||
searchResult = findSerialPort(FUNCTION_SERIAL_RX, functionConstraint);
|
||||
if (feature(FEATURE_RX_SERIAL) && !searchResult) {
|
||||
return false;
|
||||
}
|
||||
|
||||
functionConstraint = getConfiguredFunctionConstraint(FUNCTION_TELEMETRY);
|
||||
searchResult = findSerialPort(FUNCTION_TELEMETRY, functionConstraint);
|
||||
// TODO check explicitly for SmartPort config
|
||||
if (!searchResult) {
|
||||
functionConstraint = getConfiguredFunctionConstraint(FUNCTION_SMARTPORT_TELEMETRY);
|
||||
searchResult = findSerialPort(FUNCTION_SMARTPORT_TELEMETRY, functionConstraint);
|
||||
}
|
||||
if (feature(FEATURE_TELEMETRY) && !searchResult) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t functionIndex;
|
||||
uint8_t cliPortCount = 0;
|
||||
uint8_t mspPortCount = 0;
|
||||
for (functionIndex = 0; functionIndex < SERIAL_PORT_COUNT; functionIndex++) {
|
||||
if (serialPortFunctions[functionIndex].scenario & FUNCTION_CLI) {
|
||||
if (++cliPortCount > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (serialPortFunctions[functionIndex].scenario & FUNCTION_MSP) {
|
||||
if (++mspPortCount > MAX_MSP_PORT_COUNT) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
UNUSED(serialConfigToCheck);
|
||||
return true; // FIXME implement rules - 1 MSP port minimum.
|
||||
}
|
||||
|
||||
bool doesConfigurationUsePort(serialPortIdentifier_e portIdentifier)
|
||||
bool doesConfigurationUsePort(serialPortIdentifier_e identifier)
|
||||
{
|
||||
serialPortSearchResult_t *searchResult;
|
||||
const functionConstraint_t *functionConstraint;
|
||||
serialPortFunction_e function;
|
||||
|
||||
uint8_t index;
|
||||
for (index = 0; index < FUNCTION_CONSTRAINT_COUNT; index++) {
|
||||
function = functionConstraints[index].function;
|
||||
functionConstraint = findFunctionConstraint(function);
|
||||
searchResult = findSerialPort(function, functionConstraint);
|
||||
if (searchResult->portConstraint->identifier == portIdentifier) {
|
||||
for (index = 0; index < SERIAL_PORT_COUNT; index++) {
|
||||
serialPortConfig_t *candidate = &serialConfig->portConfigs[index];
|
||||
if (candidate->identifier == identifier && candidate->functionMask) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool canOpenSerialPort(serialPortFunction_e function)
|
||||
serialPort_t *openSerialPort(
|
||||
serialPortIdentifier_e identifier,
|
||||
serialPortFunction_e function,
|
||||
serialReceiveCallbackPtr callback,
|
||||
uint32_t baudRate,
|
||||
portMode_t mode,
|
||||
serialInversion_e inversion)
|
||||
{
|
||||
functionConstraint_t *functionConstraint = getConfiguredFunctionConstraint(function);
|
||||
|
||||
serialPortSearchResult_t *result = findSerialPort(function, functionConstraint);
|
||||
return result != NULL;
|
||||
}
|
||||
|
||||
bool isSerialPortFunctionShared(serialPortFunction_e functionToUse, uint16_t functionMask)
|
||||
{
|
||||
functionConstraint_t *functionConstraint = getConfiguredFunctionConstraint(functionToUse);
|
||||
serialPortSearchResult_t *result = findSerialPort(functionToUse, functionConstraint);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return result->portFunction->scenario & functionMask;
|
||||
}
|
||||
|
||||
serialPort_t *findSharedSerialPort(serialPortFunction_e functionToUse, uint16_t functionMask)
|
||||
{
|
||||
functionConstraint_t *functionConstraint = getConfiguredFunctionConstraint(functionToUse);
|
||||
serialPortSearchResult_t *result = findSerialPort(functionToUse, functionConstraint);
|
||||
|
||||
if (result->portFunction->scenario & functionMask) {
|
||||
return result->portFunction->port;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void applySerialConfigToPortFunctions(serialConfig_t *serialConfig)
|
||||
{
|
||||
uint32_t portIndex = 0, serialPortIdentifier, constraintIndex;
|
||||
|
||||
for (constraintIndex = 0; constraintIndex < SERIAL_PORT_COUNT && portIndex < SERIAL_PORT_COUNT; constraintIndex++) {
|
||||
serialPortIdentifier = serialPortConstraints[constraintIndex].identifier;
|
||||
uint32_t functionIndex = lookupSerialPortFunctionIndexByIdentifier(serialPortIdentifier);
|
||||
if (functionIndex == IDENTIFIER_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
serialPortFunctions[functionIndex].scenario = serialPortScenarios[serialConfig->serial_port_scenario[portIndex++]];
|
||||
}
|
||||
}
|
||||
|
||||
serialPort_t *openSerialPort(serialPortFunction_e function, serialReceiveCallbackPtr callback, uint32_t baudRate, portMode_t mode, serialInversion_e inversion)
|
||||
{
|
||||
serialPort_t *serialPort = NULL;
|
||||
|
||||
functionConstraint_t *initialFunctionConstraint = getConfiguredFunctionConstraint(function);
|
||||
|
||||
functionConstraint_t updatedFunctionConstraint;
|
||||
memcpy(&updatedFunctionConstraint, initialFunctionConstraint, sizeof(updatedFunctionConstraint));
|
||||
if (initialFunctionConstraint->autoBaud == NO_AUTOBAUD) {
|
||||
updatedFunctionConstraint.minBaudRate = baudRate;
|
||||
updatedFunctionConstraint.maxBaudRate = baudRate;
|
||||
}
|
||||
functionConstraint_t *functionConstraint = &updatedFunctionConstraint;
|
||||
|
||||
serialPortSearchResult_t *searchResult = findSerialPort(function, functionConstraint);
|
||||
|
||||
while(searchResult && searchResult->portFunction->port) {
|
||||
// port is already open, find the next one
|
||||
searchResult = findNextSerialPort(function, functionConstraint, searchResult);
|
||||
}
|
||||
|
||||
if (!searchResult) {
|
||||
serialPortUsage_t *serialPortUsage = findSerialPortUsageByIdentifier(identifier);
|
||||
if (serialPortUsage->function != FUNCTION_NONE) {
|
||||
// already in use
|
||||
return NULL;
|
||||
}
|
||||
|
||||
serialPortIndex_e portIndex = searchResult->portIndex;
|
||||
serialPort_t *serialPort = NULL;
|
||||
|
||||
const serialPortConstraint_t *serialPortConstraint = searchResult->portConstraint;
|
||||
|
||||
serialPortIdentifier_e identifier = serialPortConstraint->identifier;
|
||||
switch(identifier) {
|
||||
#ifdef USE_VCP
|
||||
case SERIAL_PORT_USB_VCP:
|
||||
|
@ -644,32 +220,36 @@ serialPort_t *openSerialPort(serialPortFunction_e function, serialReceiveCallbac
|
|||
|
||||
serialPort->identifier = identifier;
|
||||
|
||||
serialPorts[portIndex] = serialPort;
|
||||
|
||||
serialPortFunction_t *serialPortFunction = searchResult->portFunction;
|
||||
|
||||
serialPortFunction->port = serialPort;
|
||||
//serialPortFunction->identifier = identifier;
|
||||
|
||||
beginSerialPortFunction(serialPort, function);
|
||||
serialPortUsage->function = function;
|
||||
serialPortUsage->serialPort = serialPort;
|
||||
|
||||
return serialPort;
|
||||
}
|
||||
|
||||
void closeSerialPort(serialPort_t *serialPort) {
|
||||
serialPortUsage_t *serialPortUsage = findSerialPortUsageByPort(serialPort);
|
||||
if (!serialPortUsage) {
|
||||
// already closed
|
||||
return;
|
||||
}
|
||||
|
||||
serialPort->callback = NULL;
|
||||
|
||||
serialPortUsage->function = FUNCTION_NONE;
|
||||
serialPortUsage->serialPort = NULL;
|
||||
}
|
||||
|
||||
void serialInit(serialConfig_t *initialSerialConfig)
|
||||
{
|
||||
uint8_t index;
|
||||
|
||||
serialConfig = initialSerialConfig;
|
||||
applySerialConfigToPortFunctions(serialConfig);
|
||||
|
||||
#ifdef TELEMETRY
|
||||
if (telemetryAllowsOtherSerial(FUNCTION_MSP))
|
||||
#endif
|
||||
mspInit(serialConfig);
|
||||
memset(&serialPortUsageList, 0, sizeof(serialPortUsageList));
|
||||
|
||||
#ifdef TELEMETRY
|
||||
if (telemetryAllowsOtherSerial(FUNCTION_CLI))
|
||||
#endif
|
||||
cliInit(serialConfig);
|
||||
for (index = 0; index < SERIAL_PORT_COUNT; index++) {
|
||||
serialPortUsageList[index].identifier = serialPortIdentifiers[index];
|
||||
}
|
||||
}
|
||||
|
||||
void handleSerial(void)
|
||||
|
@ -680,10 +260,7 @@ void handleSerial(void)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef TELEMETRY
|
||||
if (telemetryAllowsOtherSerial(FUNCTION_MSP))
|
||||
#endif
|
||||
mspProcess();
|
||||
mspProcess();
|
||||
}
|
||||
|
||||
void waitForSerialPortToFinishTransmitting(serialPort_t *serialPort)
|
||||
|
@ -693,12 +270,14 @@ void waitForSerialPortToFinishTransmitting(serialPort_t *serialPort)
|
|||
};
|
||||
}
|
||||
|
||||
// evaluate all other incoming serial data
|
||||
void evaluateOtherData(uint8_t sr)
|
||||
void cliEnter(serialPort_t *serialPort);
|
||||
|
||||
void evaluateOtherData(serialPort_t *serialPort, uint8_t receivedChar)
|
||||
{
|
||||
if (sr == '#')
|
||||
cliProcess();
|
||||
else if (sr == serialConfig->reboot_character)
|
||||
if (receivedChar == '#') {
|
||||
cliEnter(serialPort);
|
||||
} else if (receivedChar == serialConfig->reboot_character) {
|
||||
systemResetToBootloader();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue