fix: Internal PXX exclusive S.PORT (#3822)
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include "mixer_scheduler.h"
|
||||
#include "hal/adc_driver.h"
|
||||
#include "hal/switch_driver.h"
|
||||
#include "hal/module_port.h"
|
||||
#include "switches.h"
|
||||
|
||||
#if defined(USBJ_EX)
|
||||
@@ -1972,10 +1973,11 @@ void menuModelSetup(event_t event)
|
||||
#endif
|
||||
if (isModuleR9MNonAccess(moduleIdx)) {
|
||||
lcdDrawTextAlignedLeft(y, STR_MODULE_TELEMETRY);
|
||||
if (isSportLineUsedByInternalModule())
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_DISABLE_INTERNAL);
|
||||
else
|
||||
if (modulePortIsPortUsedByModule(moduleIdx, ETX_MOD_PORT_SPORT)) {
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_MODULE_TELEM_ON);
|
||||
} else {
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_DISABLE_INTERNAL);
|
||||
}
|
||||
}
|
||||
else if (isModuleSBUS(moduleIdx)) {
|
||||
lcdDrawTextAlignedLeft(y, STR_WARN_BATTVOLTAGE);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "hal/adc_driver.h"
|
||||
#include "hal/adc_driver.h"
|
||||
#include "hal/switch_driver.h"
|
||||
#include "hal/module_port.h"
|
||||
|
||||
#include "opentx.h"
|
||||
#include "mixer_scheduler.h"
|
||||
@@ -1739,11 +1740,11 @@ void menuModelSetup(event_t event)
|
||||
#endif
|
||||
if (isModuleR9MNonAccess(moduleIdx)) {
|
||||
lcdDrawTextAlignedLeft(y, STR_MODULE_TELEMETRY);
|
||||
if (isSportLineUsedByInternalModule()) {
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_DISABLE_INTERNAL);
|
||||
if (modulePortIsPortUsedByModule(moduleIdx, ETX_MOD_PORT_SPORT)) {
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_MODULE_TELEM_ON);
|
||||
}
|
||||
else {
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_MODULE_TELEM_ON);
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_DISABLE_INTERNAL);
|
||||
}
|
||||
}
|
||||
else if (isModuleSBUS(moduleIdx)) {
|
||||
|
||||
@@ -57,11 +57,14 @@ static void modulePortClear(etx_module_state_t* st)
|
||||
memset(st, 0, sizeof(etx_module_state_t));
|
||||
}
|
||||
|
||||
static void _init_serial_driver(etx_module_driver_t* d, const etx_module_port_t* port,
|
||||
static bool _init_serial_driver(etx_module_driver_t* d, const etx_module_port_t* port,
|
||||
const etx_serial_init* params)
|
||||
{
|
||||
auto drv = port->drv.serial;
|
||||
d->ctx = drv->init(port->hw_def, params);
|
||||
auto ctx = drv->init(port->hw_def, params);
|
||||
if (!ctx) return false;
|
||||
|
||||
d->ctx = ctx;
|
||||
d->port = port;
|
||||
|
||||
// S.PORT specific HW settings
|
||||
@@ -80,19 +83,26 @@ static void _init_serial_driver(etx_module_driver_t* d, const etx_module_port_t*
|
||||
if (port->set_inverted) {
|
||||
port->set_inverted(params->polarity == ETX_Pol_Inverted);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _init_timer_driver(etx_module_driver_t* d, const etx_module_port_t* port,
|
||||
static bool _init_timer_driver(etx_module_driver_t* d, const etx_module_port_t* port,
|
||||
const etx_timer_config_t* cfg)
|
||||
{
|
||||
auto drv = port->drv.timer;
|
||||
d->ctx = drv->init(port->hw_def, cfg);
|
||||
auto ctx = drv->init(port->hw_def, cfg);
|
||||
if (!ctx) return false;
|
||||
|
||||
d->ctx = ctx;
|
||||
d->port = port;
|
||||
|
||||
// setup polarity
|
||||
if (port->set_inverted) {
|
||||
port->set_inverted(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _match_port(const etx_module_port_t* p, uint8_t type, uint8_t port,
|
||||
@@ -202,10 +212,11 @@ etx_module_state_t* modulePortInitSerial(uint8_t module, uint8_t port,
|
||||
const uint8_t duplex = ETX_Dir_TX_RX;
|
||||
uint8_t dir = params->direction & duplex;
|
||||
|
||||
bool init_ok = false;
|
||||
if (dir == duplex) {
|
||||
|
||||
// init RX first, in case TX was already done previously
|
||||
_init_serial_driver(&state->rx, found_port, params);
|
||||
init_ok = _init_serial_driver(&state->rx, found_port, params);
|
||||
|
||||
// do not overwrite TX state if it has already been set:
|
||||
// -> support using S.PORT in bidir mode
|
||||
@@ -214,12 +225,12 @@ etx_module_state_t* modulePortInitSerial(uint8_t module, uint8_t port,
|
||||
state->tx.ctx = state->rx.ctx;
|
||||
}
|
||||
} else if (dir == ETX_Dir_TX) {
|
||||
_init_serial_driver(&state->tx, found_port, params);
|
||||
init_ok = _init_serial_driver(&state->tx, found_port, params);
|
||||
} else if (dir == ETX_Dir_RX) {
|
||||
_init_serial_driver(&state->rx, found_port, params);
|
||||
init_ok = _init_serial_driver(&state->rx, found_port, params);
|
||||
}
|
||||
|
||||
return state;
|
||||
return init_ok ? state : nullptr;
|
||||
}
|
||||
|
||||
etx_module_state_t* modulePortInitTimer(uint8_t module, uint8_t port,
|
||||
@@ -230,9 +241,9 @@ etx_module_state_t* modulePortInitTimer(uint8_t module, uint8_t port,
|
||||
if (!found_port) return nullptr;
|
||||
|
||||
auto state = &(_module_states[module]);
|
||||
_init_timer_driver(&state->tx, found_port, cfg);
|
||||
bool init_ok = _init_timer_driver(&state->tx, found_port, cfg);
|
||||
|
||||
return state;
|
||||
return init_ok ? state : nullptr;
|
||||
}
|
||||
|
||||
static void _deinit_driver(etx_module_driver_t* d)
|
||||
@@ -262,6 +273,14 @@ void modulePortDeInit(etx_module_state_t* st)
|
||||
modulePortClear(st);
|
||||
}
|
||||
|
||||
void modulePortDeInitRxPort(etx_module_state_t* st)
|
||||
{
|
||||
if (st->rx.port) {
|
||||
_deinit_driver(&st->rx);
|
||||
memset(&st->rx, 0, sizeof(etx_module_driver_t));
|
||||
}
|
||||
}
|
||||
|
||||
etx_module_state_t* modulePortGetState(uint8_t module)
|
||||
{
|
||||
if (module >= MAX_MODULES) return nullptr;
|
||||
@@ -272,3 +291,31 @@ uint8_t modulePortGetModule(etx_module_state_t* st)
|
||||
{
|
||||
return st - _module_states;
|
||||
}
|
||||
|
||||
bool modulePortIsPortUsedByModule(uint8_t module, uint8_t port)
|
||||
{
|
||||
auto mod_st = modulePortGetState(module);
|
||||
if (!mod_st) return false;
|
||||
|
||||
auto tx_port = mod_st->tx.port;
|
||||
auto rx_port = mod_st->rx.port;
|
||||
|
||||
return (tx_port && tx_port->port == port) ||
|
||||
(rx_port && rx_port->port == port);
|
||||
}
|
||||
|
||||
bool modulePortIsPortUsed(uint8_t port)
|
||||
{
|
||||
return modulePortGetModuleForPort(port) >= 0;
|
||||
}
|
||||
|
||||
int8_t modulePortGetModuleForPort(uint8_t port)
|
||||
{
|
||||
for (uint8_t module = 0; module < MAX_MODULES; module++) {
|
||||
if (modulePortIsPortUsedByModule(module, port)) {
|
||||
return module;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -136,6 +136,9 @@ etx_module_state_t* modulePortInitTimer(uint8_t module, uint8_t port,
|
||||
// De-init port and clear data
|
||||
void modulePortDeInit(etx_module_state_t* st);
|
||||
|
||||
// De-init RX part
|
||||
void modulePortDeInitRxPort(etx_module_state_t* st);
|
||||
|
||||
// Once initialized, retrieve module serial driver and context
|
||||
etx_module_state_t* modulePortGetState(uint8_t module);
|
||||
|
||||
@@ -159,3 +162,7 @@ inline void* modulePortGetCtx(const etx_module_driver_t& d) {
|
||||
return d.ctx;
|
||||
}
|
||||
|
||||
bool modulePortIsPortUsedByModule(uint8_t module, uint8_t port);
|
||||
bool modulePortIsPortUsed(uint8_t port);
|
||||
|
||||
int8_t modulePortGetModuleForPort(uint8_t port);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "storage/storage.h"
|
||||
#include "globals.h"
|
||||
#include "MultiProtoDefs.h"
|
||||
#include "hal/module_port.h"
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
#include "telemetry/multi.h"
|
||||
@@ -728,25 +729,13 @@ inline bool isBindCh9To16Allowed(uint8_t moduleIndex)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PCBTARANIS) || defined(PCBHORUS)
|
||||
inline bool isSportLineUsedByInternalModule()
|
||||
{
|
||||
return g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_XJT_PXX1;
|
||||
}
|
||||
#else
|
||||
inline bool isSportLineUsedByInternalModule()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool isTelemAllowedOnBind(uint8_t moduleIndex)
|
||||
{
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
if (moduleIndex == INTERNAL_MODULE)
|
||||
return true;
|
||||
|
||||
if (isSportLineUsedByInternalModule())
|
||||
if (!modulePortIsPortUsedByModule(moduleIndex, ETX_MOD_PORT_SPORT))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -139,8 +139,8 @@ static void setupPulsesMulti(uint8_t*& p_buf, uint8_t module)
|
||||
}
|
||||
|
||||
// Invert telemetry if needed
|
||||
if (invert[module] & 0x80 &&
|
||||
!g_model.moduleData[module].multi.disableTelemetry) {
|
||||
uint8_t disableTelemetry = modulePortIsPortUsedByModule(module, ETX_MOD_PORT_SPORT) ? 0 : 1;
|
||||
if (invert[module] & 0x80 && !disableTelemetry) {
|
||||
if (getMultiModuleStatus(module).isValid()) {
|
||||
invert[module] &= 0x08; // Telemetry received, stop searching
|
||||
} else if (counter[module] % 100 == 0) {
|
||||
@@ -170,7 +170,7 @@ static void setupPulsesMulti(uint8_t*& p_buf, uint8_t module)
|
||||
| (g_model.header.modelId[module] & 0x30)
|
||||
| (invert[module] & 0x08)
|
||||
//| 0x04 // Future use
|
||||
| (g_model.moduleData[module].multi.disableTelemetry << 1)
|
||||
| (disableTelemetry << 1)
|
||||
| g_model.moduleData[module].multi.disableMapping));
|
||||
}
|
||||
|
||||
|
||||
@@ -21,23 +21,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pulses_common.h"
|
||||
#include "hal/serial_driver.h"
|
||||
#include "hal/module_driver.h"
|
||||
|
||||
class UartMultiPulses: public DataBuffer<uint8_t, 64>
|
||||
{
|
||||
public:
|
||||
void initFrame()
|
||||
{
|
||||
initBuffer();
|
||||
}
|
||||
|
||||
void sendByte(uint8_t b)
|
||||
{
|
||||
if (getSize() < 64)
|
||||
*ptr++ = b;
|
||||
}
|
||||
};
|
||||
|
||||
extern const etx_proto_driver_t MultiDriver;
|
||||
|
||||
@@ -111,6 +111,19 @@ void restartModule(uint8_t module)
|
||||
mixerTaskStart();
|
||||
}
|
||||
|
||||
void pulsesRestartModuleUnsafe(uint8_t module)
|
||||
{
|
||||
if (module >= MAX_MODULES)
|
||||
return;
|
||||
|
||||
auto mod_drv = pulsesGetModuleDriver(module);
|
||||
if (!mod_drv->drv) return;
|
||||
|
||||
auto drv = mod_drv->drv;
|
||||
drv->deinit(mod_drv->ctx);
|
||||
mod_drv->ctx = drv->init(module);
|
||||
}
|
||||
|
||||
#if !defined(SIMU)
|
||||
#include <FreeRTOS/include/FreeRTOS.h>
|
||||
#include <FreeRTOS/include/timers.h>
|
||||
|
||||
@@ -175,6 +175,12 @@ void pulsesSetModuleDeInitCb(module_deinit_cb_t cb);
|
||||
void restartModule(uint8_t module);
|
||||
bool restartModuleAsync(uint8_t module, uint8_t cnt_delay);
|
||||
|
||||
// Re-Init module
|
||||
//
|
||||
// Note: this can only be used from within
|
||||
// module init.
|
||||
void pulsesRestartModuleUnsafe(uint8_t module);
|
||||
|
||||
void pulsesModuleSettingsUpdate(uint8_t module);
|
||||
|
||||
void setupPulsesPPMTrainer();
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 "pxx.h"
|
||||
#include "hal/module_port.h"
|
||||
|
||||
bool pxxClearSPort()
|
||||
{
|
||||
auto sport_module = modulePortGetModuleForPort(ETX_MOD_PORT_SPORT);
|
||||
if (sport_module >= 0) {
|
||||
// verify S.PORT is not used for TX (otherwise fail early)
|
||||
auto mod_st = modulePortGetState(sport_module);
|
||||
if (mod_st && mod_st->tx.port &&
|
||||
mod_st->tx.port->port == ETX_MOD_PORT_SPORT) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// S.PORT soft-serial cannot be used for sending
|
||||
sport_module = modulePortGetModuleForPort(ETX_MOD_PORT_SPORT_INV);
|
||||
}
|
||||
|
||||
if (sport_module >= 0) {
|
||||
auto mod_st = modulePortGetState(sport_module);
|
||||
if (mod_st) modulePortDeInitRxPort(mod_st);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -45,3 +45,7 @@
|
||||
|
||||
#define EXTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/
|
||||
#define EXTMODULE_PXX1_SERIAL_BAUDRATE 420000
|
||||
|
||||
// Releases S.PORT usage from
|
||||
// the module driver using it.
|
||||
bool pxxClearSPort();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "dataconstants.h"
|
||||
#include "hal/module_port.h"
|
||||
#include "heartbeat_driver.h"
|
||||
#include "mixer_scheduler.h"
|
||||
@@ -69,14 +70,17 @@ void Pxx1Pulses<PxxTransport>::addExtraFlags(uint8_t module)
|
||||
extraFlags |= (g_model.moduleData[module].pxx.receiverTelemetryOff << 1);
|
||||
extraFlags |= (g_model.moduleData[module].pxx.receiverHigherChannels << 2);
|
||||
if (isModuleR9MNonAccess(module)) {
|
||||
extraFlags |= (min<uint8_t>(g_model.moduleData[module].pxx.power, isModuleR9M_FCC_VARIANT(module) ? (uint8_t)R9M_FCC_POWER_MAX : (uint8_t)R9M_LBT_POWER_MAX) << 3);
|
||||
if (isModuleR9M_EUPLUS(module))
|
||||
extraFlags |= (1 << 6);
|
||||
extraFlags |= (min<uint8_t>(g_model.moduleData[module].pxx.power,
|
||||
isModuleR9M_FCC_VARIANT(module)
|
||||
? (uint8_t)R9M_FCC_POWER_MAX
|
||||
: (uint8_t)R9M_LBT_POWER_MAX)
|
||||
<< 3);
|
||||
if (isModuleR9M_EUPLUS(module)) extraFlags |= (1 << 6);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_EXTERNAL_MODULE) && defined(HARDWARE_INTERNAL_MODULE)
|
||||
// Disable S.PORT if internal module is active
|
||||
if (module == EXTERNAL_MODULE && isSportLineUsedByInternalModule()) {
|
||||
// Disable S.PORT if port is not used (might be used by the internal module)
|
||||
if (module == EXTERNAL_MODULE && !modulePortIsPortUsedByModule(module, ETX_MOD_PORT_SPORT)) {
|
||||
extraFlags |= (1 << 5);
|
||||
}
|
||||
#endif
|
||||
@@ -284,6 +288,8 @@ static void* pxx1Init(uint8_t module)
|
||||
|
||||
if (module == INTERNAL_MODULE) {
|
||||
|
||||
if (!pxxClearSPort()) return nullptr;
|
||||
|
||||
txCfg.baudrate = _pxx1_internal_baudrate;
|
||||
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &txCfg, false);
|
||||
|
||||
@@ -361,7 +367,12 @@ static void* pxx1Init(uint8_t module)
|
||||
static void pxx1DeInit(void* ctx)
|
||||
{
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
auto module = modulePortGetModule(mod_st);
|
||||
modulePortDeInit(mod_st);
|
||||
|
||||
if (module == INTERNAL_MODULE) {
|
||||
pulsesRestartModuleUnsafe(EXTERNAL_MODULE);
|
||||
}
|
||||
}
|
||||
|
||||
static void pxx1SendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
|
||||
|
||||
@@ -294,7 +294,7 @@ static void serialSetupPort(int mode, etx_serial_init& params)
|
||||
case UART_MODE_TELEMETRY_MIRROR:
|
||||
// TODO: query telemetry baudrate / add setting for module
|
||||
#if defined(CROSSFIRE)
|
||||
if (modelTelemetryProtocol() == PROTOCOL_TELEMETRY_CROSSFIRE) {
|
||||
if (isModuleCrossfire(EXTERNAL_MODULE) || isModuleCrossfire(INTERNAL_MODULE)) {
|
||||
params.baudrate = CROSSFIRE_TELEM_MIRROR_BAUDRATE;
|
||||
break;
|
||||
}
|
||||
@@ -303,7 +303,8 @@ static void serialSetupPort(int mode, etx_serial_init& params)
|
||||
break;
|
||||
|
||||
case UART_MODE_TELEMETRY:
|
||||
if (modelTelemetryProtocol() == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) {
|
||||
if (isModulePPM(EXTERNAL_MODULE) &&
|
||||
g_model.telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) {
|
||||
params.baudrate = FRSKY_D_BAUDRATE;
|
||||
params.direction = ETX_Dir_RX;
|
||||
}
|
||||
|
||||
@@ -212,6 +212,7 @@ if(PXX1)
|
||||
add_definitions(-DPXX -DPXX1)
|
||||
set(PULSES_SRC
|
||||
${PULSES_SRC}
|
||||
pxx.cpp
|
||||
pxx1.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -226,7 +226,6 @@ static void _on_rx_fifo(uint8_t data)
|
||||
|
||||
static void* stm32_serial_init(void* hw_def, const etx_serial_init* params)
|
||||
{
|
||||
// TODO: check if port is already in use
|
||||
auto sp = (const stm32_serial_port*)hw_def;
|
||||
if (!sp) return nullptr;
|
||||
|
||||
@@ -234,8 +233,8 @@ static void* stm32_serial_init(void* hw_def, const etx_serial_init* params)
|
||||
auto st = stm32_serial_find_state(usart);
|
||||
if (!st || st->sp) return nullptr;
|
||||
|
||||
stm32_usart_init(usart, params);
|
||||
st->sp = sp; // TODO: only iff init() is sucessful
|
||||
if (!stm32_usart_init(usart, params)) return nullptr;
|
||||
st->sp = sp;
|
||||
|
||||
if (params->direction & ETX_Dir_TX) {
|
||||
// prepare for send_byte()
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "stm32_softserial_driver.h"
|
||||
#include "stm32_exti_driver.h"
|
||||
#include "stm32_timer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -67,9 +68,13 @@ static inline void _rx_fifo_clear()
|
||||
rxRidx = 0;
|
||||
}
|
||||
|
||||
static void _softserial_init_rx(const stm32_softserial_rx_port* port,
|
||||
static bool _softserial_init_rx(const stm32_softserial_rx_port* port,
|
||||
const etx_serial_init* params)
|
||||
{
|
||||
// Test if pin is in reset state
|
||||
uint32_t mode = LL_GPIO_GetPinMode(port->GPIOx, port->GPIO_Pin);
|
||||
if (mode != LL_GPIO_MODE_INPUT) return false;
|
||||
|
||||
rxBitCount = 0;
|
||||
rxBuffer = port->buffer.buffer;
|
||||
rxBufLen = port->buffer.length;
|
||||
@@ -80,11 +85,11 @@ static void _softserial_init_rx(const stm32_softserial_rx_port* port,
|
||||
LL_TIM_StructInit(&timInit);
|
||||
|
||||
uint32_t freq = params->baudrate * 16;
|
||||
if (!freq) return;
|
||||
if (!freq) return false;
|
||||
|
||||
timInit.Prescaler = __LL_TIM_CALC_PSC(port->TIM_Freq, freq);
|
||||
|
||||
// TODO: enable_tim_clock(port->TIMx);
|
||||
stm32_timer_enable_clock(port->TIMx);
|
||||
LL_TIM_Init(port->TIMx, &timInit);
|
||||
|
||||
LL_TIM_ClearFlag_UPDATE(port->TIMx);
|
||||
@@ -119,6 +124,8 @@ static void _softserial_init_rx(const stm32_softserial_rx_port* port,
|
||||
// Configure EXTI for raising edge (start bit; assuming inverted serial)
|
||||
_softserialPort = port;
|
||||
stm32_exti_enable(port->EXTI_Line, LL_EXTI_TRIGGER_RISING, _softserial_exti);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _softserial_deinit_gpio(const stm32_softserial_rx_port* port)
|
||||
@@ -142,7 +149,7 @@ static void _softserial_deinit_rx(const stm32_softserial_rx_port* port)
|
||||
static void* stm32_softserial_rx_init(void* hw_def, const etx_serial_init* params)
|
||||
{
|
||||
auto port = (const stm32_softserial_rx_port*)hw_def;
|
||||
_softserial_init_rx(port, params);
|
||||
if (!_softserial_init_rx(port, params)) return nullptr;
|
||||
return hw_def;
|
||||
}
|
||||
|
||||
|
||||
@@ -221,8 +221,17 @@ void stm32_usart_deinit_rx_dma(const stm32_usart_t* usart)
|
||||
// - asymmetric bitrates for half-duplex (GHOST)
|
||||
// - ??? ability to switch RX DMA OFF ??? (-> X12S)
|
||||
//
|
||||
void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params)
|
||||
bool stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params)
|
||||
{
|
||||
// Test if the GPIO pins are in reset state
|
||||
uint32_t pins = usart->GPIO_Pin;
|
||||
while(pins != 0) {
|
||||
uint32_t pin = 1 << POSITION_VAL(pins);
|
||||
uint32_t mode = LL_GPIO_GetPinMode(usart->GPIOx, pin);
|
||||
if (mode != LL_GPIO_MODE_INPUT) return false;
|
||||
pins ^= pin;
|
||||
}
|
||||
|
||||
enable_usart_clock(usart->USARTx);
|
||||
LL_USART_DeInit(usart->USARTx);
|
||||
|
||||
@@ -258,8 +267,8 @@ void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params)
|
||||
break;
|
||||
|
||||
default:
|
||||
// TODO: return some error
|
||||
return;
|
||||
stm32_usart_deinit(usart);
|
||||
return false;
|
||||
}
|
||||
|
||||
usartInit.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
|
||||
@@ -302,6 +311,8 @@ void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params)
|
||||
LL_USART_IsEnabledIT_RXNE(usart->USARTx)) {
|
||||
_enable_usart_irq(usart);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void stm32_usart_deinit(const stm32_usart_t* usart)
|
||||
|
||||
@@ -54,7 +54,7 @@ struct stm32_usart_t {
|
||||
uint8_t txDMA_IRQ_Prio;
|
||||
};
|
||||
|
||||
void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params);
|
||||
bool stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params);
|
||||
void stm32_usart_init_rx_dma(const stm32_usart_t* usart, const void* buffer, uint32_t length);
|
||||
void stm32_usart_enable_tx_irq(const stm32_usart_t* usart);
|
||||
void stm32_usart_set_idle_irq(const stm32_usart_t* usart, uint32_t enabled);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "hal/serial_driver.h"
|
||||
#include "hal/module_port.h"
|
||||
#include "dataconstants.h"
|
||||
#include "debug.h"
|
||||
|
||||
void intmoduleStop() {}
|
||||
void intmoduleFifoError() {}
|
||||
@@ -60,8 +61,32 @@ void stop_trainer_module_sbus() {}
|
||||
void init_intmodule_heartbeat() {}
|
||||
void stop_intmodule_heartbeat() {}
|
||||
|
||||
static void* init(void*, const etx_serial_init*) { return (void*)1; }
|
||||
static void deinit(void*) {}
|
||||
static bool _sport_used = false;
|
||||
|
||||
static void* init(void* ctx, const etx_serial_init*)
|
||||
{
|
||||
if (ctx == nullptr) {
|
||||
return (void*)1;
|
||||
}
|
||||
|
||||
if (ctx == (void*)&_sport_used) {
|
||||
if (_sport_used) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_sport_used = true;
|
||||
return &_sport_used;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void deinit(void* ctx)
|
||||
{
|
||||
if (ctx != (void*)&_sport_used) return;
|
||||
_sport_used = false;
|
||||
}
|
||||
|
||||
static void sendByte(void*, uint8_t) {}
|
||||
static void sendBuffer(void*, const uint8_t*, uint32_t) {}
|
||||
static void waitForTxCompleted(void*) {}
|
||||
@@ -127,7 +152,7 @@ const etx_module_port_t _internal_ports[] = {
|
||||
.type = ETX_MOD_TYPE_SERIAL,
|
||||
.dir_flags = ETX_MOD_DIR_TX | ETX_MOD_DIR_RX,
|
||||
.drv = { .serial = &_fakeSerialDriver },
|
||||
.hw_def = nullptr,
|
||||
.hw_def = &_sport_used,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
@@ -170,7 +195,7 @@ const etx_module_port_t _external_ports[] = {
|
||||
.drv = { .timer = &_fakeTimerDriver },
|
||||
.hw_def = nullptr,
|
||||
},
|
||||
// TX inverted DMA pulse train on S.PORT
|
||||
// TX inverted DMA pulse train on PPM
|
||||
{
|
||||
.port = ETX_MOD_PORT_SOFT_INV,
|
||||
.type = ETX_MOD_TYPE_SERIAL,
|
||||
@@ -184,7 +209,7 @@ const etx_module_port_t _external_ports[] = {
|
||||
.type = ETX_MOD_TYPE_SERIAL,
|
||||
.dir_flags = ETX_MOD_DIR_TX | ETX_MOD_DIR_RX,
|
||||
.drv = { .serial = &_fakeSerialDriver },
|
||||
.hw_def = nullptr,
|
||||
.hw_def = &_sport_used,
|
||||
},
|
||||
#if defined(TELEMETRY_TIMER)
|
||||
// RX soft-serial sampled bit-by-bit via timer IRQ on S.PORT
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include "opentx.h"
|
||||
#include "hal/module_port.h"
|
||||
|
||||
#include "telemetry.h"
|
||||
#include "io/multi_protolist.h"
|
||||
@@ -83,6 +84,11 @@ MultiModuleStatus &getMultiModuleStatus(uint8_t module)
|
||||
return multiModuleStatus[module];
|
||||
}
|
||||
|
||||
static uint8_t _getMultiStatusModuleIdx(const MultiModuleStatus* p)
|
||||
{
|
||||
return p - multiModuleStatus;
|
||||
}
|
||||
|
||||
uint8_t getMultiBindStatus(uint8_t module)
|
||||
{
|
||||
return multiBindStatus[module];
|
||||
@@ -116,6 +122,11 @@ MultiModuleStatus& getMultiModuleStatus(uint8_t)
|
||||
return multiModuleStatus;
|
||||
}
|
||||
|
||||
static uint8_t _getMultiStatusModuleIdx(const MultiModuleStatus*)
|
||||
{
|
||||
return EXTERNAL_MODULE;
|
||||
}
|
||||
|
||||
uint8_t getMultiBindStatus(uint8_t)
|
||||
{
|
||||
return multiBindStatus;
|
||||
@@ -497,14 +508,11 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
|
||||
void MultiModuleStatus::getStatusString(char * statusText) const
|
||||
{
|
||||
if (!isValid()) {
|
||||
#if defined(PCBFRSKY)
|
||||
#if !defined(INTERNAL_MODULE_MULTI)
|
||||
if (isSportLineUsedByInternalModule())
|
||||
if (!modulePortIsPortUsedByModule(getModuleIndex(), ETX_MOD_PORT_SPORT)) {
|
||||
strcpy(statusText, STR_DISABLE_INTERNAL);
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
strcpy(statusText, STR_MODULE_NO_TELEMETRY);
|
||||
} else {
|
||||
strcpy(statusText, STR_MODULE_NO_TELEMETRY);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!protocolValid()) {
|
||||
@@ -556,6 +564,10 @@ void MultiModuleStatus::getStatusString(char * statusText) const
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MultiModuleStatus::getModuleIndex() const {
|
||||
return _getMultiStatusModuleIdx(this);
|
||||
}
|
||||
|
||||
static void processMultiTelemetryByte(const uint8_t data, uint8_t module)
|
||||
{
|
||||
uint8_t * rxBuffer = getTelemetryRxBuffer(module);
|
||||
|
||||
@@ -120,6 +120,8 @@ struct MultiModuleStatus {
|
||||
|
||||
void getStatusString(char * statusText) const;
|
||||
|
||||
uint8_t getModuleIndex() const;
|
||||
|
||||
inline bool isValid() const { return (bool)(get_tmr10ms() - lastUpdate < 200); }
|
||||
inline bool isBufferFull() const { return (bool) (flags & 0x80); }
|
||||
inline bool supportsDisableMapping() const { return (bool) (flags & 0x40); }
|
||||
|
||||
@@ -68,8 +68,6 @@ uint8_t telemetryState = TELEMETRY_INIT;
|
||||
|
||||
TelemetryData telemetryData;
|
||||
|
||||
uint8_t telemetryProtocol = 255;
|
||||
|
||||
#if defined(INTERNAL_MODULE_SERIAL_TELEMETRY)
|
||||
static uint8_t intTelemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE];
|
||||
static uint8_t intTelemetryRxBufferCount;
|
||||
@@ -418,60 +416,9 @@ void telemetryReset()
|
||||
}
|
||||
|
||||
telemetryStreaming = 0; // reset counter only if valid telemetry packets are being detected
|
||||
|
||||
telemetryState = TELEMETRY_INIT;
|
||||
}
|
||||
|
||||
// we don't reset the telemetry here as we would also reset the consumption after model load
|
||||
void telemetryInit(uint8_t protocol)
|
||||
{
|
||||
telemetryProtocol = protocol;
|
||||
|
||||
// if (protocol == PROTOCOL_TELEMETRY_FRSKY_D) {
|
||||
// telemetryPortInit(FRSKY_D_BAUDRATE, TELEMETRY_SERIAL_DEFAULT);
|
||||
// }
|
||||
// #if defined(MULTIMODULE)
|
||||
// else if (protocol == PROTOCOL_TELEMETRY_MULTIMODULE) {
|
||||
// // The DIY Multi module always speaks 100000 baud regardless of the
|
||||
// // telemetry protocol in use
|
||||
// telemetryPortInit(MULTIMODULE_BAUDRATE, TELEMETRY_SERIAL_8E2);
|
||||
// #if defined(LUA)
|
||||
// outputTelemetryBuffer.reset();
|
||||
// #endif
|
||||
// telemetryPortSetDirectionInput();
|
||||
// } else if (protocol == PROTOCOL_TELEMETRY_SPEKTRUM) {
|
||||
// // Spektrum's own small race RX (SPM4648) uses 125000 8N1, use the same
|
||||
// // since there is no real standard
|
||||
// telemetryPortInit(125000, TELEMETRY_SERIAL_DEFAULT);
|
||||
// }
|
||||
// #endif
|
||||
|
||||
// #if defined(GHOST)
|
||||
// else if (protocol == PROTOCOL_TELEMETRY_GHOST) {
|
||||
// telemetryPortInit(GHOST_BAUDRATE, TELEMETRY_SERIAL_DEFAULT);
|
||||
// #if defined(LUA)
|
||||
// outputTelemetryBuffer.reset();
|
||||
// #endif
|
||||
// telemetryPortSetDirectionOutput();
|
||||
// }
|
||||
// #endif
|
||||
|
||||
// #if defined(AUX_SERIAL)
|
||||
// else if (protocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) {
|
||||
// telemetryPortInit(0, TELEMETRY_SERIAL_DEFAULT);
|
||||
// }
|
||||
// #endif
|
||||
// else if (protocol == PROTOCOL_TELEMETRY_DSMP) {
|
||||
// // soft serial
|
||||
// telemetryPortInvertedInit(115200);
|
||||
// } else {
|
||||
// telemetryPortInit(FRSKY_SPORT_BAUDRATE, TELEMETRY_SERIAL_WITHOUT_DMA);
|
||||
// #if defined(LUA)
|
||||
// outputTelemetryBuffer.reset();
|
||||
// #endif
|
||||
// }
|
||||
}
|
||||
|
||||
#if defined(LOG_TELEMETRY) && !defined(SIMU)
|
||||
extern FIL g_telemetryFile;
|
||||
void logTelemetryWriteStart()
|
||||
|
||||
@@ -133,60 +133,6 @@ typedef struct {
|
||||
|
||||
rxStatStruct *getRxStatLabels();
|
||||
|
||||
// TODO: this should handle only the external S.PORT line
|
||||
// - and go away in the end: one proto per module, not global!
|
||||
//
|
||||
inline uint8_t modelTelemetryProtocol()
|
||||
{
|
||||
#if defined(HARDWARE_EXTERNAL_MODULE)
|
||||
bool sportUsed = isSportLineUsedByInternalModule();
|
||||
|
||||
#if defined(CROSSFIRE)
|
||||
if (isModuleCrossfire(EXTERNAL_MODULE)) {
|
||||
return PROTOCOL_TELEMETRY_CROSSFIRE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GHOST)
|
||||
if (isModuleGhost(EXTERNAL_MODULE)) {
|
||||
return PROTOCOL_TELEMETRY_GHOST;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: PPM driver should support setting up a telemetry parser callback
|
||||
if (!sportUsed && isModulePPM(EXTERNAL_MODULE)) {
|
||||
return g_model.telemetryProtocol;
|
||||
}
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
if (!sportUsed && isModuleMultimodule(EXTERNAL_MODULE)) {
|
||||
return PROTOCOL_TELEMETRY_MULTIMODULE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(AFHDS3)
|
||||
if (isModuleAFHDS3(EXTERNAL_MODULE)) {
|
||||
return PROTOCOL_TELEMETRY_AFHDS3;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isModuleDSMP(EXTERNAL_MODULE)) {
|
||||
return PROTOCOL_TELEMETRY_DSMP;
|
||||
}
|
||||
|
||||
#endif // HARDWARE_EXTERNAL_MODULE
|
||||
|
||||
// TODO: Check if that is really necessary...
|
||||
#if defined(AFHDS2) && defined(HARDWARE_INTERNAL_MODULE)
|
||||
if (isModuleAFHDS2A(INTERNAL_MODULE)) {
|
||||
return PROTOCOL_TELEMETRY_FLYSKY_NV14;
|
||||
}
|
||||
#endif
|
||||
|
||||
// default choice
|
||||
return PROTOCOL_TELEMETRY_FRSKY_SPORT;
|
||||
}
|
||||
|
||||
#include "telemetry_sensors.h"
|
||||
|
||||
#if defined(LOG_TELEMETRY) && !defined(SIMU)
|
||||
|
||||
@@ -20,7 +20,11 @@
|
||||
*/
|
||||
|
||||
#include "gtests.h"
|
||||
#include "hal/module_driver.h"
|
||||
#include "hal/module_port.h"
|
||||
#include "pulses/modules_constants.h"
|
||||
#include "pulses/pulses.h"
|
||||
#include "translations.h"
|
||||
|
||||
TEST(ports, softserialFallback)
|
||||
{
|
||||
@@ -48,3 +52,188 @@ TEST(ports, softserialFallback)
|
||||
modulePortDeInit(mod_st);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_EXTERNAL_MODULE)
|
||||
TEST(ports, isPortUsed)
|
||||
{
|
||||
modulePortInit();
|
||||
|
||||
const etx_serial_init serialCfg = {
|
||||
.baudrate = 57600,
|
||||
.encoding = ETX_Encoding_8N1,
|
||||
.direction = ETX_Dir_TX_RX,
|
||||
.polarity = ETX_Pol_Normal,
|
||||
};
|
||||
|
||||
auto mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT,
|
||||
&serialCfg, false);
|
||||
EXPECT_TRUE(mod_st != nullptr);
|
||||
EXPECT_TRUE(mod_st && mod_st->rx.port != nullptr);
|
||||
|
||||
auto module = modulePortGetModuleForPort(ETX_MOD_PORT_SPORT);
|
||||
EXPECT_EQ(EXTERNAL_MODULE, module);
|
||||
|
||||
if (mod_st) modulePortDeInit(mod_st);
|
||||
EXPECT_FALSE(modulePortIsPortUsed(ETX_MOD_PORT_SPORT));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(INTERNAL_MODULE_PXX1) && defined(HARDWARE_EXTERNAL_MODULE)
|
||||
#include "pulses/pxx1.h"
|
||||
|
||||
static void _setModuleDrv(uint8_t module, const etx_proto_driver_t* drv, void* ctx)
|
||||
{
|
||||
auto mod_drv = pulsesGetModuleDriver(module);
|
||||
mod_drv->drv = drv;
|
||||
mod_drv->ctx = ctx;
|
||||
}
|
||||
|
||||
static void _deinitModuleDrv(uint8_t module)
|
||||
{
|
||||
auto mod_drv = pulsesGetModuleDriver(module);
|
||||
auto drv = mod_drv->drv;
|
||||
auto ctx = mod_drv->ctx;
|
||||
|
||||
drv->deinit(ctx);
|
||||
memset(mod_drv, 0, sizeof(module_pulse_driver));
|
||||
}
|
||||
|
||||
static void _sendPulses(uint8_t module, uint8_t* buffer)
|
||||
{
|
||||
auto mod_drv = pulsesGetModuleDriver(module);
|
||||
auto drv = mod_drv->drv;
|
||||
auto ctx = mod_drv->ctx;
|
||||
|
||||
int16_t* channels = &channelOutputs[0];
|
||||
drv->sendPulses(ctx, buffer, channels, 16);
|
||||
}
|
||||
|
||||
TEST(ports, deactivateRX_pxx1)
|
||||
{
|
||||
modulePortInit();
|
||||
g_model.moduleData[EXTERNAL_MODULE].type = MODULE_TYPE_R9M_PXX1;
|
||||
|
||||
void* ext_ctx = Pxx1Driver.init(EXTERNAL_MODULE);
|
||||
EXPECT_TRUE(ext_ctx != nullptr);
|
||||
EXPECT_TRUE(modulePortIsPortUsed(ETX_MOD_PORT_SPORT));
|
||||
|
||||
if (!ext_ctx) return;
|
||||
_setModuleDrv(EXTERNAL_MODULE, &Pxx1Driver, ext_ctx);
|
||||
|
||||
void* int_ctx = Pxx1Driver.init(INTERNAL_MODULE);
|
||||
EXPECT_TRUE(int_ctx != nullptr);
|
||||
EXPECT_EQ(INTERNAL_MODULE, modulePortGetModuleForPort(ETX_MOD_PORT_SPORT));
|
||||
|
||||
if (!int_ctx) return;
|
||||
_setModuleDrv(INTERNAL_MODULE, &Pxx1Driver, int_ctx);
|
||||
|
||||
_deinitModuleDrv(INTERNAL_MODULE);
|
||||
EXPECT_EQ(EXTERNAL_MODULE, modulePortGetModuleForPort(ETX_MOD_PORT_SPORT));
|
||||
|
||||
_deinitModuleDrv(EXTERNAL_MODULE);
|
||||
EXPECT_FALSE(modulePortIsPortUsed(ETX_MOD_PORT_SPORT));
|
||||
}
|
||||
|
||||
#include "pulses/multi.h"
|
||||
#include "telemetry/multi.h"
|
||||
|
||||
TEST(ports, deactivateRX_multi)
|
||||
{
|
||||
modulePortInit();
|
||||
g_model.moduleData[EXTERNAL_MODULE].type = MODULE_TYPE_MULTIMODULE;
|
||||
|
||||
void* ext_ctx = MultiDriver.init(EXTERNAL_MODULE);
|
||||
EXPECT_TRUE(ext_ctx != nullptr);
|
||||
EXPECT_TRUE(modulePortIsPortUsed(ETX_MOD_PORT_SPORT));
|
||||
|
||||
if (!ext_ctx) return;
|
||||
_setModuleDrv(EXTERNAL_MODULE, &MultiDriver, ext_ctx);
|
||||
|
||||
uint8_t buffer[64];
|
||||
_sendPulses(EXTERNAL_MODULE, buffer);
|
||||
EXPECT_FALSE(buffer[0x1A] & 2);
|
||||
|
||||
auto& mpm_status = getMultiModuleStatus(EXTERNAL_MODULE);
|
||||
mpm_status.invalidate();
|
||||
mpm_status.getStatusString((char*)buffer);
|
||||
EXPECT_STREQ(STR_MODULE_NO_TELEMETRY, (char*)buffer);
|
||||
|
||||
void* int_ctx = Pxx1Driver.init(INTERNAL_MODULE);
|
||||
EXPECT_TRUE(int_ctx != nullptr);
|
||||
EXPECT_EQ(INTERNAL_MODULE, modulePortGetModuleForPort(ETX_MOD_PORT_SPORT));
|
||||
|
||||
if (!int_ctx) return;
|
||||
_setModuleDrv(INTERNAL_MODULE, &Pxx1Driver, int_ctx);
|
||||
|
||||
_sendPulses(EXTERNAL_MODULE, buffer);
|
||||
EXPECT_TRUE(buffer[0x1A] & 2);
|
||||
|
||||
mpm_status.getStatusString((char*)buffer);
|
||||
EXPECT_STREQ(STR_DISABLE_INTERNAL, (char*)buffer);
|
||||
|
||||
_deinitModuleDrv(INTERNAL_MODULE);
|
||||
EXPECT_EQ(EXTERNAL_MODULE, modulePortGetModuleForPort(ETX_MOD_PORT_SPORT));
|
||||
|
||||
_sendPulses(EXTERNAL_MODULE, buffer);
|
||||
EXPECT_FALSE(buffer[0x1A] & 2);
|
||||
|
||||
_deinitModuleDrv(EXTERNAL_MODULE);
|
||||
EXPECT_FALSE(modulePortIsPortUsed(ETX_MOD_PORT_SPORT));
|
||||
}
|
||||
|
||||
TEST(ports, boot_pxx1_multi)
|
||||
{
|
||||
modulePortInit();
|
||||
g_model.moduleData[EXTERNAL_MODULE].type = MODULE_TYPE_MULTIMODULE;
|
||||
|
||||
// Init PXX1 internal module first
|
||||
void* int_ctx = Pxx1Driver.init(INTERNAL_MODULE);
|
||||
EXPECT_TRUE(int_ctx != nullptr);
|
||||
|
||||
if (!int_ctx) return;
|
||||
_setModuleDrv(INTERNAL_MODULE, &Pxx1Driver, int_ctx);
|
||||
|
||||
EXPECT_TRUE(modulePortIsPortUsed(ETX_MOD_PORT_SPORT));
|
||||
EXPECT_EQ(INTERNAL_MODULE, modulePortGetModuleForPort(ETX_MOD_PORT_SPORT));
|
||||
|
||||
// Init MPM external module second
|
||||
void* ext_ctx = MultiDriver.init(EXTERNAL_MODULE);
|
||||
EXPECT_TRUE(ext_ctx != nullptr);
|
||||
|
||||
if (!ext_ctx) return;
|
||||
_setModuleDrv(EXTERNAL_MODULE, &MultiDriver, ext_ctx);
|
||||
|
||||
// Verify internal module still owns S.PORT
|
||||
EXPECT_EQ(INTERNAL_MODULE, modulePortGetModuleForPort(ETX_MOD_PORT_SPORT));
|
||||
EXPECT_FALSE(modulePortIsPortUsedByModule(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT));
|
||||
|
||||
// Verify MPM sends "disable telemetry" bit
|
||||
uint8_t buffer[64];
|
||||
_sendPulses(EXTERNAL_MODULE, buffer);
|
||||
EXPECT_TRUE(buffer[0x1A] & 2);
|
||||
|
||||
// Verify MPM status
|
||||
auto& mpm_status = getMultiModuleStatus(EXTERNAL_MODULE);
|
||||
mpm_status.invalidate();
|
||||
mpm_status.getStatusString((char*)buffer);
|
||||
EXPECT_STREQ(STR_DISABLE_INTERNAL, (char*)buffer);
|
||||
|
||||
// Disable internal module
|
||||
_deinitModuleDrv(INTERNAL_MODULE);
|
||||
|
||||
// Verify external module now owns S.PORT
|
||||
EXPECT_EQ(EXTERNAL_MODULE, modulePortGetModuleForPort(ETX_MOD_PORT_SPORT));
|
||||
|
||||
// Verify MPM does not send "disable telemetry" bit
|
||||
_sendPulses(EXTERNAL_MODULE, buffer);
|
||||
EXPECT_FALSE(buffer[0x1A] & 2);
|
||||
|
||||
// Verify MPM status
|
||||
mpm_status.getStatusString((char*)buffer);
|
||||
EXPECT_STREQ(STR_MODULE_NO_TELEMETRY, (char*)buffer);
|
||||
|
||||
// disable MPM
|
||||
_deinitModuleDrv(EXTERNAL_MODULE);
|
||||
EXPECT_FALSE(modulePortIsPortUsed(ETX_MOD_PORT_SPORT));
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user