diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp
index 87baaaa6a..391ed93f4 100644
--- a/companion/src/firmwares/boards.cpp
+++ b/companion/src/firmwares/boards.cpp
@@ -574,6 +574,15 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
else
return 250000; // less than 400K
+ case HasTrainerModuleCPPM:
+ return (getCapability(board, HasTrainerModuleSBUS) || IS_FAMILY_HORUS_OR_T16(board));
+
+ case HasTrainerModuleSBUS:
+ return ((IS_TARANIS_X9LITE(board) || (IS_TARANIS_XLITE(board) && !IS_TARANIS_X9LITES(board)) ||
+ IS_TARANIS_X9DP_2019(board) || IS_TARANIS_X7_ACCESS(board) || IS_RADIOMASTER_ZORRO(board) ||
+ IS_RADIOMASTER_TX12_MK2(board) || IS_RADIOMASTER_BOXER(board)) ||
+ (getCapability(board, HasExternalModuleSupport) && (IS_TARANIS(board) && !IS_FAMILY_T12(board))));
+
default:
return 0;
}
diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h
index c38b10601..f0274e742 100644
--- a/companion/src/firmwares/boards.h
+++ b/companion/src/firmwares/boards.h
@@ -160,7 +160,10 @@ namespace Board {
HasInternalModuleSupport,
HasExternalModuleSupport,
HasAudioMuteGPIO,
- SportMaxBaudRate
+ SportMaxBaudRate,
+ HasIntModuleHeartbeatGPIO,
+ HasTrainerModuleCPPM,
+ HasTrainerModuleSBUS,
};
struct SwitchInfo
diff --git a/companion/src/firmwares/edgetx/yaml_modeldata.cpp b/companion/src/firmwares/edgetx/yaml_modeldata.cpp
index 5ca2d5a5d..0059bc921 100644
--- a/companion/src/firmwares/edgetx/yaml_modeldata.cpp
+++ b/companion/src/firmwares/edgetx/yaml_modeldata.cpp
@@ -56,7 +56,7 @@ static const YamlLookupTable trainerModeLut = {
{ TRAINER_MODE_SLAVE_JACK, "SLAVE" },
{ TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE, "MASTER_SBUS_EXT" },
{ TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE, "MASTER_CPPM_EXT" },
- { TRAINER_MODE_MASTER_BATTERY_COMPARTMENT, "MASTER_BATT_COMP" },
+ { TRAINER_MODE_MASTER_SERIAL, "MASTER_BATT_COMP" },
{ TRAINER_MODE_MASTER_BLUETOOTH, "MASTER_BT" },
{ TRAINER_MODE_SLAVE_BLUETOOTH, "SLAVE_BT" },
{ TRAINER_MODE_MULTI, "MASTER_MULTI" },
diff --git a/companion/src/firmwares/modeldata.cpp b/companion/src/firmwares/modeldata.cpp
index 855cd7f08..669ce84ea 100644
--- a/companion/src/firmwares/modeldata.cpp
+++ b/companion/src/firmwares/modeldata.cpp
@@ -1625,8 +1625,8 @@ QString ModelData::trainerModeToString(int value)
return tr("Master/SBUS Module");
case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE:
return tr("Master/CPPM Module");
- case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT:
- return tr("Master/Battery");
+ case TRAINER_MODE_MASTER_SERIAL:
+ return tr("Master/Serial");
case TRAINER_MODE_MASTER_BLUETOOTH:
return tr("Master/Bluetooth");
case TRAINER_MODE_SLAVE_BLUETOOTH:
@@ -1638,35 +1638,55 @@ QString ModelData::trainerModeToString(int value)
}
}
-// static
bool ModelData::isTrainerModeAvailable(const GeneralSettings & generalSettings, const Firmware * firmware, const int value)
{
if (value < TRAINER_MODE_FIRST || value > TRAINER_MODE_LAST)
return false;
- bool ret = true;
const Board::Type board = firmware->getBoard();
- if (!IS_TARANIS(board) ||
- IS_ACCESS_RADIO(board, Firmware::getCurrentVariant()->getId())) {
- if (value >= TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE &&
- value <= TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
- ret = false;
- } else if (generalSettings.serialPort[GeneralSettings::SP_AUX1] !=
- UART_MODE_SBUS_TRAINER &&
- value == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
- ret = false;
+ if (value == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE &&
+ IS_TARANIS_X9E(board) &&
+ generalSettings.bluetoothMode)
+ return false;
- if (generalSettings.bluetoothMode !=
- GeneralSettings::BLUETOOTH_MODE_TRAINER &&
- value >= TRAINER_MODE_MASTER_BLUETOOTH &&
- value <= TRAINER_MODE_SLAVE_BLUETOOTH)
- ret = false;
+ if (value == TRAINER_MODE_MASTER_SERIAL &&
+ (generalSettings.serialPort[GeneralSettings::SP_AUX1] != GeneralSettings::AUX_SERIAL_SBUS_TRAINER &&
+ generalSettings.serialPort[GeneralSettings::SP_AUX2] != GeneralSettings::AUX_SERIAL_SBUS_TRAINER))
+ return false;
- return ret;
+ if ((value == TRAINER_MODE_MASTER_BLUETOOTH || value == TRAINER_MODE_SLAVE_BLUETOOTH) &&
+ !IS_TARANIS_X9E(board) &&
+ generalSettings.bluetoothMode != GeneralSettings::BLUETOOTH_MODE_TRAINER)
+ return false;
+
+ if ((value == TRAINER_MODE_MASTER_JACK || value == TRAINER_MODE_SLAVE_JACK) &&
+ ((IS_TARANIS_XLITE(board) && !IS_TARANIS_X9LITES(board)) || IS_IFLIGHT_COMMANDO8(board)))
+ return false;
+
+ if (value == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE &&
+ !Boards::getCapability(board, Board::HasTrainerModuleCPPM))
+ return false;
+
+ if (value == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE &&
+ !Boards::getCapability(board, Board::HasTrainerModuleSBUS))
+ return false;
+
+ if ((value == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE || value == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE) &&
+ (Boards::getCapability(board, Board::HasTrainerModuleCPPM) ||
+ Boards::getCapability(board, Board::HasTrainerModuleSBUS)) &&
+ moduleData[1].protocol != PULSES_OFF)
+ return false;
+
+ if (value == TRAINER_MODE_MULTI &&
+ ((!Boards::getCapability(board, Board::HasInternalModuleSupport) &&
+ !Boards::getCapability(board, Board::HasExternalModuleSupport)) ||
+ (moduleData[0].protocol != PULSES_MULTIMODULE && moduleData[1].protocol != PULSES_MULTIMODULE)))
+ return false;
+
+ return true;
}
-// static
AbstractStaticItemModel * ModelData::trainerModeItemModel(const GeneralSettings & generalSettings, const Firmware * firmware)
{
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
diff --git a/companion/src/firmwares/modeldata.h b/companion/src/firmwares/modeldata.h
index 975fb05e9..8df7a30f7 100644
--- a/companion/src/firmwares/modeldata.h
+++ b/companion/src/firmwares/modeldata.h
@@ -80,7 +80,7 @@ enum TrainerMode {
TRAINER_MODE_SLAVE_JACK,
TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE,
TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE,
- TRAINER_MODE_MASTER_BATTERY_COMPARTMENT,
+ TRAINER_MODE_MASTER_SERIAL,
TRAINER_MODE_MASTER_BLUETOOTH,
TRAINER_MODE_SLAVE_BLUETOOTH,
TRAINER_MODE_MULTI,
@@ -327,8 +327,8 @@ class ModelData {
QString trainerModeToString() const;
static QString trainerModeToString(const int value);
- static bool isTrainerModeAvailable(const GeneralSettings & generalSettings, const Firmware * firmware, const int value);
- static AbstractStaticItemModel * trainerModeItemModel(const GeneralSettings & generalSettings, const Firmware * firmware);
+ bool isTrainerModeAvailable(const GeneralSettings & generalSettings, const Firmware * firmware, const int value);
+ AbstractStaticItemModel * trainerModeItemModel(const GeneralSettings & generalSettings, const Firmware * firmware);
unsigned int getFuncSwitchConfig(unsigned int index) const;
void setFuncSwitchConfig(unsigned int index, unsigned int value);
static QString funcSwitchConfigToString(unsigned int value);
diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp
index 1d6f4f417..6cf44641f 100644
--- a/companion/src/modeledit/setup.cpp
+++ b/companion/src/modeledit/setup.cpp
@@ -233,27 +233,27 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
ModelPanel(parent, model, generalSettings, firmware),
module(module),
moduleIdx(moduleIdx),
- ui(new Ui::Module)
+ ui(new Ui::Module),
+ trainerModeItemModel(nullptr)
{
lock = true;
ui->setupUi(this);
ui->label_module->setText(ModuleData::indexToString(moduleIdx, firmware));
- if (moduleIdx < 0) {
+ if (isTrainerModule(moduleIdx)) {
ui->formLayout_col1->setSpacing(0);
if (!IS_HORUS_OR_TARANIS(firmware->getBoard())) {
ui->label_trainerMode->hide();
ui->trainerMode->hide();
}
else {
- if (panelFilteredItemModels)
- ui->trainerMode->setModel(panelFilteredItemModels->getItemModel(FIM_TRAINERMODE));
+ updateTrainerModeItemModel();
ui->trainerMode->setField(model.trainerMode);
connect(ui->trainerMode, &AutoComboBox::currentDataChanged, this, [=] () {
- update();
- emit updateItemModels();
- emit modified();
+ update();
+ emit updateItemModels();
+ emit modified();
});
}
}
@@ -263,16 +263,16 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
}
if (panelFilteredItemModels) {
- if (moduleIdx >= 0) {
+ if (!isTrainerModule(moduleIdx)) {
int id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(ModuleData::protocolItemModel(generalSettings), moduleIdx + 1/*flag cannot be 0*/), QString("Module Protocol %1").arg(moduleIdx));
panelFilteredItemModels->getItemModel(id)->setSortCaseSensitivity(Qt::CaseInsensitive);
panelFilteredItemModels->getItemModel(id)->sort(0);
ui->protocol->setModel(panelFilteredItemModels->getItemModel(id));
if (ui->protocol->findData(module.protocol) < 0) {
- const QString moduleIdxDesc = moduleIdx == 0 ? tr("internal") : tr("external");
- const QString compareDesc = moduleIdx == 0 ? tr("hardware") : tr("profile");
- const QString intModuleDesc = moduleIdx == 0 ? ModuleData::typeToString(generalSettings.internalModule) : "";
+ const QString moduleIdxDesc = isInternalModule(moduleIdx) ? tr("internal") : tr("external");
+ const QString compareDesc = isInternalModule(moduleIdx) ? tr("hardware") : tr("profile");
+ const QString intModuleDesc = isInternalModule(moduleIdx) ? ModuleData::typeToString(generalSettings.internalModule) : "";
QString msg = tr("Warning: The %1 module protocol %2 is incompatible with the %3 %1 module %4 and has been set to OFF!");
msg = msg.arg(moduleIdxDesc).arg(module.protocolToString(module.protocol)).arg(compareDesc).arg(intModuleDesc);
@@ -291,7 +291,7 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
ui->protocol->setField(module.protocol, this);
}
- if (moduleIdx == 0) {
+ if (isInternalModule(moduleIdx)) {
int id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(GeneralSettings::antennaModeItemModel(true)), FIM_ANTENNAMODE);
ui->antennaMode->setModel(panelFilteredItemModels->getItemModel(id));
}
@@ -434,7 +434,7 @@ void ModulePanel::update()
unsigned int mask = 0;
unsigned int max_rx_num = 63;
- if (moduleIdx >= 0) {
+ if (!isTrainerModule(moduleIdx)) {
mask |= MASK_PROTOCOL;
switch (protocol) {
case PULSES_PXX_R9M:
@@ -461,7 +461,7 @@ void ModulePanel::update()
else if (protocol==PULSES_ACCESS_ISRM || protocol==PULSES_ACCESS_R9M ||
protocol==PULSES_ACCESS_R9M_LITE || protocol==PULSES_ACCESS_R9M_LITE_PRO)
mask |= MASK_RX_NUMBER | MASK_ACCESS;
- if (moduleIdx == 0 &&
+ if (isInternalModule(moduleIdx) &&
(protocol==PULSES_PXX_XJT_X16 ||
protocol==PULSES_PXX_XJT_D8 || protocol==PULSES_PXX_XJT_LR12) &&
HAS_EXTERNAL_ANTENNA(board) && generalSettings.antennaMode == GeneralSettings::ANTENNA_MODE_PER_MODEL)
@@ -553,7 +553,7 @@ void ModulePanel::update()
mask |= MASK_FAILSAFES;
}
- if (moduleIdx > 0)
+ if (isExternalModule(moduleIdx))
ui->telemetryBaudrate->setVisible(mask & MASK_BAUDRATE);
else
ui->telemetryBaudrate->setVisible(false);
@@ -814,6 +814,7 @@ void ModulePanel::onProtocolChanged(int index)
}
}
+ emit protocolChanged();
emit updateItemModels();
emit modified();
}
@@ -1178,6 +1179,18 @@ void ModulePanel::onClearAccessRxClicked()
}
}
+void ModulePanel::updateTrainerModeItemModel()
+{
+ if (isTrainerModule(moduleIdx)) {
+ if (trainerModeItemModel)
+ delete trainerModeItemModel;
+
+ trainerModeItemModel = new FilteredItemModel(model->trainerModeItemModel(generalSettings, firmware));
+ ui->trainerMode->setModel(trainerModeItemModel);
+ ui->trainerMode->updateValue();
+ }
+}
+
/******************************************************************************/
FunctionSwitchesPanel::FunctionSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
ModelPanel(parent, model, generalSettings, firmware),
@@ -1409,7 +1422,6 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
panelItemModels->registerItemModel(TimerData::countdownStartItemModel());
panelItemModels->registerItemModel(TimerData::persistentItemModel());
panelItemModels->registerItemModel(TimerData::modeItemModel());
- panelFilteredModels->registerItemModel(new FilteredItemModel(ModelData::trainerModeItemModel(generalSettings, firmware)), FIM_TRAINERMODE);
panelItemModels->registerItemModel(TimerData::showElapsedItemModel());
Board::Type board = firmware->getBoard();
@@ -1658,6 +1670,9 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
ui->modulesLayout->addWidget(modules[CPN_MAX_MODULES]);
connect(modules[CPN_MAX_MODULES], &ModulePanel::modified, this, &SetupPanel::modified);
connect(modules[CPN_MAX_MODULES], &ModulePanel::updateItemModels, this, &SetupPanel::onModuleUpdateItemModels);
+ for (int i = firmware->getCapability(NumFirstUsableModule); i < firmware->getCapability(NumModules); i++) {
+ connect(modules[i], &ModulePanel::protocolChanged, modules[CPN_MAX_MODULES], &ModulePanel::updateTrainerModeItemModel);
+ }
}
disableMouseScrolling();
diff --git a/companion/src/modeledit/setup.h b/companion/src/modeledit/setup.h
index ae76a64a0..0f92d3eb2 100644
--- a/companion/src/modeledit/setup.h
+++ b/companion/src/modeledit/setup.h
@@ -35,6 +35,7 @@ namespace Ui {
}
class AutoLineEdit;
+class FilteredItemModel;
class TimerPanel : public ModelPanel
{
@@ -79,11 +80,13 @@ class ModulePanel : public ModelPanel
public slots:
void onExtendedLimitsToggled();
void onFailsafeModified(unsigned index);
+ void updateTrainerModeItemModel();
signals:
void channelsRangeChanged();
void failsafeModified(unsigned index);
void updateItemModels();
+ void protocolChanged();
private slots:
void setupFailsafes();
@@ -133,6 +136,10 @@ class ModulePanel : public ModelPanel
QMap failsafeGroupsMap;
static quint8 failsafesValueDisplayType; // FailsafeValueDisplayTypes
void updateFailsafeUI(unsigned channel, quint8 updtSb);
+ FilteredItemModel *trainerModeItemModel;
+ static bool isTrainerModule(int index) { return index < 0; }
+ static bool isInternalModule(int index) { return index == 0; }
+ static bool isExternalModule(int index) { return index > 0; }
};
class FunctionSwitchesPanel : public ModelPanel