feat: Automatic soft-serial fallback for module ports (#3823)

This commit is contained in:
Raphael Coeffic
2023-10-07 12:23:51 +10:00
committed by GitHub
parent 1e925edf4a
commit 3cbcc6b7bf
17 changed files with 130 additions and 83 deletions
+1 -1
View File
@@ -1121,7 +1121,7 @@ int cliSerialPassthrough(const char **argv)
params.baudrate = baudrate;
spInternalModuleState = modulePortInitSerial(port_n, ETX_MOD_PORT_UART,
&params);
&params, false);
auto drv = modulePortGetSerialDrv(spInternalModuleState->rx);
auto ctx = modulePortGetCtx(spInternalModuleState->rx);
+38 -18
View File
@@ -95,8 +95,36 @@ static void _init_timer_driver(etx_module_driver_t* d, const etx_module_port_t*
}
}
static bool _match_port(const etx_module_port_t* p, uint8_t type, uint8_t port,
uint8_t polarity, bool softserial_fallback)
{
if (p->type == type && p->port == port) {
// either polarity matches or can be set
if (polarity != ETX_Pol_Inverted ||
p->set_inverted ||
port == ETX_MOD_PORT_SOFT_INV ||
port == ETX_MOD_PORT_SPORT_INV) {
return true;
}
}
// soft-serial fallback (1. USART -> 2. SOFT-SERIAL)
if (softserial_fallback && polarity == ETX_Pol_Inverted) {
if (port == ETX_MOD_PORT_UART && p->port == ETX_MOD_PORT_SOFT_INV) {
return true;
}
if (port == ETX_MOD_PORT_SPORT && p->port == ETX_MOD_PORT_SPORT_INV) {
return true;
}
}
return false;
}
static const etx_module_port_t* _find_port(uint8_t module, uint8_t type,
uint8_t port, uint8_t polarity)
uint8_t port, uint8_t polarity,
bool softserial_fallback)
{
if (module >= MAX_MODULES || module >= _n_modules || !_modules[module])
return nullptr;
@@ -107,18 +135,9 @@ static const etx_module_port_t* _find_port(uint8_t module, uint8_t type,
while(n_ports > 0) {
if (p->type == type && p->port == port) {
// skip the port if polarity does not match
// and cannot be set
if (polarity != ETX_Pol_Inverted ||
p->set_inverted ||
port == ETX_MOD_PORT_SOFT_INV ||
port == ETX_MOD_PORT_SPORT_INV) {
found_port = p;
break;
}
if (_match_port(p, type, port, polarity, softserial_fallback)) {
found_port = p;
break;
}
++p; --n_ports;
@@ -146,7 +165,7 @@ const etx_module_t* modulePortGetModuleDescription(uint8_t module)
const etx_module_port_t* modulePortFind(uint8_t module, uint8_t type,
uint8_t port, uint8_t polarity)
{
return _find_port(module, type, port, polarity);
return _find_port(module, type, port, polarity, false);
}
void modulePortSetPower(uint8_t module, uint8_t enable)
@@ -170,11 +189,12 @@ bool modulePortPowered(uint8_t module)
}
etx_module_state_t* modulePortInitSerial(uint8_t module, uint8_t port,
const etx_serial_init* params)
const etx_serial_init* params,
bool softserial_fallback)
{
// TODO: match capabilities (1. USART -> 2. SOFT-SERIAL)
const etx_module_port_t* found_port = _find_port(module, ETX_MOD_TYPE_SERIAL,
port, params->polarity);
port, params->polarity,
softserial_fallback);
if (!found_port) return nullptr;
auto state = &(_module_states[module]);
@@ -206,7 +226,7 @@ etx_module_state_t* modulePortInitTimer(uint8_t module, uint8_t port,
const etx_timer_config_t* cfg)
{
const etx_module_port_t* found_port = _find_port(module, ETX_MOD_TYPE_TIMER,
port, ETX_Pol_Normal);
port, ETX_Pol_Normal, false);
if (!found_port) return nullptr;
auto state = &(_module_states[module]);
+2 -1
View File
@@ -126,7 +126,8 @@ bool modulePortPowered(uint8_t module);
// Init module port with params (driver & context stored locally)
etx_module_state_t* modulePortInitSerial(uint8_t module, uint8_t port,
const etx_serial_init* params);
const etx_serial_init* params,
bool softserial_fallback);
// Init module port with params (driver & context stored locally)
etx_module_state_t* modulePortInitTimer(uint8_t module, uint8_t port,
+1 -1
View File
@@ -343,7 +343,7 @@ const char *FrskyDeviceFirmwareUpdate::doFlashFirmware(
//
uint8_t serial_module = module != SPORT_MODULE ? module : EXTERNAL_MODULE;
mod_st = modulePortInitSerial(serial_module, port, &cfg);
mod_st = modulePortInitSerial(serial_module, port, &cfg, false);
if (!mod_st) return "Communication port error";
// assume RX port is the same as TX
+8 -14
View File
@@ -90,31 +90,25 @@ bool MultiFirmwareUpdateDriver::init()
{
if (type == MULTI_TYPE_MULTIMODULE && module == INTERNAL_MODULE) {
// duplex internal USART
mod_st = modulePortInitSerial(INTERNAL_MODULE, ETX_MOD_PORT_UART, &serialInitParams);
mod_st = modulePortInitSerial(INTERNAL_MODULE, ETX_MOD_PORT_UART, &serialInitParams, false);
} else if (type == MULTI_TYPE_MULTIMODULE && module == EXTERNAL_MODULE) {
// TX on PPM (inverted softserial)
etx_serial_init params(serialInitParams);
params.direction = ETX_Dir_TX;
params.polarity = ETX_Pol_Inverted;
mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_UART, &params);
if (!mod_st) {
params.polarity = ETX_Pol_Inverted;
mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SOFT_INV, &params);
if (!mod_st) return false;
}
mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_UART, &params, true);
if (!mod_st) return false;
// RX on S.PORT (inverted softserial)
params.direction = ETX_Dir_RX;
params.polarity = ETX_Pol_Inverted;
if (!modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT, &params)) {
params.polarity = ETX_Pol_Inverted;
if (!modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT_INV, &params)) {
modulePortDeInit(mod_st);
return false;
}
if (!modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT, &params, true)) {
modulePortDeInit(mod_st);
return false;
}
} else if (type == MULTI_TYPE_ELRS && module == EXTERNAL_MODULE) {
// half-duplex on S.PORT USART
mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT, &serialInitParams);
mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT, &serialInitParams, false);
}
if (!mod_st) return false;
+1 -1
View File
@@ -44,7 +44,7 @@ static void* afhds2Init(uint8_t module)
// serial port setup
resetPulsesAFHDS2();
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART,
&afhds2SerialInitParams);
&afhds2SerialInitParams, false);
// mixer setup
mixerSchedulerSetPeriod(module, AFHDS2_PERIOD);
+3 -3
View File
@@ -1110,13 +1110,13 @@ static void* initModule(uint8_t module)
params.baudrate = AFHDS3_UART_BAUDRATE;
params.polarity =
module == INTERNAL_MODULE ? ETX_Pol_Normal : ETX_Pol_Inverted;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params, false);
#if defined(CONFIGURABLE_MODULE_PORT)
if (!mod_st && module == EXTERNAL_MODULE) {
// Try Connect using aux serial mod
params.polarity = ETX_Pol_Normal;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params, false);
}
#endif
@@ -1125,7 +1125,7 @@ static void* initModule(uint8_t module)
params.baudrate = AFHDS3_SOFTSERIAL_BAUDRATE;
params.direction = ETX_Dir_TX;
period = AFHDS3_SOFTSERIAL_COMMAND_TIMEOUT * 1000 /* us */;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &params);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &params, false);
// TODO: telemetry RX ???
}
+2 -2
View File
@@ -226,7 +226,7 @@ static void* crossfireInit(uint8_t module)
if (module == INTERNAL_MODULE) {
params.baudrate = INT_CROSSFIRE_BAUDRATE;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params, false);
}
#endif
@@ -234,7 +234,7 @@ static void* crossfireInit(uint8_t module)
if (module == EXTERNAL_MODULE) {
params.baudrate = EXT_CROSSFIRE_BAUDRATE;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &params);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &params, false);
}
#endif
+3 -10
View File
@@ -203,19 +203,12 @@ static etx_module_state_t* dsmInit(uint8_t module, uint32_t baudrate,
etx_serial_init params(dsmUartParams);
params.baudrate = baudrate;
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params);
if (!mod_st) {
// inverted soft-serial fallback
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &params);
if (!mod_st) return nullptr;
}
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params, true);
if (!mod_st) return nullptr;
if (telemetry) {
params.direction = ETX_Dir_RX;
if (!modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &params)) {
// inverted soft-serial fallback
modulePortInitSerial(module, ETX_MOD_PORT_SPORT_INV, &params);
}
modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &params, true);
}
mixerSchedulerSetPeriod(module, period);
+1 -1
View File
@@ -163,7 +163,7 @@ static const etx_serial_init ghostSerialParams = {
static void* ghostInit(uint8_t module)
{
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &ghostSerialParams);
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &ghostSerialParams, false);
if (!mod_st) return nullptr;
mixerSchedulerSetPeriod(module, GHOST_PERIOD);
+3 -8
View File
@@ -210,7 +210,7 @@ static void* multiInit(uint8_t module)
// serial port setup
// TODO: error handling
cfg.direction = ETX_Dir_TX_RX;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &cfg);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &cfg, false);
}
#endif
@@ -219,19 +219,14 @@ static void* multiInit(uint8_t module)
// serial port setup
cfg.direction = ETX_Dir_TX;
cfg.polarity = ETX_Pol_Inverted;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &cfg);
if (!mod_st) {
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &cfg);
}
// no TX port: bail out
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &cfg, true);
if (!mod_st) return nullptr;
// Init S.PORT RX channel
cfg.direction = ETX_Dir_RX;
cfg.polarity = ETX_Pol_Normal;
modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &cfg);
modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &cfg, false);
}
#endif
+1 -6
View File
@@ -111,12 +111,7 @@ static etx_serial_init ppmMLinkSerialParams = {
static bool ppmInitMLinkTelemetry(uint8_t module)
{
// Try S.PORT hardware USART (requires HW inverters)
if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &ppmMLinkSerialParams) != nullptr) {
return true;
}
// fall-back to softserial
if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT_INV, &ppmMLinkSerialParams) != nullptr) {
if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &ppmMLinkSerialParams, true) != nullptr) {
return true;
}
+5 -5
View File
@@ -285,13 +285,13 @@ static void* pxx1Init(uint8_t module)
if (module == INTERNAL_MODULE) {
txCfg.baudrate = _pxx1_internal_baudrate;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &txCfg);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &txCfg, false);
if (!mod_st) {
// assume that radios that don't have an internal UART
// will have a module that uses legacy PXX1 (PWM)
txCfg.encoding = ETX_Encoding_PXX1_PWM;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &txCfg);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &txCfg, false);
}
if (!mod_st) return nullptr;
@@ -305,14 +305,14 @@ static void* pxx1Init(uint8_t module)
case MODULE_TYPE_R9M_LITE_PXX1: {
txCfg.baudrate = EXTMODULE_PXX1_SERIAL_BAUDRATE;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &txCfg);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &txCfg, false);
if (!mod_st) return nullptr;
} break;
case MODULE_TYPE_XJT_PXX1:
case MODULE_TYPE_R9M_PXX1: {
txCfg.encoding = ETX_Encoding_PXX1_PWM;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &txCfg);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &txCfg, false);
if (!mod_st) return nullptr;
} break;
@@ -328,7 +328,7 @@ static void* pxx1Init(uint8_t module)
rxCfg.direction = ETX_Dir_TX_RX;
// TODO: handle init errors properly
if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &rxCfg) != nullptr) {
if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &rxCfg, false) != nullptr) {
auto drv = modulePortGetSerialDrv(mod_st->rx);
auto ctx = modulePortGetCtx(mod_st->rx);
if (drv && ctx && drv->setIdleCb) {
+2 -2
View File
@@ -640,7 +640,7 @@ static void* pxx2Init(uint8_t module)
if (module == INTERNAL_MODULE) {
params.baudrate = PXX2_HIGHSPEED_BAUDRATE;
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params, false);
if (!mod_st) return nullptr;
resetAccessAuthenticationCount();
}
@@ -665,7 +665,7 @@ static void* pxx2Init(uint8_t module)
return nullptr;
}
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params);
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params, false);
if (!mod_st) return nullptr;
}
+8 -9
View File
@@ -21,6 +21,7 @@
#include "sbus.h"
#include "hal/module_port.h"
#include "hal/serial_driver.h"
#include "mixer_scheduler.h"
#include "opentx.h"
@@ -96,7 +97,7 @@ const etx_serial_init sbusUartParams = {
.baudrate = SBUS_BAUDRATE,
.encoding = ETX_Encoding_8E2,
.direction = ETX_Dir_TX,
.polarity = ETX_Pol_Normal,
.polarity = ETX_Pol_Inverted,
};
static void* sbusInit(uint8_t module)
@@ -106,13 +107,8 @@ static void* sbusInit(uint8_t module)
if (module == INTERNAL_MODULE) return nullptr;
#endif
// auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &sbusUartParams);
// TODO: check if inverter is there, or mandate it somehow...
// if (!mod_st) {
// -> SOFT_INV has 'setPolarity'
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &sbusUartParams);
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &sbusUartParams, true);
if (!mod_st) return nullptr;
// }
mixerSchedulerSetPeriod(module, SBUS_PERIOD(module));
return (void*)mod_st;
@@ -139,9 +135,12 @@ static void sbusSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_
auto drv = modulePortGetSerialDrv(mod_st->tx);
auto drv_ctx = modulePortGetCtx(mod_st->tx);
// TODO: check if the port has an inverter and use it instead
if(drv->setPolarity)
auto port = mod_st->tx.port;
if (port && port->set_inverted) {
port->set_inverted(GET_SBUS_POLARITY(module));
} else if (drv->setPolarity) {
drv->setPolarity(drv_ctx, GET_SBUS_POLARITY(module));
}
drv->sendBuffer(drv_ctx, buffer, p_data - buffer);
@@ -364,7 +364,7 @@ void init_trainer_module_sbus()
if (sbus_trainer_mod_st) return;
sbus_trainer_mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_UART,
&sbusTrainerParams);
&sbusTrainerParams, false);
}
void stop_trainer_module_sbus()
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program 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.
*/
#include "gtests.h"
#include "hal/module_port.h"
TEST(ports, softserialFallback)
{
modulePortInit();
const etx_serial_init serialCfg = {
.baudrate = 57600,
.encoding = ETX_Encoding_8N1,
.direction = ETX_Dir_RX,
.polarity = ETX_Pol_Inverted,
};
bool has_softserial = modulePortFind(EXTERNAL_MODULE, ETX_MOD_TYPE_SERIAL,
ETX_MOD_PORT_SPORT_INV, ETX_Pol_Inverted);
if (has_softserial) {
auto mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT,
&serialCfg, false);
EXPECT_TRUE(mod_st == nullptr);
mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT,
&serialCfg, true);
EXPECT_TRUE(mod_st != nullptr);
if (!mod_st) return;
modulePortDeInit(mod_st);
}
}