diff --git a/CMakeLists.txt b/CMakeLists.txt index 791a427313..870252da45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(VERSION_REVISION "0") set(VERSION_SUFFIX $ENV{OPENTX_VERSION_SUFFIX}) set(VERSION_FAMILY ${VERSION_MAJOR}.${VERSION_MINOR}) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}${VERSION_SUFFIX}) -set(SDCARD_REVISION "0035") +set(SDCARD_REVISION "0036") set(SDCARD_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}V${SDCARD_REVISION}) cmake_minimum_required(VERSION 2.8) diff --git a/CREDITS.txt b/CREDITS.txt index 3136f7b6ea..0daa8f9e01 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -2093,3 +2093,135 @@ Burt Pickard-Richardson Michal Mesaros Conrad Young Martin Mathes +Jens Rainer Hansen +Mark Trible +Marc Dubois +Alan Wilkins +Daniel Hryciuk +Thomas Fox +Sidney B Harden +Augustas Sereika +David Belletete +Karl-Heinz Behn +Lena Hjort +Jan Langhorst +Alberto Scotti +John Rock +Adam Kouse +Ricardo Martins +Noel Irwin +Christoph Rausch +Anthony Hrabusicky +Sergio Tondini +Aldo Visentin +Greg Wilson +Mark Sutton +Lukas Kana +Peter Newman +Kevin Cave +Arold Reinders +Jason Plant +John Beech +Ian Parris +Danny Music +Eric Bissonnette +Riso LTD +William Booth +Ferenc Kunkli +Offer Shmuely +Troy Atneosen +Long Technologies +John Jaugilas +Jan-Hinrich Klee +Hans-Reinhard Mette +Alejandro Casals Oliver +David Homewood +John Dunning +Konrad Helbach +Bernard Delpy +Raymond Ellsworth +Bogdan Musial +Гасак Сергей +Philip Garcia +Helder Simoes +Thomas Blanchin +Jean-Luc Mesnier +Michael Bajer +David Homewood +Marc Sanders +Буров Александр +Rudy T'Jolleyn +Jay Watkins +Blaz Vodopivec +David De Salvo +Willem Verschoren +Dennis Kathrens +Alan Aucote +Richard Jerome Danstrom +David Garcia-Mendia +Mark Jones +John Zseleczky +Xiao Sun +Glenn Harvey +Albrecht Friebel +Gunter Klemke +Travis McCarthy +Franz Zier +Ian Contessa +Sean Sadler +Richard F Janczak +Mateusz Dziadosz +Thomas Merchant +M L Perkins +Stefano Boggia +Новоселов Юрий +James Rhodes +Peter Gaskill +Jacques Temey +Anthony Challis +Gerard Falaise +George McGinnis +Antoine Soulie +Tjeerd Jager +Bertold Van den Bergh +Stefanie Zerbe +James Mandelbaum +Javier J. Cordovez +Jess Barkley +Schneider Modell +Michael Hasselgaard +Thomas Young +Непочатов Алексей +Thomas Goebel +Joseph Macias +Paw Melin-Nielsen +Liam O'Brien +Ronald B Backman +Corvus Inspection Services Inc +Stuart Posnett +Clark Emerick +Helmut Sippel +Jhon Lennon Silva do Nascimento +Peter McCarthy +Bob Brown +Claude Lawyer +Peter Fithern +Michael Hoffman +Tim Smith +OpenSki Institute +Simon Melov +Richard Podolsky +James Wilson +John Norrbin +James Goins +Phillip Nguyen +Jeffrey M Engel +Richard Marotto +Greg Bell +Scott Geer +Thomas Abshier +Ernst Camenzind +Radomir Sterba +Ignacio Barrio +Bradley Murchie +Emmanuel Balintec diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt index e76779c627..4e8f11ca50 100644 --- a/companion/src/CMakeLists.txt +++ b/companion/src/CMakeLists.txt @@ -343,8 +343,12 @@ if(PCB STREQUAL X7 AND PCBREV STREQUAL ACCESS) set(FLAVOUR x7access) elseif(PCB STREQUAL X7 AND PCBREV STREQUAL T12) set(FLAVOUR t12) +elseif(PCB STREQUAL X7 AND PCBREV STREQUAL TLITE) + set(FLAVOUR tlite) elseif(PCB STREQUAL X7 AND PCBREV STREQUAL TX12) set(FLAVOUR tx12) +elseif(PCB STREQUAL X7 AND PCBREV STREQUAL T8) + set(FLAVOUR t8) elseif(PCB STREQUAL X9D+ AND PCBREV STREQUAL 2019) set(FLAVOUR x9d+2019) elseif(PCB STREQUAL X10 AND PCBREV STREQUAL EXPRESS) diff --git a/companion/src/companion.qrc b/companion/src/companion.qrc index fbbacdb489..c76418135a 100644 --- a/companion/src/companion.qrc +++ b/companion/src/companion.qrc @@ -179,6 +179,16 @@ images/simulator/JumperT12/JumperT12-x.png images/simulator/JumperT12/JumperT12-center.png images/simulator/JumperT12/JumperT12-top.png + images/simulator/JumperTLITE/bottom.png + images/simulator/JumperTLITE/bottom_right.png + images/simulator/JumperTLITE/bottom_left.png + images/simulator/JumperTLITE/left.png + images/simulator/JumperTLITE/left_top.png + images/simulator/JumperTLITE/left_bottom.png + images/simulator/JumperTLITE/right.png + images/simulator/JumperTLITE/right_top.png + images/simulator/JumperTLITE/right_bottom.png + images/simulator/JumperTLITE/top.png images/simulator/TX12/left.png images/simulator/TX12/left-pageup.png images/simulator/TX12/left-pagedn.png @@ -190,6 +200,18 @@ images/simulator/TX12/right-mdl.png images/simulator/TX12/bottom.png images/simulator/TX12/top.png + images/simulator/T8/left.png + images/simulator/T8/left-pageup.png + images/simulator/T8/left-pagedn.png + images/simulator/T8/left-rtn.png + images/simulator/T8/left-sys.png + images/simulator/T8/right.png + images/simulator/T8/right-ent.png + images/simulator/T8/right-mdl.png + images/simulator/T8/right-up.png + images/simulator/T8/right-dn.png + images/simulator/T8/bottom.png + images/simulator/T8/top.png images/simulator/JumperT16/left.png images/simulator/JumperT16/right.png images/simulator/JumperT16/top.png diff --git a/companion/src/datamodels/CMakeLists.txt b/companion/src/datamodels/CMakeLists.txt index beb7d4d2d4..446f161b3e 100644 --- a/companion/src/datamodels/CMakeLists.txt +++ b/companion/src/datamodels/CMakeLists.txt @@ -1,12 +1,12 @@ set(datamodels_SRCS - rawitemdatamodels.cpp - rawitemfilteredmodel.cpp + compounditemmodels.cpp + filtereditemmodels.cpp ) set(datamodels_HDRS - rawitemdatamodels.h - rawitemfilteredmodel.h + compounditemmodels.h + filtereditemmodels.h ) qt5_wrap_cpp(datamodels_SRCS ${datamodels_HDRS}) diff --git a/companion/src/datamodels/compounditemmodels.cpp b/companion/src/datamodels/compounditemmodels.cpp new file mode 100644 index 0000000000..2f04a34fbc --- /dev/null +++ b/companion/src/datamodels/compounditemmodels.cpp @@ -0,0 +1,758 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "compounditemmodels.h" +#include "generalsettings.h" +#include "eeprominterface.h" +#include "modeldata.h" +#include "adjustmentreference.h" + +// static +QString AbstractItemModel::idToString(const int value) +{ + switch (value) { + case IMID_Unknown: + return "Unknown"; + case IMID_RawSource: + return "RawSource"; + case IMID_RawSwitch: + return "RawSwitch"; + case IMID_Curve: + return "Curve"; + case IMID_GVarRef: + return "GVarRef"; + case IMID_ThrSource: + return "ThrSource"; + case IMID_CustomFuncAction: + return "CustomFuncAction"; + case IMID_CustomFuncResetParam: + return "CustomFuncResetParam"; + case IMID_TeleSource: + return "TeleSource"; + case IMID_RssiSource: + return "RssiSource"; + case IMID_CurveRefType: + return "CurveRefType"; + case IMID_CurveRefFunc: + return "CurveRefFunc"; + default: + return "Custom"; + } +} + +// static +void AbstractItemModel::dumpItemModelContents(AbstractItemModel * itemModel) +{ + if (itemModel) { + qDebug() << "id:" << itemModel->getId() << "name:" << itemModel->getName(); + + for (int i = 0; i < itemModel->rowCount(); ++i) { + qDebug() << "row:" << i + << "text:" << itemModel->data(itemModel->index(i, 0), Qt::DisplayRole).toString() + << "id:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Id).toInt() + << "avail:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Available).toBool() + << "flags:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Flags).toInt() + << "type:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Type).toInt(); + } + } + else + qDebug() << "Error: model not of class AbstractItemModel"; +} + +// +// AbstractStaticItemModel +// + +void AbstractStaticItemModel::loadItemList() +{ + foreach (const ListItem *item, itemList) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setText(item->text); + modelItem->setData(item->id, IMDR_Id); + modelItem->setData(item->type, IMDR_Type); + modelItem->setData(item->flags, IMDR_Flags); + modelItem->setData(item->isAvailable, IMDR_Available); + appendRow(modelItem); + } + + itemList.clear(); +}; + +// +// RawSourceItemModel +// + +RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_RawSource); + setUpdateMask(IMUE_All &~ (IMUE_Curves | IMUE_Scripts)); + + addItems(SOURCE_TYPE_NONE, RawSource::NoneGroup, 1); + for (int i = 0; i < firmware->getCapability(LuaScripts); i++) + addItems(SOURCE_TYPE_LUA_OUTPUT, RawSource::ScriptsGroup, firmware->getCapability(LuaOutputsPerScript), i * 16); + addItems(SOURCE_TYPE_VIRTUAL_INPUT, RawSource::InputsGroup, firmware->getCapability(VirtualInputs)); + addItems(SOURCE_TYPE_STICK, RawSource::SourcesGroup, board->getCapability(Board::MaxAnalogs)); + addItems(SOURCE_TYPE_TRIM, RawSource::TrimsGroup, board->getCapability(Board::NumTrims)); + addItems(SOURCE_TYPE_MAX, RawSource::SourcesGroup, 1); + addItems(SOURCE_TYPE_SWITCH, RawSource::SwitchesGroup, board->getCapability(Board::Switches)); + addItems(SOURCE_TYPE_CUSTOM_SWITCH, RawSource::SwitchesGroup, firmware->getCapability(LogicalSwitches)); + addItems(SOURCE_TYPE_CYC, RawSource::SourcesGroup, CPN_MAX_CYC); + addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, firmware->getCapability(TrainerInputs)); + addItems(SOURCE_TYPE_CH, RawSource::SourcesGroup, firmware->getCapability(Outputs)); + addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, 5); + addItems(SOURCE_TYPE_TELEMETRY, RawSource::TelemGroup, firmware->getCapability(Sensors) * 3); + addItems(SOURCE_TYPE_GVAR, RawSource::GVarsGroup, firmware->getCapability(Gvars)); +} + +void RawSourceItemModel::setDynamicItemData(QStandardItem * item, const RawSource & src) const +{ + item->setText(src.toString(modelData, generalSettings, boardType)); + item->setData(src.isAvailable(modelData, generalSettings, boardType), IMDR_Available); +} + +void RawSourceItemModel::addItems(const RawSourceType & type, const int group, const int count, const int start) +{ + for (int i = start; i < start + count; i++) { + const RawSource src = RawSource(type, i); + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(src.toValue(), IMDR_Id); + modelItem->setData(type, IMDR_Type); + modelItem->setData(group, IMDR_Flags); + setDynamicItemData(modelItem, src); + appendRow(modelItem); + } +} + +void RawSourceItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 0; i < rowCount(); ++i) + setDynamicItemData(item(i), RawSource(item(i)->data(IMDR_Id).toInt())); + + emit updateComplete(); + } +} + +// +// RawSwitchItemModel +// + +RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_RawSwitch); + setUpdateMask(IMUE_FlightModes | IMUE_LogicalSwitches | IMUE_TeleSensors); + + // Descending switch direction: NOT (!) switches + addItems(SWITCH_TYPE_ACT, -1); + addItems(SWITCH_TYPE_SENSOR, -firmware->getCapability(Sensors)); + addItems(SWITCH_TYPE_TELEMETRY, -1); + addItems(SWITCH_TYPE_FLIGHT_MODE, -firmware->getCapability(FlightModes)); + addItems(SWITCH_TYPE_VIRTUAL, -firmware->getCapability(LogicalSwitches)); + addItems(SWITCH_TYPE_TRIM, -board->getCapability(Board::NumTrimSwitches)); + addItems(SWITCH_TYPE_MULTIPOS_POT, -(board->getCapability(Board::MultiposPots) * board->getCapability(Board::MultiposPotsPositions))); + addItems(SWITCH_TYPE_SWITCH, -board->getCapability(Board::SwitchPositions)); + + // Ascending switch direction (including zero) + addItems(SWITCH_TYPE_TIMER_MODE, 5); + addItems(SWITCH_TYPE_NONE, 1); + addItems(SWITCH_TYPE_SWITCH, board->getCapability(Board::SwitchPositions)); + addItems(SWITCH_TYPE_MULTIPOS_POT, board->getCapability(Board::MultiposPots) * board->getCapability(Board::MultiposPotsPositions)); + addItems(SWITCH_TYPE_TRIM, board->getCapability(Board::NumTrimSwitches)); + addItems(SWITCH_TYPE_VIRTUAL, firmware->getCapability(LogicalSwitches)); + addItems(SWITCH_TYPE_FLIGHT_MODE, firmware->getCapability(FlightModes)); + addItems(SWITCH_TYPE_TELEMETRY, 1); + addItems(SWITCH_TYPE_SENSOR, firmware->getCapability(Sensors)); + addItems(SWITCH_TYPE_ON, 1); + addItems(SWITCH_TYPE_ONE, 1); + addItems(SWITCH_TYPE_ACT, 1); +} + +void RawSwitchItemModel::setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const +{ + item->setText(rsw.toString(boardType, generalSettings, modelData)); + item->setData(rsw.isAvailable(modelData, generalSettings, boardType), IMDR_Available); +} + +void RawSwitchItemModel::addItems(const RawSwitchType & type, int count) +{ + // Most RawSwitch() indices are one-based (vs. typical zero); these are exceptions to the rule: + const static QVector rawSwitchIndexBaseZeroTypes = QVector() << SWITCH_TYPE_NONE << SWITCH_TYPE_ON << SWITCH_TYPE_OFF << SWITCH_TYPE_TIMER_MODE; + // handle exceptions in RawSwitch() index values + const short rawIdxAdj = rawSwitchIndexBaseZeroTypes.contains(type) ? -1 : 0; + + // determine cotext flags + int context = RawSwitch::AllSwitchContexts; + switch (type) { + case SWITCH_TYPE_FLIGHT_MODE: + context &= ~RawSwitch::MixesContext; + // fallthrough + case SWITCH_TYPE_VIRTUAL: + case SWITCH_TYPE_SENSOR: + context &= ~RawSwitch::GlobalFunctionsContext; + break; + + case SWITCH_TYPE_TIMER_MODE: + context = RawSwitch::TimersContext; + break; + + case SWITCH_TYPE_NONE: + context &= ~RawSwitch::TimersContext; + break; + + case SWITCH_TYPE_ON: + case SWITCH_TYPE_ONE: + context = RawSwitch::SpecialFunctionsContext | RawSwitch::GlobalFunctionsContext; + break; + + default: + break; + } + + int i = (count < 0 ? count : 1); + count = (i < 0 ? 0 : count + i); + for ( ; i < count; ++i) { + RawSwitch rs(type, i + rawIdxAdj); + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(rs.toValue(), IMDR_Id); + modelItem->setData(type, IMDR_Type); + modelItem->setData(context, IMDR_Flags); + setDynamicItemData(modelItem, rs); + appendRow(modelItem); + } +} + +void RawSwitchItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 0; i < rowCount(); ++i) + setDynamicItemData(item(i), RawSwitch(item(i)->data(IMDR_Id).toInt())); + + emit updateComplete(); + } +} + +// +// CurveItemModel +// + +CurveItemModel::CurveItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_Curve); + + if (!modelData) + return; + + setUpdateMask(IMUE_Curves); + + const int count = firmware->getCapability(NumCurves); + + for (int i = -count ; i <= count; ++i) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(i, IMDR_Id); + modelItem->setData(i < 0 ? IMDG_Negative : i > 0 ? IMDG_Positive : IMDG_None, IMDR_Flags); + setDynamicItemData(modelItem, i); + appendRow(modelItem); + } +} + +void CurveItemModel::setDynamicItemData(QStandardItem * item, const int value) const +{ + CurveReference cr = CurveReference(CurveReference::CURVE_REF_CUSTOM, value); + item->setText(cr.toString(modelData, false)); + item->setData(cr.isAvailable(), IMDR_Available); +} + +void CurveItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 0; i < rowCount(); ++i) + setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt()); + + emit updateComplete(); + } +} + +// +// GVarReferenceItemModel +// + +GVarReferenceItemModel::GVarReferenceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_GVarRef); + + if (!modelData) + return; + + setUpdateMask(IMUE_GVars | IMUE_FlightModes | IMUE_LogicalSwitches); + + const int count = firmware->getCapability(Gvars); + + if (count > 0) { + addItems(-count); + addItems(count); + } +} + +void GVarReferenceItemModel::addItems(int count) +{ + int i = (count < 0 ? count : 1); + count = (i < 0 ? 0 : count + i); + for ( ; i < count; ++i) { + QStandardItem * modelItem = new QStandardItem(); + AdjustmentReference ar(AdjustmentReference::ADJUST_REF_GVAR, i); + modelItem->setData(ar.toValue(), IMDR_Id); + modelItem->setData(i < 0 ? IMDG_Negative : i > 0 ? IMDG_Positive : IMDG_None, IMDR_Flags); + setDynamicItemData(modelItem, ar); + appendRow(modelItem); + } +} + +void GVarReferenceItemModel::setDynamicItemData(QStandardItem * item, const AdjustmentReference & ar) const +{ + item->setText(ar.toString(modelData, false)); + item->setData(ar.isAvailable(), IMDR_Available); +} + +void GVarReferenceItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 0; i < rowCount(); ++i) + setDynamicItemData(item(i), AdjustmentReference(item(i)->data(IMDR_Id).toInt())); + + emit updateComplete(); + } +} + +// +// ThrottleSourceItemModel +// + +ThrottleSourceItemModel::ThrottleSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_ThrSource); + + if (!modelData) + return; + + setUpdateMask(IMUE_Timers | IMUE_Inputs | IMUE_TeleSensors); + + for (int i = 0; i < modelData->thrTraceSrcCount(); i++) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(i, IMDR_Id); + setDynamicItemData(modelItem, i); + appendRow(modelItem); + } +} + +void ThrottleSourceItemModel::setDynamicItemData(QStandardItem * item, const int value) const +{ + item->setText(modelData->thrTraceSrcToString(value)); + item->setData(modelData->isThrTraceSrcAvailable(generalSettings, value), IMDR_Available); +} + +void ThrottleSourceItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 0; i < rowCount(); ++i) + setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt()); + + emit updateComplete(); + } +} + +// +// CustomFuncActionItemModel +// + +CustomFuncActionItemModel::CustomFuncActionItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_CustomFuncAction); + setUpdateMask(IMUE_All &~ (IMUE_Curves | IMUE_Scripts)); + + for (int i = 0; i < AssignFunc::FuncCount; i++) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(i, IMDR_Id); + modelItem->setData(CustomFunctionData::funcContext(i), IMDR_Flags); + setDynamicItemData(modelItem, i); + appendRow(modelItem); + } +} + +void CustomFuncActionItemModel::setDynamicItemData(QStandardItem * item, const int value) const +{ + item->setText(CustomFunctionData::funcToString((AssignFunc)value, modelData)); + item->setData(CustomFunctionData::isFuncAvailable(value), IMDR_Available); +} + +void CustomFuncActionItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 0; i < rowCount(); ++i) + setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt()); + + emit updateComplete(); + } +} + +// +// CustomFuncResetParamItemModel +// + +CustomFuncResetParamItemModel::CustomFuncResetParamItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_CustomFuncResetParam); + setUpdateMask(IMUE_TeleSensors | IMUE_Timers); + + for (int i = 0; i < CustomFunctionData::resetParamCount(); i++) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(i, IMDR_Id); + setDynamicItemData(modelItem, i); + appendRow(modelItem); + } +} + +void CustomFuncResetParamItemModel::setDynamicItemData(QStandardItem * item, const int value) const +{ + item->setText(CustomFunctionData::resetToString(value, modelData)); + item->setData(CustomFunctionData::isResetParamAvailable(value, modelData), IMDR_Available); +} + +void CustomFuncResetParamItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 0; i < rowCount(); ++i) + setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt()); + + emit updateComplete(); + } +} + +// +// TelemetrySourceItemModel +// + +TelemetrySourceItemModel::TelemetrySourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_TeleSource); + + if (!modelData) + return; + + setUpdateMask(IMUE_TeleSensors | IMUE_Modules); + const int count = firmware->getCapability(Sensors); + + for (int i = -count; i <= count; ++i) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(i, IMDR_Id); + modelItem->setData(i < 0 ? IMDG_Negative : i > 0 ? IMDG_Positive : IMDG_None, IMDR_Flags); + setDynamicItemData(modelItem, i); + appendRow(modelItem); + } +} + +void TelemetrySourceItemModel::setDynamicItemData(QStandardItem * item, const int value) const +{ + item->setText(SensorData::sourceToString(modelData, value)); + item->setData(SensorData::isSourceAvailable(modelData, value), IMDR_Available); +} + +void TelemetrySourceItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 0; i < rowCount(); ++i) { + setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt()); + } + + emit updateComplete(); + } +} + +// +// RssiSourceItemModel +// + +RssiSourceItemModel::RssiSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_RssiSource); + + if (!modelData) + return; + + setUpdateMask(IMUE_TeleSensors | IMUE_Modules); + + for (int i = 0; i <= firmware->getCapability(Sensors); ++i) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setData(i, IMDR_Id); + modelItem->setData(i < 0 ? IMDG_Negative : i > 0 ? IMDG_Positive : IMDG_None, IMDR_Flags); + setDynamicItemData(modelItem, i); + appendRow(modelItem); + } +} + +void RssiSourceItemModel::setDynamicItemData(QStandardItem * item, const int value) const +{ + item->setText(SensorData::rssiSensorToString(modelData, value)); + item->setData(SensorData::isRssiSensorAvailable(modelData, value), IMDR_Available); +} + +void RssiSourceItemModel::update(const int event) +{ + if (doUpdate(event)) { + emit aboutToBeUpdated(); + + for (int i = 0; i < rowCount(); ++i) { + setDynamicItemData(item(i), item(i)->data(IMDR_Id).toInt()); + } + + emit updateComplete(); + } +} + +// +// CurveRefTypeItemModel +// + +CurveRefTypeItemModel::CurveRefTypeItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractStaticItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_CurveRefType); + + for (int i = 0; i <= CurveReference::MAX_CURVE_REF_TYPE; i++) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setText(CurveReference::typeToString((CurveReference::CurveRefType)i)); + modelItem->setData(i, IMDR_Id); + modelItem->setData(CurveReference::isTypeAvailable((CurveReference::CurveRefType)i), IMDR_Available); + appendRow(modelItem); + } +} + +// +// CurveRefFuncItemModel +// + +CurveRefFuncItemModel::CurveRefFuncItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractStaticItemModel(generalSettings, modelData, firmware, board, boardType) +{ + setId(IMID_CurveRefFunc); + + for (int i = 1; i <= CurveReference::functionCount(); i++) { + QStandardItem * modelItem = new QStandardItem(); + modelItem->setText(CurveReference::functionToString(i)); + modelItem->setData(i, IMDR_Id); + modelItem->setData(CurveReference::isFunctionAvailable(i), IMDR_Available); + appendRow(modelItem); + } +} + +// +// PrecisionItemModel +// + +PrecisionItemModel::PrecisionItemModel(const int minDecimals, const int maxDecimals, const QString suffix, const bool placeholders) : + AbstractStaticItemModel() +{ + for (int i = minDecimals, j = maxDecimals; j >= 0; i++, j--) { + QString str = QString("0.%1").arg(QString(i, '0')); + if (placeholders) + str.append(QString(j, '_')); + if (!suffix.isEmpty()) + str.append(QString(" %1").arg(suffix)); + QStandardItem * modelItem = new QStandardItem(); + modelItem->setText(str); + modelItem->setData(i, IMDR_Id); + modelItem->setData(true, IMDR_Available); + appendRow(modelItem); + } +} + +// +// CompoundItemModelFactory +// + +CompoundItemModelFactory::CompoundItemModelFactory(const GeneralSettings * const generalSettings, const ModelData * const modelData) : + generalSettings(generalSettings), + modelData(modelData) +{ + firmware = getCurrentFirmware(); + board = new Boards(getCurrentBoard()); + boardType = getCurrentBoard(); +} + +CompoundItemModelFactory::~CompoundItemModelFactory() +{ + unregisterItemModels(); + delete board; +} + +void CompoundItemModelFactory::addItemModel(const int id) +{ + switch (id) { + case AbstractItemModel::IMID_RawSource: + registerItemModel(new RawSourceItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_RawSwitch: + registerItemModel(new RawSwitchItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_Curve: + registerItemModel(new CurveItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_GVarRef: + registerItemModel(new GVarReferenceItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_ThrSource: + registerItemModel(new ThrottleSourceItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_CustomFuncAction: + registerItemModel(new CustomFuncActionItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_CustomFuncResetParam: + registerItemModel(new CustomFuncResetParamItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_TeleSource: + registerItemModel(new TelemetrySourceItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_RssiSource: + registerItemModel(new RssiSourceItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_CurveRefType: + registerItemModel(new CurveRefTypeItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + case AbstractItemModel::IMID_CurveRefFunc: + registerItemModel(new CurveRefFuncItemModel(generalSettings, modelData, firmware, board, boardType)); + break; + default: + qDebug() << "Error: unknown item model: id"; + break; + } +} + +int CompoundItemModelFactory::registerItemModel(AbstractItemModel * itemModel) +{ + if (itemModel) { + if (!isItemModelRegistered(itemModel->getId())) { + setSourceId(itemModel); + registeredItemModels.append(itemModel); + return itemModel->getId(); + } + else + return itemModel->getId(); + } + return -1; +} + +void CompoundItemModelFactory::unregisterItemModels() +{ + foreach (AbstractItemModel *itemModel, registeredItemModels) { + delete itemModel; + } +} + +void CompoundItemModelFactory::unregisterItemModel(const int id) +{ + AbstractItemModel * itemModel = getItemModel(id); + if (itemModel) + delete itemModel; +} + +AbstractItemModel * CompoundItemModelFactory::getItemModel(const int id) const +{ + foreach (AbstractItemModel * itemModel, registeredItemModels) { + if (itemModel->getId() == id) + return itemModel; + } + + return nullptr; +} + +AbstractItemModel * CompoundItemModelFactory::getItemModel(const QString name) const +{ + foreach (AbstractItemModel * itemModel, registeredItemModels) { + if (itemModel->getName() == name) + return itemModel; + } + + return nullptr; +} + +bool CompoundItemModelFactory::isItemModelRegistered(const int id) const +{ + foreach (AbstractItemModel * itemModel, registeredItemModels) { + if (itemModel->getId() == id) + return true; + } + + return false; +} + +void CompoundItemModelFactory::update(const int event) +{ + foreach (AbstractItemModel * itemModel, registeredItemModels) { + itemModel->update(event); + } +} + +void CompoundItemModelFactory::dumpAllItemModelContents() const +{ + foreach (AbstractItemModel * itemModel, registeredItemModels) { + AbstractItemModel::dumpItemModelContents(itemModel); + } +} + +void CompoundItemModelFactory::setSourceId(AbstractItemModel * itemModel) +{ + if (itemModel && itemModel->getId() == AbstractItemModel::IMID_Unknown) + itemModel->setId(AbstractItemModel::IMID_ReservedCount + registeredItemModels.count()); +} diff --git a/companion/src/datamodels/compounditemmodels.h b/companion/src/datamodels/compounditemmodels.h new file mode 100644 index 0000000000..d5a7c5f279 --- /dev/null +++ b/companion/src/datamodels/compounditemmodels.h @@ -0,0 +1,380 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include "rawsource.h" +#include "rawswitch.h" + +#include + +class GeneralSettings; +class ModelData; +class AdjustmentReference; + +class AbstractItemModel: public QStandardItemModel +{ + Q_OBJECT + public: + enum ItemModelId { + IMID_Unknown, + IMID_RawSource, + IMID_RawSwitch, + IMID_Curve, + IMID_GVarRef, + IMID_ThrSource, + IMID_CustomFuncAction, + IMID_CustomFuncResetParam, + IMID_TeleSource, + IMID_RssiSource, + IMID_CurveRefType, + IMID_CurveRefFunc, + IMID_ReservedCount, + IMID_Custom + }; + Q_ENUM(ItemModelId) + + enum ItemModelDataRoles { + IMDR_Id = Qt::UserRole, + IMDR_Type, + IMDR_Flags, + IMDR_Available + }; + Q_ENUM(ItemModelDataRoles) + + enum ItemModelDataGroups { + IMDG_None = 0x01, + IMDG_Negative = 0x02, + IMDG_Positive = 0x04 + }; + Q_ENUM(ItemModelDataGroups) + + enum ItemModelUpdateEvent { + IMUE_None = 0, + IMUE_SystemRefresh = 1 << 0, + IMUE_Channels = 1 << 1, + IMUE_Curves = 1 << 2, + IMUE_FlightModes = 1 << 3, + IMUE_GVars = 1 << 4, + IMUE_Inputs = 1 << 5, + IMUE_LogicalSwitches = 1 << 6, + IMUE_Scripts = 1 << 7, + IMUE_TeleSensors = 1 << 8, + IMUE_Timers = 1 << 9, + IMUE_Modules = 1 << 10, + IMUE_All = IMUE_SystemRefresh | IMUE_Channels | IMUE_Curves | IMUE_FlightModes | IMUE_GVars | IMUE_Inputs | + IMUE_LogicalSwitches | IMUE_Scripts | IMUE_TeleSensors | IMUE_Timers | IMUE_Modules + }; + Q_ENUM(ItemModelUpdateEvent) + + explicit AbstractItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + QStandardItemModel(nullptr), + generalSettings(generalSettings), + modelData(modelData), + firmware(firmware), + board(board), + boardType(boardType), + m_id(IMID_Unknown), + m_name(""), + m_updateMask(IMUE_None) + {} + + virtual ~AbstractItemModel() {} + + void setId(int id) { m_id = id; } + int getId () const { return m_id; } + bool isReservedModelId() const { return m_id > IMID_Unknown && m_id < IMID_ReservedCount; } + void setName(QString name) { m_name = name; } + QString getName() const { return isReservedModelId() ? idToString(m_id) : m_name; } + void setUpdateMask(const int mask) { m_updateMask = mask; } + int getUpdateMask() const { return m_updateMask; } + + inline bool doUpdate(const int event) const { return m_updateMask & event; } + + AbstractItemModel * getItemModel(const int id) const; + + static void dumpItemModelContents(AbstractItemModel * itemModel); + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) = 0; + + protected: + const GeneralSettings * generalSettings; + const ModelData * modelData; + Firmware * firmware; + const Boards * board; + const Board::Type boardType; + + private: + int m_id = IMID_Unknown; + QString m_name = ""; + int m_updateMask = IMUE_None; + + static QString idToString(const int value); +}; + +class AbstractStaticItemModel: public AbstractItemModel +{ + Q_OBJECT + public: + explicit AbstractStaticItemModel(const GeneralSettings * const generalSettings = nullptr, const ModelData * const modelData = nullptr, + Firmware * firmware = nullptr, const Boards * const board = nullptr, + const Board::Type boardType = Board::BOARD_UNKNOWN) : + AbstractItemModel(generalSettings, modelData, firmware, board, boardType) {} + virtual ~AbstractStaticItemModel() {}; + + inline void appendToItemList(QString text, int id, bool isAvailable = true, int type = 0, int flags = 0) + { itemList.append(new ListItem(text, id, isAvailable, type, flags)); } + + void loadItemList(); + + public slots: + virtual void update(const int event) override final {} + + protected: + struct ListItem + { + QString text; + int id; + bool isAvailable; + int type; + int flags; + + ListItem() {} + ListItem(QString p_text, int p_id, bool p_isAvailable, int p_type, int p_flags) : + text(p_text), id(p_id), isAvailable(p_isAvailable), type(p_type), flags(p_flags) {} + }; + + QVector itemList; +}; + +class AbstractDynamicItemModel: public AbstractItemModel +{ + Q_OBJECT + public: + explicit AbstractDynamicItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType) : + AbstractItemModel(generalSettings, modelData, firmware, board, boardType) {} + virtual ~AbstractDynamicItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) {} + + signals: + void aboutToBeUpdated(); + void updateComplete(); +}; + +class RawSourceItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~RawSourceItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const RawSource & src) const; + void addItems(const RawSourceType & type, const int group, const int count, const int start = 0); +}; + +class RawSwitchItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~RawSwitchItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const; + void addItems(const RawSwitchType & type, int count); +}; + +class CurveItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit CurveItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~CurveItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const int value) const; +}; + +class GVarReferenceItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit GVarReferenceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~GVarReferenceItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const AdjustmentReference & ar) const; + void addItems(int count); +}; + +class ThrottleSourceItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit ThrottleSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~ThrottleSourceItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const int value) const; +}; + +class CustomFuncActionItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit CustomFuncActionItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~CustomFuncActionItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const int value) const; +}; + +class CustomFuncResetParamItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit CustomFuncResetParamItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~CustomFuncResetParamItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const int value) const; +}; + +class TelemetrySourceItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit TelemetrySourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~TelemetrySourceItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const int value) const; +}; + +class RssiSourceItemModel: public AbstractDynamicItemModel +{ + Q_OBJECT + public: + explicit RssiSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~RssiSourceItemModel() {}; + + public slots: + virtual void update(const int event = IMUE_SystemRefresh) override; + + protected: + virtual void setDynamicItemData(QStandardItem * item, const int value) const; +}; + +class CurveRefTypeItemModel : public AbstractStaticItemModel +{ + Q_OBJECT + public: + explicit CurveRefTypeItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~CurveRefTypeItemModel() {}; +}; + +class CurveRefFuncItemModel : public AbstractStaticItemModel +{ + Q_OBJECT + public: + explicit CurveRefFuncItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, + Firmware * firmware, const Boards * const board, const Board::Type boardType); + virtual ~CurveRefFuncItemModel() {}; +}; + +class PrecisionItemModel : public AbstractStaticItemModel +{ + Q_OBJECT + public: + explicit PrecisionItemModel(const int minDecimals, const int maxDecimals, const QString suffix = "", const bool placeholders = false); + virtual ~PrecisionItemModel() {}; +}; + +// +// CompoundItemModelFactory +// + +class CompoundItemModelFactory +{ + public: + CompoundItemModelFactory(const GeneralSettings * const generalSettings, const ModelData * const modelData); + virtual ~CompoundItemModelFactory(); + + void addItemModel(const int id); + int registerItemModel(AbstractItemModel * itemModel); + void unregisterItemModels(); + void unregisterItemModel(const int id); + bool isItemModelRegistered(const int id) const; + AbstractItemModel * getItemModel(const int id) const; + AbstractItemModel * getItemModel(const QString name) const; + void update(const int event = AbstractItemModel::IMUE_SystemRefresh); + void dumpAllItemModelContents() const; + + protected: + const GeneralSettings * generalSettings; + const ModelData * modelData; + Firmware * firmware; + Boards * board; + Board::Type boardType; + QVector registeredItemModels; + + private: + void setSourceId(AbstractItemModel * itemModel); +}; diff --git a/companion/src/datamodels/filtereditemmodels.cpp b/companion/src/datamodels/filtereditemmodels.cpp new file mode 100644 index 0000000000..4f4e27262d --- /dev/null +++ b/companion/src/datamodels/filtereditemmodels.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "filtereditemmodels.h" + +FilteredItemModel::FilteredItemModel(AbstractItemModel * sourceModel, int flags) : + QSortFilterProxyModel(nullptr), + filterFlags(0), + m_id(0), + m_name("") +{ + setFilterRole(AbstractItemModel::IMDR_Available); + setFilterKeyColumn(0); + setFilterFlags(flags); + setDynamicSortFilter(true); + setSourceModel(sourceModel); + + AbstractDynamicItemModel * itemModel = qobject_cast(sourceModel); + if (itemModel) { + connect(itemModel, &AbstractDynamicItemModel::aboutToBeUpdated, this, &FilteredItemModel::onAboutToBeUpdated); + connect(itemModel, &AbstractDynamicItemModel::updateComplete, this, &FilteredItemModel::onUpdateComplete); + } +} + +void FilteredItemModel::setFilterFlags(int flags) +{ + if (filterFlags != flags) { + filterFlags = flags; + invalidateFilter(); + } +} + +bool FilteredItemModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const +{ + const QModelIndex & srcIdx = sourceModel()->index(sourceRow, 0, sourceParent); + if (!srcIdx.isValid() || !sourceModel()->data(srcIdx, filterRole()).toBool()) + return false; + + if (!filterFlags) + return true; + + bool ok; + const int flags = sourceModel()->data(srcIdx, AbstractItemModel::IMDR_Flags).toInt(&ok); + return (ok && (!flags || (filterFlags & flags))); +} + +void FilteredItemModel::update() const +{ + AbstractDynamicItemModel * itemModel = qobject_cast(sourceModel()); + if (itemModel) + itemModel->update(); +} + +void FilteredItemModel::onAboutToBeUpdated() +{ + emit aboutToBeUpdated(); +} + +void FilteredItemModel::onUpdateComplete() +{ + emit updateComplete(); +} + +// static +void FilteredItemModel::dumpItemModelContents(FilteredItemModel * itemModel) +{ + if (itemModel) { + qDebug() << "id:" << itemModel->getId() << "name:" << itemModel->getName(); + + for (int i = 0; i < itemModel->rowCount(); ++i) { + qDebug() << "row:" << i + << "text:" << itemModel->data(itemModel->index(i, 0), Qt::DisplayRole).toString() + << "id:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Id).toInt() + << "avail:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Available).toBool() + << "flags:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Flags).toInt() + << "type:" << itemModel->data(itemModel->index(i, 0), AbstractItemModel::IMDR_Type).toInt(); + } + } + else + qDebug() << "Error: model not of class FilteredItemModel"; +} + +// +// FilteredItemModelFactory +// + +FilteredItemModelFactory::FilteredItemModelFactory() +{ +} + +FilteredItemModelFactory::~FilteredItemModelFactory() +{ + unregisterItemModels(); +} + +int FilteredItemModelFactory::registerItemModel(FilteredItemModel * itemModel, const QString name, const int id) +{ + if (itemModel) { + if (isItemModelRegistered(name)) { + qDebug() << "Error: item model already registered with name:" << name; + return 0; + } + else if (id > -1 && isItemModelRegistered(id)) { + qDebug() << "Error: item model already registered with id:" << id; + return 0; + } + else { + int fid = id; + if (fid < 0) { + fid = registeredItemModels.count() + 1; + AbstractItemModel * mdl = qobject_cast(itemModel->sourceModel()); + if (mdl) { + fid += mdl->getId() * 128; + } + } + itemModel->setId(fid); + itemModel->setName(name); + registeredItemModels.append(itemModel); + return fid; + } + } + + qDebug() << "Error: invalid filtered item model pointer"; + return 0; +} + +void FilteredItemModelFactory::unregisterItemModels() +{ + foreach (FilteredItemModel * itemModel, registeredItemModels) { + delete itemModel; + } +} + +void FilteredItemModelFactory::unregisterItemModel(const int id) +{ + FilteredItemModel * itemModel = getItemModel(id); + if (itemModel) + delete itemModel; +} + +bool FilteredItemModelFactory::isItemModelRegistered(const int id) const +{ + return getItemModel(id); +} + +bool FilteredItemModelFactory::isItemModelRegistered(const QString name) const +{ + return getItemModel(name); +} + +FilteredItemModel * FilteredItemModelFactory::getItemModel(const int id) const +{ + foreach (FilteredItemModel * itemModel, registeredItemModels) { + if (itemModel->getId() == id) + return itemModel; + } + + return nullptr; +} + +FilteredItemModel * FilteredItemModelFactory::getItemModel(const QString name) const +{ + foreach (FilteredItemModel * itemModel, registeredItemModels) { + if (itemModel->getName() == name) + return itemModel; + } + + return nullptr; +} + +void FilteredItemModelFactory::update() +{ + foreach (FilteredItemModel * itemModel, registeredItemModels) { + itemModel->update(); + } +} + +void FilteredItemModelFactory::dumpItemModelContents(const int id) const +{ + FilteredItemModel::dumpItemModelContents(getItemModel(id)); +} + +void FilteredItemModelFactory::dumpItemModelContents(const QString name) const +{ + FilteredItemModel::dumpItemModelContents(getItemModel(name)); +} + +void FilteredItemModelFactory::dumpAllItemModelContents() const +{ + foreach (FilteredItemModel * itemModel, registeredItemModels) { + FilteredItemModel::dumpItemModelContents(itemModel); + } +} + +// +// CurveRefFilteredFactory +// + +CurveRefFilteredFactory::CurveRefFilteredFactory(CompoundItemModelFactory * sharedItemModels, const int curveFlags, const int gvarRefFlags) +{ + if (!sharedItemModels) { + qDebug() << "Error: invalid compound item model factory pointer"; + return; + } + + registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_Curve), curveFlags), + fidToString(CRFIM_CURVE), CRFIM_CURVE); + registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef), gvarRefFlags), + fidToString(CRFIM_GVARREF), CRFIM_GVARREF); + registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_CurveRefType)), + fidToString(CRFIM_TYPE), CRFIM_TYPE); + registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_CurveRefFunc)), + fidToString(CRFIM_FUNC), CRFIM_FUNC); +} + +CurveRefFilteredFactory::~CurveRefFilteredFactory() +{ +} + +// static +QString CurveRefFilteredFactory::fidToString(const int value) +{ + switch(value) { + case CRFIM_CURVE: + return "Curves"; + case CRFIM_GVARREF: + return "Global Variables"; + case CRFIM_TYPE: + return "Types"; + case CRFIM_FUNC: + return "Functions"; + default: + return CPN_STR_UNKNOWN_ITEM; + } +} diff --git a/companion/src/datamodels/filtereditemmodels.h b/companion/src/datamodels/filtereditemmodels.h new file mode 100644 index 0000000000..24668704d3 --- /dev/null +++ b/companion/src/datamodels/filtereditemmodels.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#ifndef FILTEREDITEMMODELS_H +#define FILTEREDITEMMODELS_H + +#include "compounditemmodels.h" + +#include +#include +#include + +class FilteredItemModel: public QSortFilterProxyModel +{ + Q_OBJECT + public: + enum DataFilters { + AllFilter = AbstractItemModel::IMDG_Negative | AbstractItemModel::IMDG_None | AbstractItemModel::IMDG_Positive, + AllExcludeNoneFilter = AllFilter &~ AbstractItemModel::IMDG_None, + NegativeFilter = AbstractItemModel::IMDG_Negative | AbstractItemModel::IMDG_None, + NegativeExcludeNoneFilter = AbstractItemModel::IMDG_Negative, + PositiveFilter = AbstractItemModel::IMDG_Positive | AbstractItemModel::IMDG_None, + PositiveExcludeNoneFilter = AbstractItemModel::IMDG_Positive + }; + Q_ENUM(DataFilters) + + explicit FilteredItemModel(AbstractItemModel * sourceModel, int flags); + explicit FilteredItemModel(AbstractItemModel * sourceModel) : + FilteredItemModel(sourceModel, 0) {} + virtual ~FilteredItemModel() {}; + + void setId(int id) { m_id = id; } + int getId() const { return m_id; }; + void setName(QString name) { m_name = name; } + QString getName() const { return m_name; } + + static void dumpItemModelContents(FilteredItemModel * itemModel); + + public slots: + void setFilterFlags(int flags); + void update() const; + void onAboutToBeUpdated(); + void onUpdateComplete(); + + signals: + void aboutToBeUpdated(); + void updateComplete(); + + protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override; + + int filterFlags; + + private: + int m_id = 0; + QString m_name = ""; +}; + +class FilteredItemModelFactory +{ + public: + explicit FilteredItemModelFactory(); + virtual ~FilteredItemModelFactory(); + + int registerItemModel(FilteredItemModel * itemModel, const QString name, const int id = -1); + void unregisterItemModels(); + void unregisterItemModel(const int id); + bool isItemModelRegistered(const int id) const; + bool isItemModelRegistered(const QString name) const; + FilteredItemModel * getItemModel(const int id) const; + FilteredItemModel * getItemModel(const QString name) const; + void update(); + + void dumpItemModelContents(const int id) const; + void dumpItemModelContents(const QString name) const; + void dumpAllItemModelContents() const; + + protected: + QVector registeredItemModels; +}; + +class CurveRefFilteredFactory : public FilteredItemModelFactory +{ + public: + enum FilteredItemModelId { + CRFIM_CURVE, + CRFIM_GVARREF, + CRFIM_TYPE, + CRFIM_FUNC + }; + + explicit CurveRefFilteredFactory(CompoundItemModelFactory * sharedItemModels, const int curveFlags = 0, const int gvarRefFlags = 0); + virtual ~CurveRefFilteredFactory(); + + static QString fidToString(const int value); +}; + +#endif // FILTEREDITEMMODELS_H diff --git a/companion/src/datamodels/rawitemdatamodels.cpp b/companion/src/datamodels/rawitemdatamodels.cpp deleted file mode 100644 index d7c1b66821..0000000000 --- a/companion/src/datamodels/rawitemdatamodels.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * 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 "rawitemdatamodels.h" -#include "generalsettings.h" -#include "eeprominterface.h" -#include "modeldata.h" - -RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) : - AbstractRawItemDataModel(generalSettings, modelData, parent) -{ - const Boards board = Boards(getCurrentBoard()); - Firmware * fw = getCurrentFirmware(); - - addItems(SOURCE_TYPE_NONE, RawSource::NoneGroup, 1); - for (int i = 0; i < fw->getCapability(LuaScripts); i++) - addItems(SOURCE_TYPE_LUA_OUTPUT, RawSource::ScriptsGroup, fw->getCapability(LuaOutputsPerScript), i * 16); - addItems(SOURCE_TYPE_VIRTUAL_INPUT, RawSource::InputsGroup, fw->getCapability(VirtualInputs)); - addItems(SOURCE_TYPE_STICK, RawSource::SourcesGroup, board.getCapability(Board::MaxAnalogs)); - addItems(SOURCE_TYPE_ROTARY_ENCODER, RawSource::SourcesGroup, fw->getCapability(RotaryEncoders)); - addItems(SOURCE_TYPE_TRIM, RawSource::TrimsGroup, board.getCapability(Board::NumTrims)); - addItems(SOURCE_TYPE_MAX, RawSource::SourcesGroup, 1); - addItems(SOURCE_TYPE_SWITCH, RawSource::SwitchesGroup, board.getCapability(Board::Switches)); - addItems(SOURCE_TYPE_CUSTOM_SWITCH, RawSource::SwitchesGroup, fw->getCapability(LogicalSwitches)); - addItems(SOURCE_TYPE_CYC, RawSource::SourcesGroup, CPN_MAX_CYC); - addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, fw->getCapability(TrainerInputs)); - addItems(SOURCE_TYPE_CH, RawSource::SourcesGroup, fw->getCapability(Outputs)); - addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, 5); - addItems(SOURCE_TYPE_TELEMETRY, RawSource::TelemGroup, fw->getCapability(Sensors) * 3); - addItems(SOURCE_TYPE_GVAR, RawSource::GVarsGroup, fw->getCapability(Gvars)); -} - -void RawSourceItemModel::setDynamicItemData(QStandardItem * item, const RawSource & src) const -{ - Board::Type board = getCurrentBoard(); - item->setText(src.toString(modelData, generalSettings, board)); - item->setData(src.isAvailable(modelData, generalSettings, board), IsAvailableRole); -} - -void RawSourceItemModel::addItems(const RawSourceType & type, const int group, const int count, const int start) -{ - for (int i = start; i < start + count; i++) { - const RawSource src = RawSource(type, i); - QStandardItem * modelItem = new QStandardItem(); - modelItem->setData(src.toValue(), ItemIdRole); - modelItem->setData(type, ItemTypeRole); - modelItem->setData(group, ItemFlagsRole); - setDynamicItemData(modelItem, src); - appendRow(modelItem); - } -} - -void RawSourceItemModel::update() -{ - emit dataAboutToBeUpdated(); - - for (int i = 0; i < rowCount(); ++i) - setDynamicItemData(item(i), RawSource(item(i)->data(ItemIdRole).toInt())); - - emit dataUpdateComplete(); -} - - -// -// RawSwitchItemModel -// - -RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) : - AbstractRawItemDataModel(generalSettings, modelData, parent) -{ - Boards board = Boards(getCurrentBoard()); - Firmware * fw = getCurrentFirmware(); - - // Descending switch direction: NOT (!) switches - addItems(SWITCH_TYPE_ACT, -1); - addItems(SWITCH_TYPE_SENSOR, -fw->getCapability(Sensors)); - addItems(SWITCH_TYPE_TELEMETRY, -1); - addItems(SWITCH_TYPE_FLIGHT_MODE, -fw->getCapability(FlightModes)); - addItems(SWITCH_TYPE_VIRTUAL, -fw->getCapability(LogicalSwitches)); - addItems(SWITCH_TYPE_ROTARY_ENCODER, -fw->getCapability(RotaryEncoders)); - addItems(SWITCH_TYPE_TRIM, -board.getCapability(Board::NumTrimSwitches)); - addItems(SWITCH_TYPE_MULTIPOS_POT, -(board.getCapability(Board::MultiposPots) * board.getCapability(Board::MultiposPotsPositions))); - addItems(SWITCH_TYPE_SWITCH, -board.getCapability(Board::SwitchPositions)); - - // Ascending switch direction (including zero) - addItems(SWITCH_TYPE_TIMER_MODE, 5); - addItems(SWITCH_TYPE_NONE, 1); - addItems(SWITCH_TYPE_SWITCH, board.getCapability(Board::SwitchPositions)); - addItems(SWITCH_TYPE_MULTIPOS_POT, board.getCapability(Board::MultiposPots) * board.getCapability(Board::MultiposPotsPositions)); - addItems(SWITCH_TYPE_TRIM, board.getCapability(Board::NumTrimSwitches)); - addItems(SWITCH_TYPE_ROTARY_ENCODER, fw->getCapability(RotaryEncoders)); - addItems(SWITCH_TYPE_VIRTUAL, fw->getCapability(LogicalSwitches)); - addItems(SWITCH_TYPE_FLIGHT_MODE, fw->getCapability(FlightModes)); - addItems(SWITCH_TYPE_TELEMETRY, 1); - addItems(SWITCH_TYPE_SENSOR, fw->getCapability(Sensors)); - addItems(SWITCH_TYPE_ON, 1); - addItems(SWITCH_TYPE_ONE, 1); - addItems(SWITCH_TYPE_ACT, 1); -} - -void RawSwitchItemModel::setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const -{ - const Board::Type board = getCurrentBoard(); - item->setText(rsw.toString(board, generalSettings, modelData)); - item->setData(rsw.isAvailable(modelData, generalSettings, board), IsAvailableRole); -} - -void RawSwitchItemModel::addItems(const RawSwitchType & type, int count) -{ - // Most RawSwitch() indices are one-based (vs. typical zero); these are exceptions to the rule: - const static QVector rawSwitchIndexBaseZeroTypes = QVector() << SWITCH_TYPE_NONE << SWITCH_TYPE_ON << SWITCH_TYPE_OFF << SWITCH_TYPE_TIMER_MODE; - // handle exceptions in RawSwitch() index values - const short rawIdxAdj = rawSwitchIndexBaseZeroTypes.contains(type) ? -1 : 0; - - // determine cotext flags - int context = RawSwitch::AllSwitchContexts; - switch (type) { - case SWITCH_TYPE_FLIGHT_MODE: - context &= ~RawSwitch::MixesContext; - // fallthrough - case SWITCH_TYPE_VIRTUAL: - case SWITCH_TYPE_SENSOR: - context &= ~RawSwitch::GlobalFunctionsContext; - break; - - case SWITCH_TYPE_TIMER_MODE: - context = RawSwitch::TimersContext; - break; - - case SWITCH_TYPE_NONE: - context &= ~RawSwitch::TimersContext; - break; - - case SWITCH_TYPE_ON: - case SWITCH_TYPE_ONE: - context = RawSwitch::SpecialFunctionsContext | RawSwitch::GlobalFunctionsContext; - break; - - default: - break; - } - - int i = (count < 0 ? count : 1); - count = (i < 0 ? 0 : count + i); - for ( ; i < count; ++i) { - RawSwitch rs(type, i + rawIdxAdj); - QStandardItem * modelItem = new QStandardItem(); - modelItem->setData(rs.toValue(), ItemIdRole); - modelItem->setData(type, ItemTypeRole); - modelItem->setData(context, ItemFlagsRole); - setDynamicItemData(modelItem, rs); - appendRow(modelItem); - } -} - -void RawSwitchItemModel::update() -{ - emit dataAboutToBeUpdated(); - - for (int i = 0; i < rowCount(); ++i) - setDynamicItemData(item(i), RawSwitch(item(i)->data(ItemIdRole).toInt())); - - emit dataUpdateComplete(); -} - -// -// CurveItemModel -// - -CurveItemModel::CurveItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) : - AbstractRawItemDataModel(generalSettings, modelData, parent) -{ - const int count = getCurrentFirmware()->getCapability(NumCurves); - - for (int i = -count ; i <= count; ++i) { - QStandardItem * modelItem = new QStandardItem(); - modelItem->setData(i, ItemIdRole); - int flags; - if (i < 0) - flags = DataGroups::NegativeGroup; - else if (i > 0) - flags = DataGroups::PositiveGroup; - else - flags = DataGroups::NoneGroup; - modelItem->setData(flags, ItemFlagsRole); - setDynamicItemData(modelItem, i); - appendRow(modelItem); - } -} - -void CurveItemModel::setDynamicItemData(QStandardItem * item, int index) const -{ - item->setText(CurveReference(CurveReference::CURVE_REF_CUSTOM, index).toString(modelData, false)); - item->setData(true, IsAvailableRole); -} - -void CurveItemModel::update() -{ - emit dataAboutToBeUpdated(); - - for (int i = 0; i < rowCount(); ++i) - setDynamicItemData(item(i), item(i)->data(ItemIdRole).toInt()); - - emit dataUpdateComplete(); -} - -// -// CommonItemModels -// - -CommonItemModels::CommonItemModels(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) : - QObject(parent) -{ - m_rawSourceItemModel = new RawSourceItemModel(generalSettings, modelData, parent); - m_rawSwitchItemModel = new RawSwitchItemModel(generalSettings, modelData, parent); - m_curveItemModel = new CurveItemModel(generalSettings, modelData, parent); -} - -CommonItemModels::~CommonItemModels() -{ -} - -void CommonItemModels::update(const RadioModelObjects radioModelObjects) -{ - switch (radioModelObjects) { - case RMO_CHANNELS: - case RMO_INPUTS: - case RMO_TELEMETRY_SENSORS: - case RMO_TIMERS: - m_rawSourceItemModel->update(); - break; - case RMO_FLIGHT_MODES: - case RMO_GLOBAL_VARIABLES: - case RMO_LOGICAL_SWITCHES: - m_rawSourceItemModel->update(); - m_rawSwitchItemModel->update(); - break; - case RMO_CURVES: - m_curveItemModel->update(); - break; - case RMO_SCRIPTS: - // no need to refresh - break; - default: - qDebug() << "Unknown RadioModelObject:" << radioModelObjects; - } -} diff --git a/companion/src/datamodels/rawitemdatamodels.h b/companion/src/datamodels/rawitemdatamodels.h deleted file mode 100644 index 48cb55fd20..0000000000 --- a/companion/src/datamodels/rawitemdatamodels.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * 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. - */ - -#ifndef RAWITEMDATAMODELS_H -#define RAWITEMDATAMODELS_H - -#include "rawsource.h" -#include "rawswitch.h" - -#include - -class GeneralSettings; -class ModelData; - -class AbstractRawItemDataModel: public QStandardItemModel -{ - Q_OBJECT - public: - enum DataRoles { ItemIdRole = Qt::UserRole, ItemTypeRole, ItemFlagsRole, IsAvailableRole }; - Q_ENUM(DataRoles) - - enum DataGroups { - NoneGroup = 0x01, - NegativeGroup = 0x02, - PositiveGroup = 0x04 - }; - Q_ENUM(DataGroups) - - explicit AbstractRawItemDataModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr) : - QStandardItemModel(parent), - generalSettings(generalSettings), - modelData(modelData) - {} - - public slots: - virtual void update() = 0; - - signals: - void dataAboutToBeUpdated(); - void dataUpdateComplete(); - - protected: - const GeneralSettings * generalSettings; - const ModelData * modelData; -}; - - -class RawSourceItemModel: public AbstractRawItemDataModel -{ - Q_OBJECT - public: - explicit RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr); - - public slots: - void update() override; - - protected: - void setDynamicItemData(QStandardItem * item, const RawSource & src) const; - void addItems(const RawSourceType & type, const int group, const int count, const int start = 0); -}; - - -class RawSwitchItemModel: public AbstractRawItemDataModel -{ - Q_OBJECT - public: - explicit RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr); - - public slots: - void update() override; - - protected: - void setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const; - void addItems(const RawSwitchType & type, int count); -}; - - -class CurveItemModel: public AbstractRawItemDataModel -{ - Q_OBJECT - public: - explicit CurveItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr); - - public slots: - void update() override; - - protected: - void setDynamicItemData(QStandardItem * item, int index) const; -}; - - -class CommonItemModels: public QObject -{ - Q_OBJECT - public: - enum RadioModelObjects { - RMO_CHANNELS, - RMO_CURVES, - RMO_FLIGHT_MODES, - RMO_GLOBAL_VARIABLES, - RMO_INPUTS, - RMO_LOGICAL_SWITCHES, - RMO_SCRIPTS, - RMO_TELEMETRY_SENSORS, - RMO_TIMERS - }; - Q_ENUM(RadioModelObjects) - - explicit CommonItemModels(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr); - ~CommonItemModels(); - - void update(const RadioModelObjects radioModelObjects); - RawSourceItemModel * rawSourceItemModel() const { return m_rawSourceItemModel; } - RawSwitchItemModel * rawSwitchItemModel() const { return m_rawSwitchItemModel; } - CurveItemModel * curveItemModel() const { return m_curveItemModel; } - - private: - RawSourceItemModel *m_rawSourceItemModel; - RawSwitchItemModel *m_rawSwitchItemModel; - CurveItemModel *m_curveItemModel; -}; - -#endif // RAWITEMDATAMODELS_H diff --git a/companion/src/datamodels/rawitemfilteredmodel.cpp b/companion/src/datamodels/rawitemfilteredmodel.cpp deleted file mode 100644 index abe9ca08e5..0000000000 --- a/companion/src/datamodels/rawitemfilteredmodel.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * 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 "rawitemfilteredmodel.h" - -RawItemFilteredModel::RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent) : - QSortFilterProxyModel(parent), - filterFlags(0) -{ - setFilterRole(AbstractRawItemDataModel::IsAvailableRole); - setFilterKeyColumn(0); - setFilterFlags(flags); - setDynamicSortFilter(true); - setSourceModel(sourceModel); - - AbstractRawItemDataModel * itemModel = qobject_cast(sourceModel); - if (itemModel) { - connect(itemModel, &AbstractRawItemDataModel::dataAboutToBeUpdated, this, &RawItemFilteredModel::onDataAboutToBeUpdated); - connect(itemModel, &AbstractRawItemDataModel::dataUpdateComplete, this, &RawItemFilteredModel::onDataUpdateComplete); - } -} - -void RawItemFilteredModel::setFilterFlags(int flags) -{ - if (filterFlags != flags) { - filterFlags = flags; - invalidateFilter(); - } -} - -bool RawItemFilteredModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const -{ - const QModelIndex & srcIdx = sourceModel()->index(sourceRow, 0, sourceParent); - if (!srcIdx.isValid() || !sourceModel()->data(srcIdx, filterRole()).toBool()) - return false; - - if (!filterFlags) - return true; - - bool ok; - const int flags = sourceModel()->data(srcIdx, AbstractRawItemDataModel::ItemFlagsRole).toInt(&ok); - return (ok && (!flags || (filterFlags & flags))); -} - -void RawItemFilteredModel::update() const -{ - AbstractRawItemDataModel * itemModel = qobject_cast(sourceModel()); - if (itemModel) - itemModel->update(); -} - -void RawItemFilteredModel::onDataAboutToBeUpdated() -{ - emit dataAboutToBeUpdated(); -} - -void RawItemFilteredModel::onDataUpdateComplete() -{ - emit dataUpdateComplete(); -} diff --git a/companion/src/datamodels/rawitemfilteredmodel.h b/companion/src/datamodels/rawitemfilteredmodel.h deleted file mode 100644 index 3274460f7a..0000000000 --- a/companion/src/datamodels/rawitemfilteredmodel.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * 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. - */ - -#ifndef RAWITEMFILTEREDMODEL_H -#define RAWITEMFILTEREDMODEL_H - -#include "rawitemdatamodels.h" - -#include - -class GeneralSettings; -class ModelData; - -class RawItemFilteredModel: public QSortFilterProxyModel -{ - Q_OBJECT - public: - enum DataFilters { - AllFilter = AbstractRawItemDataModel::NegativeGroup | AbstractRawItemDataModel::NoneGroup | AbstractRawItemDataModel::PositiveGroup, - AllExcludeNoneFilter = AllFilter &~ AbstractRawItemDataModel::NoneGroup, - NegativeFilter = AbstractRawItemDataModel::NegativeGroup | AbstractRawItemDataModel::NoneGroup, - NegativeExcludeNoneFilter = AbstractRawItemDataModel::NegativeGroup, - PositiveFilter = AbstractRawItemDataModel::PositiveGroup | AbstractRawItemDataModel::NoneGroup, - PositiveExcludeNoneFilter = AbstractRawItemDataModel::PositiveGroup - }; - Q_ENUM(DataFilters) - - explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent = nullptr); - explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, QObject * parent = nullptr) : RawItemFilteredModel(sourceModel, 0, parent) {} - - public slots: - void setFilterFlags(int flags); - void update() const; - void onDataAboutToBeUpdated(); - void onDataUpdateComplete(); - - signals: - void dataAboutToBeUpdated(); - void dataUpdateComplete(); - - protected: - bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override; - - int filterFlags; -}; -#endif // RAWITEMFILTEREDMODEL_H diff --git a/companion/src/dialogs/filesyncdialog.cpp b/companion/src/dialogs/filesyncdialog.cpp index 3927a3ffd9..30026c9311 100644 --- a/companion/src/dialogs/filesyncdialog.cpp +++ b/companion/src/dialogs/filesyncdialog.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include FileSyncDialog::FileSyncDialog(QWidget * parent, const SyncProcess::SyncOptions & syncOptions) : QDialog(parent), diff --git a/companion/src/firmwares/CMakeLists.txt b/companion/src/firmwares/CMakeLists.txt index e50d9241b4..b79d8fd425 100644 --- a/companion/src/firmwares/CMakeLists.txt +++ b/companion/src/firmwares/CMakeLists.txt @@ -2,27 +2,34 @@ set(firmwares_SRCS adjustmentreference.cpp boards.cpp + curvedata.cpp curvereference.cpp customfunctiondata.cpp eeprominterface.cpp generalsettings.cpp gvardata.cpp - io_data.cpp + input_data.cpp + flightmodedata.cpp + heli_data.cpp logicalswitchdata.cpp + mixdata.cpp modeldata.cpp moduledata.cpp multiprotocols.cpp + output_data.cpp radiodata.cpp radiodataconversionstate.cpp rawsource.cpp rawswitch.cpp sensordata.cpp telem_data.cpp + timerdata.cpp afhds3.cpp ersky9x/ersky9xeeprom.cpp ersky9x/ersky9xinterface.cpp opentx/opentxeeprom.cpp opentx/opentxinterface.cpp + datahelpers.cpp ) string(REPLACE ".cpp" ".h" firmwares_HDRS "${firmwares_SRCS}") diff --git a/companion/src/firmwares/adjustmentreference.cpp b/companion/src/firmwares/adjustmentreference.cpp index 7181e15dd2..ae487effad 100644 --- a/companion/src/firmwares/adjustmentreference.cpp +++ b/companion/src/firmwares/adjustmentreference.cpp @@ -19,7 +19,7 @@ */ #include "adjustmentreference.h" -#include "radiodata.h" // for ModelData +#include "modeldata.h" AdjustmentReference::AdjustmentReference(int value) { @@ -76,3 +76,8 @@ QString AdjustmentReference::toString(const ModelData * model, const bool sign) } return ret; } + +const bool AdjustmentReference::isAvailable() const +{ + return true; +} diff --git a/companion/src/firmwares/adjustmentreference.h b/companion/src/firmwares/adjustmentreference.h index 2a7b7e1416..9377cd5e88 100644 --- a/companion/src/firmwares/adjustmentreference.h +++ b/companion/src/firmwares/adjustmentreference.h @@ -45,6 +45,7 @@ class AdjustmentReference { bool isSet() const { return type != ADJUST_REF_VALUE || value != 0; } bool isValid(const int value) const; QString toString(const ModelData * model = nullptr, const bool sign = false) const; + const bool isAvailable() const; inline const int toValue() const { diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp index 82e645d057..a201d50eda 100644 --- a/companion/src/firmwares/boards.cpp +++ b/companion/src/firmwares/boards.cpp @@ -79,6 +79,8 @@ uint32_t Boards::getFourCC(Type board) return 0x3278746F; case BOARD_JUMPER_T12: return 0x3D78746F; + case BOARD_JUMPER_TLITE: + return 0x4278746F; case BOARD_JUMPER_T16: return 0x3F78746F; case BOARD_JUMPER_T18: @@ -87,11 +89,11 @@ uint32_t Boards::getFourCC(Type board) return 0x3878746F; case BOARD_RADIOMASTER_TX12: return 0x4178746F; - case BOARD_UNKNOWN: - break; + case BOARD_RADIOMASTER_T8: + return 0x4378746F; + default: + return 0; } - - return 0; } int Boards::getEEpromSize(Board::Type board) @@ -113,7 +115,9 @@ int Boards::getEEpromSize(Board::Type board) case BOARD_TARANIS_X9DP_2019: case BOARD_TARANIS_X9E: case BOARD_JUMPER_T12: + case BOARD_JUMPER_TLITE: case BOARD_RADIOMASTER_TX12: + case BOARD_RADIOMASTER_T8: return EESIZE_TARANIS; case BOARD_UNKNOWN: return EESIZE_MAX; @@ -124,9 +128,9 @@ int Boards::getEEpromSize(Board::Type board) case BOARD_JUMPER_T18: case BOARD_RADIOMASTER_TX16S: return 0; + default: + return 0; } - - return 0; } int Boards::getFlashSize(Type board) @@ -148,7 +152,9 @@ int Boards::getFlashSize(Type board) case BOARD_TARANIS_X9DP_2019: case BOARD_TARANIS_X9E: case BOARD_JUMPER_T12: + case BOARD_JUMPER_TLITE: case BOARD_RADIOMASTER_TX12: + case BOARD_RADIOMASTER_T8: return FSIZE_TARANIS; case BOARD_HORUS_X12S: case BOARD_X10: @@ -181,7 +187,7 @@ SwitchInfo Boards::getSwitchInfo(Board::Type board, int index) if (index < DIM(switches)) return switches[index]; } - else if (IS_TARANIS_XLITE(board)) { + else if (IS_TARANIS_XLITE(board) || IS_JUMPER_TLITE(board)) { const Board::SwitchInfo switches[] = { {SWITCH_3POS, "SA"}, {SWITCH_3POS, "SB"}, @@ -232,6 +238,16 @@ SwitchInfo Boards::getSwitchInfo(Board::Type board, int index) if (index < DIM(switches)) return switches[index]; } + else if (IS_RADIOMASTER_T8(board)) { + const Board::SwitchInfo switches[] = { + {SWITCH_TOGGLE, "SA"}, + {SWITCH_3POS, "SB"}, + {SWITCH_3POS, "SC"}, + {SWITCH_TOGGLE, "SD"} + }; + if (index < DIM(switches)) + return switches[index]; + } else if (IS_JUMPER_T12(board)) { const Board::SwitchInfo switches[] = { {SWITCH_3POS, "SA"}, @@ -310,6 +326,8 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) case Pots: if (IS_TARANIS_X9LITE(board)) return 1; + else if (IS_JUMPER_TLITE(board)) + return 0; else if (IS_TARANIS_SMALL(board)) return 2; else if (IS_TARANIS_X9E(board)) @@ -367,6 +385,8 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) return 7; else if (board == BOARD_TARANIS_X7) return 8; + else if (board == BOARD_JUMPER_TLITE) + return 4; else if (IS_FAMILY_T12(board)) return 8; else if (IS_TARANIS_XLITE(board)) @@ -383,9 +403,11 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) case FactoryInstalledSwitches: if (IS_TARANIS_X9E(board)) return 8; - if (IS_FAMILY_T12(board)) + else if (IS_JUMPER_TLITE(board)) + return 4; + else if (IS_FAMILY_T12(board)) return 6; - if (IS_HORUS_X12S(board)) + else if (IS_HORUS_X12S(board)) return 8; else return getCapability(board, Switches); @@ -530,8 +552,6 @@ QString Boards::getBoardName(Board::Type board) return "Taranis X7/X7S"; case BOARD_TARANIS_X7_ACCESS: return "Taranis X7/X7S Access"; - case BOARD_JUMPER_T12: - return "Jumper T12"; case BOARD_TARANIS_XLITE: return "Taranis X-Lite"; case BOARD_TARANIS_XLITES: @@ -560,6 +580,10 @@ QString Boards::getBoardName(Board::Type board) return "Horus X10/X10S"; case BOARD_X10_EXPRESS: return "Horus X10/X10S Express"; + case BOARD_JUMPER_T12: + return "Jumper T12"; + case BOARD_JUMPER_TLITE: + return "Jumper T-Lite"; case BOARD_JUMPER_T16: return "Jumper T16"; case BOARD_JUMPER_T18: @@ -568,6 +592,8 @@ QString Boards::getBoardName(Board::Type board) return "Radiomaster TX16S"; case BOARD_RADIOMASTER_TX12: return "Radiomaster TX12"; + case BOARD_RADIOMASTER_T8: + return "Radiomaster T8"; default: return tr("Unknown"); } diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h index 1e15884850..e55aeae373 100644 --- a/companion/src/firmwares/boards.h +++ b/companion/src/firmwares/boards.h @@ -53,10 +53,12 @@ namespace Board { BOARD_RADIOMASTER_TX16S, BOARD_JUMPER_T18, BOARD_RADIOMASTER_TX12, + BOARD_RADIOMASTER_T8, + BOARD_JUMPER_TLITE, + BOARD_TYPE_COUNT, + BOARD_TYPE_MAX = BOARD_TYPE_COUNT - 1 }; - constexpr int BOARD_TYPE_MAX = BOARD_RADIOMASTER_TX12; - enum PotType { POT_NONE, @@ -204,6 +206,11 @@ inline bool IS_JUMPER_T12(Board::Type board) return board == Board::BOARD_JUMPER_T12; } +inline bool IS_JUMPER_TLITE(Board::Type board) +{ + return board == Board::BOARD_JUMPER_TLITE; +} + inline bool IS_JUMPER_T16(Board::Type board) { return board == Board::BOARD_JUMPER_T16; @@ -224,6 +231,11 @@ inline bool IS_RADIOMASTER_TX12(Board::Type board) return board == Board::BOARD_RADIOMASTER_TX12; } +inline bool IS_RADIOMASTER_T8(Board::Type board) +{ + return board == Board::BOARD_RADIOMASTER_T8; +} + inline bool IS_FAMILY_T16(Board::Type board) { return board == Board::BOARD_JUMPER_T16 || board == Board::BOARD_RADIOMASTER_TX16S || board == Board::BOARD_JUMPER_T18; @@ -231,7 +243,7 @@ inline bool IS_FAMILY_T16(Board::Type board) inline bool IS_FAMILY_T12(Board::Type board) { - return board == Board::BOARD_JUMPER_T12 || board == Board::BOARD_RADIOMASTER_TX12; + return board == Board::BOARD_JUMPER_T12 || board == Board::BOARD_RADIOMASTER_TX12 || board == Board::BOARD_RADIOMASTER_T8 || board == Board::BOARD_JUMPER_TLITE; } inline bool IS_TARANIS_XLITE(Board::Type board) diff --git a/companion/src/firmwares/curvedata.cpp b/companion/src/firmwares/curvedata.cpp new file mode 100644 index 0000000000..c32eac4cc0 --- /dev/null +++ b/companion/src/firmwares/curvedata.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "curvedata.h" +#include "radiodata.h" + +CurveData::CurveData() +{ + clear(); +} + +void CurveData::clear(int count) +{ + memset(reinterpret_cast(this), 0, sizeof(CurveData)); + this->count = count; +} + +bool CurveData::isEmpty() const +{ + for (int i = 0; i < count; i++) { + if (points[i].y != 0) { + return false; + } + } + return true; +} + +QString CurveData::nameToString(const int idx) const +{ + return RadioData::getElementName(tr("CV"), idx + 1, name); +} diff --git a/companion/src/firmwares/curvedata.h b/companion/src/firmwares/curvedata.h new file mode 100644 index 0000000000..cb083375ec --- /dev/null +++ b/companion/src/firmwares/curvedata.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include "constants.h" + +#include + +class CurvePoint { + public: + int8_t x; + int8_t y; +}; + +#define CURVEDATA_NAME_LEN 6 + +class CurveData { + Q_DECLARE_TR_FUNCTIONS(CurveData) + + public: + enum CurveType { + CURVE_TYPE_STANDARD, + CURVE_TYPE_CUSTOM, + CURVE_TYPE_LAST = CURVE_TYPE_CUSTOM + }; + + CurveData(); + + CurveType type; + bool smooth; + int count; + CurvePoint points[CPN_MAX_POINTS]; + char name[CURVEDATA_NAME_LEN + 1]; + + void clear(int count = 5); + bool isEmpty() const; + QString nameToString(const int idx) const; +}; diff --git a/companion/src/firmwares/curvereference.cpp b/companion/src/firmwares/curvereference.cpp index 449dc02664..926c2d2ae3 100644 --- a/companion/src/firmwares/curvereference.cpp +++ b/companion/src/firmwares/curvereference.cpp @@ -22,7 +22,7 @@ #include "adjustmentreference.h" #include "helpers.h" #include "modeldata.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" const QString CurveReference::toString(const ModelData * model, bool verbose) const { @@ -63,6 +63,11 @@ const bool CurveReference::isValueNumber() const return (type == CURVE_REF_DIFF || type == CURVE_REF_EXPO) && AdjustmentReference(value).type == AdjustmentReference::ADJUST_REF_VALUE; } +const bool CurveReference::isAvailable() const +{ + return true; +} + // static int CurveReference::getDefaultValue(const CurveRefType type, const bool isGVar) { @@ -77,7 +82,7 @@ int CurveReference::getDefaultValue(const CurveRefType type, const bool isGVar) // static QString CurveReference::typeToString(const CurveRefType type) { - const QStringList strl = { "Diff", "Expo" , "Func", "Curve" }; + const QStringList strl = { tr("Diff"), tr("Expo") , tr("Func"), tr("Curve") }; int idx = (int)type; if (idx < 0 || idx >= strl.count()) @@ -86,8 +91,6 @@ QString CurveReference::typeToString(const CurveRefType type) return strl.at(idx); } -constexpr int MAX_CURVE_REF_FUNC { 6 }; - // static QString CurveReference::functionToString(const int value) { @@ -100,76 +103,65 @@ QString CurveReference::functionToString(const int value) return strl.at(idx); } +// static +bool CurveReference::isTypeAvailable(const CurveRefType type) +{ + bool ret = false; + Firmware * fw = getCurrentFirmware(); + + switch(type) { + case CURVE_REF_DIFF: + if (fw->getCapability(HasInputDiff)) + ret = true; + break; + case CURVE_REF_EXPO: + if (fw->getCapability(HasMixerExpo)) + ret = true; + break; + case CURVE_REF_FUNC: + case CURVE_REF_CUSTOM: + ret = true; + break; + } + + return ret; +} + +// static +bool CurveReference::isFunctionAvailable(const int value) +{ + return true; +} + +// static +int CurveReference::functionCount() +{ + return 6; +} + + /* * CurveReferenceUIManager */ -constexpr int CURVE_REF_UI_HIDE_DIFF { 0x01 }; -constexpr int CURVE_REF_UI_HIDE_EXPO { 0x02 }; -constexpr int CURVE_REF_UI_HIDE_NEGATIVE_CURVES { 0x04 }; - -// static -bool CurveReferenceUIManager::firsttime { true }; -int CurveReferenceUIManager::flags { 0 }; -bool CurveReferenceUIManager::hasCapabilityGvars { false }; -int CurveReferenceUIManager::numCurves { 0 }; -RawItemFilteredModel * CurveReferenceUIManager::curveItemModel { nullptr }; -QStandardItemModel * CurveReferenceUIManager::tempModel { nullptr }; - -CurveReferenceUIManager::CurveReferenceUIManager(QComboBox * curveValueCB, CurveReference & curve, const ModelData & model, - RawItemFilteredModel * curveItemModel, QObject * parent) : - QObject(parent), - curveTypeCB(nullptr), - curveGVarCB(nullptr), - curveValueSB(nullptr), - curveValueCB(curveValueCB), - curve(curve), - model(model), - lock(false) -{ - init(curveItemModel); -} - CurveReferenceUIManager::CurveReferenceUIManager(QComboBox * curveTypeCB, QCheckBox * curveGVarCB, QSpinBox * curveValueSB, - QComboBox * curveValueCB, CurveReference & curve, const ModelData & model, - RawItemFilteredModel * curveItemModel, QObject * parent) : + QComboBox * curveValueCB, CurveReference & curveRef, const ModelData & model, + CurveRefFilteredFactory * curveRefFilteredFactory, QObject * parent) : QObject(parent), curveTypeCB(curveTypeCB), curveGVarCB(curveGVarCB), curveValueSB(curveValueSB), curveValueCB(curveValueCB), - curve(curve), + curveRef(curveRef), model(model), - lock(false) + lock(false), + filteredModelFactory(curveRefFilteredFactory) { - init(curveItemModel); -} - -CurveReferenceUIManager::~CurveReferenceUIManager() -{ - delete tempModel; -} - -void CurveReferenceUIManager::init(RawItemFilteredModel * curveModel) -{ - tempModel = new QStandardItemModel(); - - if (firsttime) { - firsttime = false; - Firmware * fw = getCurrentFirmware(); - hasCapabilityGvars = fw->getCapability(Gvars); - numCurves = fw->getCapability(NumCurves); - curveItemModel = curveModel; - - if (!fw->getCapability(HasInputDiff)) - flags |= (CURVE_REF_UI_HIDE_DIFF | CURVE_REF_UI_HIDE_NEGATIVE_CURVES); - - if (!fw->getCapability(HasMixerExpo)) - flags |= CURVE_REF_UI_HIDE_EXPO; - } + hasCapabilityGvars = getCurrentFirmware()->getCapability(Gvars); if (curveTypeCB) { - populateTypeCB(curveTypeCB, curve); + curveTypeCB->setModel(filteredModelFactory->getItemModel(CurveRefFilteredFactory::CRFIM_TYPE)); + curveTypeCB->setCurrentIndex(curveTypeCB->findData((int)curveRef.type)); connect(curveTypeCB, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int))); } @@ -182,13 +174,20 @@ void CurveReferenceUIManager::init(RawItemFilteredModel * curveModel) connect(curveValueSB, SIGNAL(editingFinished()), this, SLOT(valueSBChanged())); } - curveValueCB->setSizeAdjustPolicy(QComboBox::AdjustToContents); - curveValueCB->setMaxVisibleItems(10); - connect(curveValueCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valueCBChanged())); + if (curveValueCB) { + curveValueCB->setSizeAdjustPolicy(QComboBox::AdjustToContents); + curveValueCB->setMaxVisibleItems(10); + connect(curveValueCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valueCBChanged())); + } update(); } +CurveReferenceUIManager::~CurveReferenceUIManager() +{ + delete filteredModelFactory; +} + #define CURVE_REF_UI_GVAR_SHOW (1<<0) #define CURVE_REF_UI_VALUE_SHOW (1<<1) #define CURVE_REF_UI_REF_SHOW (1<<2) @@ -198,12 +197,12 @@ void CurveReferenceUIManager::update() lock = true; int widgetsMask = 0; - if (curve.type == CurveReference::CURVE_REF_DIFF || curve.type == CurveReference::CURVE_REF_EXPO) { + if (curveRef.type == CurveReference::CURVE_REF_DIFF || curveRef.type == CurveReference::CURVE_REF_EXPO) { if (hasCapabilityGvars) widgetsMask |= CURVE_REF_UI_GVAR_SHOW; - if (curve.isValueNumber()) { + if (curveRef.isValueNumber()) { curveGVarCB->setChecked(false); - curveValueSB->setValue(curve.value); + curveValueSB->setValue(curveRef.value); widgetsMask |= CURVE_REF_UI_VALUE_SHOW; } else { @@ -216,7 +215,7 @@ void CurveReferenceUIManager::update() } if(curveTypeCB) { - curveTypeCB->setCurrentIndex(curveTypeCB->findData(curve.type)); + curveTypeCB->setCurrentIndex(curveTypeCB->findData(curveRef.type)); curveTypeCB->show(); } if(curveGVarCB) @@ -224,8 +223,8 @@ void CurveReferenceUIManager::update() if(curveValueSB) curveValueSB->setVisible(widgetsMask & CURVE_REF_UI_VALUE_SHOW); if(curveValueCB) { - if (curve.isValueReference()) - populateValueCB(curveValueCB, curve, &model); + if (curveRef.isValueReference()) + populateValueCB(curveValueCB); curveValueCB->setVisible(widgetsMask & CURVE_REF_UI_REF_SHOW); } @@ -235,7 +234,7 @@ void CurveReferenceUIManager::update() void CurveReferenceUIManager::gvarCBChanged(int state) { if (!lock) { - curve.value = CurveReference::getDefaultValue(curve.type, state); + curveRef.value = CurveReference::getDefaultValue(curveRef.type, state); update(); } } @@ -244,7 +243,7 @@ void CurveReferenceUIManager::typeChanged(int value) { if (!lock) { CurveReference::CurveRefType type = (CurveReference::CurveRefType)curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt(); - curve = CurveReference(type, CurveReference::getDefaultValue(type)); + curveRef = CurveReference(type, CurveReference::getDefaultValue(type)); update(); } } @@ -252,7 +251,7 @@ void CurveReferenceUIManager::typeChanged(int value) void CurveReferenceUIManager::valueSBChanged() { if (!lock) { - curve.value = curveValueSB->value(); + curveRef.value = curveValueSB->value(); update(); } } @@ -260,47 +259,24 @@ void CurveReferenceUIManager::valueSBChanged() void CurveReferenceUIManager::valueCBChanged() { if (!lock) { - curve.value = curveValueCB->itemData(curveValueCB->currentIndex()).toInt(); + curveRef.value = curveValueCB->itemData(curveValueCB->currentIndex()).toInt(); update(); } } -// static -void CurveReferenceUIManager::populateTypeCB(QComboBox * cb, const CurveReference & curveRef) +void CurveReferenceUIManager::populateValueCB(QComboBox * cb) { if (cb) { - cb->clear(); - for (int i = 0; i <= CurveReference::MAX_CURVE_REF_TYPE; i++) { - if ((curveRef.type == CurveReference::CURVE_REF_DIFF && !(flags & CURVE_REF_UI_HIDE_DIFF)) || - (curveRef.type == CurveReference::CURVE_REF_EXPO && !(flags & CURVE_REF_UI_HIDE_EXPO)) || - (curveRef.type != CurveReference::CURVE_REF_DIFF && curveRef.type != CurveReference::CURVE_REF_EXPO)) - cb->addItem(CurveReference::typeToString((CurveReference::CurveRefType)i), i); - } - - cb->setCurrentIndex(cb->findData((int)curveRef.type)); - } -} - -// static -void CurveReferenceUIManager::populateValueCB(QComboBox * cb, const CurveReference & curveRef, const ModelData * model) -{ - if (cb) { - cb->setModel(tempModel); // do not want to clear/alter the shared curves model and set to nullptr is invalid - switch (curveRef.type) { case CurveReference::CURVE_REF_DIFF: case CurveReference::CURVE_REF_EXPO: - cb->clear(); - Helpers::populateGVCB(*cb, curveRef.value, *model); + cb->setModel(filteredModelFactory->getItemModel(CurveRefFilteredFactory::CRFIM_GVARREF)); break; case CurveReference::CURVE_REF_FUNC: - cb->clear(); - for (int i = 1; i <= MAX_CURVE_REF_FUNC; i++) { - cb->addItem(CurveReference::functionToString(i), i); - } + cb->setModel(filteredModelFactory->getItemModel(CurveRefFilteredFactory::CRFIM_FUNC)); break; case CurveReference::CURVE_REF_CUSTOM: - cb->setModel(curveItemModel); + cb->setModel(filteredModelFactory->getItemModel(CurveRefFilteredFactory::CRFIM_CURVE)); break; default: break; diff --git a/companion/src/firmwares/curvereference.h b/companion/src/firmwares/curvereference.h index 0a1c7a180d..c4482c742a 100644 --- a/companion/src/firmwares/curvereference.h +++ b/companion/src/firmwares/curvereference.h @@ -29,7 +29,7 @@ class ModelData; -class RawItemFilteredModel; +class CurveRefFilteredFactory; class CurveReference { @@ -63,6 +63,7 @@ class CurveReference { const bool isValueNumber() const; const bool isValueReference() const { return !isValueNumber(); } const QString toString(const ModelData * model = nullptr, bool verbose = true) const; + const bool isAvailable() const; CurveRefType type; int value; @@ -78,6 +79,9 @@ class CurveReference { static int getDefaultValue(const CurveRefType type, const bool isGVar = false); static QString typeToString(const CurveRefType type); static QString functionToString(const int value); + static bool isTypeAvailable(const CurveRefType type); + static bool isFunctionAvailable(const int value); + static int functionCount(); }; class CurveReferenceUIManager : public QObject { @@ -85,38 +89,34 @@ class CurveReferenceUIManager : public QObject { Q_OBJECT public: - CurveReferenceUIManager(QComboBox *curveValueCB, CurveReference & curve, const ModelData & model, - RawItemFilteredModel * curveItemModel, QObject * parent = nullptr); - CurveReferenceUIManager(QComboBox *curveTypeCB, QCheckBox *curveGVarCB, QSpinBox *curveValueSB, QComboBox *curveValueCB, - CurveReference & curve, const ModelData & model, RawItemFilteredModel * curveItemModel, QObject * parent = nullptr); + explicit CurveReferenceUIManager(QComboBox *curveTypeCB, QCheckBox *curveGVarCB, QSpinBox *curveValueSB, QComboBox *curveValueCB, + CurveReference & curve, const ModelData & model, CurveRefFilteredFactory * curveRefFilteredFactory, + QObject * parent = nullptr); + + explicit CurveReferenceUIManager(QComboBox *curveValueCB, CurveReference & curve, const ModelData & model, + CurveRefFilteredFactory * curveRefFilteredFactory, QObject * parent = nullptr) : + CurveReferenceUIManager(nullptr, nullptr, nullptr, curveValueCB, curve, model, curveRefFilteredFactory, parent) {} + virtual ~CurveReferenceUIManager(); - void init(RawItemFilteredModel * curveModel); - void update(); protected slots: void gvarCBChanged(int); void typeChanged(int); void valueSBChanged(); void valueCBChanged(); + void update(); - protected: + private: QComboBox *curveTypeCB; QCheckBox *curveGVarCB; QSpinBox *curveValueSB; QComboBox *curveValueCB; - CurveReference & curve; + CurveReference & curveRef; const ModelData & model; bool lock; - - static bool firsttime; - static int flags; - static bool hasCapabilityGvars; - static int numCurves; - static RawItemFilteredModel * curveItemModel; - static QStandardItemModel * tempModel; - - static void populateTypeCB(QComboBox * cb, const CurveReference & curveRef); - static void populateValueCB(QComboBox * cb, const CurveReference & curveRef, const ModelData * model = nullptr); + bool hasCapabilityGvars; + CurveRefFilteredFactory *filteredModelFactory; + void populateValueCB(QComboBox * cb); }; #endif // CURVEREFERENCE_H diff --git a/companion/src/firmwares/customfunctiondata.cpp b/companion/src/firmwares/customfunctiondata.cpp index d6918e27c8..98157cae24 100644 --- a/companion/src/firmwares/customfunctiondata.cpp +++ b/companion/src/firmwares/customfunctiondata.cpp @@ -22,6 +22,17 @@ #include "eeprominterface.h" #include "radiodata.h" #include "radiodataconversionstate.h" +#include "compounditemmodels.h" + +void CustomFunctionData::convert(RadioDataConversionState & cstate) +{ + cstate.setComponent(tr("CFN"), 8); + cstate.setSubComp(nameToString(cstate.subCompIdx, (cstate.toModel() ? false : true))); + swtch.convert(cstate); + if (func == FuncVolume || func == FuncBacklight || func == FuncPlayValue || (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast && adjustMode == 1)) { + param = RawSource(param).convert(cstate.withComponentField("PARAM")).toValue(); + } +} void CustomFunctionData::clear() { @@ -36,14 +47,21 @@ bool CustomFunctionData::isEmpty() const return (swtch.type == SWITCH_TYPE_NONE); } -QString CustomFunctionData::nameToString(int index, bool globalContext) const +// static +QString CustomFunctionData::nameToString(const int index, const bool globalContext) { - return RadioData::getElementName((globalContext ? tr("GF") : tr("SF")), index+1, 0, true); + return RadioData::getElementName((globalContext ? tr("GF") : tr("SF")), index + 1, 0, true); } QString CustomFunctionData::funcToString(const ModelData * model) const { - if (func >= FuncOverrideCH1 && func <= FuncOverrideCH32) + return funcToString(func, model); +} + +// static +QString CustomFunctionData::funcToString(const AssignFunc func, const ModelData * model) +{ + if (func >= FuncOverrideCH1 && func <= FuncOverrideCHLast) return tr("Override %1").arg(RawSource(SOURCE_TYPE_CH, func).toString(model)); else if (func == FuncTrainer) return tr("Trainer Sticks"); @@ -65,8 +83,8 @@ QString CustomFunctionData::funcToString(const ModelData * model) const return tr("Haptic"); else if (func == FuncReset) return tr("Reset"); - else if (func >= FuncSetTimer1 && func <= FuncSetTimer3) - return tr("Set Timer %1").arg(func-FuncSetTimer1+1); + else if (func >= FuncSetTimer1 && func <= FuncSetTimerLast) + return tr("Set %1").arg(RawSource(SOURCE_TYPE_SPECIAL, SOURCE_TYPE_SPECIAL_TIMER1_IDX + func - FuncSetTimer1).toString(model)); else if (func == FuncVario) return tr("Vario"); else if (func == FuncPlayPrompt) @@ -76,7 +94,7 @@ QString CustomFunctionData::funcToString(const ModelData * model) const else if (func == FuncPlayValue) return tr("Play Value"); else if (func == FuncPlayScript) - return tr("Play Script"); + return tr("Lua Script"); else if (func == FuncLogs) return tr("SD Logs"); else if (func == FuncVolume) @@ -90,62 +108,22 @@ QString CustomFunctionData::funcToString(const ModelData * model) const else if (func == FuncBackgroundMusicPause) return tr("Background Music Pause"); else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast) - return tr("Adjust %1").arg(RawSource(SOURCE_TYPE_GVAR, func-FuncAdjustGV1).toString(model)); + return tr("Adjust %1").arg(RawSource(SOURCE_TYPE_GVAR, func - FuncAdjustGV1).toString(model)); else if (func == FuncSetFailsafe) return tr("Set Failsafe"); else if (func == FuncRangeCheckInternalModule) - return tr("RangeCheck Int. Module"); + return tr("Range Check Int. Module"); else if (func == FuncRangeCheckExternalModule) - return tr("RangeCheck Ext. Module"); + return tr("Range Check Ext. Module"); else if (func == FuncBindInternalModule) return tr("Bind Int. Module"); else if (func == FuncBindExternalModule) return tr("Bind Ext. Module"); else { - return QString("???"); // Highlight unknown functions with output of question marks.(BTW should not happen that we do not know what a function is) + return QString(CPN_STR_UNKNOWN_ITEM); } } -void CustomFunctionData::populateResetParams(const ModelData * model, QComboBox * b, unsigned int value = 0) -{ - int val = 0; - Firmware * firmware = Firmware::getCurrentVariant(); - - b->addItem(tr("Timer1"), val++); - b->addItem(tr("Timer2"), val++); - b->addItem( tr("Timer3"), val++); - b->addItem(tr("Flight"), val++); - b->addItem(tr("Telemetry"), val++); - int reCount = firmware->getCapability(RotaryEncoders); - if (reCount == 1) { - b->addItem(tr("Rotary Encoder"), val++); - } - else if (reCount == 2) { - b->addItem(tr("REa"), val++); - b->addItem(tr("REb"), val++); - } - if (model) { - for (int i = 0; i < firmware->getCapability(Sensors); ++i) { - if (model->sensorData[i].isAvailable()) { - RawSource item = RawSource(SOURCE_TYPE_TELEMETRY, 3 * i); - b->addItem(item.toString(model), val + i); - } - } - } - b->setCurrentIndex(b->findData(value)); -} - -void CustomFunctionData::populatePlaySoundParams(QStringList & qs) -{ - qs <<"Beep 1" << "Beep 2" << "Beep 3" << "Warn1" << "Warn2" << "Cheep" << "Ratata" << "Tick" << "Siren" << "Ring" ; - qs << "SciFi" << "Robot" << "Chirp" << "Tada" << "Crickt" << "AlmClk" ; -} - -void CustomFunctionData::populateHapticParams(QStringList & qs) -{ - qs << "0" << "1" << "2" << "3"; -} - QString CustomFunctionData::paramToString(const ModelData * model) const { QStringList qs; @@ -153,34 +131,19 @@ QString CustomFunctionData::paramToString(const ModelData * model) const return QString("%1").arg(param); } else if (func == FuncLogs) { - return QString("%1").arg(param/10.0) + tr("s"); + return QString("%1").arg(param / 10.0) + tr("s"); } else if (func == FuncPlaySound) { - CustomFunctionData::populatePlaySoundParams(qs); - if (param>=0 && param<(int)qs.count()) - return qs.at(param); - else - return tr("Inconsistent parameter"); + return playSoundToString(param); } else if (func == FuncPlayHaptic) { - CustomFunctionData::populateHapticParams(qs); - if (param>=0 && param<(int)qs.count()) - return qs.at(param); - else - return tr("Inconsistent parameter"); + return harpicToString(param); } else if (func == FuncReset) { - QComboBox cb; - CustomFunctionData::populateResetParams(model, &cb); - int pos = cb.findData(param); - if (pos >= 0) - return cb.itemText(pos); - else - return tr("Inconsistent parameter"); + return resetToString(param, model); } else if (func == FuncVolume || func == FuncPlayValue || func == FuncBacklight) { - RawSource item(param); - return item.toString(model); + return RawSource(param).toString(model); } else if (func == FuncPlayPrompt || func == FuncPlayBoth) { if ( getCurrentFirmware()->getCapability(VoicesAsNumbers)) { @@ -193,16 +156,14 @@ QString CustomFunctionData::paramToString(const ModelData * model) const else if (func >= FuncAdjustGV1 && func < FuncCount) { switch (adjustMode) { case FUNC_ADJUST_GVAR_CONSTANT: - return tr("Value ")+QString("%1").arg(param); + return gvarAdjustModeToString(adjustMode) + QString(" %1").arg(param); case FUNC_ADJUST_GVAR_SOURCE: case FUNC_ADJUST_GVAR_GVAR: return RawSource(param).toString(); case FUNC_ADJUST_GVAR_INCDEC: - float val; - QString unit; - val = param * model->gvarData[func - FuncAdjustGV1].multiplierGet(); - unit = model->gvarData[func - FuncAdjustGV1].unitToString(); - return QString("Increment: %1%2").arg(val).arg(unit); + const float val = param * model->gvarData[func - FuncAdjustGV1].multiplierGet(); + const QString unit = model->gvarData[func - FuncAdjustGV1].unitToString(); + return gvarAdjustModeToString(adjustMode) + QString(": %1%2").arg(val).arg(unit); } } return ""; @@ -210,24 +171,29 @@ QString CustomFunctionData::paramToString(const ModelData * model) const QString CustomFunctionData::repeatToString() const { - if (repeatParam == -1) { - return tr("played once, not during startup"); + return repeatToString(repeatParam); +} + +// static +QString CustomFunctionData::repeatToString(const int value) +{ + if (value == -1) { + return tr("Played once, not during startup"); } - else if (repeatParam == 0) { - return ""; + else if (value == 0) { + return tr("No repeat"); } else { - unsigned int step = 1; - return tr("repeat(%1s)").arg(step*repeatParam); + return tr("Repeat %1s").arg(value); } } QString CustomFunctionData::enabledToString() const { - if ((func >= FuncOverrideCH1 && func <= FuncOverrideCH32) || + if ((func >= FuncOverrideCH1 && func <= FuncOverrideCHLast) || (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast) || (func == FuncReset) || - (func >= FuncSetTimer1 && func <= FuncSetTimer2) || + (func >= FuncSetTimer1 && func <= FuncSetTimerLast) || (func == FuncVolume) || (func == FuncBacklight) || (func <= FuncInstantTrim)) { @@ -238,12 +204,197 @@ QString CustomFunctionData::enabledToString() const return ""; } -void CustomFunctionData::convert(RadioDataConversionState & cstate) +// static +bool CustomFunctionData::isFuncAvailable(const int index) { - cstate.setComponent(tr("CFN"), 8); - cstate.setSubComp(nameToString(cstate.subCompIdx, (cstate.toModel() ? false : true))); - swtch.convert(cstate); - if (func == FuncVolume || func == FuncBacklight || func == FuncPlayValue || (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast && adjustMode == 1)) { - param = RawSource(param).convert(cstate.withComponentField("PARAM")).toValue(); + Firmware * fw = getCurrentFirmware(); + + bool ret = (((index >= FuncOverrideCH1 && index <= FuncOverrideCHLast) && !fw->getCapability(SafetyChannelCustomFunction)) || + ((index == FuncVolume || index == FuncBackgroundMusic || index == FuncBackgroundMusicPause) && !fw->getCapability(HasVolume)) || + ((index == FuncPlayScript && !IS_HORUS_OR_TARANIS(fw->getBoard()))) || + ((index == FuncPlayHaptic) && !fw->getCapability(Haptic)) || + ((index == FuncPlayBoth) && !fw->getCapability(HasBeeper)) || + ((index == FuncLogs) && !fw->getCapability(HasSDLogs)) || + ((index >= FuncSetTimer1 && index <= FuncSetTimerLast) && index > FuncSetTimer1 + fw->getCapability(Timers)) || + ((index == FuncScreenshot) && !IS_HORUS_OR_TARANIS(fw->getBoard())) || + ((index >= FuncRangeCheckInternalModule && index <= FuncBindExternalModule) && !fw->getCapability(DangerousFunctions)) || + ((index >= FuncAdjustGV1 && index <= FuncAdjustGVLast) && !fw->getCapability(Gvars)) + ); + return !ret; +} + +// static +int CustomFunctionData::funcContext(const int index) +{ + int ret = AllFunctionContexts; + + if ((index >= FuncOverrideCH1 && index <= FuncOverrideCHLast) || + (index >= FuncRangeCheckInternalModule && index <= FuncBindExternalModule) || + (index >= FuncAdjustGV1 && index <= FuncAdjustGVLast)) + ret &= ~GlobalFunctionsContext; + + return ret; +} + +// static +QString CustomFunctionData::resetToString(const int value, const ModelData * model) +{ + Firmware * firmware = getCurrentFirmware(); + int step = CPN_MAX_TIMERS; + + if (value < step) { + if (value < firmware->getCapability(Timers)) + return RawSource(SOURCE_TYPE_SPECIAL, value + SOURCE_TYPE_SPECIAL_TIMER1_IDX).toString(model); + else + return QString(CPN_STR_UNKNOWN_ITEM); + } + + if (value < ++step) + return tr("Flight"); + + if (value < ++step) + return tr("Telemetry"); + + if (value < step + firmware->getCapability(Sensors)) + return RawSource(SOURCE_TYPE_TELEMETRY, 3 * (value - step)).toString(model); + + return QString(CPN_STR_UNKNOWN_ITEM); +} + +// static +int CustomFunctionData::resetParamCount() +{ + Firmware * firmware = getCurrentFirmware(); + + return CPN_MAX_TIMERS + 2 + firmware->getCapability(Sensors); +} + +// static +bool CustomFunctionData::isResetParamAvailable(const int index, const ModelData * model) +{ + Firmware * firmware = getCurrentFirmware(); + + if (index < CPN_MAX_TIMERS) { + if (index < firmware->getCapability(Timers)) + return true; + else + return false; + } + else if (index < CPN_MAX_TIMERS + 2) + return true; + else if (model && index < resetParamCount()) + return model->sensorData[index - (CPN_MAX_TIMERS + 2)].isAvailable(); + + return false; +} + +QString CustomFunctionData::harpicToString() const +{ + return harpicToString(param); +} + +// static +QString CustomFunctionData::harpicToString(const int value) +{ + return QString("%1").arg(value); +} + +// static +QStringList CustomFunctionData::playSoundStringList() +{ + return QStringList({ tr("Beep 1"), tr("Beep 2"), tr("Beep 3"), tr("Warn 1"), tr("Warn 2"), tr("Cheep"), tr("Ratata"), tr("Tick"), + tr("Siren"), tr("Ring"), tr("Sci Fi"), tr("Robot"), tr("Chirp"), tr("Tada"), tr("Cricket"), tr("Alarm Clock") }); +} + +QString CustomFunctionData::playSoundToString() const +{ + return playSoundToString(param); +} + +// static +QString CustomFunctionData::playSoundToString(const int value) +{ + const QStringList strl = playSoundStringList(); + if (value < strl.count()) + return strl.at(value); + else + return QString(CPN_STR_UNKNOWN_ITEM); +} + +QString CustomFunctionData::gvarAdjustModeToString() const +{ + return gvarAdjustModeToString(adjustMode); +} + +// static +QString CustomFunctionData::gvarAdjustModeToString(const int value) +{ + switch (value) { + case FUNC_ADJUST_GVAR_CONSTANT: + return tr("Value"); + case FUNC_ADJUST_GVAR_SOURCE: + return tr("Source"); + case FUNC_ADJUST_GVAR_GVAR: + return tr("Global Variable"); + case FUNC_ADJUST_GVAR_INCDEC: + return tr("Inc/Decrement"); + default: + return QString(CPN_STR_UNKNOWN_ITEM); } } + +// static +AbstractStaticItemModel * CustomFunctionData::repeatItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("customfunctiondata.repeat"); + + for (int i = -1; i <= 60; i++) { + mdl->appendToItemList(repeatToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} + +// static +AbstractStaticItemModel * CustomFunctionData::playSoundItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("customfunctiondata.playsound"); + + for (int i = 0; i < playSoundStringList().count(); i++) { + mdl->appendToItemList(playSoundToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} + +// static +AbstractStaticItemModel * CustomFunctionData::harpicItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("customfunctiondata.harpic"); + + for (int i = 0; i <= 3; i++) { + mdl->appendToItemList(harpicToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} + +// static +AbstractStaticItemModel * CustomFunctionData::gvarAdjustModeItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("customfunctiondata.gvaradjustmode"); + + for (int i = 0; i < FUNC_ADJUST_GVAR_COUNT; i++) { + mdl->appendToItemList(gvarAdjustModeToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} diff --git a/companion/src/firmwares/customfunctiondata.h b/companion/src/firmwares/customfunctiondata.h index 93f9969e81..d5a08a96fd 100644 --- a/companion/src/firmwares/customfunctiondata.h +++ b/companion/src/firmwares/customfunctiondata.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef CUSTOMFUNCTIONDATA_H -#define CUSTOMFUNCTIONDATA_H +#pragma once #include "boards.h" #include "constants.h" @@ -32,10 +31,12 @@ class Firmware; class ModelData; class GeneralSettings; class RadioDataConversionState; +class AbstractStaticItemModel; enum AssignFunc { FuncOverrideCH1 = 0, - FuncOverrideCH32 = FuncOverrideCH1+CPN_MAX_CHNOUT-1, + FuncOverrideCHLast = FuncOverrideCH1 + CPN_MAX_CHNOUT - 1, + FuncOverrideCH32 = FuncOverrideCHLast, // TODO remove FuncTrainer, FuncTrainerRUD, FuncTrainerELE, @@ -47,8 +48,9 @@ enum AssignFunc { FuncPlayHaptic, FuncReset, FuncSetTimer1, - FuncSetTimer2, - FuncSetTimer3, + FuncSetTimer2, // TODO remove + FuncSetTimer3, // TODO remove + FuncSetTimerLast = FuncSetTimer1 + CPN_MAX_TIMERS - 1, FuncVario, FuncPlayPrompt, FuncPlayBoth, @@ -61,7 +63,7 @@ enum AssignFunc { FuncBackgroundMusic, FuncBackgroundMusicPause, FuncAdjustGV1, - FuncAdjustGVLast = FuncAdjustGV1+CPN_MAX_GVARS-1, + FuncAdjustGVLast = FuncAdjustGV1 + CPN_MAX_GVARS - 1, FuncSetFailsafe, FuncRangeCheckInternalModule, FuncRangeCheckExternalModule, @@ -76,14 +78,23 @@ enum GVarAdjustModes FUNC_ADJUST_GVAR_CONSTANT, FUNC_ADJUST_GVAR_SOURCE, FUNC_ADJUST_GVAR_GVAR, - FUNC_ADJUST_GVAR_INCDEC + FUNC_ADJUST_GVAR_INCDEC, + FUNC_ADJUST_GVAR_COUNT }; class CustomFunctionData { Q_DECLARE_TR_FUNCTIONS(CustomFunctionData) public: - CustomFunctionData(AssignFunc func=FuncOverrideCH1) { clear(); this->func = func; } + enum CustomFunctionContext + { + GlobalFunctionsContext = 0x01, + SpecialFunctionsContext = 0x02, + + AllFunctionContexts = GlobalFunctionsContext | SpecialFunctionsContext + }; + + CustomFunctionData(AssignFunc func = FuncOverrideCH1) { clear(); this->func = func; } RawSwitch swtch; AssignFunc func; int param; @@ -92,21 +103,33 @@ class CustomFunctionData { unsigned int adjustMode; int repeatParam; - void clear(); - bool isEmpty() const; - QString nameToString(int index, bool globalContext = false) const; - QString funcToString(const ModelData * model = NULL) const; - QString paramToString(const ModelData * model) const; - QString repeatToString() const; - QString enabledToString() const; - - static void populateResetParams(const ModelData * model, QComboBox * b, unsigned int value); - static void populatePlaySoundParams(QStringList & qs); - static void populateHapticParams(QStringList & qs); - void convert(RadioDataConversionState & cstate); + void clear(); + bool isEmpty() const; + QString funcToString(const ModelData * model = nullptr) const; + QString paramToString(const ModelData * model = nullptr) const; + QString repeatToString() const; + QString enabledToString() const; + QString playSoundToString() const; + QString harpicToString() const; + QString gvarAdjustModeToString() const; + + static QString nameToString(const int index, const bool globalContext = false); + static QString funcToString(const AssignFunc func, const ModelData * model = nullptr); + static bool isFuncAvailable(const int index); + static int funcContext(const int index); + static QString resetToString(const int value, const ModelData * model = nullptr); + static int resetParamCount(); + static bool isResetParamAvailable(const int index, const ModelData * model = nullptr); + static QString repeatToString(const int value); + static QStringList playSoundStringList(); + static QString playSoundToString(const int value); + static QString harpicToString(const int value); + static QStringList gvarAdjustModeStringList(); + static QString gvarAdjustModeToString(const int value); + static AbstractStaticItemModel * repeatItemModel(); + static AbstractStaticItemModel * playSoundItemModel(); + static AbstractStaticItemModel * harpicItemModel(); + static AbstractStaticItemModel * gvarAdjustModeItemModel(); }; - - -#endif // CUSTOMFUNCTIONDATA_H diff --git a/companion/src/firmwares/datahelpers.cpp b/companion/src/firmwares/datahelpers.cpp new file mode 100644 index 0000000000..8ae759a1bf --- /dev/null +++ b/companion/src/firmwares/datahelpers.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "datahelpers.h" + +QString DataHelpers::boolToString(const bool value, const BoolFormat format) +{ + static const char *strings[] = { + QT_TRANSLATE_NOOP("DataHelpers", "Disabled"), + QT_TRANSLATE_NOOP("DataHelpers", "Enabled"), + QT_TRANSLATE_NOOP("DataHelpers", "OFF"), + QT_TRANSLATE_NOOP("DataHelpers", "ON"), + QT_TRANSLATE_NOOP("DataHelpers", "False"), + QT_TRANSLATE_NOOP("DataHelpers", "True"), + QT_TRANSLATE_NOOP("DataHelpers", "N"), + QT_TRANSLATE_NOOP("DataHelpers", "Y"), + QT_TRANSLATE_NOOP("DataHelpers", "No"), + QT_TRANSLATE_NOOP("DataHelpers", "Yes") + }; + + return QCoreApplication::translate("DataHelpers", strings[format * 2 + value]); +} + +QString DataHelpers::getElementName(const QString & prefix, const unsigned int index, const char * name, const bool padding) +{ + QString result = prefix; + result.append(padding ? QString("%1").arg(index, 2, 10, QChar('0')) : QString("%1").arg(index)); + if (name && QString(name).trimmed().length() > 0) + result.append(":" + QString(name).trimmed()); + + return result; +} + +QString DataHelpers::timeToString(const int value, const unsigned int mask) +{ + bool negative = value < 0 ? true : false; + int val = abs(value); + + QString result = QString("%1").arg(negative ? "-" : ((mask & TIMESTR_MASK_PADSIGN) ? " " : "")); + + if (mask & TIMESTR_MASK_HRSMINS) { + int hours = val / 3600; + if (hours > 0 || (mask & TIMESTR_MASK_ZEROHRS)) { + val -= hours * 3600; + result.append(QString("%1:").arg(hours, 2, 10, QLatin1Char('0'))); + } + } + + int minutes = val / 60; + int seconds = val % 60; + result.append(QString("%1:%2").arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0'))); + return result; +} diff --git a/companion/src/firmwares/datahelpers.h b/companion/src/firmwares/datahelpers.h new file mode 100644 index 0000000000..ccd3b0f64b --- /dev/null +++ b/companion/src/firmwares/datahelpers.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include + +class FieldRange +{ + public: + FieldRange(): + decimals(0), + min(0.0), + max(0.0), + step(1.0), + offset(0.0), + prefix(""), + unit("") + { + } + + float getValue(int value) { return float(value) * step; } + + int decimals; + double min; + double max; + double step; + double offset; + QString prefix; + QString unit; +}; + + +constexpr unsigned int TIMESTR_MASK_HRSMINS { 1 << 1 }; +constexpr unsigned int TIMESTR_MASK_ZEROHRS { 1 << 2 }; +constexpr unsigned int TIMESTR_MASK_PADSIGN { 1 << 3 }; + +namespace DataHelpers +{ + enum BoolFormat { + BOOL_FMT_ENABLEDISABLE, + BOOL_FMT_ONOFF, + BOOL_FMT_TRUEFALSE, + BOOL_FMT_YN, + BOOL_FMT_YESNO + }; + + QString boolToString(const bool value, const BoolFormat format); + QString getElementName(const QString & prefix, const unsigned int index, const char * name = 0, const bool padding = false); + QString timeToString(const int value, const unsigned int mask); + +} diff --git a/companion/src/firmwares/io_data.cpp b/companion/src/firmwares/flightmodedata.cpp similarity index 56% rename from companion/src/firmwares/io_data.cpp rename to companion/src/firmwares/flightmodedata.cpp index a958750d8f..c0a268e967 100644 --- a/companion/src/firmwares/io_data.cpp +++ b/companion/src/firmwares/flightmodedata.cpp @@ -18,121 +18,17 @@ * GNU General Public License for more details. */ -#include "io_data.h" - -#include "radiodata.h" // for RadioData::getElementName +#include "flightmodedata.h" +#include "radiodata.h" #include "radiodataconversionstate.h" -/* - * ExpoData - */ - -void ExpoData::convert(RadioDataConversionState & cstate) +void FlightModeData::convert(RadioDataConversionState & cstate) { - cstate.setComponent(tr("INP"), 3); - cstate.setSubComp(RawSource(SOURCE_TYPE_VIRTUAL_INPUT, chn).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx)); - srcRaw.convert(cstate); + cstate.setComponent("FMD", 2); + cstate.setSubComp(nameToString(cstate.subCompIdx)); swtch.convert(cstate); } -bool ExpoData::isEmpty() const -{ - return (chn == 0 && mode == INPUT_MODE_NONE); -} - -/* - * MixData - */ - -void MixData::convert(RadioDataConversionState & cstate) -{ - cstate.setComponent(tr("MIX"), 4); - cstate.setSubComp(RawSource(SOURCE_TYPE_CH, destCh-1).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx)); - srcRaw.convert(cstate); - swtch.convert(cstate); -} - -bool MixData::isEmpty() const -{ - return (destCh == 0); -} - -/* - * LimitData - */ - -QString LimitData::minToString() const -{ - return QString::number((qreal)min/10); -} - -QString LimitData::maxToString() const -{ - return QString::number((qreal)max/10); -} - -QString LimitData::revertToString() const -{ - return revert ? tr("INV") : tr("NOR"); -} - -QString LimitData::nameToString(int index) const -{ - return RadioData::getElementName(tr("CH"), index + 1, name); -} - -QString LimitData::offsetToString() const -{ - return QString::number((qreal)offset/10, 'f', 1); -} - -void LimitData::clear() -{ - memset(reinterpret_cast(this), 0, sizeof(LimitData)); - min = -1000; - max = +1000; -} - -bool LimitData::isEmpty() const -{ - return (min == -1000 && max == 1000 && !revert && !offset && !ppmCenter && !symetrical && name[0] == '\0' && !curve.isSet()); -} - -/* - * CurveData - */ - -CurveData::CurveData() -{ - clear(); -} - -void CurveData::clear(int count) -{ - memset(this, 0, sizeof(CurveData)); - this->count = count; -} - -bool CurveData::isEmpty() const -{ - for (int i=0; i(this), 0, sizeof(FlightModeData)); @@ -149,13 +45,6 @@ QString FlightModeData::nameToString(int phaseIdx) const return RadioData::getElementName(tr("FM"), phaseIdx, name); // names are zero-based, FM0, FM1, etc } -void FlightModeData::convert(RadioDataConversionState & cstate) -{ - cstate.setComponent("FMD", 2); - cstate.setSubComp(nameToString(cstate.subCompIdx)); - swtch.convert(cstate); -} - bool FlightModeData::isEmpty(int phaseIdx) const { if (name[0] != '\0' || swtch.isSet() || fadeIn != 0 || fadeOut != 0) diff --git a/companion/src/firmwares/flightmodedata.h b/companion/src/firmwares/flightmodedata.h new file mode 100644 index 0000000000..8578d04e52 --- /dev/null +++ b/companion/src/firmwares/flightmodedata.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include "constants.h" +#include "rawswitch.h" + +#include + +class RadioDataConversionState; + +#define FLIGHTMODE_NAME_LEN 10 +#define RENC_MAX_VALUE 1024 +#define RENC_MIN_VALUE -RENC_MAX_VALUE + +class FlightModeData { + Q_DECLARE_TR_FUNCTIONS(FlightModeData) + + public: + FlightModeData() { clear(0); } + + int trimMode[CPN_MAX_TRIMS]; + int trimRef[CPN_MAX_TRIMS]; + int trim[CPN_MAX_TRIMS]; + RawSwitch swtch; + char name[FLIGHTMODE_NAME_LEN + 1]; + unsigned int fadeIn; + unsigned int fadeOut; + int rotaryEncoders[CPN_MAX_ENCODERS]; + int gvars[CPN_MAX_GVARS]; + + void convert(RadioDataConversionState & cstate); + void clear(const int phaseIdx); + bool isEmpty(int phaseIdx) const; + QString nameToString(int phaseIdx) const; + bool isGVarEmpty(int phaseIdx, int gvIdx) const; + bool isREncEmpty(int phaseIdx, int reIdx) const; + int linkedFlightModeZero(int phaseIdx, int maxOwnValue) const; + int linkedGVarFlightModeZero(int phaseIdx) const; + int linkedREncFlightModeZero(int phaseIdx) const; +}; diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp index 005900c93e..f9df851b2d 100644 --- a/companion/src/firmwares/generalsettings.cpp +++ b/companion/src/firmwares/generalsettings.cpp @@ -94,6 +94,12 @@ GeneralSettings::GeneralSettings() vBatMin = -23; // 6.7V vBatMax = -37; // 8.3V } + else if (IS_JUMPER_TLITE(board)) { + // 1S Li-Ion + vBatWarn = 32; + vBatMin = -60; //3V + vBatMax = -78; //4.2V + } else if (IS_TARANIS(board)) { // NI-MH 7.2V, X9D, X9D+ and X7 vBatWarn = 65; @@ -239,6 +245,10 @@ void GeneralSettings::setDefaultControlTypes(Board::Type board) switchConfig[i] = Boards::getSwitchInfo(board, i).config; } + // TLite does not have pots or sliders + if (IS_JUMPER_TLITE(board)) + return; + // TODO: move to Boards, like with switches if (IS_FAMILY_HORUS_OR_T16(board)) { potConfig[0] = Board::POT_WITH_DETENT; diff --git a/companion/src/firmwares/heli_data.cpp b/companion/src/firmwares/heli_data.cpp new file mode 100644 index 0000000000..b1fb7b36e5 --- /dev/null +++ b/companion/src/firmwares/heli_data.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "heli_data.h" diff --git a/companion/src/firmwares/heli_data.h b/companion/src/firmwares/heli_data.h new file mode 100644 index 0000000000..734b29928c --- /dev/null +++ b/companion/src/firmwares/heli_data.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include "rawsource.h" + +#include + +class SwashRingData { + Q_DECLARE_TR_FUNCTIONS(SwashRingData) + + public: + SwashRingData() { clear(); } + + int elevatorWeight; + int aileronWeight; + int collectiveWeight; + unsigned int type; + RawSource collectiveSource; + RawSource aileronSource; + RawSource elevatorSource; + unsigned int value; + + void clear() { memset(reinterpret_cast(this), 0, sizeof(SwashRingData)); } +}; + diff --git a/companion/src/firmwares/input_data.cpp b/companion/src/firmwares/input_data.cpp new file mode 100644 index 0000000000..9b9ecfe209 --- /dev/null +++ b/companion/src/firmwares/input_data.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "input_data.h" +#include "radiodataconversionstate.h" + +void ExpoData::convert(RadioDataConversionState & cstate) +{ + cstate.setComponent(tr("INP"), 3); + cstate.setSubComp(RawSource(SOURCE_TYPE_VIRTUAL_INPUT, chn).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx)); + srcRaw.convert(cstate); + swtch.convert(cstate); +} + +bool ExpoData::isEmpty() const +{ + return (chn == 0 && mode == INPUT_MODE_NONE); +} diff --git a/companion/src/firmwares/input_data.h b/companion/src/firmwares/input_data.h new file mode 100644 index 0000000000..27b6b62820 --- /dev/null +++ b/companion/src/firmwares/input_data.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include "curvereference.h" +#include "rawsource.h" +#include "rawswitch.h" + +#include + +class RadioDataConversionState; + +enum InputMode { + INPUT_MODE_NONE, + INPUT_MODE_POS, + INPUT_MODE_NEG, + INPUT_MODE_BOTH +}; + +#define EXPODATA_NAME_LEN 10 + +class ExpoData { + Q_DECLARE_TR_FUNCTIONS(ExpoData) + + public: + ExpoData() { clear(); } + + RawSource srcRaw; + unsigned int scale; + unsigned int mode; // InputMode + unsigned int chn; + RawSwitch swtch; + unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4 + int weight; + int offset; + CurveReference curve; + int carryTrim; + char name[EXPODATA_NAME_LEN + 1]; + + void convert(RadioDataConversionState & cstate); + void clear() { memset(reinterpret_cast(this), 0, sizeof(ExpoData)); } + bool isEmpty() const; +}; diff --git a/companion/src/firmwares/io_data.h b/companion/src/firmwares/io_data.h deleted file mode 100644 index b70b174ea8..0000000000 --- a/companion/src/firmwares/io_data.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * 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. - */ - -#ifndef IO_DATA_H -#define IO_DATA_H - -#include "constants.h" -#include "curvereference.h" -#include "rawsource.h" -#include "rawswitch.h" - -#include - -class RadioDataConversionState; - -enum InputMode { - INPUT_MODE_NONE, - INPUT_MODE_POS, - INPUT_MODE_NEG, - INPUT_MODE_BOTH -}; - -#define EXPODATA_NAME_LEN 10 - -class ExpoData { - Q_DECLARE_TR_FUNCTIONS(ExpoData) - - public: - ExpoData() { clear(); } - RawSource srcRaw; - unsigned int scale; - unsigned int mode; // InputMode - unsigned int chn; - RawSwitch swtch; - unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4 - int weight; - int offset; - CurveReference curve; - int carryTrim; - char name[EXPODATA_NAME_LEN+1]; - void clear() { memset(reinterpret_cast(this), 0, sizeof(ExpoData)); } - void convert(RadioDataConversionState & cstate); - bool isEmpty() const; -}; - -enum MltpxValue { - MLTPX_ADD=0, - MLTPX_MUL=1, - MLTPX_REP=2 -}; - -#define MIXDATA_NAME_LEN 10 - -class MixData { - Q_DECLARE_TR_FUNCTIONS(MixData) - - public: - MixData() { clear(); } - void convert(RadioDataConversionState & cstate); - - unsigned int destCh; // 1..CPN_MAX_CHNOUT - RawSource srcRaw; - int weight; - RawSwitch swtch; - CurveReference curve; //0=symmetrisch - unsigned int delayUp; - unsigned int delayDown; - unsigned int speedUp; // Servogeschwindigkeit aus Tabelle (10ms Cycle) - unsigned int speedDown; // 0 nichts - int carryTrim; - bool noExpo; - MltpxValue mltpx; // multiplex method 0=+ 1=* 2=replace - unsigned int mixWarn; // mixer warning - unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4 - int sOffset; - char name[MIXDATA_NAME_LEN+1]; - - void clear() { memset(reinterpret_cast(this), 0, sizeof(MixData)); } - bool isEmpty() const; -}; - -#define LIMITDATA_NAME_LEN 6 - -class LimitData { - Q_DECLARE_TR_FUNCTIONS(LimitData) - - public: - LimitData() { clear(); } - int min; - int max; - bool revert; - int offset; - int ppmCenter; - bool symetrical; - int failsafe; - char name[LIMITDATA_NAME_LEN + 1]; - CurveReference curve; - QString minToString() const; - QString maxToString() const; - QString offsetToString() const; - QString revertToString() const; - QString nameToString(int index) const; - void clear(); - bool isEmpty() const; -}; - -class CurvePoint { - public: - int8_t x; - int8_t y; -}; - -#define CURVEDATA_NAME_LEN 6 - -class CurveData { - Q_DECLARE_TR_FUNCTIONS(CurveData) - - public: - enum CurveType { - CURVE_TYPE_STANDARD, - CURVE_TYPE_CUSTOM, - CURVE_TYPE_LAST = CURVE_TYPE_CUSTOM - }; - - CurveData(); - void clear(int count = 5); - bool isEmpty() const; - QString nameToString(const int idx) const; - - CurveType type; - bool smooth; - int count; - CurvePoint points[CPN_MAX_POINTS]; - char name[CURVEDATA_NAME_LEN+1]; -}; - -#define FLIGHTMODE_NAME_LEN 10 -#define RENC_MAX_VALUE 1024 -#define RENC_MIN_VALUE -RENC_MAX_VALUE - -class FlightModeData { - Q_DECLARE_TR_FUNCTIONS(FlightModeData) - - public: - FlightModeData() { clear(0); } - int trimMode[CPN_MAX_TRIMS]; - int trimRef[CPN_MAX_TRIMS]; - int trim[CPN_MAX_TRIMS]; - RawSwitch swtch; - char name[FLIGHTMODE_NAME_LEN+1]; - unsigned int fadeIn; - unsigned int fadeOut; - int rotaryEncoders[CPN_MAX_ENCODERS]; - int gvars[CPN_MAX_GVARS]; - void clear(const int phaseIdx); - QString nameToString(int phaseIdx) const; - void convert(RadioDataConversionState & cstate); - bool isEmpty(int phaseIdx) const; - bool isGVarEmpty(int phaseIdx, int gvIdx) const; - bool isREncEmpty(int phaseIdx, int reIdx) const; - int linkedFlightModeZero(int phaseIdx, int maxOwnValue) const; - int linkedGVarFlightModeZero(int phaseIdx) const; - int linkedREncFlightModeZero(int phaseIdx) const; -}; - -class SwashRingData { - Q_DECLARE_TR_FUNCTIONS(SwashRingData) - - public: - SwashRingData() { clear(); } - int elevatorWeight; - int aileronWeight; - int collectiveWeight; - unsigned int type; - RawSource collectiveSource; - RawSource aileronSource; - RawSource elevatorSource; - unsigned int value; - void clear() { memset(reinterpret_cast(this), 0, sizeof(SwashRingData)); } -}; - -#endif // IO_DATA_H diff --git a/companion/src/firmwares/mixdata.cpp b/companion/src/firmwares/mixdata.cpp new file mode 100644 index 0000000000..ac2893a4d1 --- /dev/null +++ b/companion/src/firmwares/mixdata.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "mixdata.h" +#include "radiodataconversionstate.h" + +void MixData::convert(RadioDataConversionState & cstate) +{ + cstate.setComponent(tr("MIX"), 4); + cstate.setSubComp(RawSource(SOURCE_TYPE_CH, destCh-1).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % tr(" (@%1)").arg(cstate.subCompIdx)); + srcRaw.convert(cstate); + swtch.convert(cstate); +} + +bool MixData::isEmpty() const +{ + return (destCh == 0); +} diff --git a/companion/src/firmwares/mixdata.h b/companion/src/firmwares/mixdata.h new file mode 100644 index 0000000000..dc81298f05 --- /dev/null +++ b/companion/src/firmwares/mixdata.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include "curvereference.h" +#include "rawsource.h" +#include "rawswitch.h" + +#include + +class RadioDataConversionState; + +enum MltpxValue { + MLTPX_ADD, + MLTPX_MUL, + MLTPX_REP +}; + +#define MIXDATA_NAME_LEN 10 + +class MixData { + Q_DECLARE_TR_FUNCTIONS(MixData) + + public: + MixData() { clear(); } + + unsigned int destCh; // 1..CPN_MAX_CHNOUT + RawSource srcRaw; + int weight; + RawSwitch swtch; + CurveReference curve; + unsigned int delayUp; + unsigned int delayDown; + unsigned int speedUp; + unsigned int speedDown; + int carryTrim; + bool noExpo; + MltpxValue mltpx; + unsigned int mixWarn; + unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4 + int sOffset; + char name[MIXDATA_NAME_LEN + 1]; + + void convert(RadioDataConversionState & cstate); + void clear() { memset(reinterpret_cast(this), 0, sizeof(MixData)); } + bool isEmpty() const; +}; diff --git a/companion/src/firmwares/modeldata.cpp b/companion/src/firmwares/modeldata.cpp index 930df092c3..679e90f5fd 100644 --- a/companion/src/firmwares/modeldata.cpp +++ b/companion/src/firmwares/modeldata.cpp @@ -27,31 +27,6 @@ #include "helpers.h" #include "adjustmentreference.h" -/* - * TimerData - */ - -void TimerData::convert(RadioDataConversionState & cstate) -{ - cstate.setComponent(tr("TMR"), 1); - cstate.setSubComp(tr("Timer %1").arg(cstate.subCompIdx + 1)); - mode.convert(cstate); -} - -bool TimerData::isEmpty() -{ - return (mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0) && name[0] == '\0' && minuteBeep == 0 && countdownBeep == COUNTDOWN_SILENT && val == 0 && persistent == 0 /*&& pvalue == 0*/); -} - -QString TimerData::nameToString(int index) const -{ - return RadioData::getElementName(tr("TMR", "as in Timer"), index + 1, name); -} - -/* - * ModelData - */ - ModelData::ModelData() { clear(); @@ -678,41 +653,56 @@ int ModelData::updateReference() LogicalSwitchData *lsd = &logicalSw[i]; if (!lsd->isEmpty()) { bool clearlsd = false; + int oldval1; + int oldval2; CSFunctionFamily family = lsd->getFunctionFamily(); switch(family) { case LS_FAMILY_VOFS: - updateSourceIntRef(lsd->val1); - if (lsd->val1 == 0) - clearlsd = true; + if (lsd->val1 != 0) { + updateSourceIntRef(lsd->val1); + if (lsd->val1 == 0) + clearlsd = true; + } break; case LS_FAMILY_STICKY: case LS_FAMILY_VBOOL: - updateSwitchIntRef(lsd->val1); - updateSwitchIntRef(lsd->val2); - if (lsd->val1 == 0 && lsd->val2 == 0) + oldval1 = lsd->val1; + oldval2 = lsd->val2; + if (lsd->val1 != 0) + updateSwitchIntRef(lsd->val1); + if (lsd->val2 != 0) + updateSwitchIntRef(lsd->val2); + if (lsd->val1 == 0 && lsd->val2 == 0 && ((lsd->val1 != oldval1 && oldval2 == 0) || (lsd->val2 != oldval2 && oldval1 == 0))) clearlsd = true; break; case LS_FAMILY_EDGE: - updateSwitchIntRef(lsd->val1); - if (lsd->val1 == 0) - clearlsd = true; + if (lsd->val1 != 0) { + updateSwitchIntRef(lsd->val1); + if (lsd->val1 == 0) + clearlsd = true; + } break; case LS_FAMILY_VCOMP: - updateSourceIntRef(lsd->val1); - updateSourceIntRef(lsd->val2); - if (lsd->val1 == 0 && lsd->val2 == 0) + oldval1 = lsd->val1; + oldval2 = lsd->val2; + if (lsd->val1 != 0) + updateSourceIntRef(lsd->val1); + if (lsd->val2 != 0) + updateSourceIntRef(lsd->val2); + if (lsd->val1 == 0 && lsd->val2 == 0 && ((lsd->val1 != oldval1 && oldval2 == 0) || (lsd->val2 != oldval2 && oldval1 == 0))) clearlsd = true; break; default: break; } - if (clearlsd) { + + if (lsd->andsw != 0) + updateSwitchIntRef(lsd->andsw); + + if (clearlsd && lsd->andsw == 0) { lsd->clear(); appendUpdateReferenceParams(REF_UPD_TYPE_LOGICAL_SWITCH, REF_UPD_ACT_CLEAR, i); } - else { - updateSwitchIntRef(lsd->andsw); - } } } //s1.report("Logical Switches"); @@ -841,6 +831,7 @@ void ModelData::updateTypeIndexRef(R & curRef, const T type, const int idxAdj, c newRef.index = abs(curRef.index); div_t idx = div(newRef.index, updRefInfo.occurences); + div_t newidx; switch (updRefInfo.action) { @@ -858,9 +849,10 @@ void ModelData::updateTypeIndexRef(R & curRef, const T type, const int idxAdj, c if (idx.quot < (updRefInfo.index1 + idxAdj)) return; - newRef.index += updRefInfo.shift; + newRef.index = ((idx.quot + updRefInfo.shift) * updRefInfo.occurences) + idx.rem; + newidx = div(newRef.index, updRefInfo.occurences); - if (idx.quot < (updRefInfo.index1 + idxAdj) || idx.quot > (updRefInfo.maxindex + idxAdj)) { + if (newidx.quot < (updRefInfo.index1 + idxAdj) || newidx.quot > (updRefInfo.maxindex + idxAdj)) { if (defClear) newRef.clear(); else { @@ -1106,7 +1098,7 @@ void ModelData::updateFlightModeFlags(unsigned int & curRef) switch (updRefInfo.action) { case REF_UPD_ACT_CLEAR: - flag[updRefInfo.index1] = false; + flag[updRefInfo.index1] = true; break; case REF_UPD_ACT_SHIFT: if(updRefInfo.shift < 0) { @@ -1114,7 +1106,7 @@ void ModelData::updateFlightModeFlags(unsigned int & curRef) if (i - updRefInfo.shift <= updRefInfo.maxindex) flag[i] = flag[i - updRefInfo.shift]; else - flag[i] = false; + flag[i] = true; } } else { @@ -1122,7 +1114,7 @@ void ModelData::updateFlightModeFlags(unsigned int & curRef) if (i - updRefInfo.shift >= updRefInfo.index1) flag[i] = flag[i - updRefInfo.shift]; else - flag[i] = false; + flag[i] = true; } } break; @@ -1381,7 +1373,6 @@ void ModelData::sortMixes() void ModelData::updateResetParam(CustomFunctionData * cfd) { - if (cfd->func != FuncReset) return; @@ -1392,6 +1383,11 @@ void ModelData::updateResetParam(CustomFunctionData * cfd) switch (updRefInfo.type) { + case REF_UPD_TYPE_TIMER: + if (cfd->param < 0 || cfd->param > 2) + return; + idxAdj = -2; // reverse earlier offset required for rawsource + break; case REF_UPD_TYPE_SENSOR: idxAdj = 5/*3 Timers + Flight + Telemetery*/ + firmware->getCapability(RotaryEncoders); if (cfd->param < idxAdj || cfd->param > (idxAdj + firmware->getCapability(Sensors))) @@ -1439,3 +1435,118 @@ void ModelData::updateResetParam(CustomFunctionData * cfd) updRefInfo.updcnt++; } } + +QString ModelData::thrTraceSrcToString() const +{ + return thrTraceSrcToString((int)thrTraceSrc); +} + +QString ModelData::thrTraceSrcToString(const int index) const +{ + Firmware * firmware = getCurrentFirmware(); + const Boards board = Boards(getCurrentBoard()); + const int pscnt = board.getCapability(Board::Pots) + board.getCapability(Board::Sliders); + + if (index == 0) + return tr("THR"); + else if (index <= pscnt) + return board.getAnalogInputName(index + board.getCapability(Board::Sticks) - 1); + else if (index <= pscnt + firmware->getCapability(Outputs)) + return RawSource(SOURCE_TYPE_CH, index - pscnt - 1).toString(this); + + return QString(CPN_STR_UNKNOWN_ITEM); +} + +int ModelData::thrTraceSrcCount() const +{ + const Boards board = Boards(getCurrentBoard()); + Firmware * firmware = getCurrentFirmware(); + + return 1 + board.getCapability(Board::Pots) + board.getCapability(Board::Sliders) + firmware->getCapability(Outputs); +} + +bool ModelData::isThrTraceSrcAvailable(const GeneralSettings * generalSettings, const int index) const +{ + const Boards board = Boards(getCurrentBoard()); + + if (index > 0 && index <= board.getCapability(Board::Pots) + board.getCapability(Board::Sliders)) + return RawSource(SOURCE_TYPE_STICK, index + board.getCapability(Board::Sticks) - 1).isAvailable(this, generalSettings, board.getBoardType()); + else + return true; +} + +void ModelData::limitsClear(const int index) +{ + if (index < 0 || index >= CPN_MAX_CHNOUT) + return; + + if (!limitData[index].isEmpty()) { + limitData[index].clear(); + updateAllReferences(REF_UPD_TYPE_CHANNEL, REF_UPD_ACT_CLEAR, index); + } +} + +void ModelData::limitsClearAll() +{ + for (int i = 0; i < CPN_MAX_CHNOUT; i++) { + limitsClear(i); + } +} + +void ModelData::limitsDelete(const int index) +{ + if (index < 0 || index >= CPN_MAX_CHNOUT) + return; + + memmove(&limitData[index], &limitData[index + 1], (CPN_MAX_CHNOUT - (index + 1)) * sizeof(LimitData)); + limitData[CPN_MAX_CHNOUT - 1].clear(); + updateAllReferences(REF_UPD_TYPE_CHANNEL, REF_UPD_ACT_SHIFT, index, 0, -1); +} + +void ModelData::limitsGet(const int index, QByteArray & data) +{ + if (index < 0 || index >= CPN_MAX_CHNOUT) + return; + + data.append((char*)&limitData[index], sizeof(LimitData)); +} + +void ModelData::limitsInsert(const int index) +{ + if (index < 0 || index >= CPN_MAX_CHNOUT) + return; + + memmove(&limitData[index + 1], &limitData[index], (CPN_MAX_CHNOUT - (index + 1)) * sizeof(LimitData)); + limitData[index].clear(); + updateAllReferences(REF_UPD_TYPE_CHANNEL, REF_UPD_ACT_SHIFT, index, 0, 1); +} + +void ModelData::limitsMove(const int index, const int offset) +{ + if (index + offset < 0 || index + offset >= CPN_MAX_CHNOUT) + return; + + int idx1 = index; + int idx2; + const int direction = offset < 0 ? -1 : 1; + const int cnt = abs(offset); + + for (int i = 1; i <= cnt; i++) { + idx2 = idx1 + direction; + LimitData tmp = limitData[idx2]; + LimitData *d1 = &limitData[idx1]; + LimitData *d2 = &limitData[idx2]; + memcpy(d2, d1, sizeof(LimitData)); + memcpy(d1, &tmp, sizeof(LimitData)); + updateAllReferences(REF_UPD_TYPE_CHANNEL, REF_UPD_ACT_SWAP, idx1, idx2); + idx1 += direction; + } +} + +void ModelData::limitsSet(const int index, const QByteArray & data) +{ + if (index < 0 || index >= CPN_MAX_CHNOUT || data.size() < (int)sizeof(LimitData)) + return; + + memcpy(&limitData[index], data.constData(), sizeof(LimitData)); +} diff --git a/companion/src/firmwares/modeldata.h b/companion/src/firmwares/modeldata.h index 7eacdc26d6..f834a07796 100644 --- a/companion/src/firmwares/modeldata.h +++ b/companion/src/firmwares/modeldata.h @@ -18,17 +18,22 @@ * GNU General Public License for more details. */ -#ifndef MODELDATA_H -#define MODELDATA_H +#pragma once #include "constants.h" +#include "curvedata.h" #include "customfunctiondata.h" #include "gvardata.h" -#include "io_data.h" +#include "flightmodedata.h" +#include "heli_data.h" +#include "input_data.h" #include "logicalswitchdata.h" +#include "mixdata.h" #include "moduledata.h" +#include "output_data.h" #include "sensordata.h" #include "telem_data.h" +#include "timerdata.h" #include @@ -51,33 +56,6 @@ class RSSIAlarmData { } }; -#define TIMER_NAME_LEN 8 - -class TimerData { - Q_DECLARE_TR_FUNCTIONS(TimerData) - - public: - enum CountDownMode { - COUNTDOWN_SILENT, - COUNTDOWN_BEEPS, - COUNTDOWN_VOICE, - COUNTDOWN_HAPTIC - }; - TimerData() { clear(); } - RawSwitch mode; - char name[TIMER_NAME_LEN+1]; - bool minuteBeep; - unsigned int countdownBeep; - unsigned int val; - unsigned int persistent; - int pvalue; - void clear() { memset(reinterpret_cast(this), 0, sizeof(TimerData)); mode = RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); } - void convert(RadioDataConversionState & cstate); - bool isEmpty(); - bool isModeOff() { return mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); } - QString nameToString(int index) const; -}; - #define CPN_MAX_SCRIPTS 9 #define CPN_MAX_SCRIPT_INPUTS 10 class ScriptData { @@ -283,6 +261,18 @@ class ModelData { bool hasExpoChildren(const int index); bool hasExpoSiblings(const int index); void removeMix(const int idx); + QString thrTraceSrcToString() const; + QString thrTraceSrcToString(const int index) const; + int thrTraceSrcCount() const; + bool isThrTraceSrcAvailable(const GeneralSettings * generalSettings, const int index) const; + + void limitsClear(const int index); + void limitsClearAll(); + void limitsDelete(const int index); + void limitsGet(const int index, QByteArray & data); + void limitsInsert(const int index); + void limitsMove(const int index, const int offset); + void limitsSet(const int index, const QByteArray & data); protected: void removeGlobalVar(int & var); @@ -340,5 +330,3 @@ class ModelData { void sortMixes(); void updateResetParam(CustomFunctionData * cfd); }; - -#endif // MODELDATA_H diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index 264a3ad6a4..f9fc8c8f52 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -76,6 +76,8 @@ inline int MAX_POTS(Board::Type board, int version) { if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board)) return 3; + if (IS_FAMILY_T12(board)) + return 2; return Boards::getCapability(board, Board::Pots); } @@ -85,6 +87,8 @@ inline int MAX_POTS_STORAGE(Board::Type board, int version) return 3; if (version >= 219 && IS_FAMILY_HORUS_OR_T16(board)) return 5; + if (IS_FAMILY_T12(board)) + return 2; return Boards::getCapability(board, Board::Pots); } @@ -92,6 +96,8 @@ inline int MAX_POTS_SOURCES(Board::Type board, int version) { if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board)) return 5; + if (IS_FAMILY_T12(board)) + return 2; return Boards::getCapability(board, Board::Pots); } @@ -2305,7 +2311,8 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig internalField.Append(new UnsignedField<2>(this, modelData.timers[i].countdownBeep)); internalField.Append(new BoolField<1>(this, modelData.timers[i].minuteBeep)); internalField.Append(new UnsignedField<2>(this, modelData.timers[i].persistent)); - internalField.Append(new SpareBitsField<3>(this)); + internalField.Append(new SignedField<2>(this, modelData.timers[i].countdownStart)); + internalField.Append(new UnsignedField<1>(this, modelData.timers[i].direction)); if (HAS_LARGE_LCD(board)) internalField.Append(new ZCharField<8>(this, modelData.timers[i].name, "Timer name")); else diff --git a/companion/src/firmwares/opentx/opentxeeprom.h b/companion/src/firmwares/opentx/opentxeeprom.h index aabbe2284c..c3395693db 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.h +++ b/companion/src/firmwares/opentx/opentxeeprom.h @@ -37,6 +37,8 @@ #define TARANIS_X9LITES_VARIANT 0x0801 #define JUMPER_T12_VARIANT 0x4001 #define RADIOMASTER_TX12_VARIANT 0x4002 +#define JUMPER_TLITE_VARIANT 0x4003 +#define RADIOMASTER_T8_VARIANT 0x4004 class OpenTxGeneralData: public TransformedField { public: diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index 04f02eb29a..1190062c57 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -60,6 +60,8 @@ const char * OpenTxEepromInterface::getName() switch (board) { case BOARD_JUMPER_T12: return "OpenTX for Jumper T12"; + case BOARD_JUMPER_TLITE: + return "OpenTX for Jumper T-Lite"; case BOARD_JUMPER_T16: return "OpenTX for Jumper T16"; case BOARD_JUMPER_T18: @@ -68,6 +70,8 @@ const char * OpenTxEepromInterface::getName() return "OpenTX for Radiomaster TX16S"; case BOARD_RADIOMASTER_TX12: return "OpenTX for Radiomaster TX12"; + case BOARD_RADIOMASTER_T8: + return "OpenTX for Radiomaster T8"; case BOARD_TARANIS_X9D: return "OpenTX for FrSky Taranis X9D"; case BOARD_TARANIS_X9DP: @@ -336,9 +340,15 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, u else if (IS_JUMPER_T12(board)) { variant |= JUMPER_T12_VARIANT; } + else if (IS_JUMPER_TLITE(board)) { + variant |= JUMPER_TLITE_VARIANT; + } else if (IS_RADIOMASTER_TX12(board)) { variant |= RADIOMASTER_TX12_VARIANT; } + else if (IS_RADIOMASTER_T8(board)) { + variant |= RADIOMASTER_T8_VARIANT; + } OpenTxGeneralData generator((GeneralSettings &)radioData.generalSettings, board, version, variant); // generator.dump(); QByteArray data; @@ -683,8 +693,12 @@ int OpenTxFirmware::getCapability(::Capability capability) return TARANIS_XLITE_VARIANT; else if (IS_JUMPER_T12(board)) return JUMPER_T12_VARIANT; + else if (IS_JUMPER_TLITE(board)) + return JUMPER_TLITE_VARIANT; else if (IS_RADIOMASTER_TX12(board)) return RADIOMASTER_TX12_VARIANT; + else if (IS_RADIOMASTER_T8(board)) + return RADIOMASTER_T8_VARIANT; else return 0; case MavlinkTelemetry: @@ -746,7 +760,7 @@ bool OpenTxFirmware::isAvailable(PulsesProtocol proto, int port) case PULSES_ACCST_ISRM_D16: return IS_ACCESS_RADIO(board, id); case PULSES_MULTIMODULE: - return id.contains("internalmulti") || IS_RADIOMASTER_TX16S(board) || IS_JUMPER_T18(board); + return id.contains("internalmulti") || IS_RADIOMASTER_TX16S(board) || IS_JUMPER_T18(board) || IS_RADIOMASTER_TX12(board) || IS_JUMPER_TLITE(board); default: return false; } @@ -778,7 +792,7 @@ bool OpenTxFirmware::isAvailable(PulsesProtocol proto, int port) case PULSES_XJT_LITE_X16: case PULSES_XJT_LITE_D8: case PULSES_XJT_LITE_LR12: - return (IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board)); + return (IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || IS_JUMPER_TLITE(board)); default: return false; } @@ -949,11 +963,21 @@ bool OpenTxEepromInterface::checkVariant(unsigned int version, unsigned int vari variantError = true; } } + else if (IS_JUMPER_TLITE(board)) { + if (variant != JUMPER_TLITE_VARIANT) { + variantError = true; + } + } else if (IS_RADIOMASTER_TX12(board)) { if (variant != RADIOMASTER_TX12_VARIANT) { variantError = true; } } + else if (IS_RADIOMASTER_T8(board)) { + if (variant != RADIOMASTER_T8_VARIANT) { + variantError = true; + } + } else if (IS_TARANIS(board)) { if (variant != 0) { variantError = true; @@ -1275,6 +1299,16 @@ void registerOpenTxFirmwares() registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX); + /* Jumper T-Lite board */ + firmware = new OpenTxFirmware("opentx-tlite", QCoreApplication::translate("Firmware", "Jumper T-Lite"), BOARD_JUMPER_TLITE); + addOpenTxCommonOptions(firmware); + firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support")); + firmware->addOption("nogvars", Firmware::tr("Disable Global variables")); + firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen")); + addOpenTxFontOptions(firmware); + registerOpenTxFirmware(firmware); + addOpenTxRfOptions(firmware, FLEX); + /* Jumper T16 board */ firmware = new OpenTxFirmware("opentx-t16", Firmware::tr("Jumper T16 / T16+ / T16 Pro"), BOARD_JUMPER_T16); addOpenTxFrskyOptions(firmware); @@ -1294,6 +1328,17 @@ void registerOpenTxFirmwares() registerOpenTxFirmware(firmware); addOpenTxRfOptions(firmware, FLEX); + /* Radiomaster T8 board */ + firmware = new OpenTxFirmware("opentx-t8", QCoreApplication::translate("Firmware", "Radiomaster T8"), BOARD_RADIOMASTER_T8); + addOpenTxCommonOptions(firmware); + firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support")); + firmware->addOption("nogvars", Firmware::tr("Disable Global variables")); + firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen")); + addOpenTxFontOptions(firmware); + registerOpenTxFirmware(firmware); + addOpenTxRfOptions(firmware, NONE); + firmware->addOption("bindkey", Firmware::tr("Allow bind using bind key")); + /* Radiomaster TX16S board */ firmware = new OpenTxFirmware("opentx-tx16s", Firmware::tr("Radiomaster TX16S / SE / Hall / Masterfire"), BOARD_RADIOMASTER_TX16S); addOpenTxFrskyOptions(firmware); diff --git a/companion/src/firmwares/output_data.cpp b/companion/src/firmwares/output_data.cpp new file mode 100644 index 0000000000..d5cc585eef --- /dev/null +++ b/companion/src/firmwares/output_data.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "output_data.h" +#include "radiodata.h" +#include "radiodataconversionstate.h" + +void LimitData::clear() +{ + memset(reinterpret_cast(this), 0, sizeof(LimitData)); + min = -1000; + max = +1000; +} + +bool LimitData::isEmpty() const +{ + LimitData tmp; + return !memcmp(this, &tmp, sizeof(LimitData)); +} + +QString LimitData::minToString() const +{ + return QString::number((qreal)min / 10); +} + +QString LimitData::maxToString() const +{ + return QString::number((qreal)max / 10); +} + +QString LimitData::revertToString() const +{ + return revert ? tr("INV") : tr("NOR"); +} + +QString LimitData::nameToString(int index) const +{ + return RadioData::getElementName(tr("CH"), index + 1, name); +} + +QString LimitData::offsetToString() const +{ + return QString::number((qreal)offset / 10, 'f', 1); +} diff --git a/companion/src/firmwares/output_data.h b/companion/src/firmwares/output_data.h new file mode 100644 index 0000000000..423f03e497 --- /dev/null +++ b/companion/src/firmwares/output_data.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include "curvereference.h" + +#include + +#define LIMITDATA_NAME_LEN 6 + +class LimitData { + Q_DECLARE_TR_FUNCTIONS(LimitData) + + public: + LimitData() { clear(); } + + int min; + int max; + bool revert; + int offset; + int ppmCenter; + bool symetrical; + int failsafe; + char name[LIMITDATA_NAME_LEN + 1]; + CurveReference curve; + + void clear(); + bool isEmpty() const; + QString minToString() const; + QString maxToString() const; + QString offsetToString() const; + QString revertToString() const; + QString nameToString(int index) const; +}; diff --git a/companion/src/firmwares/radiodata.cpp b/companion/src/firmwares/radiodata.cpp index 8054e5b1a4..c833281fdc 100644 --- a/companion/src/firmwares/radiodata.cpp +++ b/companion/src/firmwares/radiodata.cpp @@ -22,23 +22,6 @@ #include "radiodataconversionstate.h" #include "eeprominterface.h" -// static -QString RadioData::getElementName(const QString & prefix, unsigned int index, const char * name, bool padding) -{ - QString result = prefix; - if (padding) - result += QString("%1").arg(index, 2, 10, QChar('0')); - else - result += QString("%1").arg(index); - if (name) { - QString trimmed = QString(name).trimmed(); - if (trimmed.length() > 0) { - result += ":" + QString(name).trimmed(); - } - } - return result; -} - RadioData::RadioData() { models.resize(getCurrentFirmware()->getCapability(Models)); diff --git a/companion/src/firmwares/radiodata.h b/companion/src/firmwares/radiodata.h index 29d29e4eb4..d289f18460 100644 --- a/companion/src/firmwares/radiodata.h +++ b/companion/src/firmwares/radiodata.h @@ -1,9 +1,10 @@ -#ifndef _RADIODATA_H_ -#define _RADIODATA_H_ +#pragma once #include "generalsettings.h" #include "modeldata.h" +#include "datahelpers.h" // required for getElementName + #include class RadioDataConversionState; @@ -32,10 +33,10 @@ class RadioData { void fixModelFilenames(); QString getNextModelFilename(); - static QString getElementName(const QString & prefix, unsigned int index, const char * name = 0, bool padding = false); + // leave here until all calls repointed + static QString getElementName(const QString & prefix, unsigned int index, const char * name = 0, bool padding = false) + { return DataHelpers::getElementName(prefix, index, name, padding); } protected: void fixModelFilename(unsigned int index); }; - -#endif // _RADIODATA_H_ diff --git a/companion/src/firmwares/rawsource.cpp b/companion/src/firmwares/rawsource.cpp index 67a640c33f..898c0ca4a2 100644 --- a/companion/src/firmwares/rawsource.cpp +++ b/companion/src/firmwares/rawsource.cpp @@ -60,7 +60,7 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting result.min = -30000 * result.step; result.max = +30000 * result.step; result.decimals = sensor.prec; - result.unit = sensor.unitString(); + result.unit = SensorData::unitToString(qr.quot); break; } @@ -143,14 +143,14 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con static const QString rotary[] = { tr("REa"), tr("REb") }; if (index<0) { - return tr("???"); + return QString(CPN_STR_UNKNOWN_ITEM); } QString result; int genAryIdx = 0; switch (type) { case SOURCE_TYPE_NONE: - return tr("----"); + return QString(CPN_STR_NONE_ITEM); case SOURCE_TYPE_VIRTUAL_INPUT: { @@ -161,7 +161,7 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con } case SOURCE_TYPE_LUA_OUTPUT: - return tr("LUA%1%2").arg(index/16+1).arg(QChar('a'+index%16)); + return tr("LUA%1%2").arg(index / 16 + 1).arg(QChar('a' + index % 16)); case SOURCE_TYPE_STICK: if (generalSettings) { @@ -193,10 +193,10 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con return result; case SOURCE_TYPE_CUSTOM_SWITCH: - return RawSwitch(SWITCH_TYPE_VIRTUAL, index+1).toString(); + return RawSwitch(SWITCH_TYPE_VIRTUAL, index + 1).toString(); case SOURCE_TYPE_CYC: - return tr("CYC%1").arg(index+1); + return tr("CYC%1").arg(index + 1); case SOURCE_TYPE_PPM: return RadioData::getElementName(tr("TR", "as in Trainer"), index + 1); @@ -208,18 +208,15 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con return LimitData().nameToString(index); case SOURCE_TYPE_SPECIAL: - result = CHECK_IN_ARRAY(special, index); - // TODO refactor timers into own source type - if (result.startsWith("Timer")) { - bool ok; - int n = result.right(1).toInt(&ok); - if (ok) { - if (model) - result = model->timers[n - 1].nameToString(n - 1); - else - result = TimerData().nameToString(n - 1); - } + if (index >= SOURCE_TYPE_SPECIAL_TIMER1_IDX && index <= SOURCE_TYPE_SPECIAL_TIMER1_IDX + CPN_MAX_TIMERS - 1) { + if (model) + result = model->timers[index - SOURCE_TYPE_SPECIAL_TIMER1_IDX].nameToString(index - SOURCE_TYPE_SPECIAL_TIMER1_IDX); + else + result = TimerData().nameToString(index - SOURCE_TYPE_SPECIAL_TIMER1_IDX); } + else + result = CHECK_IN_ARRAY(special, index); + return result; case SOURCE_TYPE_TELEMETRY: @@ -241,7 +238,7 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con return GVarData().nameToString(index); default: - return tr("???"); + return QString(CPN_STR_UNKNOWN_ITEM); } } @@ -409,4 +406,3 @@ QStringList RawSource::getSwitchList(Boards board) const } return ret; } - diff --git a/companion/src/firmwares/rawsource.h b/companion/src/firmwares/rawsource.h index 9d0b194500..a7d293173c 100644 --- a/companion/src/firmwares/rawsource.h +++ b/companion/src/firmwares/rawsource.h @@ -178,6 +178,9 @@ enum RawSourceType { MAX_SOURCE_TYPE }; +constexpr int SOURCE_TYPE_STICK_THR_IDX { 3 }; // TODO is there a function to determine index? +constexpr int SOURCE_TYPE_SPECIAL_TIMER1_IDX { 2 }; // TODO temp const until Timers own source type + class RawSourceRange { Q_DECLARE_TR_FUNCTIONS(RawSourceRange) diff --git a/companion/src/firmwares/sensordata.cpp b/companion/src/firmwares/sensordata.cpp index a9b8d76404..ae602bd0d6 100644 --- a/companion/src/firmwares/sensordata.cpp +++ b/companion/src/firmwares/sensordata.cpp @@ -19,9 +19,9 @@ */ #include "sensordata.h" - -#include "radiodata.h" #include "modeldata.h" +#include "eeprominterface.h" +#include "compounditemmodels.h" void SensorData::updateUnit() { @@ -31,9 +31,322 @@ void SensorData::updateUnit() } } -QString SensorData::unitString() const +QString SensorData::nameToString(int index) const { - switch (unit) { + return DataHelpers::getElementName(tr("TELE"), index + 1, label); +} + +QString SensorData::getOrigin(const ModelData * model) const +{ + if (type != TELEM_TYPE_CUSTOM || !id) + return QString(); + + const ModuleData & module = model->moduleData[moduleIdx]; + if (module.isPxx2Module() && rxIdx <= 2 && module.access.receivers & (1 << rxIdx)) { + return QString(module.access.receiverName[rxIdx]); + } + else { + return QString(); + } +} + +bool SensorData::isEmpty() const +{ + return (!isAvailable() && type == 0 && id == 0 && subid == 0 && instance == 0 && rxIdx == 0 && moduleIdx == 0 && unit == 0 && ratio == 0 && prec == 0 && offset == 0 && autoOffset == 0 && filter == 0 && onlyPositive == 0 && logs == 0); +} + +QString SensorData::idToString() const +{ + return idToString(id); +} + +QString SensorData::typeToString() const +{ + return typeToString(type); +} + +QString SensorData::formulaToString() const +{ + return formulaToString(formula); +} + +QString SensorData::cellIndexToString() const +{ + return cellIndexToString(index); +} + +QString SensorData::unitToString() const +{ + return unitToString(unit); +} + +QString SensorData::precToString() const +{ + return precToString(prec); +} + +int SensorData::getMask() const +{ + int mask = 0; + + if (type == TELEM_TYPE_CALCULATED) { + if (formula < TELEM_FORMULA_CELL) + mask |= SENSOR_ISCONFIGURABLE | SENSOR_HAS_POSITIVE; + if (formula == TELEM_FORMULA_DIST) + mask |= SENSOR_HAS_GPS; + if (formula == TELEM_FORMULA_CELL) + mask |= SENSOR_HAS_CELLS; + if (formula == TELEM_FORMULA_CONSUMPTION) + mask |= SENSOR_HAS_CONSUMPTION; + if (formula <= TELEM_FORMULA_MULTIPLY) + mask |= SENSOR_HAS_SOURCES_12; + if (formula < TELEM_FORMULA_MULTIPLY) + mask |= SENSOR_HAS_SOURCES_34; + if (formula == TELEM_FORMULA_TOTALIZE) + mask |= SENSOR_HAS_TOTALIZE; + } + else { + if (unit < UNIT_FIRST_VIRTUAL) + mask |= (SENSOR_ISCONFIGURABLE | SENSOR_HAS_RATIO | SENSOR_HAS_POSITIVE); + } + + if (mask & SENSOR_ISCONFIGURABLE && unit != UNIT_FAHRENHEIT) + mask |= SENSOR_HAS_PRECISION; + + return mask; +} + +constexpr char FMT_LABEL[] { "%1: " }; +constexpr char FMT_VALUE[] { "%1 " }; +constexpr char FMT_LABEL_VALUE[] { "%1: %2 " }; + +QString SensorData::paramsToString(const ModelData * model) const +{ + if (!isAvailable()) + return ""; + + QString str; + int mask = getMask(); + + if (type == TELEM_TYPE_CALCULATED) { + str.append(QString(FMT_LABEL_VALUE).arg(tr("Formula")).arg(formulaToString())); + } + else { + str.append(QString(FMT_LABEL_VALUE).arg(tr("Id")).arg(idToString())); + str.append(QString(FMT_LABEL_VALUE).arg(tr("Instance")).arg(instance)); + } + + if (mask & SENSOR_HAS_CELLS) { + str.append(QString(FMT_LABEL_VALUE).arg(tr("Sensor")).arg(sourceToString(model, source))); + str.append(QString(FMT_VALUE).arg(cellIndexToString())); + } + + if (mask & SENSOR_HAS_SOURCES_12) { + str.append(QString(FMT_LABEL).arg(tr("Sources"))); + for (int i = 0; i < 4; i++) { + if (i < 2 || mask & SENSOR_HAS_SOURCES_34) { + str.append(QString(FMT_VALUE).arg(sourceToString(model, sources[i]))); + } + } + } + + if (mask & SENSOR_HAS_CONSUMPTION || mask & SENSOR_HAS_TOTALIZE) + str.append(QString(FMT_LABEL_VALUE).arg(tr("Sensor")).arg(sourceToString(model, amps))); + + if (mask & SENSOR_HAS_GPS) { + str.append(QString(FMT_LABEL_VALUE).arg(tr("GPS")).arg(sourceToString(model, gps))); + str.append(QString(FMT_LABEL_VALUE).arg(tr("Alt")).arg(sourceToString(model, alt))); + } + + if (mask & SENSOR_ISCONFIGURABLE) + str.append(QString(FMT_LABEL_VALUE).arg(tr("Unit")).arg(unitToString())); + + if (mask & SENSOR_HAS_PRECISION) + str.append(QString(FMT_LABEL_VALUE).arg(tr("Precision")).arg(precToString())); + + if (mask & SENSOR_HAS_RATIO) { + if (unit != UNIT_RPMS) { + int precsn = prec == 0 ? 1 : pow(10, prec); + str.append(QString(FMT_LABEL_VALUE).arg(tr("Ratio")).arg((float)ratio / 10)); + str.append(QString(FMT_LABEL_VALUE).arg(tr("Offset")).arg(QString::number((float)offset / precsn, 'f', prec))); + str.append(QString(FMT_LABEL_VALUE).arg(tr("Auto Offset")).arg(DataHelpers::boolToString(autoOffset, DataHelpers::BOOL_FMT_YN))); + } + else { + str.append(QString(FMT_LABEL_VALUE).arg(tr("Blades")).arg(ratio)); // TODO refactor to dedicated RPMS field + str.append(QString(FMT_LABEL_VALUE).arg(tr("Multiplier")).arg(offset)); // TODO refactor to dedicated RPMS field + } + } + + if (mask & SENSOR_ISCONFIGURABLE) + str.append(QString(FMT_LABEL_VALUE).arg(tr("Filter")).arg(DataHelpers::boolToString(filter, DataHelpers::BOOL_FMT_YN))); + + if (type == TELEM_TYPE_CALCULATED) + str.append(QString(FMT_LABEL_VALUE).arg(tr("Persist")).arg(DataHelpers::boolToString(persistent, DataHelpers::BOOL_FMT_YN))); + + if (mask & SENSOR_HAS_POSITIVE) + str.append(QString(FMT_LABEL_VALUE).arg(tr("Positive")).arg(DataHelpers::boolToString(onlyPositive, DataHelpers::BOOL_FMT_YN))); + + str.append(QString(FMT_LABEL_VALUE).arg(tr("Log")).arg(DataHelpers::boolToString(logs, DataHelpers::BOOL_FMT_YN))); + + return str; +} + +FieldRange SensorData::getRatioRange() const +{ + FieldRange result; + + if (unit == SensorData::UNIT_RPMS) { + result.decimals = 0; + result.max = 30000; + result.min = 1; + result.step = 1; + } + else { + result.decimals = 1; + result.max = 30000; + result.min = 0; + result.step = 0.1; + } + + return result; +} + +FieldRange SensorData::getOffsetRange() const +{ + FieldRange result; + + if (unit == SensorData::UNIT_RPMS) { + result.decimals = 0; + result.max = 30000; + result.min = 1; + result.step = 1; + } + else { + result.decimals = prec; + result.max = 30000.0f / powf(10.0f, prec); + result.min = -result.max; + result.step = pow(0.1, prec); + } + + return result; +} + +void SensorData::formulaChanged() +{ + switch (formula) { + case TELEM_FORMULA_CELL: + prec = 2; + unit = UNIT_VOLTS; + break; + case TELEM_FORMULA_CONSUMPTION: + prec = 0; + unit = UNIT_MAH; + break; + case TELEM_FORMULA_DIST: + prec = 0; + unit = UNIT_METERS; + break; + } +} + +void SensorData::unitChanged() +{ + if (unit == UNIT_FAHRENHEIT) + prec = 0; +} + +// static +QString SensorData::idToString(const int value) +{ + return QString::number(value, 16).toUpper(); +} + +// static +QString SensorData::typeToString(const int value) +{ + switch(value) { + case TELEM_TYPE_CUSTOM: + return tr("Custom"); + case TELEM_TYPE_CALCULATED: + return tr("Calculated"); + default: + return CPN_STR_UNKNOWN_ITEM; + } +} + +// static +QString SensorData::formulaToString(const int value) +{ + switch(value) { + case TELEM_FORMULA_ADD: + return tr("Add"); + case TELEM_FORMULA_AVERAGE: + return tr("Average"); + case TELEM_FORMULA_MIN: + return tr("Minimum"); + case TELEM_FORMULA_MAX: + return tr("Maximum"); + case TELEM_FORMULA_MULTIPLY: + return tr("Multiply"); + case TELEM_FORMULA_TOTALIZE: + return tr("Totalize"); + case TELEM_FORMULA_CELL: + return tr("Cell"); + case TELEM_FORMULA_CONSUMPTION: + return tr("Consumption"); + case TELEM_FORMULA_DIST: + return tr("Distance"); + default: + return CPN_STR_UNKNOWN_ITEM; + } +} + +// static +QString SensorData::cellIndexToString(const int value) +{ + if (value == TELEM_CELL_INDEX_LOWEST) + return tr("Lowest"); + if (value > TELEM_CELL_INDEX_LOWEST && value < TELEM_CELL_INDEX_HIGHEST) + return tr("Cell %1").arg(value - TELEM_CELL_INDEX_LOWEST); + if (value== TELEM_CELL_INDEX_HIGHEST) + return tr("Highest"); + if (value == TELEM_CELL_INDEX_DELTA) + return tr("Delta"); + return CPN_STR_UNKNOWN_ITEM; +} + +// static +QString SensorData::precToString(const int value) +{ + return QString("0.%1").arg(QString(value, '0')); +} + +// static +QString SensorData::sourceToString(const ModelData * model, const int index, const bool sign) +{ + if (model) { + const QString prfx = sign ? index < 0 ? "-" : "+" : ""; + + if (abs(index) > 0) { + const SensorData &sd = model->sensorData[abs(index) - 1]; + if (sd.type == SensorData::TELEM_TYPE_CUSTOM) + return QString("%1%2 (%3)").arg(prfx).arg(sd.label).arg(sd.getOrigin(model)); + else + return QString("%1%2").arg(prfx).arg(sd.label); + } + else + return CPN_STR_NONE_ITEM; + } + + return ""; +} + +// static +QString SensorData::unitToString(const int value) +{ + switch (value) { + case UNIT_RAW: + return tr("Raw (-)"); case UNIT_VOLTS: return tr("V"); case UNIT_AMPS: @@ -91,30 +404,111 @@ QString SensorData::unitString() const case UNIT_US: return tr("uS"); default: - return ""; + return CPN_STR_UNKNOWN_ITEM; } } -QString SensorData::nameToString(int index) const +// static +bool SensorData::isSourceAvailable(const ModelData * model, const int index) { - return RadioData::getElementName(tr("TELE"), index + 1, label); + Firmware * firmware = getCurrentFirmware(); + const int sensorcnt = firmware->getCapability(Sensors); + const int i = abs(index); + + if (model && sensorcnt > 0 && i <= sensorcnt) { + if (i > 0) + return model->sensorData[i - 1].isAvailable(); + else + return true; + } + + return false; } -QString SensorData::getOrigin(const ModelData * model) const -{ - if (type != TELEM_TYPE_CUSTOM || !id) - return QString(); +#define RSSI_ID 0xF101 - const ModuleData & module = model->moduleData[moduleIdx]; - if (module.isPxx2Module() && rxIdx <= 2 && module.access.receivers & (1 << rxIdx)) { - return QString(module.access.receiverName[rxIdx]); - } +// static +bool SensorData::isRssiSensorAvailable(const ModelData * model, const int value) +{ + if (value == 0) + return true; else { - return QString(); + const SensorData &sensor = model->sensorData[abs(value) - 1]; + return (sensor.isAvailable() && sensor.id == RSSI_ID); } } -bool SensorData::isEmpty() const +// static +QString SensorData::rssiSensorToString(const ModelData * model, const int value) { - return (!isAvailable() && type == 0 && id == 0 && subid == 0 && instance == 0 && rxIdx == 0 && moduleIdx == 0 && unit == 0 && ratio == 0 && prec == 0 && offset == 0 && autoOffset == 0 && filter == 0 && onlyPositive == 0 && logs == 0); + if (value == 0) + return tr("(default)"); + else + return sourceToString(model, value); +} + +// static +AbstractStaticItemModel * SensorData::typeItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("sensordata.type"); + + for (int i = 0; i <= TELEM_TYPE_LAST; i++) { + mdl->appendToItemList(typeToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} + +// static +AbstractStaticItemModel * SensorData::formulaItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("sensordata.formula"); + + for (int i = 0; i <= TELEM_FORMULA_LAST; i++) { + mdl->appendToItemList(formulaToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} + +// static +AbstractStaticItemModel * SensorData::cellIndexItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("sensordata.cellindex"); + + for (int i = 0; i <= TELEM_CELL_INDEX_LAST; i++) { + mdl->appendToItemList(cellIndexToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} + +// static +AbstractStaticItemModel * SensorData::unitItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName("sensordata.unit"); + + for (int i = 0; i <= UNIT_MAX; i++) { + QString str = unitToString(i); + if (str != CPN_STR_UNKNOWN_ITEM) + mdl->appendToItemList(str, i); + } + + mdl->loadItemList(); + return mdl; +} + +// static +PrecisionItemModel * SensorData::precisionItemModel() +{ + PrecisionItemModel * mdl = new PrecisionItemModel(0, 2); + mdl->setName("sensordata.precision"); + return mdl; } diff --git a/companion/src/firmwares/sensordata.h b/companion/src/firmwares/sensordata.h index a2b993bcc0..8a032cec52 100644 --- a/companion/src/firmwares/sensordata.h +++ b/companion/src/firmwares/sensordata.h @@ -18,17 +18,32 @@ * GNU General Public License for more details. */ -#ifndef SENSORDATA_H -#define SENSORDATA_H +#pragma once + +#include "datahelpers.h" #include -constexpr int CPN_MAX_SENSORS = 60; -constexpr int SENSOR_LABEL_LEN = 4; +constexpr int CPN_MAX_SENSORS { 60 }; +constexpr int SENSOR_LABEL_LEN { 4 }; + +constexpr int SENSOR_ISCONFIGURABLE { 1 << 1 }; +constexpr int SENSOR_HAS_GPS { 1 << 2 }; +constexpr int SENSOR_HAS_CELLS { 1 << 3 }; +constexpr int SENSOR_HAS_CONSUMPTION { 1 << 4 }; +constexpr int SENSOR_HAS_RATIO { 1 << 5 }; +constexpr int SENSOR_HAS_TOTALIZE { 1 << 6 }; +constexpr int SENSOR_HAS_SOURCES_12 { 1 << 7 }; +constexpr int SENSOR_HAS_SOURCES_34 { 1 << 8 }; +constexpr int SENSOR_HAS_POSITIVE { 1 << 9 }; +constexpr int SENSOR_HAS_PRECISION { 1 << 10 }; class ModelData; +class AbstractStaticItemModel; +class PrecisionItemModel; class SensorData { + Q_DECLARE_TR_FUNCTIONS(SensorData) public: @@ -36,7 +51,8 @@ class SensorData { enum { TELEM_TYPE_CUSTOM, - TELEM_TYPE_CALCULATED + TELEM_TYPE_CALCULATED, + TELEM_TYPE_LAST = TELEM_TYPE_CALCULATED }; enum @@ -63,6 +79,7 @@ class SensorData { TELEM_CELL_INDEX_6, TELEM_CELL_INDEX_HIGHEST, TELEM_CELL_INDEX_DELTA, + TELEM_CELL_INDEX_LAST = TELEM_CELL_INDEX_DELTA }; enum @@ -163,11 +180,37 @@ class SensorData { bool isAvailable() const { return strlen(label) > 0; } void updateUnit(); - QString unitString() const; QString nameToString(int index) const; QString getOrigin(const ModelData* model) const; void clear() { memset(this, 0, sizeof(SensorData)); } bool isEmpty() const; -}; + QString idToString() const; + QString typeToString() const; + QString formulaToString() const; + QString cellIndexToString() const; + QString unitToString() const; + QString precToString() const; + int getMask() const; + QString paramsToString(const ModelData * model) const; + FieldRange getRatioRange() const; + FieldRange getOffsetRange() const; + void formulaChanged(); + void unitChanged(); -#endif // SENSORDATA_H + static QString sourceToString(const ModelData * model, const int index, const bool sign = false); + static bool isSourceAvailable(const ModelData * model, const int index); + static QString idToString(const int value); + static QString typeToString(const int value); + static QString formulaToString(const int value); + static QString cellIndexToString(const int value); + static QString unitToString(const int value); + static QString precToString(const int value); + static bool isRssiSensorAvailable(const ModelData * model, const int value); + static QString rssiSensorToString(const ModelData * model, const int value); + + static AbstractStaticItemModel * typeItemModel(); + static AbstractStaticItemModel * formulaItemModel(); + static AbstractStaticItemModel * cellIndexItemModel(); + static AbstractStaticItemModel * unitItemModel(); + static PrecisionItemModel * precisionItemModel(); +}; diff --git a/companion/src/firmwares/timerdata.cpp b/companion/src/firmwares/timerdata.cpp new file mode 100644 index 0000000000..9034ed7e07 --- /dev/null +++ b/companion/src/firmwares/timerdata.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "timerdata.h" +#include "radiodataconversionstate.h" +#include "compounditemmodels.h" + +void TimerData::convert(RadioDataConversionState & cstate) +{ + cstate.setComponent(tr("TMR"), 1); + cstate.setSubComp(tr("Timer %1").arg(cstate.subCompIdx + 1)); + mode.convert(cstate); +} + +void TimerData::clear() +{ + memset(reinterpret_cast(this), 0, sizeof(TimerData)); + mode = RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); +} + +bool TimerData::isEmpty() +{ + return (mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0) && name[0] == '\0' && minuteBeep == 0 && countdownBeep == COUNTDOWNBEEP_SILENT && val == 0 && persistent == 0 /*&& pvalue == 0*/); +} + +bool TimerData::isModeOff() +{ + return mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); +} + +QString TimerData::nameToString(int index) const +{ + return DataHelpers::getElementName(tr("TMR", "as in Timer"), index + 1, name); +} + +QString TimerData::countdownBeepToString() const +{ + return countdownBeepToString(countdownBeep); +} + +QString TimerData::countdownStartToString() const +{ + if (countdownBeep == COUNTDOWNBEEP_SILENT) + return ""; + else + return countdownStartToString(countdownStart); +} + +QString TimerData::persistentToString(const bool verbose) const +{ + return persistentToString(persistent, verbose); +} + +QString TimerData::pvalueToString() const +{ + return pvalueToString(pvalue); +} + +QString TimerData::valToString() const +{ + return valToString(val); +} + +void TimerData::countdownBeepChanged() +{ + if (countdownBeep == COUNTDOWNBEEP_SILENT) + countdownStart = 0; +} + +// static +QString TimerData::countdownBeepToString(const int value) +{ + switch(value) { + case COUNTDOWNBEEP_SILENT: + return tr("Silent"); + case COUNTDOWNBEEP_BEEPS: + return tr("Beeps"); + case COUNTDOWNBEEP_VOICE: + return tr("Voice"); + case COUNTDOWNBEEP_HAPTIC: + return tr("Haptic"); + default: + return CPN_STR_UNKNOWN_ITEM; + } +} + +// static +QString TimerData::countdownStartToString(const int value) +{ + switch(value) { + case COUNTDOWNSTART_5: + return tr("5s"); + case COUNTDOWNSTART_10: + return tr("10s"); + case COUNTDOWNSTART_20: + return tr("20s"); + case COUNTDOWNSTART_30: + return tr("30s"); + default: + return CPN_STR_UNKNOWN_ITEM; + } +} + +// static +QString TimerData::persistentToString(const int value, const bool verbose) +{ + switch(value) { + case PERSISTENT_NOT: + return verbose ? tr("Not persistent") : tr("NOT"); + case PERSISTENT_FLIGHT: + return verbose ? tr("Persistent (flight)") : tr("Flight"); + case PERSISTENT_MANUALRESET: + return verbose ? tr("Persistent (manual reset)") : tr("Manual reset"); + default: + return CPN_STR_UNKNOWN_ITEM; + } +} + +// static +QString TimerData::pvalueToString(const int value) +{ + return DataHelpers::timeToString(value, TIMESTR_MASK_HRSMINS | TIMESTR_MASK_ZEROHRS); +} + +// static +QString TimerData::valToString(const int value) +{ + return DataHelpers::timeToString(value, TIMESTR_MASK_HRSMINS | TIMESTR_MASK_ZEROHRS); +} + +// static +AbstractStaticItemModel * TimerData::countdownBeepItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName(AIM_TIMER_COUNTDOWNBEEP); + + for (int i = 0; i < COUNTDOWNBEEP_COUNT; i++) { + mdl->appendToItemList(countdownBeepToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} + +// static +AbstractStaticItemModel * TimerData::countdownStartItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName(AIM_TIMER_COUNTDOWNSTART); + + for (int i = COUNTDOWNSTART_LAST; i >= COUNTDOWNSTART_FIRST; i--) { + mdl->appendToItemList(countdownStartToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} + +// static +AbstractStaticItemModel * TimerData::persistentItemModel() +{ + AbstractStaticItemModel * mdl = new AbstractStaticItemModel(); + mdl->setName(AIM_TIMER_PERSISTENT); + + for (int i = 0; i < PERSISTENT_COUNT; i++) { + mdl->appendToItemList(persistentToString(i), i); + } + + mdl->loadItemList(); + return mdl; +} diff --git a/companion/src/firmwares/timerdata.h b/companion/src/firmwares/timerdata.h new file mode 100644 index 0000000000..07cc1eedde --- /dev/null +++ b/companion/src/firmwares/timerdata.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include "rawswitch.h" +#include "datahelpers.h" + +#include + +class RadioDataConversionState; +class AbstractStaticItemModel; + +constexpr char AIM_TIMER_COUNTDOWNBEEP[] {"timerdata.countdownBeep"}; +constexpr char AIM_TIMER_COUNTDOWNSTART[] {"timerdata.countdownStart"}; +constexpr char AIM_TIMER_PERSISTENT[] {"timerdata.persistent"}; + +constexpr int TIMER_NAME_LEN {8}; + +class TimerData { + Q_DECLARE_TR_FUNCTIONS(TimerData) + + public: + enum CountDownBeepType { + COUNTDOWNBEEP_SILENT, + COUNTDOWNBEEP_BEEPS, + COUNTDOWNBEEP_VOICE, + COUNTDOWNBEEP_HAPTIC, + COUNTDOWNBEEP_COUNT + }; + + enum CountDownStart { + COUNTDOWNSTART_30 = -2, + COUNTDOWNSTART_FIRST = COUNTDOWNSTART_30, + COUNTDOWNSTART_20, + COUNTDOWNSTART_10, + COUNTDOWNSTART_5, + COUNTDOWNSTART_LAST = COUNTDOWNSTART_5 + }; + + enum PersistentType { + PERSISTENT_NOT, + PERSISTENT_FLIGHT, + PERSISTENT_MANUALRESET, + PERSISTENT_COUNT + }; + + TimerData() { clear(); } + + RawSwitch mode; + char name[TIMER_NAME_LEN + 1]; + bool minuteBeep; + unsigned int countdownBeep; + unsigned int val; + unsigned int persistent; + int countdownStart; + unsigned int direction; + int pvalue; + + void convert(RadioDataConversionState & cstate); + void clear(); + bool isEmpty(); + bool isModeOff(); + QString nameToString(int index) const; + QString countdownBeepToString() const; + QString countdownStartToString() const; + QString persistentToString(const bool verbose = true) const; + QString pvalueToString() const; + QString valToString() const; + void countdownBeepChanged(); + + static QString countdownBeepToString(const int value); + static QString countdownStartToString(const int value); + static QString persistentToString(const int value, const bool verbose = true); + static QString pvalueToString(const int value); + static QString valToString(const int value); + static AbstractStaticItemModel * countdownBeepItemModel(); + static AbstractStaticItemModel * countdownStartItemModel(); + static AbstractStaticItemModel * persistentItemModel(); + +}; diff --git a/companion/src/generaledit/generaledit.cpp b/companion/src/generaledit/generaledit.cpp index bff9d3f83e..e80038f9f7 100644 --- a/companion/src/generaledit/generaledit.cpp +++ b/companion/src/generaledit/generaledit.cpp @@ -28,7 +28,7 @@ #include "hardware.h" #include "../modeledit/customfunctions.h" #include "verticalscrollarea.h" -#include "rawitemdatamodels.h" +#include "compounditemmodels.h" GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * firmware) : QDialog(parent), @@ -56,10 +56,14 @@ GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * fir } } - commonItemModels = new CommonItemModels(&generalSettings, nullptr, this); + sharedItemModels = new CompoundItemModelFactory(&generalSettings, nullptr); + sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSource); + sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSwitch); + sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncAction); + sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncResetParam); addTab(new GeneralSetupPanel(this, generalSettings, firmware), tr("Setup")); - addTab(new CustomFunctionsPanel(this, nullptr, generalSettings, firmware, commonItemModels), tr("Global Functions")); + addTab(new CustomFunctionsPanel(this, nullptr, generalSettings, firmware, sharedItemModels), tr("Global Functions")); addTab(new TrainerPanel(this, generalSettings, firmware), tr("Trainer")); addTab(new HardwarePanel(this, generalSettings, firmware), tr("Hardware")); addTab(new CalibrationPanel(this, generalSettings, firmware), tr("Calibration")); @@ -70,6 +74,7 @@ GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * fir GeneralEdit::~GeneralEdit() { delete ui; + delete sharedItemModels; } void GeneralEdit::closeEvent(QCloseEvent *event) diff --git a/companion/src/generaledit/generaledit.h b/companion/src/generaledit/generaledit.h index 3f73a9e014..b2e6caa821 100644 --- a/companion/src/generaledit/generaledit.h +++ b/companion/src/generaledit/generaledit.h @@ -25,7 +25,7 @@ #include "eeprominterface.h" #include "genericpanel.h" -class CommonItemModels; +class CompoundItemModelFactory; namespace Ui { class GeneralEdit; @@ -73,7 +73,7 @@ class GeneralEdit : public QDialog QVector panels; void addTab(GenericPanel *panel, QString text); void closeEvent(QCloseEvent *event); - CommonItemModels *commonItemModels; + CompoundItemModelFactory *sharedItemModels; }; #endif // _GENERALEDIT_H_ diff --git a/companion/src/generaledit/generalsetup.ui b/companion/src/generaledit/generalsetup.ui index 7353b9c4ba..422eddc7df 100644 --- a/companion/src/generaledit/generalsetup.ui +++ b/companion/src/generaledit/generalsetup.ui @@ -1527,7 +1527,7 @@ Mode 4: Battery warning voltage. This is the threashhold where the battery warning sounds. -Acceptable values are 5v..10v +Acceptable values are 3v..12v @@ -1539,7 +1539,7 @@ Acceptable values are 5v..10v 1 - 4.000000000000000 + 3.000000000000000 12.000000000000000 @@ -1679,7 +1679,7 @@ Acceptable values are 5v..10v 1 - 4.000000000000000 + 3.000000000000000 16.000000000000000 @@ -1708,7 +1708,7 @@ Acceptable values are 5v..10v 1 - 4.000000000000000 + 3.000000000000000 16.000000000000000 diff --git a/companion/src/helpers.cpp b/companion/src/helpers.cpp index 020f1b45bf..c1cd7de79f 100644 --- a/companion/src/helpers.cpp +++ b/companion/src/helpers.cpp @@ -32,6 +32,7 @@ #include "simulatorinterface.h" #include "simulatormainwindow.h" #include "storage/sdcard.h" +#include "filtereditemmodels.h" #include #include @@ -117,7 +118,8 @@ void CompanionIcon::addImage(const QString & baseimage, Mode mode, State state) * GVarGroup */ -GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBox * weightCB, int & weight, const ModelData & model, const int deflt, const int mini, const int maxi, const double step, bool allowGvars): +GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBox * weightCB, int & weight, const ModelData & model, + const int deflt, const int mini, const int maxi, const double step, FilteredItemModel * gvarModel): QObject(), weightGV(weightGV), weightSB(weightSB), @@ -131,8 +133,8 @@ GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBo step(step), lock(true) { - if (allowGvars && getCurrentFirmware()->getCapability(Gvars)) { - Helpers::populateGVCB(*weightCB, weight, model); + if (gvarModel && gvarModel->rowCount() > 0) { + weightCB->setModel(gvarModel); connect(weightGV, SIGNAL(stateChanged(int)), this, SLOT(gvarCBChanged(int))); connect(weightCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged())); } @@ -152,12 +154,19 @@ GVarGroup::GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBo void GVarGroup::gvarCBChanged(int state) { - weightCB->setVisible(state); - if (weightSB) + if (!lock) { + weightCB->setVisible(state); + if (weightGV->isChecked()) { + // set CB to +GV1 + int cnt = getCurrentFirmware()->getCapability(Gvars); + if (weightCB->count() > cnt) + weightCB->setCurrentIndex(cnt); + else + weightCB->setCurrentIndex(0); + } weightSB->setVisible(!state); - else - weightSB->setVisible(!state); - valuesChanged(); + valuesChanged(); + } } void GVarGroup::valuesChanged() @@ -168,7 +177,7 @@ void GVarGroup::valuesChanged() else if (sb) weight = sb->value(); else - weight = round(dsb->value()/step); + weight = round(dsb->value() / step); emit valueChanged(); } @@ -180,7 +189,7 @@ void GVarGroup::setWeight(int val) int tval; - if (val>maxi || val maxi || val < mini) { tval = deflt; weightGV->setChecked(true); weightSB->hide(); @@ -214,27 +223,6 @@ void GVarGroup::setWeight(int val) * Helpers namespace functions */ -void Helpers::populateGVCB(QComboBox & b, int value, const ModelData & model) -{ - int count = getCurrentFirmware()->getCapability(Gvars); - - b.clear(); - - for (int i=-count; i<=-1; i++) { - int16_t gval = (int16_t)(-10000+i); - b.addItem("-" + RawSource(SOURCE_TYPE_GVAR, abs(i)-1).toString(&model), gval); - } - - for (int i=1; i<=count; i++) { - int16_t gval = (int16_t)(10000+i); - b.addItem(RawSource(SOURCE_TYPE_GVAR, i-1).toString(&model), gval); - } - - b.setCurrentIndex(b.findData(value)); - if (b.currentIndex() == -1) - b.setCurrentIndex(count); -} - // TODO: Move lookup to GVarData class (w/out combobox) void Helpers::populateGvarUseCB(QComboBox * b, unsigned int phase) { diff --git a/companion/src/helpers.h b/companion/src/helpers.h index 107ca2aa0a..8bb1cc6b8c 100644 --- a/companion/src/helpers.h +++ b/companion/src/helpers.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _HELPERS_H_ -#define _HELPERS_H_ +#pragma once #include "eeprominterface.h" #include @@ -60,12 +59,15 @@ class CompanionIcon: public QIcon { void addImage(const QString &baseimage, Mode mode = Normal, State state = Off); }; +class FilteredItemModel; + class GVarGroup: public QObject { Q_OBJECT public: - GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBox * weightCB, int & weight, const ModelData & model, const int deflt, const int mini, const int maxi, const double step=1.0, bool allowGVars=true); + GVarGroup(QCheckBox * weightGV, QAbstractSpinBox * weightSB, QComboBox * weightCB, int & weight, const ModelData & model, + const int deflt, const int mini, const int maxi, const double step = 1.0, FilteredItemModel * gvarModel = nullptr); void setWeight(int val); @@ -101,7 +103,6 @@ class GVarGroup: public QObject { namespace Helpers { void populateGvarUseCB(QComboBox *b, unsigned int phase); - void populateGVCB(QComboBox & b, int value, const ModelData & model); void populateFileComboBox(QComboBox * b, const QSet & set, const QString & current); void getFileComboBoxValue(QComboBox * b, char * dest, int length); @@ -234,5 +235,3 @@ private: }; extern Stopwatch gStopwatch; - -#endif // _HELPERS_H_ diff --git a/companion/src/images/simulator/JumperTLITE/bottom.png b/companion/src/images/simulator/JumperTLITE/bottom.png new file mode 100644 index 0000000000..d7e3f42fc8 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/bottom.png differ diff --git a/companion/src/images/simulator/JumperTLITE/bottom_left.png b/companion/src/images/simulator/JumperTLITE/bottom_left.png new file mode 100644 index 0000000000..e6332207c7 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/bottom_left.png differ diff --git a/companion/src/images/simulator/JumperTLITE/bottom_right.png b/companion/src/images/simulator/JumperTLITE/bottom_right.png new file mode 100644 index 0000000000..ee59125478 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/bottom_right.png differ diff --git a/companion/src/images/simulator/JumperTLITE/center_LCD.png b/companion/src/images/simulator/JumperTLITE/center_LCD.png new file mode 100644 index 0000000000..f3249de168 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/center_LCD.png differ diff --git a/companion/src/images/simulator/JumperTLITE/left.png b/companion/src/images/simulator/JumperTLITE/left.png new file mode 100644 index 0000000000..eb54a39675 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/left.png differ diff --git a/companion/src/images/simulator/JumperTLITE/left_bottom.png b/companion/src/images/simulator/JumperTLITE/left_bottom.png new file mode 100644 index 0000000000..60e4d30a71 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/left_bottom.png differ diff --git a/companion/src/images/simulator/JumperTLITE/left_top.png b/companion/src/images/simulator/JumperTLITE/left_top.png new file mode 100644 index 0000000000..5ded766e05 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/left_top.png differ diff --git a/companion/src/images/simulator/JumperTLITE/right.png b/companion/src/images/simulator/JumperTLITE/right.png new file mode 100644 index 0000000000..6c455081f3 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/right.png differ diff --git a/companion/src/images/simulator/JumperTLITE/right_bottom.png b/companion/src/images/simulator/JumperTLITE/right_bottom.png new file mode 100644 index 0000000000..55c1e5f5f7 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/right_bottom.png differ diff --git a/companion/src/images/simulator/JumperTLITE/right_top.png b/companion/src/images/simulator/JumperTLITE/right_top.png new file mode 100644 index 0000000000..6e83d354e2 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/right_top.png differ diff --git a/companion/src/images/simulator/JumperTLITE/top.png b/companion/src/images/simulator/JumperTLITE/top.png new file mode 100644 index 0000000000..d90d836d84 Binary files /dev/null and b/companion/src/images/simulator/JumperTLITE/top.png differ diff --git a/companion/src/images/simulator/T8/bottom.png b/companion/src/images/simulator/T8/bottom.png new file mode 100644 index 0000000000..055c7db62c Binary files /dev/null and b/companion/src/images/simulator/T8/bottom.png differ diff --git a/companion/src/images/simulator/T8/left-pagedn.png b/companion/src/images/simulator/T8/left-pagedn.png new file mode 100644 index 0000000000..6b290e3688 Binary files /dev/null and b/companion/src/images/simulator/T8/left-pagedn.png differ diff --git a/companion/src/images/simulator/T8/left-pageup.png b/companion/src/images/simulator/T8/left-pageup.png new file mode 100644 index 0000000000..c155649a1a Binary files /dev/null and b/companion/src/images/simulator/T8/left-pageup.png differ diff --git a/companion/src/images/simulator/T8/left-rtn.png b/companion/src/images/simulator/T8/left-rtn.png new file mode 100644 index 0000000000..95cc700f64 Binary files /dev/null and b/companion/src/images/simulator/T8/left-rtn.png differ diff --git a/companion/src/images/simulator/T8/left-sys.png b/companion/src/images/simulator/T8/left-sys.png new file mode 100644 index 0000000000..7943ed93d4 Binary files /dev/null and b/companion/src/images/simulator/T8/left-sys.png differ diff --git a/companion/src/images/simulator/T8/left.png b/companion/src/images/simulator/T8/left.png new file mode 100644 index 0000000000..ff25c95437 Binary files /dev/null and b/companion/src/images/simulator/T8/left.png differ diff --git a/companion/src/images/simulator/T8/right-dn.png b/companion/src/images/simulator/T8/right-dn.png new file mode 100644 index 0000000000..82a3835764 Binary files /dev/null and b/companion/src/images/simulator/T8/right-dn.png differ diff --git a/companion/src/images/simulator/T8/right-ent.png b/companion/src/images/simulator/T8/right-ent.png new file mode 100644 index 0000000000..8c3be3a565 Binary files /dev/null and b/companion/src/images/simulator/T8/right-ent.png differ diff --git a/companion/src/images/simulator/T8/right-mdl.png b/companion/src/images/simulator/T8/right-mdl.png new file mode 100644 index 0000000000..f385c652ef Binary files /dev/null and b/companion/src/images/simulator/T8/right-mdl.png differ diff --git a/companion/src/images/simulator/T8/right-up.png b/companion/src/images/simulator/T8/right-up.png new file mode 100644 index 0000000000..5e3bd39edb Binary files /dev/null and b/companion/src/images/simulator/T8/right-up.png differ diff --git a/companion/src/images/simulator/T8/right.png b/companion/src/images/simulator/T8/right.png new file mode 100644 index 0000000000..1016d8de50 Binary files /dev/null and b/companion/src/images/simulator/T8/right.png differ diff --git a/companion/src/images/simulator/T8/top.png b/companion/src/images/simulator/T8/top.png new file mode 100644 index 0000000000..962119223e Binary files /dev/null and b/companion/src/images/simulator/T8/top.png differ diff --git a/companion/src/mainwindow.cpp b/companion/src/mainwindow.cpp index 9d490da39e..23c5f71b7c 100644 --- a/companion/src/mainwindow.cpp +++ b/companion/src/mainwindow.cpp @@ -1585,7 +1585,7 @@ void MainWindow::updateWindowActions() QString scut; if (++count < 10) scut = tr("Alt+%1").arg(count); - QAction * act = addActToGroup(windowsListActions, "", "", "window_ptr", qVariantFromValue(win), QVariant(), scut); + QAction * act = addActToGroup(windowsListActions, "", "", "window_ptr", QVariant::fromValue(win), QVariant(), scut); act->setChecked(win == mdiArea->activeSubWindow()); updateWindowActionTitle(win, act); } diff --git a/companion/src/modeledit/channels.cpp b/companion/src/modeledit/channels.cpp index d2818368e1..806ea144e7 100644 --- a/companion/src/modeledit/channels.cpp +++ b/companion/src/modeledit/channels.cpp @@ -20,44 +20,33 @@ #include "channels.h" #include "helpers.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" -LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model, int min, int max, int deflt, ModelPanel * panel): +LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model, + int min, int max, int deflt, FilteredItemModel * gvarModel, ModelPanel * panel): firmware(firmware), spinbox(new QDoubleSpinBox()), - value(value), - displayStep(0.1) + value(value) { - Board::Type board = firmware->getBoard(); - bool allowGVars = IS_HORUS_OR_TARANIS(board); - int internalStep = 1; - spinbox->setProperty("index", row); spinbox->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); spinbox->setAccelerated(true); + spinbox->setDecimals(1); if (firmware->getCapability(PPMUnitMicroseconds)) { displayStep = 0.512; - spinbox->setDecimals(1); spinbox->setSuffix("us"); } else { - spinbox->setDecimals(0); + displayStep = 0.1; spinbox->setSuffix("%"); } - if (deflt == 0 /*it's the offset*/) { - spinbox->setDecimals(1); - } - else { - internalStep *= 10; - } - - spinbox->setSingleStep(displayStep * internalStep); + spinbox->setSingleStep(displayStep); spinbox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); QHBoxLayout *horizontalLayout = new QHBoxLayout(); - QCheckBox *gv = new QCheckBox(tr("GV")); + gv = new QCheckBox(tr("GV")); gv->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); horizontalLayout->addWidget(gv); QComboBox *cb = new QComboBox(); @@ -65,7 +54,7 @@ LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row horizontalLayout->addWidget(cb); horizontalLayout->addWidget(spinbox); tableLayout->addLayout(row, col, horizontalLayout); - gvarGroup = new GVarGroup(gv, spinbox, cb, value, model, deflt, min, max, displayStep, allowGVars); + gvarGroup = new GVarGroup(gv, spinbox, cb, value, model, deflt, min, max, displayStep, gvarModel); QObject::connect(gvarGroup, &GVarGroup::valueChanged, panel, &ModelPanel::modified); } @@ -84,28 +73,32 @@ void LimitsGroup::updateMinMax(int max) if (spinbox->maximum() == 0) { spinbox->setMinimum(-max * displayStep); gvarGroup->setMinimum(-max); - if (value < -max) { + if (!gv->isChecked() && value < -max) { value = -max; } } if (spinbox->minimum() == 0) { spinbox->setMaximum(max * displayStep); gvarGroup->setMaximum(max); - if (value > max) { + if (!gv->isChecked() && value > max) { value = max; } } } -ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels): + +ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels): ModelPanel(parent, model, generalSettings, firmware), - commonItemModels(commonItemModels) + sharedItemModels(sharedItemModels) { chnCapability = firmware->getCapability(Outputs); int channelNameMaxLen = firmware->getCapability(ChannelsName); - curveFilteredModel = new RawItemFilteredModel(commonItemModels->curveItemModel(), RawItemFilteredModel::AllFilter, this); - connect(curveFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &ChannelsPanel::onModelDataAboutToBeUpdated); - connect(curveFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &ChannelsPanel::onModelDataUpdateComplete); + dialogFilteredItemModels = new FilteredItemModelFactory(); + + int crvid = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_Curve)), "Curve"); + connectItemModelEvents(dialogFilteredItemModels->getItemModel(crvid)); + + int gvid = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef)), "GVarRef"); QStringList headerLabels; headerLabels << "#"; @@ -147,13 +140,13 @@ ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSetting } // Channel offset - chnOffset[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].offset, model, -1000, 1000, 0, this); + chnOffset[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].offset, model, -1000, 1000, 0, dialogFilteredItemModels->getItemModel(gvid), this); // Channel min - chnMin[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].min, model, -model.getChannelsMax() * 10, 0, -1000, this); + chnMin[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].min, model, -model.getChannelsMax() * 10, 0, -1000, dialogFilteredItemModels->getItemModel(gvid), this); // Channel max - chnMax[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].max, model, 0, model.getChannelsMax() * 10, 1000, this); + chnMax[i] = new LimitsGroup(firmware, tableLayout, i, col++, model.limitData[i].max, model, 0, model.getChannelsMax() * 10, 1000, dialogFilteredItemModels->getItemModel(gvid), this); // Channel inversion invCB[i] = new QComboBox(this); @@ -166,7 +159,7 @@ ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSetting if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { curveCB[i] = new QComboBox(this); curveCB[i]->setProperty("index", i); - curveCB[i]->setModel(curveFilteredModel); + curveCB[i]->setModel(dialogFilteredItemModels->getItemModel(crvid)); connect(curveCB[i], SIGNAL(currentIndexChanged(int)), this, SLOT(curveEdited())); tableLayout->addWidget(i, col++, curveCB[i]); } @@ -214,6 +207,7 @@ ChannelsPanel::~ChannelsPanel() delete centerSB[i]; delete symlimitsChk[i]; } + delete dialogFilteredItemModels; } void ChannelsPanel::symlimitsEdited() @@ -241,12 +235,11 @@ void ChannelsPanel::nameEdited() void ChannelsPanel::refreshExtendedLimits() { - int channelMax = model->getChannelsMax(); + int channelMax = model->getChannelsMax() * 10; for (int i = 0 ; i < CPN_MAX_CHNOUT; i++) { - chnOffset[i]->updateMinMax(10 * channelMax); - chnMin[i]->updateMinMax(10 * channelMax); - chnMax[i]->updateMinMax(10 * channelMax); + chnMin[i]->updateMinMax(channelMax); + chnMax[i]->updateMinMax(channelMax); } emit modified(); } @@ -319,10 +312,9 @@ void ChannelsPanel::cmPaste() { QByteArray data; if (hasClipboardData(&data)) { - memcpy(&model->limitData[selectedIndex], data.constData(), sizeof(LimitData)); + model->limitsSet(selectedIndex, data); updateLine(selectedIndex); updateItemModels(); - emit modified(); } } @@ -331,22 +323,18 @@ void ChannelsPanel::cmDelete() if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) return; - memmove(&model->limitData[selectedIndex], &model->limitData[selectedIndex + 1], (CPN_MAX_CHNOUT - (selectedIndex + 1)) * sizeof(LimitData)); - model->limitData[chnCapability - 1].clear(); - model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1); - + model->limitsDelete(selectedIndex); for (int i = selectedIndex; i < chnCapability; i++) { updateLine(i); } updateItemModels(); - emit modified(); } void ChannelsPanel::cmCopy() { QByteArray data; - data.append((char*)&model->limitData[selectedIndex], sizeof(LimitData)); + model->limitsGet(selectedIndex, data); QMimeData *mimeData = new QMimeData; mimeData->setData(MIMETYPE_CHANNEL, data); QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); @@ -412,12 +400,18 @@ bool ChannelsPanel::moveUpAllowed() const void ChannelsPanel::cmMoveUp() { - swapData(selectedIndex, selectedIndex - 1); + model->limitsMove(selectedIndex, -1); + updateLine(selectedIndex - 1); + updateLine(selectedIndex); + updateItemModels(); } void ChannelsPanel::cmMoveDown() { - swapData(selectedIndex, selectedIndex + 1); + model->limitsMove(selectedIndex, 1); + updateLine(selectedIndex); + updateLine(selectedIndex + 1); + updateItemModels(); } void ChannelsPanel::cmClear(bool prompt) @@ -427,11 +421,9 @@ void ChannelsPanel::cmClear(bool prompt) return; } - model->limitData[selectedIndex].clear(); - model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, selectedIndex); + model->limitsClear(selectedIndex); updateLine(selectedIndex); updateItemModels(); - emit modified(); } void ChannelsPanel::cmClearAll() @@ -439,47 +431,33 @@ void ChannelsPanel::cmClearAll() if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Channels. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) return; - for (int i = 0; i < chnCapability; i++) { - model->limitData[i].clear(); - model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, i); - updateLine(i); - } + model->limitsClearAll(); + update(); updateItemModels(); - emit modified(); } void ChannelsPanel::cmInsert() { - memmove(&model->limitData[selectedIndex + 1], &model->limitData[selectedIndex], (CPN_MAX_CHNOUT - (selectedIndex + 1)) * sizeof(LimitData)); - model->limitData[selectedIndex].clear(); - model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1); - update(); - updateItemModels(); - emit modified(); -} - -void ChannelsPanel::swapData(int idx1, int idx2) -{ - if ((idx1 != idx2) && (!model->limitData[idx1].isEmpty() || !model->limitData[idx2].isEmpty())) { - LimitData chntmp = model->limitData[idx2]; - LimitData *chn1 = &model->limitData[idx1]; - LimitData *chn2 = &model->limitData[idx2]; - memcpy(chn2, chn1, sizeof(LimitData)); - memcpy(chn1, &chntmp, sizeof(LimitData)); - model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); - updateLine(idx1); - updateLine(idx2); - updateItemModels(); - emit modified(); + model->limitsInsert(selectedIndex); + for (int i = selectedIndex; i < chnCapability; i++) { + updateLine(i); } + + updateItemModels(); } -void ChannelsPanel::onModelDataAboutToBeUpdated() +void ChannelsPanel::connectItemModelEvents(const FilteredItemModel * itemModel) +{ + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &ChannelsPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &ChannelsPanel::onItemModelUpdateComplete); +} + +void ChannelsPanel::onItemModelAboutToBeUpdated() { lock = true; } -void ChannelsPanel::onModelDataUpdateComplete() +void ChannelsPanel::onItemModelUpdateComplete() { update(); lock = false; @@ -487,5 +465,6 @@ void ChannelsPanel::onModelDataUpdateComplete() void ChannelsPanel::updateItemModels() { - commonItemModels->update(CommonItemModels::RMO_CHANNELS); + sharedItemModels->update(AbstractItemModel::IMUE_Channels); + emit modified(); } diff --git a/companion/src/modeledit/channels.h b/companion/src/modeledit/channels.h index a481feec20..5d76007187 100644 --- a/companion/src/modeledit/channels.h +++ b/companion/src/modeledit/channels.h @@ -18,16 +18,15 @@ * GNU General Public License for more details. */ -#ifndef _CHANNELS_H_ -#define _CHANNELS_H_ +#pragma once #include "helpers.h" #include "modeledit.h" #include -class CommonItemModels; -class RawItemFilteredModel; +class CompoundItemModelFactory; +class FilteredItemModelFactory; constexpr char MIMETYPE_CHANNEL[] = "application/x-companion-channel"; @@ -38,7 +37,8 @@ class LimitsGroup Q_DECLARE_TR_FUNCTIONS(LimitsGroup) public: - LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model, int min, int max, int deflt, ModelPanel * panel=NULL); + LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row, int col, int & value, const ModelData & model, + int min, int max, int deflt, FilteredItemModel * gvarModel, ModelPanel * panel = nullptr); ~LimitsGroup(); void setValue(int val); @@ -50,6 +50,7 @@ class LimitsGroup GVarGroup *gvarGroup; int &value; double displayStep; + QCheckBox *gv; }; class ChannelsPanel : public ModelPanel @@ -57,8 +58,9 @@ class ChannelsPanel : public ModelPanel Q_OBJECT public: - ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); - ~ChannelsPanel(); + ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, + CompoundItemModelFactory * sharedItemModels); + virtual ~ChannelsPanel(); public slots: void refreshExtendedLimits(); @@ -81,15 +83,14 @@ class ChannelsPanel : public ModelPanel void cmClear(bool prompt = true); void cmClearAll(); void onCustomContextMenuRequested(QPoint pos); - void onModelDataAboutToBeUpdated(); - void onModelDataUpdateComplete(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: bool hasClipboardData(QByteArray * data = nullptr) const; bool insertAllowed() const; bool moveDownAllowed() const; bool moveUpAllowed() const; - void swapData(int idx1, int idx2); QLineEdit *name[CPN_MAX_CHNOUT]; LimitsGroup *chnOffset[CPN_MAX_CHNOUT]; LimitsGroup *chnMin[CPN_MAX_CHNOUT]; @@ -100,9 +101,8 @@ class ChannelsPanel : public ModelPanel QCheckBox *symlimitsChk[CPN_MAX_CHNOUT]; int selectedIndex; int chnCapability; - CommonItemModels * commonItemModels; - RawItemFilteredModel *curveFilteredModel; + CompoundItemModelFactory *sharedItemModels; void updateItemModels(); + void connectItemModelEvents(const FilteredItemModel * itemModel); + FilteredItemModelFactory *dialogFilteredItemModels; }; - -#endif // _CHANNELS_H_ diff --git a/companion/src/modeledit/curves.cpp b/companion/src/modeledit/curves.cpp index 9e60f30c3b..7f8b80219e 100644 --- a/companion/src/modeledit/curves.cpp +++ b/companion/src/modeledit/curves.cpp @@ -23,7 +23,7 @@ #include "node.h" #include "edge.h" #include "helpers.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" #define GFX_MARGIN 16 @@ -109,11 +109,12 @@ float curveSymmetricalX(float x, float coeff, float yMin, float yMid, float yMax return y; } -CurvesPanel::CurvesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels): +CurvesPanel::CurvesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, + CompoundItemModelFactory * sharedItemModels): ModelPanel(parent, model, generalSettings, firmware), ui(new Ui::Curves), currentCurve(0), - commonItemModels(commonItemModels) + sharedItemModels(sharedItemModels) { ui->setupUi(this); @@ -812,7 +813,7 @@ void CurvesPanel::swapData(int idx1, int idx2) void CurvesPanel::updateItemModels() { - commonItemModels->update(CommonItemModels::RMO_CURVES); + sharedItemModels->update(AbstractItemModel::IMUE_Curves); } CustomScene::CustomScene(QGraphicsView * view) : diff --git a/companion/src/modeledit/curves.h b/companion/src/modeledit/curves.h index 8df3a85285..c66f79cb7a 100644 --- a/companion/src/modeledit/curves.h +++ b/companion/src/modeledit/curves.h @@ -26,7 +26,7 @@ #include #include -class CommonItemModels; +class CompoundItemModelFactory; constexpr char MIMETYPE_CURVE[] = "application/x-companion-curve"; @@ -61,7 +61,7 @@ class CurvesPanel : public ModelPanel Q_OBJECT public: - CurvesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); + CurvesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels); virtual ~CurvesPanel(); virtual void update(); @@ -121,7 +121,7 @@ class CurvesPanel : public ModelPanel bool moveDownAllowed() const; bool moveUpAllowed() const; void swapData(int idx1, int idx2); - CommonItemModels * commonItemModels; + CompoundItemModelFactory * sharedItemModels; void updateItemModels(); }; diff --git a/companion/src/modeledit/customfunctions.cpp b/companion/src/modeledit/customfunctions.cpp index c3ee895b78..c773e90e5a 100644 --- a/companion/src/modeledit/customfunctions.cpp +++ b/companion/src/modeledit/customfunctions.cpp @@ -19,57 +19,15 @@ */ #include "customfunctions.h" -#include "rawitemfilteredmodel.h" #include "helpers.h" #include "appdata.h" #include -RepeatComboBox::RepeatComboBox(QWidget *parent, int & repeatParam): - QComboBox(parent), - repeatParam(repeatParam) -{ - unsigned int step = 1; - int value = repeatParam/step; - - setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); - - if (step == 1) { - addItem(tr("Played once, not during startup"), -1); - value++; - } - - addItem(tr("No repeat"), 0); - - for (unsigned int i = step; i <= 60; i += step) { - addItem(tr("%1s").arg(i), i); - } - - setCurrentIndex(value); - - connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(onIndexChanged(int))); -} - -void RepeatComboBox::onIndexChanged(int index) -{ - repeatParam = itemData(index).toInt(); - emit modified(); -} - -void RepeatComboBox::update() -{ - unsigned int step = 1; - int value = repeatParam/step; - if (step == 1) { - value++; - } - setCurrentIndex(value); -} - -CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels): +CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware, + CompoundItemModelFactory * sharedItemModels): GenericPanel(parent, model, generalSettings, firmware), functions(model ? model->customFn : generalSettings.customFn), - commonItemModels(commonItemModels), mediaPlayerCurrent(-1), mediaPlayer(nullptr), modelsUpdateCnt(0) @@ -77,21 +35,41 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, lock = true; fswCapability = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions); - rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), model ? RawSwitch::SpecialFunctionsContext : RawSwitch::GlobalFunctionsContext, this); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &CustomFunctionsPanel::onModelDataAboutToBeUpdated); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &CustomFunctionsPanel::onModelDataUpdateComplete); + tabModelFactory = new CompoundItemModelFactory(&generalSettings, model); + playSoundId = tabModelFactory->registerItemModel(CustomFunctionData::playSoundItemModel()); + harpicId = tabModelFactory->registerItemModel(CustomFunctionData::harpicItemModel()); + repeatId = tabModelFactory->registerItemModel(CustomFunctionData::repeatItemModel()); + gvarAdjustModeId = tabModelFactory->registerItemModel(CustomFunctionData::gvarAdjustModeItemModel()); - rawSourceAllModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), this); - connect(rawSourceAllModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &CustomFunctionsPanel::onModelDataAboutToBeUpdated); - connect(rawSourceAllModel, &RawItemFilteredModel::dataUpdateComplete, this, &CustomFunctionsPanel::onModelDataUpdateComplete); + tabFilterFactory = new FilteredItemModelFactory(); - rawSourceInputsModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), RawSource::InputSourceGroups, this); - connect(rawSourceInputsModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &CustomFunctionsPanel::onModelDataAboutToBeUpdated); - connect(rawSourceInputsModel, &RawItemFilteredModel::dataUpdateComplete, this, &CustomFunctionsPanel::onModelDataUpdateComplete); + funcActionsId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_CustomFuncAction), + model ? CustomFunctionData::AllFunctionContexts : CustomFunctionData::GlobalFunctionsContext), + "Function Actions"); + connectItemModelEvents(tabFilterFactory->getItemModel(funcActionsId)); - rawSourceGVarsModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), RawSource::GVarsGroup, this); - connect(rawSourceGVarsModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &CustomFunctionsPanel::onModelDataAboutToBeUpdated); - connect(rawSourceGVarsModel, &RawItemFilteredModel::dataUpdateComplete, this, &CustomFunctionsPanel::onModelDataUpdateComplete); + funcResetParamId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_CustomFuncResetParam)), + "Reset Params"); + connectItemModelEvents(tabFilterFactory->getItemModel(funcResetParamId)); + + rawSwitchId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch), + model ? RawSwitch::SpecialFunctionsContext : RawSwitch::GlobalFunctionsContext), + "RawSwitch"); + connectItemModelEvents(tabFilterFactory->getItemModel(rawSwitchId)); + + rawSourceAllId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource)), + "RawSource All"); + connectItemModelEvents(tabFilterFactory->getItemModel(rawSourceAllId)); + + rawSourceInputsId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), + RawSource::InputSourceGroups), + "RawSource Inputs"); + connectItemModelEvents(tabFilterFactory->getItemModel(rawSourceInputsId)); + + rawSourceGVarsId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), + RawSource::GVarsGroup), + "RawSource GVars"); + connectItemModelEvents(tabFilterFactory->getItemModel(rawSourceGVarsId)); if (!firmware->getCapability(VoicesAsNumbers)) { tracksSet = getFilesSet(getSoundsPath(generalSettings), QStringList() << "*.wav" << "*.WAV", firmware->getCapability(VoicesMaxLength)); @@ -121,7 +99,7 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, playIcon.addImage("stop.png", QIcon::Normal, QIcon::On); QStringList headerLabels; - headerLabels << "#" << tr("Switch") << tr("Action") << tr("Parameters") << tr("Enable"); + headerLabels << "#" << tr("Switch") << tr("Action") << tr("Parameters") << ""; TableLayout * tableLayout = new TableLayout(this, fswCapability, headerLabels); for (int i = 0; i < fswCapability; i++) { @@ -138,32 +116,26 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint))); tableLayout->addWidget(i, 0, label); - // s1.report("label"); // The switch fswtchSwtch[i] = new QComboBox(this); - fswtchSwtch[i]->setModel(rawSwitchFilteredModel); - fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(functions[i].swtch.toValue())); fswtchSwtch[i]->setProperty("index", i); + fswtchSwtch[i]->setModel(tabFilterFactory->getItemModel(rawSwitchId)); + fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(functions[i].swtch.toValue())); fswtchSwtch[i]->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum); + fswtchSwtch[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents); fswtchSwtch[i]->setMaxVisibleItems(10); connect(fswtchSwtch[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited())); tableLayout->addWidget(i, 1, fswtchSwtch[i]); - // s1.report("switch"); // The function fswtchFunc[i] = new QComboBox(this); - if (!i) { - populateFuncCB(fswtchFunc[i], functions[i].func); - } - else { - fswtchFunc[i]->setModel(fswtchFunc[0]->model()); - fswtchFunc[i]->setCurrentIndex(fswtchFunc[i]->findData(functions[i].func)); - } fswtchFunc[i]->setProperty("index", i); + fswtchFunc[i]->setModel(tabFilterFactory->getItemModel(funcActionsId)); + fswtchFunc[i]->setCurrentIndex(fswtchFunc[i]->findData(functions[i].func)); + fswtchFunc[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents); connect(fswtchFunc[i], SIGNAL(currentIndexChanged(int)), this, SLOT(functionEdited())); tableLayout->addWidget(i, 2, fswtchFunc[i]); - // s1.report("func"); // The parameters QHBoxLayout * paramLayout = new QHBoxLayout(); @@ -171,15 +143,15 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, fswtchGVmode[i] = new QComboBox(this); fswtchGVmode[i]->setProperty("index", i); - populateGVmodeCB(fswtchGVmode[i], functions[i].adjustMode); + fswtchGVmode[i]->setModel(tabModelFactory->getItemModel(gvarAdjustModeId)); fswtchGVmode[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents); connect(fswtchGVmode[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited())); paramLayout->addWidget(fswtchGVmode[i]); fswtchParamGV[i] = new QCheckBox(this); fswtchParamGV[i]->setProperty("index", i); - fswtchParamGV[i]->setText("GV"); - fswtchParamGV[i]->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum); + fswtchParamGV[i]->setText(tr("GV")); + fswtchParamGV[i]->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); connect(fswtchParamGV[i], SIGNAL(stateChanged(int)), this, SLOT(customFunctionEdited())); paramLayout->addWidget(fswtchParamGV[i]); @@ -210,15 +182,6 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, connect(fswtchParamArmT[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited())); connect(fswtchParamArmT[i], SIGNAL(editTextChanged ( const QString)), this, SLOT(customFunctionEdited())); - fswtchBLcolor[i] = new QSlider(this); - fswtchBLcolor[i]->setProperty("index", i); - fswtchBLcolor[i]->setMinimum(0); - fswtchBLcolor[i]->setMaximum(100); - fswtchBLcolor[i]->setSingleStep(1); - fswtchBLcolor[i]->setOrientation(Qt::Horizontal); - paramLayout->addWidget(fswtchBLcolor[i]); - connect(fswtchBLcolor[i], SIGNAL(sliderReleased()), this, SLOT(customFunctionEdited())); - playBT[i] = new QToolButton(this); playBT[i]->setProperty("index", i); playBT[i]->setIcon(playIcon); @@ -228,9 +191,13 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, QHBoxLayout * repeatLayout = new QHBoxLayout(); tableLayout->addLayout(i, 4, repeatLayout); - fswtchRepeat[i] = new RepeatComboBox(this, functions[i].repeatParam); + fswtchRepeat[i] = new QComboBox(this); + fswtchRepeat[i]->setProperty("index", i); + fswtchRepeat[i]->setModel(tabModelFactory->getItemModel(repeatId)); + fswtchRepeat[i]->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); + fswtchRepeat[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents); repeatLayout->addWidget(fswtchRepeat[i], i + 1); - connect(fswtchRepeat[i], SIGNAL(modified()), this, SLOT(onRepeatModified())); + connect(fswtchRepeat[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited())); fswtchEnable[i] = new QCheckBox(this); fswtchEnable[i]->setProperty("index", i); @@ -253,6 +220,8 @@ CustomFunctionsPanel::~CustomFunctionsPanel() { if (mediaPlayer) stopSound(mediaPlayerCurrent); + delete tabModelFactory; + delete tabFilterFactory; } void CustomFunctionsPanel::onMediaPlayerStateChanged(QMediaPlayer::State state) @@ -332,7 +301,6 @@ void CustomFunctionsPanel::toggleSound(bool play) #define CUSTOM_FUNCTION_ENABLE (1<<6) #define CUSTOM_FUNCTION_REPEAT (1<<7) #define CUSTOM_FUNCTION_PLAY (1<<8) -#define CUSTOM_FUNCTION_BL_COLOR (1<<9) #define CUSTOM_FUNCTION_SHOW_FUNC (1<<10) @@ -362,11 +330,6 @@ void CustomFunctionsPanel::functionEdited() } } -void CustomFunctionsPanel::onRepeatModified() -{ - emit modified(); -} - void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified) { CustomFunctionData & cfn = functions[i]; @@ -413,8 +376,8 @@ void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified) else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast) { int gvidx = func - FuncAdjustGV1; if (modified) - cfn.adjustMode = fswtchGVmode[i]->currentIndex(); - fswtchGVmode[i]->setCurrentIndex(cfn.adjustMode); + cfn.adjustMode = fswtchGVmode[i]->currentData().toInt(); + fswtchGVmode[i]->setCurrentIndex(fswtchGVmode[i]->findData(cfn.adjustMode)); widgetsMask |= CUSTOM_FUNCTION_GV_MODE | CUSTOM_FUNCTION_ENABLE; if (cfn.adjustMode == FUNC_ADJUST_GVAR_CONSTANT || cfn.adjustMode == FUNC_ADJUST_GVAR_INCDEC) { if (modified) @@ -467,8 +430,10 @@ void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified) } else if (func == FuncPlaySound || func == FuncPlayHaptic || func == FuncPlayValue || func == FuncPlayPrompt || func == FuncPlayBoth || func == FuncBackgroundMusic) { if (func != FuncBackgroundMusic) { + if (modified) + cfn.repeatParam = fswtchRepeat[i]->currentData().toInt(); widgetsMask |= CUSTOM_FUNCTION_REPEAT; - fswtchRepeat[i]->update(); + fswtchRepeat[i]->setCurrentIndex(fswtchRepeat[i]->findData(cfn.repeatParam)); } if (func == FuncPlayValue) { if (modified) @@ -492,7 +457,7 @@ void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified) if (modified) { if (fswtchParamGV[i]->isChecked()) { fswtchParam[i]->setMinimum(1); - cfn.param = std::min(fswtchParam[i]->value(),5.0)+(fswtchParamGV[i]->isChecked() ? 250 : 0); + cfn.param = std::min(fswtchParam[i]->value(), 5.0) + (fswtchParamGV[i]->isChecked() ? 250 : 0); } else { cfn.param = fswtchParam[i]->value(); @@ -576,7 +541,6 @@ void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified) fswtchEnable[i]->setChecked(false); fswtchRepeat[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_REPEAT); fswtchGVmode[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_MODE); - fswtchBLcolor[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_BL_COLOR); playBT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_PLAY); } @@ -652,77 +616,43 @@ void CustomFunctionsPanel::onCustomContextMenuRequested(QPoint pos) contextMenu.exec(globalPos); } -void CustomFunctionsPanel::populateFuncCB(QComboBox *b, unsigned int value) -{ - b->clear(); - for (unsigned int i = 0; i < FuncCount; i++) { - if (((i >= FuncOverrideCH1 && i <= FuncOverrideCH32) && (!model || !firmware->getCapability(SafetyChannelCustomFunction))) || - ((i == FuncVolume || i == FuncBackgroundMusic || i == FuncBackgroundMusicPause) && !firmware->getCapability(HasVolume)) || - ((i == FuncPlayScript && !IS_HORUS_OR_TARANIS(firmware->getBoard()))) || - ((i == FuncPlayHaptic) && !firmware->getCapability(Haptic)) || - ((i == FuncPlayBoth) && !firmware->getCapability(HasBeeper)) || - ((i == FuncLogs) && !firmware->getCapability(HasSDLogs)) || - ((i == FuncSetTimer3) && firmware->getCapability(Timers) < 3) || - ((i == FuncScreenshot) && !IS_HORUS_OR_TARANIS(firmware->getBoard())) || - ((i >= FuncRangeCheckInternalModule && i <= FuncBindExternalModule) && (!model || !firmware->getCapability(DangerousFunctions))) || - ((i >= FuncAdjustGV1 && i <= FuncAdjustGVLast) && (!model || !firmware->getCapability(Gvars))) - ) { - // skipped - continue; - } - else { - b->addItem(CustomFunctionData(AssignFunc(i)).funcToString(model), i); - if (i == value) { - b->setCurrentIndex(b->count() - 1); - } - } - } -} - -void CustomFunctionsPanel::populateGVmodeCB(QComboBox *b, unsigned int value) -{ - b->clear(); - b->addItem(tr("Value")); - b->addItem(tr("Source")); - b->addItem(tr("GVAR")); - b->addItem(tr("Increment")); - b->setCurrentIndex(value); -} - void CustomFunctionsPanel::populateFuncParamCB(QComboBox *b, uint function, unsigned int value, unsigned int adjustmode) { QStringList qs; b->setModel(new QStandardItemModel(b)); // clear combo box but not any shared item model if (function == FuncPlaySound) { - CustomFunctionData::populatePlaySoundParams(qs); - b->addItems(qs); - b->setCurrentIndex(value); + b->setModel(tabModelFactory->getItemModel(playSoundId)); + b->setCurrentIndex(b->findData(value)); } else if (function == FuncPlayHaptic) { - CustomFunctionData::populateHapticParams(qs); - b->addItems(qs); - b->setCurrentIndex(value); + b->setModel(tabModelFactory->getItemModel(harpicId)); + b->setCurrentIndex(b->findData(value)); } else if (function == FuncReset) { - CustomFunctionData::populateResetParams(model, b, value); + b->setModel(tabFilterFactory->getItemModel(funcResetParamId)); + b->setCurrentIndex(b->findData(value)); } else if (function == FuncVolume || function == FuncBacklight) { - b->setModel(rawSourceInputsModel); + b->setModel(tabFilterFactory->getItemModel(rawSourceInputsId)); b->setCurrentIndex(b->findData(value)); } else if (function == FuncPlayValue) { - b->setModel(rawSourceAllModel); + b->setModel(tabFilterFactory->getItemModel(rawSourceAllId)); b->setCurrentIndex(b->findData(value)); } else if (function >= FuncAdjustGV1 && function <= FuncAdjustGVLast) { switch (adjustmode) { case 1: - b->setModel(rawSourceInputsModel); + b->setModel(tabFilterFactory->getItemModel(rawSourceInputsId)); b->setCurrentIndex(b->findData(value)); + if (b->currentIndex() < 0) + b->setCurrentIndex(0); break; case 2: - b->setModel(rawSourceGVarsModel); + b->setModel(tabFilterFactory->getItemModel(rawSourceGVarsId)); b->setCurrentIndex(b->findData(value)); + if (b->currentIndex() < 0) + b->setCurrentIndex(0); break; } } @@ -827,13 +757,19 @@ bool CustomFunctionsPanel::moveUpAllowed() const return selectedIndex > 0; } -void CustomFunctionsPanel::onModelDataAboutToBeUpdated() +void CustomFunctionsPanel::connectItemModelEvents(FilteredItemModel * itemModel) +{ + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &CustomFunctionsPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &CustomFunctionsPanel::onItemModelUpdateComplete); +} + +void CustomFunctionsPanel::onItemModelAboutToBeUpdated() { lock = true; modelsUpdateCnt++; } -void CustomFunctionsPanel::onModelDataUpdateComplete() +void CustomFunctionsPanel::onItemModelUpdateComplete() { modelsUpdateCnt--; if (modelsUpdateCnt < 1) { diff --git a/companion/src/modeledit/customfunctions.h b/companion/src/modeledit/customfunctions.h index 9b3e3d2385..87775246d4 100644 --- a/companion/src/modeledit/customfunctions.h +++ b/companion/src/modeledit/customfunctions.h @@ -18,45 +18,26 @@ * GNU General Public License for more details. */ -#ifndef _CUSTOMFUNCTIONS_H_ -#define _CUSTOMFUNCTIONS_H_ +#pragma once #include "modeledit.h" #include "eeprominterface.h" +#include "compounditemmodels.h" +#include "filtereditemmodels.h" #include -class CommonItemModels; -class RawItemFilteredModel; class TimerEdit; constexpr char MIMETYPE_CUSTOM_FUNCTION[] = "application/x-companion-custom-function"; -class RepeatComboBox: public QComboBox -{ - Q_OBJECT - - public: - RepeatComboBox(QWidget * parent, int & repeatParam); - void update(); - - signals: - void modified(); - - private slots: - void onIndexChanged(int); - - protected: - int & repeatParam; -}; - class CustomFunctionsPanel : public GenericPanel { Q_OBJECT public: - CustomFunctionsPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); - ~CustomFunctionsPanel(); + CustomFunctionsPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels); + virtual ~CustomFunctionsPanel(); virtual void update(); @@ -68,7 +49,6 @@ class CustomFunctionsPanel : public GenericPanel void functionEdited(); void onCustomContextMenuRequested(QPoint pos); void refreshCustomFunction(int index, bool modified=false); - void onRepeatModified(); bool playSound(int index); void stopSound(int index); void toggleSound(bool play); @@ -83,12 +63,10 @@ class CustomFunctionsPanel : public GenericPanel void cmInsert(); void cmClear(bool prompt = true); void cmClearAll(); - void onModelDataAboutToBeUpdated(); - void onModelDataUpdateComplete(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: - void populateFuncCB(QComboBox *b, unsigned int value); - void populateGVmodeCB(QComboBox *b, unsigned int value); void populateFuncParamCB(QComboBox *b, uint function, unsigned int value, unsigned int adjustmode=0); bool hasClipboardData(QByteArray * data = nullptr) const; bool insertAllowed() const; @@ -96,11 +74,20 @@ class CustomFunctionsPanel : public GenericPanel bool moveUpAllowed() const; void swapData(int idx1, int idx2); void resetCBsAndRefresh(int idx); - CommonItemModels * commonItemModels; - RawItemFilteredModel * rawSwitchFilteredModel; - RawItemFilteredModel * rawSourceAllModel; - RawItemFilteredModel * rawSourceInputsModel; - RawItemFilteredModel * rawSourceGVarsModel; + void connectItemModelEvents(FilteredItemModel * itemModel); + + CompoundItemModelFactory * tabModelFactory; + FilteredItemModelFactory * tabFilterFactory; + int funcActionsId; + int funcResetParamId; + int rawSwitchId; + int rawSourceAllId; + int rawSourceInputsId; + int rawSourceGVarsId; + int playSoundId; + int harpicId; + int repeatId; + int gvarAdjustModeId; QSet tracksSet; QSet scriptsSet; @@ -114,14 +101,11 @@ class CustomFunctionsPanel : public GenericPanel QComboBox * fswtchParamT[CPN_MAX_SPECIAL_FUNCTIONS]; QComboBox * fswtchParamArmT[CPN_MAX_SPECIAL_FUNCTIONS]; QCheckBox * fswtchEnable[CPN_MAX_SPECIAL_FUNCTIONS]; - RepeatComboBox * fswtchRepeat[CPN_MAX_SPECIAL_FUNCTIONS]; + QComboBox * fswtchRepeat[CPN_MAX_SPECIAL_FUNCTIONS]; QComboBox * fswtchGVmode[CPN_MAX_SPECIAL_FUNCTIONS]; - QSlider * fswtchBLcolor[CPN_MAX_SPECIAL_FUNCTIONS]; QMediaPlayer * mediaPlayer; int selectedIndex; int fswCapability; int modelsUpdateCnt; }; - -#endif // _CUSTOMFUNCTIONS_H_ diff --git a/companion/src/modeledit/expodialog.cpp b/companion/src/modeledit/expodialog.cpp index afebbeb27f..be549144ca 100644 --- a/companion/src/modeledit/expodialog.cpp +++ b/companion/src/modeledit/expodialog.cpp @@ -20,12 +20,11 @@ #include "expodialog.h" #include "ui_expodialog.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" #include "helpers.h" ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, GeneralSettings & generalSettings, - Firmware * firmware, QString & inputName, RawItemFilteredModel * rawSourceModel, - RawItemFilteredModel * rawSwitchModel, RawItemFilteredModel * curveItemModel) : + Firmware * firmware, QString & inputName, CompoundItemModelFactory * sharedItemModels) : QDialog(parent), ui(new Ui::ExpoDialog), model(model), @@ -38,6 +37,9 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G { ui->setupUi(this); + dialogFilteredItemModels = new FilteredItemModelFactory(); + int id; + QLabel * lb_fp[CPN_MAX_FLIGHT_MODES] = {ui->lb_FP0, ui->lb_FP1, ui->lb_FP2, ui->lb_FP3, ui->lb_FP4, ui->lb_FP5, ui->lb_FP6, ui->lb_FP7, ui->lb_FP8 }; QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0, ui->cb_FP1, ui->cb_FP2, ui->cb_FP3, ui->cb_FP4, ui->cb_FP5, ui->cb_FP6, ui->cb_FP7, ui->cb_FP8 }; for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) { @@ -48,11 +50,20 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G setWindowTitle(tr("Edit %1").arg(RawSource(srcType, ed->chn).toString(&model, &generalSettings))); QRegExp rx(CHAR_FOR_NAMES_REGEX); - gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, ed->weight, model, 100, -100, 100); - gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, ed->offset, model, 0, -100, 100); - curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, ed->curve, model, curveItemModel, this); + id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef)), "GVarRef"); + gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, ed->weight, model, 100, -100, 100, 1.0, + dialogFilteredItemModels->getItemModel(id)); + gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, ed->offset, model, 0, -100, 100, 1.0, + dialogFilteredItemModels->getItemModel(id)); - ui->switchesCB->setModel(rawSwitchModel); + curveRefFilteredItemModels = new CurveRefFilteredFactory(sharedItemModels, + firmware->getCapability(HasInputDiff) ? 0 : FilteredItemModel::PositiveFilter); + curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, ed->curve, model, + curveRefFilteredItemModels, this); + + id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch), + RawSwitch::MixesContext), "RawSwitch"); + ui->switchesCB->setModel(dialogFilteredItemModels->getItemModel(id)); ui->switchesCB->setCurrentIndex(ui->switchesCB->findData(ed->swtch.toValue())); ui->sideCB->setCurrentIndex(ed->mode - 1); @@ -83,7 +94,10 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G if (firmware->getCapability(VirtualInputs)) { ui->inputName->setMaxLength(firmware->getCapability(InputsLength)); - ui->sourceCB->setModel(rawSourceModel); + id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), + (RawSource::InputSourceGroups & ~RawSource::NoneGroup & ~RawSource::InputsGroup) | RawSource::TelemGroup), + "RawSource"); + ui->sourceCB->setModel(dialogFilteredItemModels->getItemModel(id)); ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(ed->srcRaw.toValue())); ui->inputName->setValidator(new QRegExpValidator(rx, this)); ui->inputName->setText(inputName); @@ -135,9 +149,10 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G ExpoDialog::~ExpoDialog() { + delete ui; delete gvWeightGroup; delete gvOffsetGroup; - delete ui; + delete dialogFilteredItemModels; } void ExpoDialog::updateScale() diff --git a/companion/src/modeledit/expodialog.h b/companion/src/modeledit/expodialog.h index b77d558522..f4980d344b 100644 --- a/companion/src/modeledit/expodialog.h +++ b/companion/src/modeledit/expodialog.h @@ -26,7 +26,9 @@ #include "modelprinter.h" class GVarGroup; -class RawItemFilteredModel; +class CompoundItemModelFactory; +class FilteredItemModelFactory; +class CurveRefFilteredFactory; class CurveReferenceUIManager; namespace Ui { @@ -37,9 +39,8 @@ class ExpoDialog : public QDialog { Q_OBJECT public: ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expodata, GeneralSettings & generalSettings, - Firmware * firmware, QString & inputName, RawItemFilteredModel * rawSourceItemModel, - RawItemFilteredModel * rawSwitchItemModel, RawItemFilteredModel * curveItemModel); - ~ExpoDialog(); + Firmware * firmware, QString & inputName, CompoundItemModelFactory * sharedItemModels); + virtual ~ExpoDialog(); protected: void updateScale(); @@ -65,6 +66,8 @@ class ExpoDialog : public QDialog { ModelPrinter modelPrinter; bool lock; QCheckBox * cb_fp[CPN_MAX_FLIGHT_MODES]; + FilteredItemModelFactory *dialogFilteredItemModels; + CurveRefFilteredFactory *curveRefFilteredItemModels; }; #endif // _EXPODIALOG_H_ diff --git a/companion/src/modeledit/flightmodes.cpp b/companion/src/modeledit/flightmodes.cpp index 32188feea6..224d69965e 100644 --- a/companion/src/modeledit/flightmodes.cpp +++ b/companion/src/modeledit/flightmodes.cpp @@ -20,19 +20,19 @@ #include "flightmodes.h" #include "ui_flightmode.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" #include "helpers.h" #include "customdebug.h" -FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseIdx, GeneralSettings & generalSettings, Firmware * firmware, RawItemFilteredModel * rawSwitchFilteredModel): +FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseIdx, GeneralSettings & generalSettings, Firmware * firmware, + FilteredItemModel * rawSwitchFilteredModel): ModelPanel(parent, model, generalSettings, firmware), ui(new Ui::FlightMode), phaseIdx(phaseIdx), phase(model.flightModeData[phaseIdx]) { ui->setupUi(this); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &FlightModePanel::onModelDataAboutToBeUpdated); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &FlightModePanel::onModelDataUpdateComplete); + connectItemModelEvents(rawSwitchFilteredModel); ui->labelName->setContextMenuPolicy(Qt::CustomContextMenu); ui->labelName->setToolTip(tr("Popup menu available")); @@ -1361,12 +1361,18 @@ void FlightModePanel::gvSwapData(int idx1, int idx2) } } -void FlightModePanel::onModelDataAboutToBeUpdated() +void FlightModePanel::connectItemModelEvents(const FilteredItemModel * itemModel) +{ + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &FlightModePanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &FlightModePanel::onItemModelUpdateComplete); +} + +void FlightModePanel::onItemModelAboutToBeUpdated() { lock = true; } -void FlightModePanel::onModelDataUpdateComplete() +void FlightModePanel::onItemModelUpdateComplete() { update(); lock = false; @@ -1374,11 +1380,14 @@ void FlightModePanel::onModelDataUpdateComplete() /**********************************************************/ -FlightModesPanel::FlightModesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels): +FlightModesPanel::FlightModesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, + CompoundItemModelFactory * sharedItemModels): ModelPanel(parent, model, generalSettings, firmware), - commonItemModels(commonItemModels) + sharedItemModels(sharedItemModels) { - rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::MixesContext, this); + rawSwitchFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch), RawSwitch::MixesContext); + connectItemModelEvents(rawSwitchFilteredModel); + modesCount = firmware->getCapability(FlightModes); QGridLayout * gridLayout = new QGridLayout(this); @@ -1403,6 +1412,7 @@ FlightModesPanel::FlightModesPanel(QWidget * parent, ModelData & model, GeneralS FlightModesPanel::~FlightModesPanel() { + delete rawSwitchFilteredModel; } QString FlightModesPanel::getTabName(int index) @@ -1431,10 +1441,24 @@ void FlightModesPanel::update() emit updated(); } +void FlightModesPanel::connectItemModelEvents(const FilteredItemModel * itemModel) +{ + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &FlightModesPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &FlightModesPanel::onItemModelUpdateComplete); +} + +void FlightModesPanel::onItemModelAboutToBeUpdated() +{ +} + +void FlightModesPanel::onItemModelUpdateComplete() +{ +} + void FlightModesPanel::updateItemModels() { - commonItemModels->update(CommonItemModels::RMO_FLIGHT_MODES); - commonItemModels->update(CommonItemModels::RMO_GLOBAL_VARIABLES); + sharedItemModels->update(AbstractItemModel::IMUE_FlightModes); + sharedItemModels->update(AbstractItemModel::IMUE_GVars); } void FlightModesPanel::onTabIndexChanged(int index) diff --git a/companion/src/modeledit/flightmodes.h b/companion/src/modeledit/flightmodes.h index ca3619c6cf..33fd87e8af 100644 --- a/companion/src/modeledit/flightmodes.h +++ b/companion/src/modeledit/flightmodes.h @@ -24,8 +24,8 @@ #include "modeledit.h" #include "eeprominterface.h" -class CommonItemModels; -class RawItemFilteredModel; +class CompoundItemModelFactory; +class FilteredItemModel; constexpr char MIMETYPE_FLIGHTMODE[] = "application/x-companion-flightmode"; constexpr char MIMETYPE_GVAR_PARAMS[] = "application/x-companion-gvar-params"; @@ -41,7 +41,8 @@ class FlightModePanel : public ModelPanel Q_OBJECT public: - FlightModePanel(QWidget *parent, ModelData &model, int modeIdx, GeneralSettings & generalSettings, Firmware * firmware, RawItemFilteredModel * rawSwitchFilteredModel); + FlightModePanel(QWidget *parent, ModelData &model, int modeIdx, GeneralSettings & generalSettings, Firmware * firmware, + FilteredItemModel * rawSwitchFilteredModel); virtual ~FlightModePanel(); virtual void update(); @@ -90,8 +91,8 @@ class FlightModePanel : public ModelPanel void gvCmPaste(); void gvCmMoveDown(); void gvCmMoveUp(); - void onModelDataAboutToBeUpdated(); - void onModelDataUpdateComplete(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: Ui::FlightMode *ui; @@ -138,6 +139,7 @@ class FlightModePanel : public ModelPanel bool gvMoveDownAllowed() const; bool gvMoveUpAllowed() const; void gvSwapData(int idx1, int idx2); + void connectItemModelEvents(const FilteredItemModel * itemModel); }; class FlightModesPanel : public ModelPanel @@ -145,7 +147,7 @@ class FlightModesPanel : public ModelPanel Q_OBJECT public: - FlightModesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); + FlightModesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels); virtual ~FlightModesPanel(); public slots: @@ -157,16 +159,19 @@ class FlightModesPanel : public ModelPanel private slots: void onPhaseNameChanged(); void onTabIndexChanged(int index); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: QString getTabName(int index); int modesCount; QTabWidget *tabWidget; - CommonItemModels *commonItemModels; - RawItemFilteredModel *rawSwitchFilteredModel; + CompoundItemModelFactory *sharedItemModels; + FilteredItemModel *rawSwitchFilteredModel; QVector panels; void updateItemModels(); + void connectItemModelEvents(const FilteredItemModel * itemModel); }; #endif // _FLIGHTMODES_H_ diff --git a/companion/src/modeledit/heli.cpp b/companion/src/modeledit/heli.cpp index 1b86077993..ef86c57938 100644 --- a/companion/src/modeledit/heli.cpp +++ b/companion/src/modeledit/heli.cpp @@ -21,18 +21,16 @@ #include "heli.h" #include "ui_heli.h" #include "helpers.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" -HeliPanel::HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels): +HeliPanel::HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels): ModelPanel(parent, model, generalSettings, firmware), - ui(new Ui::Heli), - commonItemModels(commonItemModels) + ui(new Ui::Heli) { ui->setupUi(this); - rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), RawSource::InputSourceGroups, this); - connect(rawSourceFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &HeliPanel::onModelDataAboutToBeUpdated); - connect(rawSourceFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &HeliPanel::onModelDataUpdateComplete); + rawSourceFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), RawSource::InputSourceGroups); + connectItemModelEvents(rawSourceFilteredModel); connect(ui->swashType, SIGNAL(currentIndexChanged(int)), this, SLOT(edited())); connect(ui->swashRingVal, SIGNAL(editingFinished()), this, SLOT(edited())); @@ -71,6 +69,7 @@ HeliPanel::HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & gener HeliPanel::~HeliPanel() { delete ui; + delete rawSourceFilteredModel; } void HeliPanel::update() @@ -118,12 +117,18 @@ void HeliPanel::edited() } } -void HeliPanel::onModelDataAboutToBeUpdated() +void HeliPanel::connectItemModelEvents(const FilteredItemModel * itemModel) +{ + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &HeliPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &HeliPanel::onItemModelUpdateComplete); +} + +void HeliPanel::onItemModelAboutToBeUpdated() { lock = true; } -void HeliPanel::onModelDataUpdateComplete() +void HeliPanel::onItemModelUpdateComplete() { update(); lock = false; diff --git a/companion/src/modeledit/heli.h b/companion/src/modeledit/heli.h index ee9a3ac36d..eb3c7d54eb 100644 --- a/companion/src/modeledit/heli.h +++ b/companion/src/modeledit/heli.h @@ -23,8 +23,8 @@ #include "modeledit.h" -class CommonItemModels; -class RawItemFilteredModel; +class CompoundItemModelFactory; +class FilteredItemModel; namespace Ui { class Heli; @@ -35,19 +35,19 @@ class HeliPanel : public ModelPanel Q_OBJECT public: - HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); - ~HeliPanel(); + HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels); + virtual ~HeliPanel(); void update(); private slots: void edited(); - void onModelDataAboutToBeUpdated(); - void onModelDataUpdateComplete(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: Ui::Heli *ui; - CommonItemModels * commonItemModels; - RawItemFilteredModel * rawSourceFilteredModel; + FilteredItemModel * rawSourceFilteredModel; + void connectItemModelEvents(const FilteredItemModel * itemModel); }; #endif // _HELI_H_ diff --git a/companion/src/modeledit/inputs.cpp b/companion/src/modeledit/inputs.cpp index ee2347aeeb..1f7fd2b0bd 100644 --- a/companion/src/modeledit/inputs.cpp +++ b/companion/src/modeledit/inputs.cpp @@ -21,25 +21,19 @@ #include "inputs.h" #include "expodialog.h" #include "helpers.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" -InputsPanel::InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels): +InputsPanel::InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels): ModelPanel(parent, model, generalSettings, firmware), expoInserted(false), modelPrinter(firmware, generalSettings, model), - commonItemModels(commonItemModels) + sharedItemModels(sharedItemModels), + modelsUpdateCnt(0) { - rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), (RawSource::InputSourceGroups & ~ RawSource::NoneGroup & ~RawSource::InputsGroup), this); - connect(rawSourceFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &InputsPanel::onModelDataAboutToBeUpdated); - connect(rawSourceFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &InputsPanel::onModelDataUpdateComplete); - - rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::MixesContext, this); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &InputsPanel::onModelDataAboutToBeUpdated); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &InputsPanel::onModelDataUpdateComplete); - - curveFilteredModel = new RawItemFilteredModel(commonItemModels->curveItemModel(), RawItemFilteredModel::AllFilter, this); - connect(curveFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &InputsPanel::onModelDataAboutToBeUpdated); - connect(curveFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &InputsPanel::onModelDataUpdateComplete); + connectItemModelEvents(AbstractItemModel::IMID_RawSource); + connectItemModelEvents(AbstractItemModel::IMID_RawSwitch); + connectItemModelEvents(AbstractItemModel::IMID_Curve); + connectItemModelEvents(AbstractItemModel::IMID_GVarRef); inputsCount = firmware->getCapability(VirtualInputs); if (inputsCount == 0) @@ -194,7 +188,7 @@ void InputsPanel::gm_openExpo(int index) if (firmware->getCapability(VirtualInputs)) inputName = model->inputNames[ed.chn]; - ExpoDialog *dlg = new ExpoDialog(this, *model, &ed, generalSettings, firmware, inputName, rawSourceFilteredModel, rawSwitchFilteredModel, curveFilteredModel); + ExpoDialog *dlg = new ExpoDialog(this, *model, &ed, generalSettings, firmware, inputName, sharedItemModels); if (dlg->exec()) { model->expoData[index] = ed; if (firmware->getCapability(VirtualInputs)) @@ -357,6 +351,9 @@ void InputsPanel::expoOpen(QListWidgetItem *item) if (!item) item = ExposlistWidget->currentItem(); + if (item == nullptr) + return; + int idx = item->data(Qt::UserRole).toByteArray().at(0); if (idx < 0) { int ch = -idx - 1; @@ -374,7 +371,11 @@ void InputsPanel::expoOpen(QListWidgetItem *item) void InputsPanel::expoAdd() { - int index = ExposlistWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0); + QListWidgetItem *item = ExposlistWidget->currentItem(); + if (item == nullptr) + return; + + int index = item->data(Qt::UserRole).toByteArray().at(0); if (index < 0) { // if empty then return relevant index expoOpen(); @@ -579,13 +580,15 @@ bool InputsPanel::cmInputMoveUpAllowed() const void InputsPanel::cmInputClear() { - if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all lines for the selected Inputs. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all lines for the selected Input. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) return; for (int i = CPN_MAX_EXPOS - 1; i >= 0; i--) { ExpoData *ed = &model->expoData[i]; - if ((int)ed->chn == inputIdx) - model->removeInput(i); + if (!ed->isEmpty()) { + if ((int)ed->chn == inputIdx) + model->removeInput(i); + } } model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, inputIdx); update(); @@ -595,15 +598,17 @@ void InputsPanel::cmInputClear() void InputsPanel::cmInputDelete() { - if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete all lines for the selected Inputs. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete all lines for the selected Input. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) return; - for (int i = 0; i < CPN_MAX_EXPOS; i++) { + for (int i = CPN_MAX_EXPOS - 1; i >= 0; i--) { ExpoData *ed = &model->expoData[i]; - if ((int)ed->chn == inputIdx) - model->removeInput(i); - else if ((int)ed->chn > inputIdx) - ed->chn--; + if (!ed->isEmpty()) { + if ((int)ed->chn == inputIdx) + model->removeInput(i); + else if ((int)ed->chn > inputIdx) + ed->chn--; + } } for (int i = inputIdx; i < inputsCount; i++) { @@ -730,18 +735,31 @@ int InputsPanel::getInputIndexFromSelected() return idx; } -void InputsPanel::onModelDataAboutToBeUpdated() +void InputsPanel::connectItemModelEvents(const int id) { - lock = true; + AbstractDynamicItemModel * itemModel = qobject_cast(sharedItemModels->getItemModel(id)); + if (itemModel) { + connect(itemModel, &AbstractDynamicItemModel::aboutToBeUpdated, this, &InputsPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &AbstractDynamicItemModel::updateComplete, this, &InputsPanel::onItemModelUpdateComplete); + } } -void InputsPanel::onModelDataUpdateComplete() +void InputsPanel::onItemModelAboutToBeUpdated() { - update(); - lock = false; + lock = true; + modelsUpdateCnt++; +} + +void InputsPanel::onItemModelUpdateComplete() +{ + modelsUpdateCnt--; + if (modelsUpdateCnt < 1) { + update(); + lock = false; + } } void InputsPanel::updateItemModels() { - commonItemModels->update(CommonItemModels::RMO_INPUTS); + sharedItemModels->update(AbstractItemModel::IMUE_Inputs); } diff --git a/companion/src/modeledit/inputs.h b/companion/src/modeledit/inputs.h index ea12432132..9b360ec194 100644 --- a/companion/src/modeledit/inputs.h +++ b/companion/src/modeledit/inputs.h @@ -25,8 +25,8 @@ #include "mixerslistwidget.h" #include "modelprinter.h" -class CommonItemModels; -class RawItemFilteredModel; +class CompoundItemModelFactory; +class FilteredItemModel; constexpr char MIMETYPE_EXPO[] = "application/x-companion-expo"; @@ -35,7 +35,7 @@ class InputsPanel : public ModelPanel Q_OBJECT public: - InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); + InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels); virtual ~InputsPanel(); virtual void update(); @@ -62,8 +62,8 @@ class InputsPanel : public ModelPanel void cmInputInsert(); void cmInputMoveDown(); void cmInputMoveUp(); - void onModelDataAboutToBeUpdated(); - void onModelDataUpdateComplete(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: bool expoInserted; @@ -72,10 +72,8 @@ class InputsPanel : public ModelPanel ModelPrinter modelPrinter; int selectedIdx; int inputIdx; - CommonItemModels * commonItemModels; - RawItemFilteredModel *rawSourceFilteredModel; - RawItemFilteredModel *rawSwitchFilteredModel; - RawItemFilteredModel *curveFilteredModel; + CompoundItemModelFactory *sharedItemModels; + int modelsUpdateCnt; int getExpoIndex(unsigned int dch); bool gm_insertExpo(int idx); @@ -97,6 +95,7 @@ class InputsPanel : public ModelPanel int getIndexFromSelected(); int getInputIndexFromSelected(); void updateItemModels(); + void connectItemModelEvents(const int id); }; #endif // _INPUTS_H_ diff --git a/companion/src/modeledit/logicalswitches.cpp b/companion/src/modeledit/logicalswitches.cpp index cacd5c6fd1..499df9e49a 100644 --- a/companion/src/modeledit/logicalswitches.cpp +++ b/companion/src/modeledit/logicalswitches.cpp @@ -19,25 +19,25 @@ */ #include "logicalswitches.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" #include "helpers.h" #include -LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels): +LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, + CompoundItemModelFactory * sharedItemModels): ModelPanel(parent, model, generalSettings, firmware), - commonItemModels(commonItemModels), + sharedItemModels(sharedItemModels), selectedIndex(0), modelsUpdateCnt(0) { - rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::LogicalSwitchesContext, this); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &LogicalSwitchesPanel::onModelDataAboutToBeUpdated); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &LogicalSwitchesPanel::onModelDataUpdateComplete); + rawSwitchFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch), + RawSwitch::LogicalSwitchesContext); + connectItemModelEvents(rawSwitchFilteredModel); const int srcGroups = firmware->getCapability(GvarsInCS) ? 0 : (RawSource::AllSourceGroups & ~RawSource::GVarsGroup); - rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), srcGroups, this); - connect(rawSourceFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &LogicalSwitchesPanel::onModelDataAboutToBeUpdated); - connect(rawSourceFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &LogicalSwitchesPanel::onModelDataUpdateComplete); + rawSourceFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), srcGroups); + connectItemModelEvents(rawSourceFilteredModel); lsCapability = firmware->getCapability(LogicalSwitches); lsCapabilityExt = firmware->getCapability(LogicalSwitchesExt); @@ -161,6 +161,8 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, LogicalSwitchesPanel::~LogicalSwitchesPanel() { + delete rawSourceFilteredModel; + delete rawSwitchFilteredModel; } void LogicalSwitchesPanel::onFunctionChanged() @@ -644,16 +646,22 @@ void LogicalSwitchesPanel::swapData(int idx1, int idx2) void LogicalSwitchesPanel::updateItemModels() { lock = true; - commonItemModels->update(CommonItemModels::RMO_LOGICAL_SWITCHES); + sharedItemModels->update(AbstractItemModel::IMUE_LogicalSwitches); } -void LogicalSwitchesPanel::onModelDataAboutToBeUpdated() +void LogicalSwitchesPanel::connectItemModelEvents(const FilteredItemModel * itemModel) +{ + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &LogicalSwitchesPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &LogicalSwitchesPanel::onItemModelUpdateComplete); +} + +void LogicalSwitchesPanel::onItemModelAboutToBeUpdated() { lock = true; modelsUpdateCnt++; } -void LogicalSwitchesPanel::onModelDataUpdateComplete() +void LogicalSwitchesPanel::onItemModelUpdateComplete() { modelsUpdateCnt--; if (modelsUpdateCnt < 1) { diff --git a/companion/src/modeledit/logicalswitches.h b/companion/src/modeledit/logicalswitches.h index 87a360408a..f1c2f8397e 100644 --- a/companion/src/modeledit/logicalswitches.h +++ b/companion/src/modeledit/logicalswitches.h @@ -24,8 +24,8 @@ #include "modeledit.h" #include "radiodata.h" -class CommonItemModels; -class RawItemFilteredModel; +class CompoundItemModelFactory; +class FilteredItemModel; class TimerEdit; constexpr char MIMETYPE_LOGICAL_SWITCH[] = "application/x-companion-logical-switch"; @@ -35,7 +35,7 @@ class LogicalSwitchesPanel : public ModelPanel Q_OBJECT public: - LogicalSwitchesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); + LogicalSwitchesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels); virtual ~LogicalSwitchesPanel(); virtual void update(); @@ -60,8 +60,8 @@ class LogicalSwitchesPanel : public ModelPanel void cmInsert(); void cmClear(bool prompt = true); void cmClearAll(); - void onModelDataAboutToBeUpdated(); - void onModelDataUpdateComplete(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: QComboBox * cbFunction[CPN_MAX_LOGICAL_SWITCHES]; @@ -74,9 +74,9 @@ class LogicalSwitchesPanel : public ModelPanel QDoubleSpinBox * dsbDelay[CPN_MAX_LOGICAL_SWITCHES]; QComboBox * cbSource1[CPN_MAX_LOGICAL_SWITCHES]; QComboBox * cbSource2[CPN_MAX_LOGICAL_SWITCHES]; - CommonItemModels * commonItemModels; - RawItemFilteredModel * rawSwitchFilteredModel; - RawItemFilteredModel * rawSourceFilteredModel; + CompoundItemModelFactory * sharedItemModels; + FilteredItemModel * rawSwitchFilteredModel; + FilteredItemModel * rawSourceFilteredModel; int selectedIndex; void populateFunctionCB(QComboBox *b); void updateTimerParam(QDoubleSpinBox *sb, int timer, double minimum=0); @@ -89,6 +89,7 @@ class LogicalSwitchesPanel : public ModelPanel bool moveUpAllowed() const; int modelsUpdateCnt; void updateItemModels(); + void connectItemModelEvents(const FilteredItemModel * itemModel); }; #endif // _LOGICALSWITCHES_H_ diff --git a/companion/src/modeledit/mixerdialog.cpp b/companion/src/modeledit/mixerdialog.cpp index 00d2badc87..6cc39ffd15 100644 --- a/companion/src/modeledit/mixerdialog.cpp +++ b/companion/src/modeledit/mixerdialog.cpp @@ -21,11 +21,11 @@ #include "mixerdialog.h" #include "ui_mixerdialog.h" #include "radiodata.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" #include "helpers.h" MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, GeneralSettings & generalSettings, Firmware * firmware, - RawItemFilteredModel * rawSourceModel, RawItemFilteredModel * rawSwitchModel, RawItemFilteredModel * curveItemModel) : + CompoundItemModelFactory * sharedItemModels) : QDialog(parent), ui(new Ui::MixerDialog), model(model), @@ -36,6 +36,9 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, { ui->setupUi(this); + dialogFilteredItemModels = new FilteredItemModelFactory(); + int id; + QRegExp rx(CHAR_FOR_NAMES_REGEX); QLabel * lb_fp[CPN_MAX_FLIGHT_MODES] = {ui->lb_FP0, ui->lb_FP1, ui->lb_FP2, ui->lb_FP3, ui->lb_FP4, ui->lb_FP5, ui->lb_FP6, ui->lb_FP7, ui->lb_FP8 }; QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0, ui->cb_FP1, ui->cb_FP2, ui->cb_FP3, ui->cb_FP4, ui->cb_FP5, ui->cb_FP6, ui->cb_FP7, ui->cb_FP8 }; @@ -45,14 +48,24 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, this->setWindowTitle(tr("DEST -> %1").arg(RawSource(SOURCE_TYPE_CH, md->destCh - 1).toString(&model, &generalSettings))); - ui->sourceCB->setModel(rawSourceModel); + id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), + (RawSource::InputSourceGroups & ~RawSource::NoneGroup) | RawSource::ScriptsGroup), + "RawSource"); + ui->sourceCB->setModel(dialogFilteredItemModels->getItemModel(id)); ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(md->srcRaw.toValue())); int limit = firmware->getCapability(OffsetWeight); + id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_GVarRef)), "GVarRef"); - gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, md->weight, model, 100, -limit, limit); - gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, md->sOffset, model, 0, -limit, limit); - curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, md->curve, model, curveItemModel, this); + gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, md->weight, model, 100, -limit, limit, 1.0, + dialogFilteredItemModels->getItemModel(id)); + gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, md->sOffset, model, 0, -limit, limit, 1.0, + dialogFilteredItemModels->getItemModel(id)); + + curveRefFilteredItemModels = new CurveRefFilteredFactory(sharedItemModels, + firmware->getCapability(HasMixerExpo) ? 0 : FilteredItemModel::PositiveFilter); + curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, md->curve, model, + curveRefFilteredItemModels, this); ui->MixDR_CB->setChecked(md->noExpo == 0); @@ -104,7 +117,9 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, } } - ui->switchesCB->setModel(rawSwitchModel); + id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch), + RawSwitch::MixesContext), "RawSwitch"); + ui->switchesCB->setModel(dialogFilteredItemModels->getItemModel(id)); ui->switchesCB->setCurrentIndex(ui->switchesCB->findData(md->swtch.toValue())); ui->warningCB->setCurrentIndex(md->mixWarn); ui->mltpxCB->setCurrentIndex(md->mltpx); @@ -150,6 +165,7 @@ MixerDialog::~MixerDialog() delete ui; delete gvWeightGroup; delete gvOffsetGroup; + delete dialogFilteredItemModels; } void MixerDialog::changeEvent(QEvent *e) diff --git a/companion/src/modeledit/mixerdialog.h b/companion/src/modeledit/mixerdialog.h index 6d2131de2c..04ff1aeaf3 100644 --- a/companion/src/modeledit/mixerdialog.h +++ b/companion/src/modeledit/mixerdialog.h @@ -25,7 +25,9 @@ #include "eeprominterface.h" class GVarGroup; -class RawItemFilteredModel; +class CompoundItemModelFactory; +class FilteredItemModelFactory; +class CurveRefFilteredFactory; class CurveReferenceUIManager; namespace Ui { @@ -36,7 +38,7 @@ class MixerDialog : public QDialog { Q_OBJECT public: MixerDialog(QWidget *parent, ModelData & model, MixData *mixdata, GeneralSettings & generalSettings, Firmware * firmware, - RawItemFilteredModel * rawSourceModel, RawItemFilteredModel * rawSwitchModel, RawItemFilteredModel * curveItemModel); + CompoundItemModelFactory * sharedItemModels); ~MixerDialog(); protected: @@ -61,6 +63,8 @@ class MixerDialog : public QDialog { GVarGroup * gvOffsetGroup; CurveReferenceUIManager * curveGroup; QCheckBox * cb_fp[CPN_MAX_FLIGHT_MODES]; + FilteredItemModelFactory *dialogFilteredItemModels; + CurveRefFilteredFactory *curveRefFilteredItemModels; }; #endif // _MIXERDIALOG_H_ diff --git a/companion/src/modeledit/mixes.cpp b/companion/src/modeledit/mixes.cpp index f02a574172..023888760b 100644 --- a/companion/src/modeledit/mixes.cpp +++ b/companion/src/modeledit/mixes.cpp @@ -20,26 +20,20 @@ #include "mixes.h" #include "helpers.h" -#include "rawitemfilteredmodel.h" +#include "filtereditemmodels.h" -MixesPanel::MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,CommonItemModels * commonItemModels): +MixesPanel::MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels): ModelPanel(parent, model, generalSettings, firmware), mixInserted(false), highlightedSource(0), modelPrinter(firmware, generalSettings, model), - commonItemModels(commonItemModels) + sharedItemModels(sharedItemModels), + modelsUpdateCnt(0) { - rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), ((RawSource::InputSourceGroups | RawSource::ScriptsGroup) & ~ RawSource::NoneGroup), this); - connect(rawSourceFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &MixesPanel::onModelDataAboutToBeUpdated); - connect(rawSourceFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &MixesPanel::onModelDataUpdateComplete); - - rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::MixesContext, this); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &MixesPanel::onModelDataAboutToBeUpdated); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &MixesPanel::onModelDataUpdateComplete); - - curveFilteredModel = new RawItemFilteredModel(commonItemModels->curveItemModel(), RawItemFilteredModel::AllFilter, this); - connect(curveFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &MixesPanel::onModelDataAboutToBeUpdated); - connect(curveFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &MixesPanel::onModelDataUpdateComplete); + connectItemModelEvents(AbstractItemModel::IMID_RawSource); + connectItemModelEvents(AbstractItemModel::IMID_RawSwitch); + connectItemModelEvents(AbstractItemModel::IMID_Curve); + connectItemModelEvents(AbstractItemModel::IMID_GVarRef); QGridLayout * mixesLayout = new QGridLayout(this); @@ -189,7 +183,7 @@ void MixesPanel::gm_openMix(int index) MixData mixd(model->mixData[index]); - MixerDialog *dlg = new MixerDialog(this, *model, &mixd, generalSettings, firmware, rawSourceFilteredModel, rawSwitchFilteredModel, curveFilteredModel); + MixerDialog *dlg = new MixerDialog(this, *model, &mixd, generalSettings, firmware, sharedItemModels); if(dlg->exec()) { model->mixData[index] = mixd; emit modified(); @@ -360,7 +354,11 @@ void MixesPanel::mixersDuplicate() void MixesPanel::mixerOpen() { - int idx = mixersListWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0); + QListWidgetItem *item = mixersListWidget->currentItem(); + if (item == nullptr) + return; + + int idx = item->data(Qt::UserRole).toByteArray().at(0); if(idx < 0) { int i = -idx; idx = getMixerIndex(i); //get mixer index to insert @@ -377,7 +375,11 @@ void MixesPanel::mixerOpen() void MixesPanel::mixerHighlight() { - int idx = mixersListWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0); + QListWidgetItem *item = mixersListWidget->currentItem(); + if (item == nullptr) + return; + + int idx = item->data(Qt::UserRole).toByteArray().at(0); int dest; if (idx<0) { dest = -idx; @@ -545,13 +547,26 @@ void MixesPanel::clearMixes() } } -void MixesPanel::onModelDataAboutToBeUpdated() +void MixesPanel::connectItemModelEvents(const int id) { - lock = true; + AbstractDynamicItemModel * itemModel = qobject_cast(sharedItemModels->getItemModel(id)); + if (itemModel) { + connect(itemModel, &AbstractDynamicItemModel::aboutToBeUpdated, this, &MixesPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &AbstractDynamicItemModel::updateComplete, this, &MixesPanel::onItemModelUpdateComplete); + } } -void MixesPanel::onModelDataUpdateComplete() +void MixesPanel::onItemModelAboutToBeUpdated() { - update(); - lock = false; + lock = true; + modelsUpdateCnt++; +} + +void MixesPanel::onItemModelUpdateComplete() +{ + modelsUpdateCnt--; + if (modelsUpdateCnt < 1) { + update(); + lock = false; + } } diff --git a/companion/src/modeledit/mixes.h b/companion/src/modeledit/mixes.h index 014786b74a..c298df11ae 100644 --- a/companion/src/modeledit/mixes.h +++ b/companion/src/modeledit/mixes.h @@ -26,15 +26,15 @@ #include "mixerdialog.h" #include "modelprinter.h" -class CommonItemModels; -class RawItemFilteredModel; +class CompoundItemModelFactory; +class FilteredItemModel; class MixesPanel : public ModelPanel { Q_OBJECT public: - MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); + MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels); virtual ~MixesPanel(); virtual void update(); @@ -60,18 +60,16 @@ class MixesPanel : public ModelPanel void mimeMixerDropped(int index, const QMimeData *data, Qt::DropAction action); void pasteMixerMimeData(const QMimeData * mimeData, int destIdx); - void onModelDataAboutToBeUpdated(); - void onModelDataUpdateComplete(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: MixersListWidget * mixersListWidget; bool mixInserted; unsigned int highlightedSource; ModelPrinter modelPrinter; - CommonItemModels * commonItemModels; - RawItemFilteredModel *rawSourceFilteredModel; - RawItemFilteredModel *rawSwitchFilteredModel; - RawItemFilteredModel *curveFilteredModel; + CompoundItemModelFactory *sharedItemModels; + int modelsUpdateCnt; int getMixerIndex(unsigned int dch); bool gm_insertMix(int idx); @@ -83,6 +81,7 @@ class MixesPanel : public ModelPanel void setSelectedByMixList(QList list); void AddMixerLine(int dest); QString getMixerText(int dest, bool newChannel); + void connectItemModelEvents(const int id); }; #endif // _MIXES_H_ diff --git a/companion/src/modeledit/modeledit.cpp b/companion/src/modeledit/modeledit.cpp index 41989ba537..146bc01f0d 100644 --- a/companion/src/modeledit/modeledit.cpp +++ b/companion/src/modeledit/modeledit.cpp @@ -33,7 +33,7 @@ #include "customfunctions.h" #include "telemetry.h" #include "appdata.h" -#include "rawitemdatamodels.h" +#include "compounditemmodels.h" ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmware * firmware) : QDialog(parent), @@ -53,42 +53,54 @@ ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmw GeneralSettings &generalSettings = radioData.generalSettings; ModelData &model = radioData.models[modelId]; - commonItemModels = new CommonItemModels(&generalSettings, &model, this); + sharedItemModels = new CompoundItemModelFactory(&generalSettings, &model); + sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSource); + sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSwitch); + sharedItemModels->addItemModel(AbstractItemModel::IMID_Curve); + sharedItemModels->addItemModel(AbstractItemModel::IMID_GVarRef); + sharedItemModels->addItemModel(AbstractItemModel::IMID_ThrSource); + sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncAction); + sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncResetParam); + sharedItemModels->addItemModel(AbstractItemModel::IMID_TeleSource); + sharedItemModels->addItemModel(AbstractItemModel::IMID_RssiSource); + sharedItemModels->addItemModel(AbstractItemModel::IMID_CurveRefType); + sharedItemModels->addItemModel(AbstractItemModel::IMID_CurveRefFunc); + s1.report("Init"); - SetupPanel * setupPanel = new SetupPanel(this, model, generalSettings, firmware, commonItemModels); + SetupPanel * setupPanel = new SetupPanel(this, model, generalSettings, firmware, sharedItemModels); addTab(setupPanel, tr("Setup")); s1.report("Setup"); if (firmware->getCapability(Heli)) { - addTab(new HeliPanel(this, model, generalSettings, firmware, commonItemModels), tr("Heli")); + addTab(new HeliPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Heli")); s1.report("Heli"); } - addTab(new FlightModesPanel(this, model, generalSettings, firmware, commonItemModels), tr("Flight Modes")); + addTab(new FlightModesPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Flight Modes")); s1.report("Flight Modes"); - addTab(new InputsPanel(this, model, generalSettings, firmware, commonItemModels), tr("Inputs")); + addTab(new InputsPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Inputs")); s1.report("Inputs"); - addTab(new MixesPanel(this, model, generalSettings, firmware, commonItemModels), tr("Mixes")); + addTab(new MixesPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Mixes")); s1.report("Mixes"); - ChannelsPanel * channelsPanel = new ChannelsPanel(this, model, generalSettings, firmware, commonItemModels); + ChannelsPanel * channelsPanel = new ChannelsPanel(this, model, generalSettings, firmware, sharedItemModels); addTab(channelsPanel, tr("Outputs")); s1.report("Outputs"); - addTab(new CurvesPanel(this, model, generalSettings, firmware, commonItemModels), tr("Curves")); + addTab(new CurvesPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Curves")); s1.report("Curves"); - addTab(new LogicalSwitchesPanel(this, model, generalSettings, firmware, commonItemModels), tr("Logical Switches")); + addTab(new LogicalSwitchesPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Logical Switches")); s1.report("Logical Switches"); - addTab(new CustomFunctionsPanel(this, &model, generalSettings, firmware, commonItemModels), tr("Special Functions")); + addTab(new CustomFunctionsPanel(this, &model, generalSettings, firmware, sharedItemModels), tr("Special Functions")); s1.report("Special Functions"); if (firmware->getCapability(Telemetry)) { - addTab(new TelemetryPanel(this, model, generalSettings, firmware, commonItemModels), tr("Telemetry")); + addTab(new TelemetryPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Telemetry")); s1.report("Telemetry"); } @@ -104,6 +116,7 @@ ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmw ModelEdit::~ModelEdit() { delete ui; + delete sharedItemModels; } void ModelEdit::closeEvent(QCloseEvent *event) diff --git a/companion/src/modeledit/modeledit.h b/companion/src/modeledit/modeledit.h index 9095101bf7..0bd4af9d8a 100644 --- a/companion/src/modeledit/modeledit.h +++ b/companion/src/modeledit/modeledit.h @@ -25,7 +25,7 @@ #include "genericpanel.h" class RadioData; -class CommonItemModels; +class CompoundItemModelFactory; namespace Ui { class ModelEdit; @@ -60,12 +60,12 @@ class ModelEdit : public QDialog private: Ui::ModelEdit *ui; int modelId; - RadioData & radioData; - Firmware * firmware; + RadioData &radioData; + Firmware *firmware; QVector panels; - CommonItemModels * commonItemModels; + CompoundItemModelFactory *sharedItemModels; - void addTab(GenericPanel *panel, QString text); + void addTab(GenericPanel * panel, QString text); void launchSimulation(); }; diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index e4f67178d3..3a3a7e9109 100644 --- a/companion/src/modeledit/setup.cpp +++ b/companion/src/modeledit/setup.cpp @@ -22,7 +22,6 @@ #include "ui_setup.h" #include "ui_setup_timer.h" #include "ui_setup_module.h" -#include "rawitemfilteredmodel.h" #include "appdata.h" #include "modelprinter.h" #include "multiprotocols.h" @@ -31,55 +30,61 @@ #include -TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, QWidget * prevFocus, RawItemFilteredModel * rawSwitchFilteredModel): +constexpr char FIM_TIMERSWITCH[] {"Timer Switch"}; +constexpr char FIM_THRSOURCE[] {"Throttle Source"}; + +TimerPanel::TimerPanel(QWidget * parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, + QWidget * prevFocus, FilteredItemModelFactory * panelFilteredModels, CompoundItemModelFactory * panelItemModels): ModelPanel(parent, model, generalSettings, firmware), timer(timer), - ui(new Ui::Timer) + ui(new Ui::Timer), + modelsUpdateCnt(0) { ui->setupUi(this); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &TimerPanel::onModelDataAboutToBeUpdated); - connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &TimerPanel::onModelDataUpdateComplete); + connectItemModelEvents(panelFilteredModels->getItemModel(FIM_TIMERSWITCH)); lock = true; // Name int length = firmware->getCapability(TimersName); - if (length == 0) { + if (length == 0) ui->name->hide(); + else { + ui->name->setField(timer.name, length, this); + connect(ui->name, SIGNAL(currentDataChanged()), this, SLOT(onNameChanged())); + } + + ui->value->setField(timer.val, this); + ui->value->setMaximumTime(firmware->getMaxTimerStart()); + + ui->mode->setModel(panelFilteredModels->getItemModel(FIM_TIMERSWITCH)); + ui->mode->setField(timer.mode, this); + + ui->countdownBeep->setModel(panelItemModels->getItemModel(AIM_TIMER_COUNTDOWNBEEP)); + ui->countdownBeep->setField(timer.countdownBeep, this); + connect(ui->countdownBeep, SIGNAL(currentDataChanged(int)), this, SLOT(onCountdownBeepChanged(int))); + + ui->minuteBeep->setField(timer.minuteBeep, this); + + if (firmware->getCapability(PermTimers)) { + ui->persistent->setModel(panelItemModels->getItemModel(AIM_TIMER_PERSISTENT)); + ui->persistent->setField(timer.persistent, this); } else { - ui->name->setMaxLength(length); - } - - // Mode - ui->mode->setModel(rawSwitchFilteredModel); - ui->mode->setCurrentIndex(ui->mode->findData(timer.mode.toValue())); - connect(ui->mode, SIGNAL(activated(int)), this, SLOT(onModeChanged(int))); - - if (!firmware->getCapability(PermTimers)) { ui->persistent->hide(); ui->persistentValue->hide(); } - ui->countdownBeep->setField(timer.countdownBeep, this); - ui->countdownBeep->addItem(tr("Silent"), TimerData::COUNTDOWN_SILENT); - ui->countdownBeep->addItem(tr("Beeps"), TimerData::COUNTDOWN_BEEPS); - ui->countdownBeep->addItem(tr("Voice"), TimerData::COUNTDOWN_VOICE); - ui->countdownBeep->addItem(tr("Haptic"), TimerData::COUNTDOWN_HAPTIC); - - ui->value->setMaximumTime(firmware->getMaxTimerStart()); - - ui->persistent->setField(timer.persistent, this); - ui->persistent->addItem(tr("Not persistent"), 0); - ui->persistent->addItem(tr("Persistent (flight)"), 1); - ui->persistent->addItem(tr("Persistent (manual reset)"), 2); + ui->countdownStart->setModel(panelItemModels->getItemModel(AIM_TIMER_COUNTDOWNSTART)); + ui->countdownStart->setField(timer.countdownStart, this); disableMouseScrolling(); QWidget::setTabOrder(prevFocus, ui->name); QWidget::setTabOrder(ui->name, ui->value); QWidget::setTabOrder(ui->value, ui->mode); QWidget::setTabOrder(ui->mode, ui->countdownBeep); - QWidget::setTabOrder(ui->countdownBeep, ui->minuteBeep); + QWidget::setTabOrder(ui->countdownBeep, ui->countdownStart); + QWidget::setTabOrder(ui->countdownStart, ui->minuteBeep); QWidget::setTabOrder(ui->minuteBeep, ui->persistent); update(); @@ -95,32 +100,27 @@ void TimerPanel::update() { lock = true; - ui->name->setText(timer.name); + ui->name->updateValue(); + ui->mode->updateValue(); + ui->value->updateValue(); + ui->countdownBeep->updateValue(); + ui->minuteBeep->updateValue(); + ui->countdownStart->updateValue(); - int hour = timer.val / 3600; - int min = (timer.val - (hour * 3600)) / 60; - int sec = (timer.val - (hour * 3600)) % 60; - - ui->mode->setCurrentIndex(ui->mode->findData(timer.mode.toValue())); - ui->value->setTime(QTime(hour, min, sec)); - - if (firmware->getCapability(PermTimers)) { - int sign = 1; - int pvalue = timer.pvalue; - if (pvalue < 0) { - pvalue = -pvalue; - sign = -1; - } - int hours = pvalue / 3600; - pvalue -= hours * 3600; - int minutes = pvalue / 60; - int seconds = pvalue % 60; - ui->persistentValue->setText(QString(" %1(%2:%3:%4)").arg(sign < 0 ? "-" :" ").arg(hours, 2, 10, QLatin1Char('0')).arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0'))); + if (timer.countdownBeep == TimerData::COUNTDOWNBEEP_SILENT) { + ui->countdownStartLabel->setEnabled(false); + ui->countdownStart->setEnabled(false); + } + else { + ui->countdownStartLabel->setEnabled(true); + ui->countdownStart->setEnabled(true); + } + + if (firmware->getCapability(PermTimers)) { + ui->persistent->updateValue(); + ui->persistentValue->setText(timer.pvalueToString()); } - ui->countdownBeep->updateValue(); - ui->minuteBeep->setChecked(timer.minuteBeep); - ui->persistent->updateValue(); lock = false; } @@ -129,58 +129,36 @@ QWidget * TimerPanel::getLastFocus() return ui->persistent; } -void TimerPanel::on_value_editingFinished() +void TimerPanel::connectItemModelEvents(const FilteredItemModel * itemModel) { - if (!lock) { - unsigned val = ui->value->time().hour() * 3600 + ui->value->time().minute() * 60 + ui->value->time().second(); - if (timer.val != val) { - timer.val = val; - emit modified(); - } - } + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &TimerPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &TimerPanel::onItemModelUpdateComplete); } -void TimerPanel::onModeChanged(int index) -{ - if (!lock) { - bool ok; - const RawSwitch rs(ui->mode->itemData(index).toInt(&ok)); - if (ok && timer.mode.toValue() != rs.toValue()) { - timer.mode = rs; - emit modified(); - } - } -} - -void TimerPanel::on_minuteBeep_toggled(bool checked) -{ - if (!lock) { - timer.minuteBeep = checked; - emit modified(); - } -} - -void TimerPanel::on_name_editingFinished() -{ - if (!lock) { - if (QString(timer.name) != ui->name->text()) { - int length = ui->name->maxLength(); - strncpy(timer.name, ui->name->text().toLatin1(), length); - emit nameChanged(); - emit modified(); - } - } -} - -void TimerPanel::onModelDataAboutToBeUpdated() +void TimerPanel::onItemModelAboutToBeUpdated() { lock = true; + modelsUpdateCnt++; } -void TimerPanel::onModelDataUpdateComplete() +void TimerPanel::onItemModelUpdateComplete() { + modelsUpdateCnt--; + if (modelsUpdateCnt < 1) { + update(); + lock = false; + } +} + +void TimerPanel::onNameChanged() +{ + emit nameChanged(); +} + +void TimerPanel::onCountdownBeepChanged(int index) +{ + timer.countdownBeepChanged(); update(); - lock = false; } /******************************************************************************/ @@ -679,6 +657,7 @@ void ModulePanel::onProtocolChanged(int index) module.protocol = ui->protocol->itemData(index).toInt(); module.channelsCount = module.getMaxChannelCount(); update(); + emit updateItemModels(); emit modified(); } } @@ -779,6 +758,7 @@ void ModulePanel::onMultiProtocolChanged(int index) module.subType = std::min(module.subType, maxSubTypes - 1); module.channelsCount = module.getMaxChannelCount(); update(); + emit updateItemModels(); emit modified(); lock = false; } @@ -991,18 +971,34 @@ void ModulePanel::onClearAccessRxClicked() /******************************************************************************/ -SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels): +SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, + CompoundItemModelFactory * sharedItemModels) : ModelPanel(parent, model, generalSettings, firmware), ui(new Ui::Setup), - commonItemModels(commonItemModels) + sharedItemModels(sharedItemModels) { ui->setupUi(this); - rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::TimersContext, this); - - Board::Type board = firmware->getBoard(); lock = true; + panelFilteredModels = new FilteredItemModelFactory(); + + panelFilteredModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch), + RawSwitch::TimersContext), + FIM_TIMERSWITCH); + connectItemModelEvents(panelFilteredModels->getItemModel(FIM_TIMERSWITCH)); + + panelFilteredModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_ThrSource)), + FIM_THRSOURCE); + connectItemModelEvents(panelFilteredModels->getItemModel(FIM_THRSOURCE)); + + panelItemModels = new CompoundItemModelFactory(&generalSettings, &model); + panelItemModels->registerItemModel(TimerData::countdownBeepItemModel()); + panelItemModels->registerItemModel(TimerData::countdownStartItemModel()); + panelItemModels->registerItemModel(TimerData::persistentItemModel()); + + Board::Type board = firmware->getBoard(); + memset(modules, 0, sizeof(modules)); QRegExp rx(CHAR_FOR_NAMES_REGEX); @@ -1082,7 +1078,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge for (int i = 0; i < CPN_MAX_TIMERS; i++) { if (i < timersCount) { - timers[i] = new TimerPanel(this, model, model.timers[i], generalSettings, firmware, prevFocus, rawSwitchFilteredModel); + timers[i] = new TimerPanel(this, model, model.timers[i], generalSettings, firmware, prevFocus, panelFilteredModels, panelItemModels); ui->gridLayout->addWidget(timers[i], 1+i, 1); connect(timers[i], &TimerPanel::modified, this, &SetupPanel::modified); connect(timers[i], &TimerPanel::nameChanged, this, &SetupPanel::onTimerNameChanged); @@ -1118,6 +1114,9 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge ui->toplcdTimer->hide(); } + ui->throttleSource->setModel(panelFilteredModels->getItemModel(FIM_THRSOURCE)); + ui->throttleSource->setField(model.thrTraceSrc, this); + if (!firmware->getCapability(HasDisplayText)) { ui->displayText->hide(); ui->editText->hide(); @@ -1223,6 +1222,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i); ui->modulesLayout->addWidget(modules[i]); connect(modules[i], &ModulePanel::modified, this, &SetupPanel::modified); + connect(modules[i], &ModulePanel::updateItemModels, this, &SetupPanel::onModuleUpdateItemModels); connect(this, &SetupPanel::extendedLimitsToggled, modules[i], &ModulePanel::onExtendedLimitsToggled); } @@ -1248,6 +1248,8 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge SetupPanel::~SetupPanel() { delete ui; + delete panelFilteredModels; + delete panelItemModels; } void SetupPanel::on_extendedLimits_toggled(bool checked) @@ -1281,14 +1283,6 @@ void SetupPanel::on_trimIncrement_currentIndexChanged(int index) emit modified(); } -void SetupPanel::on_throttleSource_currentIndexChanged(int index) -{ - if (!lock) { - model->thrTraceSrc = ui->throttleSource->currentData().toUInt(); - emit modified(); - } -} - void SetupPanel::on_throttleTrimSwitch_currentIndexChanged(int index) { if (!lock) { @@ -1347,28 +1341,6 @@ void SetupPanel::on_image_currentIndexChanged(int index) } } -void SetupPanel::populateThrottleSourceCB() -{ - Board::Type board = firmware->getBoard(); - lock = true; - ui->throttleSource->clear(); - ui->throttleSource->addItem(tr("THR"), 0); - - int idx = 1; - for (int i = 0; i < getBoardCapability(board, Board::Pots) + getBoardCapability(board, Board::Sliders); i++, idx++) { - if (RawSource(SOURCE_TYPE_STICK, 4 + i).isAvailable(model, &generalSettings, board)) { - ui->throttleSource->addItem(firmware->getAnalogInputName(4 + i), idx); - } - } - for (int i = 0; i < firmware->getCapability(Outputs); i++, idx++) { - ui->throttleSource->addItem(RawSource(SOURCE_TYPE_CH, i).toString(model, &generalSettings), idx); - } - - int thrTraceSrcIdx = ui->throttleSource->findData(model->thrTraceSrc); - ui->throttleSource->setCurrentIndex(thrTraceSrcIdx); - lock = false; -} - void SetupPanel::populateThrottleTrimSwitchCB() { Board::Type board = firmware->getBoard(); @@ -1396,7 +1368,7 @@ void SetupPanel::update() { ui->name->setText(model->name); ui->throttleReverse->setChecked(model->throttleReversed); - populateThrottleSourceCB(); + ui->throttleSource->updateValue(); populateThrottleTrimSwitchCB(); ui->throttleWarning->setChecked(!model->disableThrottleWarning); ui->trimIncrement->setCurrentIndex(model->trimInc+2); @@ -1750,7 +1722,27 @@ void SetupPanel::onTimerNameChanged() updateItemModels(); } +void SetupPanel::connectItemModelEvents(const FilteredItemModel * itemModel) +{ + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &SetupPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &SetupPanel::onItemModelUpdateComplete); +} + +void SetupPanel::onItemModelAboutToBeUpdated() +{ +} + +void SetupPanel::onItemModelUpdateComplete() +{ +} + void SetupPanel::updateItemModels() { - commonItemModels->update(CommonItemModels::RMO_TIMERS); + sharedItemModels->update(AbstractItemModel::IMUE_Timers); + emit updated(); +} + +void SetupPanel::onModuleUpdateItemModels() +{ + sharedItemModels->update(AbstractItemModel::IMUE_Modules); } diff --git a/companion/src/modeledit/setup.h b/companion/src/modeledit/setup.h index c56e63ea14..82e69ec75e 100644 --- a/companion/src/modeledit/setup.h +++ b/companion/src/modeledit/setup.h @@ -18,17 +18,15 @@ * GNU General Public License for more details. */ -#ifndef _SETUP_H_ -#define _SETUP_H_ +#pragma once #include "modeledit.h" #include "eeprominterface.h" +#include "compounditemmodels.h" +#include "filtereditemmodels.h" constexpr char MIMETYPE_TIMER[] = "application/x-companion-timer"; -class CommonItemModels; -class RawItemFilteredModel; - namespace Ui { class Setup; class Timer; @@ -40,19 +38,18 @@ class TimerPanel : public ModelPanel Q_OBJECT public: - TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, QWidget *prevFocus, RawItemFilteredModel * switchModel); + TimerPanel(QWidget * parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, + QWidget * prevFocus, FilteredItemModelFactory * panelFilteredModels, CompoundItemModelFactory * panelItemModels); virtual ~TimerPanel(); virtual void update(); QWidget * getLastFocus(); private slots: - void onModeChanged(int index); - void on_value_editingFinished(); - void on_minuteBeep_toggled(bool checked); - void on_name_editingFinished(); - void onModelDataAboutToBeUpdated(); - void onModelDataUpdateComplete(); + void onNameChanged(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); + void onCountdownBeepChanged(int index); signals: void nameChanged(); @@ -60,6 +57,8 @@ class TimerPanel : public ModelPanel private: TimerData & timer; Ui::Timer * ui; + void connectItemModelEvents(const FilteredItemModel * itemModel); + int modelsUpdateCnt; }; class ModulePanel : public ModelPanel @@ -78,6 +77,7 @@ class ModulePanel : public ModelPanel signals: void channelsRangeChanged(); void failsafeModified(unsigned index); + void updateItemModels(); private slots: void setupFailsafes(); @@ -131,7 +131,7 @@ class SetupPanel : public ModelPanel Q_OBJECT public: - SetupPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); + SetupPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels); virtual ~SetupPanel(); virtual void update(); @@ -142,7 +142,6 @@ class SetupPanel : public ModelPanel private slots: void on_name_editingFinished(); - void on_throttleSource_currentIndexChanged(int index); void on_throttleTrimSwitch_currentIndexChanged(int index); void on_throttleTrim_toggled(bool checked); void on_extendedLimits_toggled(bool checked); @@ -170,6 +169,9 @@ class SetupPanel : public ModelPanel void cmTimerMoveDown(); void cmTimerMoveUp(); void onTimerNameChanged(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); + void onModuleUpdateItemModels(); private: Ui::Setup *ui; @@ -177,12 +179,11 @@ class SetupPanel : public ModelPanel QVector startupSwitchesCheckboxes; QVector potWarningCheckboxes; QVector centerBeepCheckboxes; - ModulePanel * modules[CPN_MAX_MODULES+1]; + ModulePanel * modules[CPN_MAX_MODULES + 1]; TimerPanel * timers[CPN_MAX_TIMERS]; void updateStartupSwitches(); void updatePotWarnings(); void updateBeepCenter(); - void populateThrottleSourceCB(); void populateThrottleTrimSwitchCB(); int timersCount; int selectedTimerIndex; @@ -191,9 +192,9 @@ class SetupPanel : public ModelPanel bool moveTimerDownAllowed() const; bool moveTimerUpAllowed() const; void swapTimerData(int idx1, int idx2); - CommonItemModels * commonItemModels; - RawItemFilteredModel * rawSwitchFilteredModel; + CompoundItemModelFactory * sharedItemModels; void updateItemModels(); - }; - -#endif // _SETUP_H_ + void connectItemModelEvents(const FilteredItemModel * itemModel); + CompoundItemModelFactory * panelItemModels; + FilteredItemModelFactory * panelFilteredModels; +}; diff --git a/companion/src/modeledit/setup.ui b/companion/src/modeledit/setup.ui index 8b24091918..ee0ec28a3a 100644 --- a/companion/src/modeledit/setup.ui +++ b/companion/src/modeledit/setup.ui @@ -604,7 +604,7 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi - + 0 diff --git a/companion/src/modeledit/setup_timer.ui b/companion/src/modeledit/setup_timer.ui index b6b920a102..67b929bdb1 100644 --- a/companion/src/modeledit/setup_timer.ui +++ b/companion/src/modeledit/setup_timer.ui @@ -9,7 +9,7 @@ 0 0 - 675 + 874 33 @@ -20,11 +20,20 @@ 6 - + + 0 + + + 0 + + + 0 + + 0 - + 80 @@ -34,7 +43,7 @@ - + true @@ -47,7 +56,7 @@ - + @@ -60,7 +69,17 @@ - + + + Start + + + + + + + + Minute Call @@ -97,6 +116,21 @@ QComboBox
autocombobox.h
+ + AutoLineEdit + QLineEdit +
autolineedit.h
+
+ + AutoCheckBox + QCheckBox +
autocheckbox.h
+
+ + AutoTimeEdit + QTimeEdit +
autotimeedit.h
+
diff --git a/companion/src/modeledit/telemetry.cpp b/companion/src/modeledit/telemetry.cpp index e980c39438..bb32790b82 100644 --- a/companion/src/modeledit/telemetry.cpp +++ b/companion/src/modeledit/telemetry.cpp @@ -24,24 +24,37 @@ #include "ui_telemetry_sensor.h" #include "helpers.h" #include "appdata.h" -#include "rawitemfilteredmodel.h" #include -TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware, RawItemFilteredModel * rawSourceModel): +constexpr char FIM_RAWSOURCE[] {"Raw Source"}; +constexpr char FIM_TELEALLSRC[] {"Tele All Source"}; +constexpr char FIM_TELEPOSSRC[] {"Tele Pos Source"}; +constexpr char FIM_SENSORTYPE[] {"Sensor.Type"}; +constexpr char FIM_SENSORFORMULA[] {"Sensor.Formula"}; +constexpr char FIM_SENSORCELLINDEX[] {"Sensor.CellIndex"}; +constexpr char FIM_SENSORUNIT[] {"Sensor.Unit"}; +constexpr char FIM_SENSORPRECISION[] {"Sensor.Precision"}; +constexpr char FIM_RSSISOURCE[] {"Rssi Source"}; + +TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, + Firmware * firmware, const bool & parentLock, FilteredItemModelFactory * panelFilteredItemModels): ModelPanel(parent, model, generalSettings, firmware), ui(new Ui::TelemetryCustomScreen), - screen(screen) + screen(screen), + modelsUpdateCnt(0), + parentLock(parentLock) { ui->setupUi(this); - connect(rawSourceModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &TelemetryCustomScreen::onModelDataAboutToBeUpdated); - connect(rawSourceModel, &RawItemFilteredModel::dataUpdateComplete, this, &TelemetryCustomScreen::onModelDataUpdateComplete); + + FilteredItemModel * rawSourceFilteredModel = panelFilteredItemModels->getItemModel(FIM_RAWSOURCE); + connectItemModelEvents(rawSourceFilteredModel); for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensLines); l++) { for (int c = 0; c < firmware->getCapability(TelemetryCustomScreensFieldsPerLine); c++) { fieldsCB[l][c] = new QComboBox(this); fieldsCB[l][c]->setProperty("index", c + (l << 8)); - fieldsCB[l][c]->setModel(rawSourceModel); + fieldsCB[l][c]->setModel(rawSourceFilteredModel); ui->screenNumsLayout->addWidget(fieldsCB[l][c], l, c, 1, 1); connect(fieldsCB[l][c], SIGNAL(activated(int)), this, SLOT(customFieldChanged(int))); } @@ -50,7 +63,7 @@ TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model, for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensBars); l++) { barsCB[l] = new QComboBox(this); barsCB[l]->setProperty("index", l); - barsCB[l]->setModel(rawSourceModel); + barsCB[l]->setModel(rawSourceFilteredModel); connect(barsCB[l], SIGNAL(activated(int)), this, SLOT(barSourceChanged(int))); ui->screenBarsLayout->addWidget(barsCB[l], l, 0, 1, 1); @@ -99,7 +112,7 @@ TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model, lock = false; if (IS_TARANIS(firmware->getBoard())) { - QSet scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/TELEMETRY", QStringList() << "*.lua", 8); + QSet scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/TELEMETRY", QStringList() << "*.lua", 6); Helpers::populateFileComboBox(ui->scriptName, scriptsSet, screen.body.script.filename); connect(ui->scriptName, SIGNAL(currentIndexChanged(int)), this, SLOT(scriptNameEdited())); connect(ui->scriptName, SIGNAL(editTextChanged ( const QString)), this, SLOT(scriptNameEdited())); @@ -203,7 +216,7 @@ void TelemetryCustomScreen::updateBar(int line) void TelemetryCustomScreen::on_screenType_currentIndexChanged(int index) { - if (!lock) { + if (!isLocked()) { memset(reinterpret_cast(&screen.body), 0, sizeof(screen.body)); update(); emit modified(); @@ -212,7 +225,7 @@ void TelemetryCustomScreen::on_screenType_currentIndexChanged(int index) void TelemetryCustomScreen::scriptNameEdited() { - if (!lock) { + if (!isLocked()) { lock = true; Helpers::getFileComboBoxValue(ui->scriptName, screen.body.script.filename, 8); emit modified(); @@ -222,7 +235,7 @@ void TelemetryCustomScreen::scriptNameEdited() void TelemetryCustomScreen::customFieldChanged(int value) { - if (lock || !sender() || !qobject_cast(sender())) + if (isLocked() || !sender() || !qobject_cast(sender())) return; bool ok; @@ -238,7 +251,7 @@ void TelemetryCustomScreen::customFieldChanged(int value) void TelemetryCustomScreen::barSourceChanged(int value) { - if (lock || !sender() || !qobject_cast(sender())) + if (isLocked() || !sender() || !qobject_cast(sender())) return; bool ok; @@ -256,7 +269,7 @@ void TelemetryCustomScreen::barSourceChanged(int value) void TelemetryCustomScreen::barMinChanged(double value) { - if (!lock) { + if (!isLocked()) { int line = sender()->property("index").toInt(); screen.body.bars[line].barMin = round(value / minSB[line]->singleStep()); // TODO set min (maxSB) @@ -266,7 +279,7 @@ void TelemetryCustomScreen::barMinChanged(double value) void TelemetryCustomScreen::barMaxChanged(double value) { - if (!lock) { + if (!isLocked()) { int line = sender()->property("index").toInt(); screen.body.bars[line].barMax = round((value) / maxSB[line]->singleStep()); // TODO set max (minSB) @@ -276,7 +289,7 @@ void TelemetryCustomScreen::barMaxChanged(double value) void TelemetryCustomScreen::barTimeChanged() { - if (!lock) { + if (!isLocked()) { int line = sender()->property("index").toInt(); int & valRef = (sender()->property("type").toString() == "min" ? screen.body.bars[line].barMin : screen.body.bars[line].barMax); TimerEdit * te = qobject_cast(sender()); @@ -289,29 +302,48 @@ void TelemetryCustomScreen::barTimeChanged() } } -void TelemetryCustomScreen::onModelDataAboutToBeUpdated() +void TelemetryCustomScreen::connectItemModelEvents(const FilteredItemModel * itemModel) { - lock = true; + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &TelemetryCustomScreen::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &TelemetryCustomScreen::onItemModelUpdateComplete); } -void TelemetryCustomScreen::onModelDataUpdateComplete() +void TelemetryCustomScreen::onItemModelAboutToBeUpdated() { - update(); - lock = false; + lock = true; + modelsUpdateCnt++; +} + +void TelemetryCustomScreen::onItemModelUpdateComplete() +{ + modelsUpdateCnt--; + if (modelsUpdateCnt < 1) { + // leave updating to parent + lock = false; + } } /******************************************************/ -TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, int sensorCapability, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): +TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, int sensorCapability, ModelData & model, + GeneralSettings & generalSettings, Firmware * firmware, const bool & parentLock, + FilteredItemModelFactory * panelFilteredItemModels) : ModelPanel(parent, model, generalSettings, firmware), ui(new Ui::TelemetrySensor), sensor(sensor), - lock(false), sensorIndex(sensorIndex), selectedIndex(0), - sensorCapability(sensorCapability) + sensorCapability(sensorCapability), + modelsUpdateCnt(0), + parentLock(parentLock) { ui->setupUi(this); + FilteredItemModel * fltmdl; + + connectItemModelEvents(panelFilteredItemModels->getItemModel(FIM_TELEALLSRC)); + connectItemModelEvents(panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC)); + + lock = true; ui->numLabel->setText(tr("TELE%1").arg(sensorIndex + 1)); ui->numLabel->setProperty("index", sensorIndex); ui->numLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); @@ -324,8 +356,19 @@ TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, ui->numLabel->setToolTip(tr("Popup menu available")); ui->numLabel->setMouseTracking(true); connect(ui->numLabel, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_customContextMenuRequested(QPoint))); + ui->name->setField(sensor.label, SENSOR_LABEL_LEN); + connect(ui->name, SIGNAL(currentDataChanged()), this, SLOT(on_nameDataChanged())); ui->id->setField(sensor.id, this); ui->instance->setField(sensor.instance, this); + ui->type->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORTYPE)); + ui->type->setField(sensor.type); + connect(ui->type, SIGNAL(currentDataChanged(int)), this, SLOT(update())); + ui->formula->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORFORMULA)); + ui->formula->setField(sensor.formula); + connect(ui->formula, SIGNAL(currentDataChanged(int)), this, SLOT(on_formulaDataChanged())); + ui->unit->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORUNIT)); + ui->unit->setField(sensor.unit); + connect(ui->unit, SIGNAL(currentDataChanged(int)), this, SLOT(on_unitDataChanged())); ui->ratio->setField(sensor.ratio, this); ui->offset->setField(sensor.offset, this); ui->autoOffset->setField(sensor.autoOffset, this); @@ -333,21 +376,31 @@ TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, ui->logs->setField(sensor.logs, this); ui->persistent->setField(sensor.persistent, this); ui->onlyPositive->setField(sensor.onlyPositive, this); + fltmdl = panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC); + ui->gpsSensor->setModel(fltmdl); ui->gpsSensor->setField(sensor.gps, this); + ui->altSensor->setModel(fltmdl); ui->altSensor->setField(sensor.alt, this); + ui->ampsSensor->setModel(fltmdl); ui->ampsSensor->setField(sensor.amps, this); + ui->cellsSensor->setModel(fltmdl); ui->cellsSensor->setField(sensor.source, this); - ui->cellsIndex->addItem(tr("Lowest"), SensorData::TELEM_CELL_INDEX_LOWEST); - for (int i = SensorData::TELEM_CELL_INDEX_LOWEST + 1; i < SensorData::TELEM_CELL_INDEX_HIGHEST; i++) - ui->cellsIndex->addItem(tr("Cell %1").arg(i), i); - ui->cellsIndex->addItem(tr("Highest"), SensorData::TELEM_CELL_INDEX_HIGHEST); - ui->cellsIndex->addItem(tr("Delta"), SensorData::TELEM_CELL_INDEX_DELTA); + ui->cellsIndex->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORCELLINDEX)); ui->cellsIndex->setField(sensor.index); + fltmdl = panelFilteredItemModels->getItemModel(FIM_TELEALLSRC); + ui->source1->setModel(fltmdl); ui->source1->setField(sensor.sources[0], this); + ui->source2->setModel(fltmdl); ui->source2->setField(sensor.sources[1], this); + ui->source3->setModel(fltmdl); ui->source3->setField(sensor.sources[2], this); + ui->source4->setModel(fltmdl); ui->source4->setField(sensor.sources[3], this); - ui->prec->setField(sensor.prec, 0, 2, false, "", this); + ui->prec->setModel(panelFilteredItemModels->getItemModel(FIM_SENSORPRECISION)); + ui->prec->setField(sensor.prec); + connect(ui->prec, SIGNAL(currentDataChanged(int)), this, SLOT(on_precDataChanged())); + lock = false; + update(); } @@ -358,19 +411,13 @@ TelemetrySensorPanel::~TelemetrySensorPanel() void TelemetrySensorPanel::update() { - bool isConfigurable = false; - bool gpsFieldsDisplayed = false; - bool cellsFieldsDisplayed = false; - bool consFieldsDisplayed = false; - bool ratioFieldsDisplayed = false; - bool totalizeFieldsDisplayed = false; - bool sources12FieldsDisplayed = false; - bool sources34FieldsDisplayed = false; - lock = true; - ui->name->setText(sensor.label); - ui->type->setCurrentIndex(sensor.type); - ui->unit->setCurrentIndex(sensor.unit); + int mask = sensor.getMask(); + + ui->name->updateValue(); + ui->type->updateValue(); + ui->formula->updateValue(); + ui->unit->updateValue(); ui->id->updateValue(); ui->instance->updateValue(); ui->ratio->updateValue(); @@ -396,22 +443,11 @@ void TelemetrySensorPanel::update() ui->originLabel->hide(); ui->origin->hide(); ui->formula->show(); - ui->formula->setCurrentIndex(sensor.formula); - isConfigurable = (sensor.formula < SensorData::TELEM_FORMULA_CELL); - gpsFieldsDisplayed = (sensor.formula == SensorData::TELEM_FORMULA_DIST); - cellsFieldsDisplayed = (sensor.formula == SensorData::TELEM_FORMULA_CELL); - consFieldsDisplayed = (sensor.formula == SensorData::TELEM_FORMULA_CONSUMPTION); - sources12FieldsDisplayed = (sensor.formula <= SensorData::TELEM_FORMULA_MULTIPLY); - sources34FieldsDisplayed = (sensor.formula < SensorData::TELEM_FORMULA_MULTIPLY); - totalizeFieldsDisplayed = (sensor.formula == SensorData::TELEM_FORMULA_TOTALIZE); - updateSourcesComboBox(ui->source1, true); - updateSourcesComboBox(ui->source2, true); - updateSourcesComboBox(ui->source3, true); - updateSourcesComboBox(ui->source4, true); - updateSourcesComboBox(ui->gpsSensor, false); - updateSourcesComboBox(ui->altSensor, false); - updateSourcesComboBox(ui->ampsSensor, false); - updateSourcesComboBox(ui->cellsSensor, false); + ui->formula->setCurrentIndex(ui->formula->findData(sensor.formula)); + ui->source1->updateValue(); + ui->source2->updateValue(); + ui->source3->updateValue(); + ui->source4->updateValue(); } else { ui->idLabel->show(); @@ -422,152 +458,78 @@ void TelemetrySensorPanel::update() ui->originLabel->setVisible(!origin.isEmpty()); ui->origin->setVisible(!origin.isEmpty()); ui->origin->setText(origin); - ui->formula->hide(); - isConfigurable = sensor.unit < SensorData::UNIT_FIRST_VIRTUAL; - ratioFieldsDisplayed = (sensor.unit < SensorData::UNIT_FIRST_VIRTUAL); - if (sensor.unit == SensorData::UNIT_RPMS) { - if (ui->ratio->decimals()) { - ui->ratio->setDecimals(0); - ui->ratio->setMaximum(30000); - ui->ratio->setMinimum(1); - ui->ratio->setSingleStep(1); - ui->offset->setDecimals(0); - ui->offset->setMaximum(30000); - ui->offset->setMinimum(1); - ui->offset->setSingleStep(1); - } - } - else { - if (!ui->ratio->decimals()) { - ui->ratio->setDecimals(1); - ui->ratio->setMaximum(3000); - ui->ratio->setMinimum(0); - ui->ratio->setSingleStep(0.1); - } - if (ui->offset->decimals() != (int)sensor.prec) { - ui->offset->setDecimals(sensor.prec); - ui->offset->setMaximum(30000.0f / powf(10.0f, sensor.prec)); - ui->offset->setMinimum(-ui->offset->maximum()); - ui->offset->setSingleStep(pow(0.1, sensor.prec)); - } - } + FieldRange rng = sensor.getRatioRange(); + ui->ratio->setDecimals(rng.decimals); + ui->ratio->setMaximum(rng.max); + ui->ratio->setMinimum(rng.min); + ui->ratio->setSingleStep(rng.step); + rng = sensor.getOffsetRange(); + ui->offset->setDecimals(rng.decimals); + ui->offset->setMaximum(rng.max); + ui->offset->setMinimum(rng.min); + ui->offset->setSingleStep(rng.step); } - ui->ratioLabel->setVisible(ratioFieldsDisplayed && sensor.unit != SensorData::UNIT_RPMS); - ui->bladesLabel->setVisible(sensor.unit == SensorData::UNIT_RPMS); - ui->ratio->setVisible(ratioFieldsDisplayed); - ui->offsetLabel->setVisible(ratioFieldsDisplayed && sensor.unit != SensorData::UNIT_RPMS); - ui->multiplierLabel->setVisible(sensor.unit == SensorData::UNIT_RPMS); - ui->offset->setVisible(ratioFieldsDisplayed); - ui->precLabel->setVisible(isConfigurable && sensor.unit != SensorData::UNIT_FAHRENHEIT); - ui->prec->setVisible(isConfigurable && sensor.unit != SensorData::UNIT_FAHRENHEIT); - ui->unit->setVisible((sensor.type == SensorData::TELEM_TYPE_CALCULATED && (sensor.formula == SensorData::TELEM_FORMULA_DIST)) || isConfigurable); - ui->gpsSensorLabel->setVisible(gpsFieldsDisplayed); - ui->gpsSensor->setVisible(gpsFieldsDisplayed); - ui->altSensorLabel->setVisible(gpsFieldsDisplayed); - ui->altSensor->setVisible(gpsFieldsDisplayed); - ui->ampsSensorLabel->setVisible(consFieldsDisplayed || totalizeFieldsDisplayed); - ui->ampsSensor->setVisible(consFieldsDisplayed || totalizeFieldsDisplayed); - ui->cellsSensorLabel->setVisible(cellsFieldsDisplayed); - ui->cellsSensor->setVisible(cellsFieldsDisplayed); - ui->cellsIndex->setVisible(cellsFieldsDisplayed); - ui->source1->setVisible(sources12FieldsDisplayed); - ui->source2->setVisible(sources12FieldsDisplayed); - ui->source3->setVisible(sources34FieldsDisplayed); - ui->source4->setVisible(sources34FieldsDisplayed); - ui->autoOffset->setVisible(sensor.unit != SensorData::UNIT_RPMS && isConfigurable); - ui->filter->setVisible(isConfigurable); - ui->persistent->setVisible(sensor.type == SensorData::TELEM_TYPE_CALCULATED); + ui->ratioLabel->setVisible(mask & SENSOR_HAS_RATIO && sensor.unit != SensorData::UNIT_RPMS); + ui->bladesLabel->setVisible(mask & SENSOR_HAS_RATIO && sensor.unit == SensorData::UNIT_RPMS); + ui->ratio->setVisible(mask & SENSOR_HAS_RATIO); + + ui->offsetLabel->setVisible(mask & SENSOR_HAS_RATIO && sensor.unit != SensorData::UNIT_RPMS); + ui->multiplierLabel->setVisible(mask & SENSOR_HAS_RATIO && sensor.unit == SensorData::UNIT_RPMS); + ui->offset->setVisible(mask & SENSOR_HAS_RATIO); + + ui->precLabel->setVisible(mask & SENSOR_HAS_PRECISION); + ui->prec->setVisible(mask & SENSOR_HAS_PRECISION); + + ui->unit->setVisible(mask & SENSOR_ISCONFIGURABLE); + + ui->gpsSensorLabel->setVisible(mask & SENSOR_HAS_GPS); + ui->gpsSensor->setVisible(mask & SENSOR_HAS_GPS); + + ui->altSensorLabel->setVisible(mask & SENSOR_HAS_GPS); + ui->altSensor->setVisible(mask & SENSOR_HAS_GPS); + + ui->ampsSensorLabel->setVisible(mask & SENSOR_HAS_CONSUMPTION || mask & SENSOR_HAS_TOTALIZE); + ui->ampsSensor->setVisible(mask & SENSOR_HAS_CONSUMPTION || mask & SENSOR_HAS_TOTALIZE); + + ui->cellsSensorLabel->setVisible(mask & SENSOR_HAS_CELLS); + ui->cellsSensor->setVisible(mask & SENSOR_HAS_CELLS); + ui->cellsIndex->setVisible(mask & SENSOR_HAS_CELLS); + + ui->source1->setVisible(mask & SENSOR_HAS_SOURCES_12); + ui->source2->setVisible(mask & SENSOR_HAS_SOURCES_12); + ui->source3->setVisible(mask & SENSOR_HAS_SOURCES_34); + ui->source4->setVisible(mask & SENSOR_HAS_SOURCES_34); + + ui->autoOffset->setEnabled(mask & SENSOR_HAS_RATIO && sensor.unit != SensorData::UNIT_RPMS); + ui->onlyPositive->setEnabled(mask & SENSOR_HAS_POSITIVE); + ui->filter->setEnabled(mask & SENSOR_ISCONFIGURABLE); + ui->persistent->setEnabled(sensor.type == SensorData::TELEM_TYPE_CALCULATED); lock = false; } -void populateTelemetrySourcesComboBox(AutoComboBox * cb, const ModelData * model, bool negative) +void TelemetrySensorPanel::on_nameDataChanged() { - cb->clear(); - if (negative) { - for (int i = -CPN_MAX_SENSORS; i < 0; ++i) { - const SensorData& sensor = model->sensorData[-i - 1]; - if (sensor.isAvailable()) { - if (sensor.type == SensorData::TELEM_TYPE_CUSTOM) - cb->addItem(QString("-%1 (%2)").arg(sensor.label, sensor.getOrigin(model)), i); - else - cb->addItem(QString("-%1").arg(sensor.label), i); - } - } - } - cb->addItem("---", 0); - for (unsigned i = 1; i <= CPN_MAX_SENSORS; ++i) { - const SensorData& sensor = model->sensorData[i-1]; - if (sensor.isAvailable()) { - if (sensor.type == SensorData::TELEM_TYPE_CUSTOM) - cb->addItem(QString("%1 (%2)").arg(sensor.label, sensor.getOrigin(model)), i); - else - cb->addItem(QString("%1").arg(sensor.label), i); - } - } + emit dataModified(); } -void TelemetrySensorPanel::updateSourcesComboBox(AutoComboBox * cb, bool negative) +void TelemetrySensorPanel::on_formulaDataChanged() { - populateTelemetrySourcesComboBox(cb, model, negative); + sensor.formulaChanged(); + update(); } -void TelemetrySensorPanel::on_name_editingFinished() +void TelemetrySensorPanel::on_unitDataChanged() { - if (!lock) { - strcpy(sensor.label, ui->name->text().toLatin1()); - emit dataModified(); - } + sensor.unitChanged(); + update(); } -void TelemetrySensorPanel::on_type_currentIndexChanged(int index) +void TelemetrySensorPanel::on_precDataChanged() { - if (!lock) { - sensor.type = index; - update(); - emit modified(); - } -} - -void TelemetrySensorPanel::on_formula_currentIndexChanged(int index) -{ - if (!lock) { - sensor.formula = index; - if (sensor.formula == SensorData::TELEM_FORMULA_CELL) { - sensor.prec = 2; - sensor.unit = SensorData::UNIT_VOLTS; - } - else if (sensor.formula == SensorData::TELEM_FORMULA_CONSUMPTION) { - sensor.prec = 0; - sensor.unit = SensorData::UNIT_MAH; - } - else if (sensor.formula == SensorData::TELEM_FORMULA_DIST) { - sensor.prec = 0; - sensor.unit = SensorData::UNIT_METERS; - } - emit dataModified(); - } -} - -void TelemetrySensorPanel::on_unit_currentIndexChanged(int index) -{ - if (!lock) { - sensor.unit = index; - if (sensor.unit == SensorData::UNIT_FAHRENHEIT) { - sensor.prec = 0; - } - update(); - emit modified(); - } -} - -void TelemetrySensorPanel::on_prec_valueChanged() -{ - if (!lock) { - update(); - } + update(); } void TelemetrySensorPanel::on_customContextMenuRequested(QPoint pos) @@ -686,15 +648,74 @@ void TelemetrySensorPanel::cmMoveDown() emit moveDownSensor(selectedIndex); } +void TelemetrySensorPanel::connectItemModelEvents(const FilteredItemModel * itemModel) +{ + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &TelemetrySensorPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &TelemetrySensorPanel::onItemModelUpdateComplete); +} + +void TelemetrySensorPanel::onItemModelAboutToBeUpdated() +{ + lock = true; + modelsUpdateCnt++; +} + +void TelemetrySensorPanel::onItemModelUpdateComplete() +{ + modelsUpdateCnt--; + if (modelsUpdateCnt < 1) { + // leave updating to parent + lock = false; + } +} + /******************************************************/ -TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels): +TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, + CompoundItemModelFactory * sharedItemModels): ModelPanel(parent, model, generalSettings, firmware), ui(new Ui::Telemetry), - commonItemModels(commonItemModels) + sharedItemModels(sharedItemModels), + modelsUpdateCnt(0) { ui->setupUi(this); - rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), this); + + panelItemModels = new CompoundItemModelFactory(&generalSettings, &model); + panelFilteredItemModels = new FilteredItemModelFactory(); + int id; + + id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource)), + FIM_RAWSOURCE); + connectItemModelEvents(id); + + id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_TeleSource)), + FIM_TELEALLSRC); + connectItemModelEvents(id); + + id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_TeleSource), + FilteredItemModel::PositiveFilter), + FIM_TELEPOSSRC); + connectItemModelEvents(id); + + + id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RssiSource)), + FIM_RSSISOURCE); + connectItemModelEvents(id); + + id = panelItemModels->registerItemModel(SensorData::typeItemModel()); + panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORTYPE); + + id = panelItemModels->registerItemModel(SensorData::formulaItemModel()); + panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORFORMULA); + + id = panelItemModels->registerItemModel(SensorData::cellIndexItemModel()); + panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORCELLINDEX); + + id = panelItemModels->registerItemModel(SensorData::unitItemModel()); + panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORUNIT); + + id = panelItemModels->registerItemModel(SensorData::precisionItemModel()); + panelFilteredItemModels->registerItemModel(new FilteredItemModel(panelItemModels->getItemModel(id)), FIM_SENSORPRECISION); sensorCapability = firmware->getCapability(Sensors); if (sensorCapability > CPN_MAX_SENSORS) // TODO should be role of getCapability @@ -704,13 +725,15 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin model.frsky.usrProto = 1; } + ui->varioSource->setModel(panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC)); ui->varioSource->setField(model.frsky.varioSource, this); ui->varioCenterSilent->setField(model.frsky.varioCenterSilent, this); ui->A1GB->hide(); ui->A2GB->hide(); for (int i = 0; i < sensorCapability; ++i) { - TelemetrySensorPanel * panel = new TelemetrySensorPanel(this, model.sensorData[i], i, sensorCapability, model, generalSettings, firmware); + TelemetrySensorPanel * panel = new TelemetrySensorPanel(this, model.sensorData[i], i, sensorCapability, model, generalSettings, + firmware, lock, panelFilteredItemModels); ui->sensorsLayout->addWidget(panel); sensorPanels[i] = panel; connect(panel, SIGNAL(dataModified()), this, SLOT(on_dataModifiedSensor())); @@ -723,7 +746,9 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin } if (IS_TARANIS_X9(firmware->getBoard())) { + ui->voltsSource->setModel(panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC)); ui->voltsSource->setField(model.frsky.voltsSource, this); + ui->altitudeSource->setModel(panelFilteredItemModels->getItemModel(FIM_TELEPOSSRC)); ui->altitudeSource->setField(model.frsky.altitudeSource, this); } else { @@ -731,7 +756,8 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin } for (int i = 0; i < firmware->getCapability(TelemetryCustomScreens); i++) { - TelemetryCustomScreen * tab = new TelemetryCustomScreen(this, model, model.frsky.screens[i], generalSettings, firmware, rawSourceFilteredModel); + TelemetryCustomScreen * tab = new TelemetryCustomScreen(this, model, model.frsky.screens[i], generalSettings, firmware, lock, + panelFilteredItemModels); ui->customScreens->addTab(tab, tr("Telemetry screen %1").arg(i + 1)); telemetryCustomScreens[i] = tab; connect(tab, &TelemetryCustomScreen::modified, this, &TelemetryPanel::onModified); @@ -745,10 +771,14 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin TelemetryPanel::~TelemetryPanel() { delete ui; + delete panelFilteredItemModels; + delete panelItemModels; } void TelemetryPanel::update() { + lock = true; + if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { if (model->moduleData[0].protocol == PULSES_OFF && model->moduleData[1].protocol == PULSES_PPM) { ui->telemetryProtocol->setEnabled(true); @@ -758,10 +788,10 @@ void TelemetryPanel::update() ui->telemetryProtocol->setCurrentIndex(0); } - populateTelemetrySourcesComboBox(ui->rssiSourceCB, model, false); - populateTelemetrySourcesComboBox(ui->voltsSource, model, false); - populateTelemetrySourcesComboBox(ui->altitudeSource, model, false); - populateTelemetrySourcesComboBox(ui->varioSource, model, false); + ui->rssiSourceCB->updateValue(); + ui->voltsSource->updateValue(); + ui->altitudeSource->updateValue(); + ui->varioSource->updateValue(); } for (int i = 0; i < sensorCapability; ++i) { @@ -771,6 +801,8 @@ void TelemetryPanel::update() for (int i = 0; i < firmware->getCapability(TelemetryCustomScreens); i++) { telemetryCustomScreens[i]->update(); } + + lock = false; } void TelemetryPanel::setup() @@ -787,14 +819,16 @@ void TelemetryPanel::setup() ui->ignoreSensorIds->setField(model->frsky.ignoreSensorIds, this); ui->disableTelemetryAlarms->setField(model->rssiAlarms.disabled); + ui->rssiAlarmWarningSB->setRange(45 - 30, 45 + 30); ui->rssiAlarmWarningSB->setValue(model->rssiAlarms.warning); + ui->rssiAlarmCriticalSB->setRange(42 - 30, 42 + 30); ui->rssiAlarmCriticalSB->setValue(model->rssiAlarms.critical); ui->rssiSourceLabel->show(); ui->rssiSourceLabel->setText(tr("Source")); + ui->rssiSourceCB->setModel(panelFilteredItemModels->getItemModel(FIM_RSSISOURCE)); ui->rssiSourceCB->setField(model->rssiSource, this); ui->rssiSourceCB->show(); - populateTelemetrySourcesComboBox(ui->rssiSourceCB, model, false); ui->rssiAlarmWarningCB->hide(); ui->rssiAlarmCriticalCB->hide(); @@ -842,44 +876,9 @@ void TelemetryPanel::setup() lock = false; } -void TelemetryPanel::populateVarioSource() -{ - AutoComboBox * cb = ui->varioSource; - cb->setField(model->frsky.varioSource, this); - cb->addItem(tr("Alti"), TELEMETRY_VARIO_SOURCE_ALTI); - cb->addItem(tr("Alti+"), TELEMETRY_VARIO_SOURCE_ALTI_PLUS); - cb->addItem(tr("VSpeed"), TELEMETRY_VARIO_SOURCE_VSPEED); - cb->addItem(tr("A1"), TELEMETRY_VARIO_SOURCE_A1); - cb->addItem(tr("A2"), TELEMETRY_VARIO_SOURCE_A2); -} - -void TelemetryPanel::populateVoltsSource() -{ - AutoComboBox * cb = ui->frskyVoltCB; - cb->setField(model->frsky.voltsSource, this); - cb->addItem(tr("A1"), TELEMETRY_VOLTS_SOURCE_A1); - cb->addItem(tr("A2"), TELEMETRY_VOLTS_SOURCE_A2); - cb->addItem(tr("A3"), TELEMETRY_VOLTS_SOURCE_A3); - cb->addItem(tr("A4"), TELEMETRY_VOLTS_SOURCE_A4); - cb->addItem(tr("FAS"), TELEMETRY_VOLTS_SOURCE_FAS); - cb->addItem(tr("Cells"), TELEMETRY_VOLTS_SOURCE_CELLS); -} - -void TelemetryPanel::populateCurrentSource() -{ - AutoComboBox * cb = ui->frskyCurrentCB; - cb->setField(model->frsky.currentSource, this); - cb->addItem(tr("---"), TELEMETRY_CURRENT_SOURCE_NONE); - cb->addItem(tr("A1"), TELEMETRY_CURRENT_SOURCE_A1); - cb->addItem(tr("A2"), TELEMETRY_CURRENT_SOURCE_A2); - cb->addItem(tr("A3"), TELEMETRY_CURRENT_SOURCE_A3); - cb->addItem(tr("A4"), TELEMETRY_CURRENT_SOURCE_A4); - cb->addItem(tr("FAS"), TELEMETRY_CURRENT_SOURCE_FAS); -} - void TelemetryPanel::on_telemetryProtocol_currentIndexChanged(int index) { - if (!lock) { + if (!isLocked()) { model->telemetryProtocol = index; emit modified(); } @@ -892,7 +891,7 @@ void TelemetryPanel::onModified() void TelemetryPanel::on_bladesCount_editingFinished() { - if (!lock) { + if (!isLocked()) { model->frsky.blades = ui->bladesCount->value(); emit modified(); } @@ -900,7 +899,7 @@ void TelemetryPanel::on_bladesCount_editingFinished() void TelemetryPanel::on_frskyProtoCB_currentIndexChanged(int index) { - if (!lock) { + if (!isLocked()) { model->frsky.usrProto = index; for (int i = 0; i < firmware->getCapability(TelemetryCustomScreens); i++) telemetryCustomScreens[i]->update(); @@ -910,31 +909,39 @@ void TelemetryPanel::on_frskyProtoCB_currentIndexChanged(int index) void TelemetryPanel::on_rssiAlarmWarningSB_editingFinished() { - model->rssiAlarms.warning= ui->rssiAlarmWarningSB->value(); - emit modified(); + if (!isLocked()) { + model->rssiAlarms.warning= ui->rssiAlarmWarningSB->value(); + emit modified(); + } } void TelemetryPanel::on_rssiAlarmCriticalSB_editingFinished() { - model->rssiAlarms.critical = ui->rssiAlarmCriticalSB->value(); - emit modified(); + if (!isLocked()) { + model->rssiAlarms.critical = ui->rssiAlarmCriticalSB->value(); + emit modified(); + } } void TelemetryPanel::on_varioLimitMin_DSB_editingFinished() { - model->frsky.varioMin = round(ui->varioLimitMin_DSB->value() + 10); - emit modified(); + if (!isLocked()) { + model->frsky.varioMin = round(ui->varioLimitMin_DSB->value() + 10); + emit modified(); + } } void TelemetryPanel::on_varioLimitMax_DSB_editingFinished() { - model->frsky.varioMax = round(ui->varioLimitMax_DSB->value() - 10); - emit modified(); + if (!isLocked()) { + model->frsky.varioMax = round(ui->varioLimitMax_DSB->value() - 10); + emit modified(); + } } void TelemetryPanel::on_varioLimitCenterMin_DSB_editingFinished() { - if (!lock) { + if (!isLocked()) { if (ui->varioLimitCenterMin_DSB->value() > ui->varioLimitCenterMax_DSB->value()) { ui->varioLimitCenterMax_DSB->setValue(ui->varioLimitCenterMin_DSB->value()); } @@ -945,7 +952,7 @@ void TelemetryPanel::on_varioLimitCenterMin_DSB_editingFinished() void TelemetryPanel::on_varioLimitCenterMax_DSB_editingFinished() { - if (!lock) { + if (!isLocked()) { if (ui->varioLimitCenterMin_DSB->value() > ui->varioLimitCenterMax_DSB->value()) { ui->varioLimitCenterMax_DSB->setValue(ui->varioLimitCenterMin_DSB->value()); } @@ -956,21 +963,27 @@ void TelemetryPanel::on_varioLimitCenterMax_DSB_editingFinished() void TelemetryPanel::on_fasOffset_DSB_editingFinished() { - model->frsky.fasOffset = ui->fasOffset_DSB->value() * 10; - emit modified(); + if (!isLocked()) { + model->frsky.fasOffset = ui->fasOffset_DSB->value() * 10; + emit modified(); + } } void TelemetryPanel::on_mahCount_SB_editingFinished() { - model->frsky.storedMah = ui->mahCount_SB->value(); - emit modified(); + if (!isLocked()) { + model->frsky.storedMah = ui->mahCount_SB->value(); + emit modified(); + } } void TelemetryPanel::on_mahCount_ChkB_toggled(bool checked) { - model->frsky.mAhPersistent = checked; - ui->mahCount_SB->setDisabled(!checked); - emit modified(); + if (!isLocked()) { + model->frsky.mAhPersistent = checked; + ui->mahCount_SB->setDisabled(!checked); + emit modified(); + } } void TelemetryPanel::on_clearAllSensors() @@ -980,9 +993,7 @@ void TelemetryPanel::on_clearAllSensors() model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_CLEAR, i); } - updateItemModels(); - update(); - emit modified(); + on_dataModifiedSensor(); } void TelemetryPanel::on_insertSensor(int selectedIndex) @@ -990,10 +1001,7 @@ void TelemetryPanel::on_insertSensor(int selectedIndex) memmove(&model->sensorData[selectedIndex + 1], &model->sensorData[selectedIndex], (CPN_MAX_SENSORS - (selectedIndex + 1)) * sizeof(SensorData)); model->sensorData[selectedIndex].clear(); model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1); - - updateItemModels(); - update(); - emit modified(); + on_dataModifiedSensor(); } void TelemetryPanel::on_deleteSensor(int selectedIndex) @@ -1004,10 +1012,7 @@ void TelemetryPanel::on_deleteSensor(int selectedIndex) memmove(&model->sensorData[selectedIndex], &model->sensorData[selectedIndex + 1], (CPN_MAX_SENSORS - (selectedIndex + 1)) * sizeof(SensorData)); model->sensorData[CPN_MAX_SENSORS - 1].clear(); model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1); - - updateItemModels(); - update(); - emit modified(); + on_dataModifiedSensor(); } void TelemetryPanel::on_moveUpSensor(int selectedIndex) @@ -1029,20 +1034,34 @@ void TelemetryPanel::swapData(int idx1, int idx2) memcpy(sd2, sd1, sizeof(SensorData)); memcpy(sd1, &sdtmp, sizeof(SensorData)); model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); - updateItemModels(); - update(); - emit modified(); + on_dataModifiedSensor(); } } void TelemetryPanel::on_dataModifiedSensor() { - updateItemModels(); - update(); + sharedItemModels->update(AbstractItemModel::IMUE_TeleSensors); emit modified(); } -void TelemetryPanel::updateItemModels() +void TelemetryPanel::connectItemModelEvents(const int id) { - commonItemModels->update(CommonItemModels::RMO_TELEMETRY_SENSORS); + FilteredItemModel * itemModel = panelFilteredItemModels->getItemModel(id); + connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &TelemetryPanel::onItemModelAboutToBeUpdated); + connect(itemModel, &FilteredItemModel::updateComplete, this, &TelemetryPanel::onItemModelUpdateComplete); +} + +void TelemetryPanel::onItemModelAboutToBeUpdated() +{ + lock = true; + modelsUpdateCnt++; +} + +void TelemetryPanel::onItemModelUpdateComplete() +{ + modelsUpdateCnt--; + if (modelsUpdateCnt < 1) { + update(); + lock = false; + } } diff --git a/companion/src/modeledit/telemetry.h b/companion/src/modeledit/telemetry.h index 9719c7df61..3f04bebf66 100644 --- a/companion/src/modeledit/telemetry.h +++ b/companion/src/modeledit/telemetry.h @@ -18,17 +18,15 @@ * GNU General Public License for more details. */ -#ifndef _TELEMETRY_H_ -#define _TELEMETRY_H_ +#pragma once #include "modeledit.h" #include "eeprominterface.h" +#include "filtereditemmodels.h" -constexpr char MIMETYPE_TELE_SENSOR[] = "application/x-companion-tele-sensor"; +constexpr char MIMETYPE_TELE_SENSOR[] {"application/x-companion-tele-sensor"}; class AutoComboBox; -class CommonItemModels; -class RawItemFilteredModel; class TimerEdit; namespace Ui { @@ -42,7 +40,8 @@ class TelemetryCustomScreen: public ModelPanel Q_OBJECT public: - TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware, RawItemFilteredModel * rawSourceModel); + TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware, + const bool & parentLock, FilteredItemModelFactory * panelFilteredItemModels); ~TelemetryCustomScreen(); void update(); @@ -54,8 +53,8 @@ class TelemetryCustomScreen: public ModelPanel void barMinChanged(double value); void barMaxChanged(double value); void barTimeChanged(); - void onModelDataAboutToBeUpdated(); - void onModelDataUpdateComplete(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: void updateBar(int line); @@ -67,6 +66,11 @@ class TelemetryCustomScreen: public ModelPanel QDoubleSpinBox * maxSB[4]; TimerEdit * minTime[4]; TimerEdit * maxTime[4]; + int modelsUpdateCnt; + const bool &parentLock; + + inline bool isLocked() { return lock | parentLock; } + void connectItemModelEvents(const FilteredItemModel * itemModel); }; class TelemetrySensorPanel: public ModelPanel @@ -74,7 +78,9 @@ class TelemetrySensorPanel: public ModelPanel Q_OBJECT public: - TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, int sensorCapability, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); + TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, int sensorCapability, ModelData & model, + GeneralSettings & generalSettings, Firmware * firmware, const bool & parentLock, + FilteredItemModelFactory * panelFilteredItemModels); ~TelemetrySensorPanel(); void update(); @@ -86,13 +92,7 @@ class TelemetrySensorPanel: public ModelPanel void moveUpSensor(int index); void moveDownSensor(int index); - protected slots: - void on_name_editingFinished(); - void on_type_currentIndexChanged(int index); - void on_formula_currentIndexChanged(int index); - void on_unit_currentIndexChanged(int index); - void on_prec_valueChanged(); void on_customContextMenuRequested(QPoint pos); bool hasClipboardData(QByteArray * data = nullptr) const; void cmCopy(); @@ -104,20 +104,27 @@ class TelemetrySensorPanel: public ModelPanel void cmDelete(); void cmMoveUp(); void cmMoveDown(); - - protected: - void updateSourcesComboBox(AutoComboBox * cb, bool negative); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); + void on_nameDataChanged(); + void on_formulaDataChanged(); + void on_unitDataChanged(); + void on_precDataChanged(); private: Ui::TelemetrySensor * ui; SensorData & sensor; - bool lock = false; int sensorIndex = 0; int selectedIndex = 0; int sensorCapability; bool insertAllowed() const; bool moveDownAllowed() const; bool moveUpAllowed() const; + int modelsUpdateCnt; + const bool &parentLock; + + inline bool isLocked() { return lock | parentLock; } + void connectItemModelEvents(const FilteredItemModel * itemModel); }; class TelemetryPanel : public ModelPanel @@ -125,7 +132,8 @@ class TelemetryPanel : public ModelPanel Q_OBJECT public: - TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels); + TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, + CompoundItemModelFactory * sharedItemModels); virtual ~TelemetryPanel(); virtual void update(); @@ -152,22 +160,22 @@ class TelemetryPanel : public ModelPanel void on_moveUpSensor(int index); void on_moveDownSensor(int index); void on_dataModifiedSensor(); + void onItemModelAboutToBeUpdated(); + void onItemModelUpdateComplete(); private: Ui::Telemetry *ui; - TelemetryCustomScreen * telemetryCustomScreens[4]; - TelemetrySensorPanel * sensorPanels[CPN_MAX_SENSORS]; + TelemetryCustomScreen *telemetryCustomScreens[4]; + TelemetrySensorPanel *sensorPanels[CPN_MAX_SENSORS]; int sensorCapability; - CommonItemModels * commonItemModels; - RawItemFilteredModel * rawSourceFilteredModel; + CompoundItemModelFactory *sharedItemModels; + CompoundItemModelFactory *panelItemModels; + FilteredItemModelFactory *panelFilteredItemModels; + int modelsUpdateCnt; void setup(); void telBarUpdate(); - void populateVoltsSource(); - void populateCurrentSource(); - void populateVarioSource(); void swapData(int idx1, int idx2); - void updateItemModels(); + void connectItemModelEvents(const int id); + inline bool isLocked() { return lock; } }; - -#endif // _TELEMETRY_H_ diff --git a/companion/src/modeledit/telemetry_sensor.ui b/companion/src/modeledit/telemetry_sensor.ui index 12af2cf069..e70cc7aa2d 100644 --- a/companion/src/modeledit/telemetry_sensor.ui +++ b/companion/src/modeledit/telemetry_sensor.ui @@ -40,7 +40,7 @@
- + 0 @@ -59,23 +59,13 @@ - + 0 0 - - - Custom - - - - - Calculated - - @@ -147,7 +137,7 @@
- + 0 @@ -175,58 +165,13 @@ - + 0 0 - - - Add - - - - - Average - - - - - Min - - - - - Max - - - - - Multiply - - - - - Totalize - - - - - Cell - - - - - Consumption - - - - - Dist - - @@ -412,138 +357,13 @@ - + 0 0 - - - Raw (-) - - - - - V - - - - - A - - - - - mA - - - - - kt - - - - - m/s - - - - - ft/s - - - - - km/h - - - - - mph - - - - - m - - - - - ft - - - - - °C - - - - - °F - - - - - % - - - - - mAh - - - - - W - - - - - mW - - - - - dBm - - - - - RPM - - - - - g - - - - - ° - - - - - Rad - - - - - mL - - - - - US fl.Oz. - - - - - ml/min - - @@ -560,7 +380,7 @@ - + @@ -720,9 +540,9 @@
autohexspinbox.h
- AutoPrecisionComboBox - QComboBox -
autoprecisioncombobox.h
+ AutoLineEdit + QLineEdit +
autolineedit.h
diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp index 61bfedda94..1d7df4f93f 100644 --- a/companion/src/modelprinter.cpp +++ b/companion/src/modelprinter.cpp @@ -298,27 +298,6 @@ QString ModelPrinter::printCenterBeep() return (strl.isEmpty() ? tr("None") : strl.join(" ")); } -QString ModelPrinter::printTimer(int idx) -{ - return printTimer(model.timers[idx]); -} - -QString ModelPrinter::printTimer(const TimerData & timer) -{ - QStringList result; - if (firmware->getCapability(TimersName) && timer.name[0]) - result += tr("Name") + QString("(%1)").arg(timer.name); - result += printTimeValue(timer.val, MASK_TIMEVALUE_HRSMINS | MASK_TIMEVALUE_ZEROHRS); - result += timer.mode.toString(); - if (timer.countdownBeep) - result += tr("Countdown") + QString("(%1)").arg(printTimerCountdownBeep(timer.countdownBeep)); - if (timer.minuteBeep) - result += tr("Minute call"); - if (timer.persistent) - result += tr("Persistent") + QString("(%1)").arg(printTimerPersistent(timer.persistent)); - return result.join(", "); -} - QString ModelPrinter::printTrim(int flightModeIndex, int stickIndex) { const FlightModeData & fm = model.flightModeData[flightModeIndex]; @@ -938,36 +917,6 @@ QString ModelPrinter::printFailsafeMode(unsigned int fsmode) } } -QString ModelPrinter::printTimerCountdownBeep(unsigned int countdownBeep) -{ - switch (countdownBeep) { - case TimerData::COUNTDOWN_SILENT: - return tr("Silent"); - case TimerData::COUNTDOWN_BEEPS: - return tr("Beeps"); - case TimerData::COUNTDOWN_VOICE: - return tr("Voice"); - case TimerData::COUNTDOWN_HAPTIC: - return tr("Haptic"); - default: - return CPN_STR_UNKNOWN_ITEM; - } -} - -QString ModelPrinter::printTimerPersistent(unsigned int persistent) -{ - switch (persistent) { - case 0: - return tr("OFF"); - case 1: - return tr("Flight"); - case 2: - return tr("Manual reset"); - default: - return CPN_STR_UNKNOWN_ITEM; - } -} - QString ModelPrinter::printSettingsTrim() { QStringList str; @@ -1032,26 +981,6 @@ QString ModelPrinter::printPPMFrameLength(int ppmFL) return QString::number(result); } -QString ModelPrinter::printTimerName(int idx) -{ - QString result; - result = tr("Tmr") + QString("%1").arg(idx+1); - if (firmware->getCapability(TimersName) && model.timers[idx].name[0]) - result.append(":" + QString(model.timers[idx].name)); - - return result; -} - -QString ModelPrinter::printTimerTimeValue(unsigned int val) -{ - return printTimeValue(val, MASK_TIMEVALUE_HRSMINS | MASK_TIMEVALUE_ZEROHRS); -} - -QString ModelPrinter::printTimerMinuteBeep(bool mb) -{ - return printBoolean(mb, BOOLEAN_YESNO); -} - QString ModelPrinter::printTelemetryProtocol(unsigned int val) { switch (val) { @@ -1071,17 +1000,6 @@ QString ModelPrinter::printRssiAlarmsDisabled(bool mb) return printBoolean(!mb, BOOLEAN_ENABLEDISABLE); } -QString ModelPrinter::printTelemetrySource(int val) -{ - QStringList strings = QStringList() << tr("None"); - - for (unsigned i=1; i<=CPN_MAX_SENSORS; ++i) { - strings << QString("%1").arg(model.sensorData[i-1].label); - } - - return QString("%1%2").arg((val < 0 ? "-" : "")).arg(strings.value(abs(val))); -} - QString ModelPrinter::printVarioSource(unsigned int val) { switch (val) { @@ -1155,144 +1073,6 @@ QString ModelPrinter::printIgnoreSensorIds(bool mb) return printBoolean(mb, BOOLEAN_ENABLEDISABLE); } -QString ModelPrinter::printSensorType(unsigned int val) -{ - switch (val) { - case SensorData::TELEM_TYPE_CUSTOM: - return tr("Custom"); - case SensorData::TELEM_TYPE_CALCULATED: - return tr("Calculated"); - default: - return CPN_STR_UNKNOWN_ITEM; - } -} - -QString ModelPrinter::printSensorFormula(unsigned int val) -{ - switch (val) { - case SensorData::TELEM_FORMULA_ADD: - return tr("Add"); - case SensorData::TELEM_FORMULA_AVERAGE: - return tr("Average"); - case SensorData::TELEM_FORMULA_MIN: - return tr("Min"); - case SensorData::TELEM_FORMULA_MAX: - return tr("Max"); - case SensorData::TELEM_FORMULA_MULTIPLY: - return tr("Multiply"); - case SensorData::TELEM_FORMULA_TOTALIZE: - return tr("Totalise"); - case SensorData::TELEM_FORMULA_CELL: - return tr("Cell"); - case SensorData::TELEM_FORMULA_CONSUMPTION: - return tr("Consumption"); - case SensorData::TELEM_FORMULA_DIST: - return tr("Distance"); - default: - return CPN_STR_UNKNOWN_ITEM; - } -} - -QString ModelPrinter::printSensorCells(unsigned int val) -{ - QStringList strings; - - strings << tr("Lowest"); - for (int i=1; i<=6; i++) - strings << tr("Cell %1").arg(i); - strings << tr("Highest") << tr("Delta"); - - return strings.value(val); -} - -QString ModelPrinter::printSensorTypeCond(unsigned int idx) -{ - if (!model.sensorData[idx].isAvailable()) - return ""; - else - return printSensorType(model.sensorData[idx].type); -} - -QString ModelPrinter::printSensorParams(unsigned int idx) -{ - QString str = ""; - SensorData sensor = model.sensorData[idx]; - - if (!sensor.isAvailable()) - return str; - - bool isConfigurable = false; - bool gpsFieldsPrinted = false; - bool cellsFieldsPrinted = false; - bool consFieldsPrinted = false; - bool ratioFieldsPrinted = false; - bool totalizeFieldsPrinted = false; - bool sources12FieldsPrinted = false; - bool sources34FieldsPrinted = false; - - if (sensor.type == SensorData::TELEM_TYPE_CALCULATED) { - isConfigurable = (sensor.formula < SensorData::TELEM_FORMULA_CELL); - gpsFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_DIST); - cellsFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_CELL); - consFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_CONSUMPTION); - sources12FieldsPrinted = (sensor.formula <= SensorData::TELEM_FORMULA_MULTIPLY); - sources34FieldsPrinted = (sensor.formula < SensorData::TELEM_FORMULA_MULTIPLY); - totalizeFieldsPrinted = (sensor.formula == SensorData::TELEM_FORMULA_TOTALIZE); - - str.append(printLabelValue(tr("F"), printSensorFormula(sensor.formula))); - } - else { - isConfigurable = sensor.unit < SensorData::UNIT_FIRST_VIRTUAL; - ratioFieldsPrinted = (sensor.unit < SensorData::UNIT_FIRST_VIRTUAL); - - str.append(printLabelValue(tr("Id"), QString::number(sensor.id,16).toUpper())); - str.append(printLabelValue(tr("Inst"), QString::number(sensor.instance))); - } - if (cellsFieldsPrinted) { - str.append(printLabelValue(tr("Sensor"), QString("%1 %2").arg(printTelemetrySource(sensor.source), false).arg(printSensorCells(sensor.index)))); - } - if (sources12FieldsPrinted) { - QStringList srcs; - for (int i=0;i<4;i++) { - if (i < 2 || sources34FieldsPrinted) { - srcs << printTelemetrySource(sensor.sources[i]); - } - } - str.append(printLabelValues(tr("Sources"), srcs)); - } - if (consFieldsPrinted || totalizeFieldsPrinted) - str.append(printLabelValue(tr("Sensor"), printTelemetrySource(sensor.amps))); - if (gpsFieldsPrinted) { - str.append(printLabelValue(tr("GPS"), printTelemetrySource(sensor.gps))); - str.append(printLabelValue(tr("Alt"), printTelemetrySource(sensor.alt))); - } - QString u = sensor.unitString(); - u = u.trimmed() == "" ? "-" : u; - str.append(printLabelValue(tr("Unit"), u)); - if (isConfigurable && sensor.unit != SensorData::UNIT_FAHRENHEIT) - str.append(printLabelValue(tr("Prec"), printTelemetryPrecision(sensor.prec))); - if (ratioFieldsPrinted) { - if (sensor.unit != SensorData::UNIT_RPMS) { - int prec = sensor.prec == 0 ? 1 : pow(10, sensor.prec); - str.append(printLabelValue(tr("Ratio"), QString::number((float)sensor.ratio / 10))); - str.append(printLabelValue(tr("Offset"), QString::number((float)sensor.offset / prec, 'f', sensor.prec))); - } - else if (sensor.unit == SensorData::UNIT_RPMS) { - str.append(printLabelValue(tr("Blades"), QString::number(sensor.ratio))); - str.append(printLabelValue(tr("Multi"), QString::number(sensor.offset))); - } - } - if (sensor.unit != SensorData::UNIT_RPMS && isConfigurable) - str.append(printLabelValue(tr("Auto Offset"), printBoolean(sensor.autoOffset, BOOLEAN_YN))); - if (isConfigurable) - str.append(printLabelValue(tr("Filter"), printBoolean(sensor.filter, BOOLEAN_YN))); - if (sensor.type == SensorData::TELEM_TYPE_CALCULATED) - str.append(printLabelValue(tr("Persist"), printBoolean(sensor.persistent, BOOLEAN_YN))); - str.append(printLabelValue(tr("Positive"), printBoolean(sensor.onlyPositive, BOOLEAN_YN))); - str.append(printLabelValue(tr("Log"), printBoolean(sensor.logs, BOOLEAN_YN), false)); - return str; -} - QString ModelPrinter::printTelemetryScreenType(unsigned int val) { switch (val) { @@ -1373,17 +1153,3 @@ QString ModelPrinter::printChecklist() } return str; } - -QString ModelPrinter::printTelemetryPrecision(unsigned int val) -{ - switch (val) { - case 0: - return tr("0."); - case 1: - return tr("0.0"); - case 2: - return tr("0.00"); - default: - return CPN_STR_UNKNOWN_ITEM; - } -} diff --git a/companion/src/modelprinter.h b/companion/src/modelprinter.h index 2cce3585d7..8be56bd64a 100644 --- a/companion/src/modelprinter.h +++ b/companion/src/modelprinter.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _MODELPRINTER_H_ -#define _MODELPRINTER_H_ +#pragma once #include #include @@ -68,8 +67,6 @@ class ModelPrinter: public QObject QString printTrim(int flightModeIndex, int stickIndex); QString printGlobalVar(int flightModeIndex, int gvarIndex); QString printRotaryEncoder(int flightModeIndex, int reIndex); - QString printTimer(int idx); - QString printTimer(const TimerData & timer); QString printInputName(int idx); QString printInputLine(int idx); QString printInputLine(const ExpoData & ed); @@ -105,33 +102,21 @@ class ModelPrinter: public QObject QString printFailsafe(int idx); QString printFailsafeMode(unsigned int fsmode); QString printFailsafeValue(int val); - QString printTimerCountdownBeep(unsigned int countdownBeep); - QString printTimerPersistent(unsigned int persistent); QString printPPMFrameLength(int ppmFL); - QString printTimerName(int idx); QString printTimeValue(const int value, const unsigned int mask); - QString printTimerMinuteBeep(bool mb); - QString printTimerTimeValue(unsigned int val); QString printTelemetryProtocol(unsigned int val); QString printLabelValue(const QString & lbl, const QString & val, const bool sep = false); QString printLabelValues(const QString & lbl, const QStringList & vals, const bool sep = false); QString printRssiAlarmsDisabled(bool mb); - QString printTelemetrySource(int val); QString printVarioSource(unsigned int val); QString printVarioCenterSilent(bool mb); QString printVoltsSource(unsigned int val); QString printCurrentSource(unsigned int val); QString printMahPersistent(bool mb); QString printIgnoreSensorIds(bool mb); - QString printSensorType(unsigned int val); - QString printSensorFormula(unsigned int val); - QString printSensorCells(unsigned int val); - QString printSensorTypeCond(unsigned int idx); - QString printSensorParams(unsigned int idx); QString printTelemetryScreenType(unsigned int val); QString printTelemetryScreen(unsigned int idx, unsigned int line, unsigned int width); QString printChecklist(); - QString printTelemetryPrecision(unsigned int val); private: Firmware * firmware; @@ -139,5 +124,3 @@ class ModelPrinter: public QObject const ModelData & model; }; - -#endif // _MODELPRINTER_H_ diff --git a/companion/src/multimodelprinter.cpp b/companion/src/multimodelprinter.cpp index 4da889cb1f..0ebef18847 100644 --- a/companion/src/multimodelprinter.cpp +++ b/companion/src/multimodelprinter.cpp @@ -334,18 +334,19 @@ QString MultiModelPrinter::printTimers() QString str; MultiColumns columns(modelPrinterMap.size()); columns.appendSectionTableStart(); - columns.appendRowHeader(QStringList() << tr("Timers") << tr("Time") << tr("Switch") << tr("Countdown") << tr("Min.call") << tr("Persist")); + columns.appendRowHeader(QStringList() << tr("Timers") << tr("Time") << tr("Switch") << tr("Countdown") << tr("Start") << tr("Min.call") << tr("Persist")); for (int i=0; igetCapability(Timers); i++) { columns.appendRowStart(); columns.appendCellStart(20, true); - COMPARE(modelPrinter->printTimerName(i)); + COMPARE(model->timers[i].nameToString(i)); columns.appendCellEnd(true); - COMPARECELLWIDTH(modelPrinter->printTimerTimeValue(model->timers[i].val), 15); - COMPARECELLWIDTH(model->timers[i].mode.toString(), 15); - COMPARECELLWIDTH(modelPrinter->printTimerCountdownBeep(model->timers[i].countdownBeep), 15); - COMPARECELLWIDTH(modelPrinter->printTimerMinuteBeep(model->timers[i].minuteBeep), 15); - COMPARECELLWIDTH(modelPrinter->printTimerPersistent(model->timers[i].persistent), 20); + COMPARECELLWIDTH(model->timers[i].valToString(), 10); + COMPARECELLWIDTH(model->timers[i].mode.toString(), 10); + COMPARECELLWIDTH(model->timers[i].countdownBeepToString(), 10); + COMPARECELLWIDTH(model->timers[i].countdownStartToString(), 10); + COMPARECELLWIDTH(DataHelpers::boolToString(model->timers[i].minuteBeep, DataHelpers::BOOL_FMT_YESNO), 10); + COMPARECELLWIDTH(model->timers[i].persistentToString(false), 15); columns.appendRowEnd(); } columns.appendTableEnd(); @@ -777,7 +778,7 @@ QString MultiModelPrinter::printTelemetry() if (firmware->getCapability(HasVario)) { columns.appendRowStart(tr("Altimetry"), 20); if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { - LABELCOMPARECELL(tr("Vario source"), modelPrinter->printTelemetrySource(model->frsky.varioSource), 80); + LABELCOMPARECELL(tr("Vario source"), SensorData::sourceToString(model, model->frsky.varioSource), 80); } else { LABELCOMPARECELL(tr("Vario source"), modelPrinter->printVarioSource(model->frsky.varioSource), 80); @@ -801,8 +802,8 @@ QString MultiModelPrinter::printTelemetry() if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { columns.appendRowStart(tr("Top Bar"), 20); columns.appendCellStart(80); - COMPARESTRING(tr("Volts source"), modelPrinter->printTelemetrySource(model->frsky.voltsSource), true); - COMPARESTRING(tr("Altitude source"), modelPrinter->printTelemetrySource(model->frsky.altitudeSource), false); + COMPARESTRING(tr("Volts source"), SensorData::sourceToString(model, model->frsky.voltsSource), true); + COMPARESTRING(tr("Altitude source"), SensorData::sourceToString(model, model->frsky.altitudeSource), false); columns.appendCellEnd(); columns.appendRowEnd(); } @@ -822,9 +823,9 @@ QString MultiModelPrinter::printSensors() int count = 0; columns.appendSectionTableStart(); columns.appendRowHeader(QStringList() << tr("Name") << tr("Type") << tr("Parameters")); - for (unsigned i=0; isensorData[i].isAvailable()) { tsEmpty = false; break; @@ -836,8 +837,8 @@ QString MultiModelPrinter::printSensors() columns.appendCellStart(20, true); COMPARE(model->sensorData[i].nameToString(i)); columns.appendCellEnd(true); - COMPARECELLWIDTH(modelPrinter->printSensorTypeCond(i), 15); - COMPARECELLWIDTH(modelPrinter->printSensorParams(i), 65); + COMPARECELLWIDTH(model->sensorData[i].isAvailable() ? model->sensorData[i].typeToString() : "", 15); + COMPARECELLWIDTH(model->sensorData[i].paramsToString(model), 65); columns.appendRowEnd(); } } diff --git a/companion/src/shared/CMakeLists.txt b/companion/src/shared/CMakeLists.txt index 2fbbafbf97..ffd5942bfd 100644 --- a/companion/src/shared/CMakeLists.txt +++ b/companion/src/shared/CMakeLists.txt @@ -16,6 +16,7 @@ set(shared_HDRS genericpanel.h hexspinbox.h autoprecisioncombobox.h + autotimeedit.h ) qt5_wrap_cpp(shared_SRCS ${shared_HDRS}) diff --git a/companion/src/shared/autobitsetcheckbox.h b/companion/src/shared/autobitsetcheckbox.h index 6274e01179..af831948e3 100644 --- a/companion/src/shared/autobitsetcheckbox.h +++ b/companion/src/shared/autobitsetcheckbox.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef AUTOBITSETCHECKBOX_H -#define AUTOBITSETCHECKBOX_H +#pragma once #include #include "genericpanel.h" @@ -35,7 +34,8 @@ class AutoBitsetCheckBox: public QCheckBox Q_PROPERTY(int toggleMask READ toggleMask WRITE setToggleMask) public: - explicit AutoBitsetCheckBox(QWidget *parent = nullptr) : AutoBitsetCheckBox(QString(), parent) {} + explicit AutoBitsetCheckBox(QWidget *parent = nullptr) : + AutoBitsetCheckBox(QString(), parent) {} explicit AutoBitsetCheckBox(const QString &text, QWidget *parent = nullptr) : QCheckBox(text, parent) { @@ -43,26 +43,32 @@ class AutoBitsetCheckBox: public QCheckBox } // int field constructors - explicit AutoBitsetCheckBox(int & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) : AutoBitsetCheckBox(field, bitmask, false, text, parent) {} - explicit AutoBitsetCheckBox(int & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) : QCheckBox(text, parent) + explicit AutoBitsetCheckBox(int & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) : + AutoBitsetCheckBox(field, bitmask, false, text, parent) {} + explicit AutoBitsetCheckBox(int & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) : + QCheckBox(text, parent) { setField(field, bitmask, invert); init(); } - explicit AutoBitsetCheckBox(int & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) : QCheckBox(text, parent) + explicit AutoBitsetCheckBox(int & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) : + QCheckBox(text, parent) { setField(field, bitmask, false, toggleMask); init(); } // unsigned field constructors - explicit AutoBitsetCheckBox(unsigned & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) : AutoBitsetCheckBox(field, bitmask, false, text, parent) {} - explicit AutoBitsetCheckBox(unsigned & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) : QCheckBox(text, parent) + explicit AutoBitsetCheckBox(unsigned & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) : + AutoBitsetCheckBox(field, bitmask, false, text, parent) {} + explicit AutoBitsetCheckBox(unsigned & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) : + QCheckBox(text, parent) { setField(field, bitmask, invert); init(); } - explicit AutoBitsetCheckBox(unsigned & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) : QCheckBox(text, parent) + explicit AutoBitsetCheckBox(unsigned & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) : + QCheckBox(text, parent) { setField(field, bitmask, false, toggleMask); init(); @@ -105,6 +111,8 @@ class AutoBitsetCheckBox: public QCheckBox void updateValue() { + if (m_panel && m_panel->lock) + return; if (!m_field) return; const bool oldLock = setLocked(true); @@ -174,5 +182,3 @@ class AutoBitsetCheckBox: public QCheckBox bool m_lock = false; GenericPanel * m_panel = nullptr; }; - -#endif // AUTOBITSETCHECKBOX_H diff --git a/companion/src/shared/autocheckbox.h b/companion/src/shared/autocheckbox.h index df99278a20..1c1a7207c4 100644 --- a/companion/src/shared/autocheckbox.h +++ b/companion/src/shared/autocheckbox.h @@ -18,57 +18,64 @@ * GNU General Public License for more details. */ -#ifndef _AUTOCHECKBOX_H_ -#define _AUTOCHECKBOX_H_ +#pragma once #include -#include "modeledit/modeledit.h" +#include "genericpanel.h" class AutoCheckBox: public QCheckBox { Q_OBJECT public: - explicit AutoCheckBox(QWidget *parent = 0): + explicit AutoCheckBox(QWidget * parent = nullptr): QCheckBox(parent), - field(NULL), - panel(NULL), + field(nullptr), + panel(nullptr), lock(false) { connect(this, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool))); } - void setField(bool & field, ModelPanel * panel=NULL) + void setField(bool & field, GenericPanel * panel = nullptr) { this->field = &field; this->panel = panel; updateValue(); } + void setEnabled(bool enabled) + { + QCheckBox::setEnabled(enabled); + } + void updateValue() { - lock = true; if (field) { + lock = true; setChecked(*field); + lock = false; } - lock = false; } + signals: + void currentDataChanged(bool value); + protected slots: void onToggled(bool checked) { + if (panel && panel->lock) + return; if (field && !lock) { *field = checked; - if (panel) { + emit currentDataChanged(checked); + if (panel) emit panel->modified(); - } } } protected: - bool * field; - ModelPanel * panel; - bool lock; + bool *field = nullptr; + GenericPanel *panel = nullptr; + bool lock = false; }; - -#endif // _AUTOCHECKBOX_H_ diff --git a/companion/src/shared/autocombobox.h b/companion/src/shared/autocombobox.h index fcb1845ac3..ca60545558 100644 --- a/companion/src/shared/autocombobox.h +++ b/companion/src/shared/autocombobox.h @@ -18,78 +18,134 @@ * GNU General Public License for more details. */ -#ifndef _AUTOCOMBOBOX_H_ -#define _AUTOCOMBOBOX_H_ +#pragma once #include #include "genericpanel.h" +#include "rawsource.h" +#include "rawswitch.h" class AutoComboBox: public QComboBox { Q_OBJECT public: - explicit AutoComboBox(QWidget *parent = nullptr): - QComboBox(parent) + explicit AutoComboBox(QWidget * parent = nullptr): + QComboBox(parent), + field(nullptr), + panel(nullptr), + next(0), + lock(false), + hasModel(false), + rawSource(nullptr), + rawSwitch(nullptr) { connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int))); } void clear() { - lock = true; - QComboBox::clear(); - next = 0; - lock = false; + if (!hasModel) { + lock = true; + QComboBox::clear(); + next = 0; + lock = false; + } } virtual void insertItems(int index, const QStringList & items) { - foreach(QString item, items) { - addItem(item); + if (!hasModel) { + foreach(QString item, items) { + addItem(item); + } } } virtual void addItem(const QString & item) { - addItem(item, next++); + if (!hasModel) + addItem(item, next++); } virtual void addItem(const QString & item, int value) { - lock = true; - QComboBox::addItem(item, value); - lock = false; - updateValue(); + if (!hasModel) { + lock = true; + QComboBox::addItem(item, value); + lock = false; + updateValue(); + } } - void setField(unsigned int & field, GenericPanel * panel=nullptr) + void setField(unsigned int & field, GenericPanel * panel = nullptr) { this->field = (int *)&field; + this->rawSource = nullptr; + this->rawSwitch = nullptr; this->panel = panel; updateValue(); } - void setField(int & field, GenericPanel * panel=nullptr) + void setField(int & field, GenericPanel * panel = nullptr) { this->field = &field; + this->rawSource = nullptr; + this->rawSwitch = nullptr; this->panel = panel; updateValue(); } + void setField(RawSource & field, GenericPanel * panel = nullptr) + { + this->rawSource = &field; + this->rawSwitch = nullptr; + this->field = nullptr; + this->panel = panel; + updateValue(); + } + + void setField(RawSwitch & field, GenericPanel * panel = nullptr) + { + this->rawSwitch = &field; + this->rawSource = nullptr; + this->field = nullptr; + this->panel = panel; + updateValue(); + } + + void setModel(QAbstractItemModel * model) + { + lock = true; + QComboBox::setModel(model); + lock = false; + hasModel = true; + updateValue(); + } + void setAutoIndexes() { - for (int i=0; itoValue())); + else if (rawSwitch) + setCurrentIndex(findData(rawSwitch->toValue())); + lock = false; } @@ -99,20 +155,39 @@ class AutoComboBox: public QComboBox protected slots: void onCurrentIndexChanged(int index) { - const int val = itemData(index).toInt(); - if (field && !lock) { + if (panel && panel->lock) + return; + if (lock || index < 0) + return; + + bool ok; + const int val = itemData(index).toInt(&ok); + if (!ok) + return; + + if (field && *field != val) { *field = val; - if (panel) - emit panel->modified(); } + else if (rawSource && rawSource->toValue() != val) { + *rawSource = RawSource(val); + } + else if (rawSwitch && rawSwitch->toValue() != val) { + *rawSwitch = RawSwitch(val); + } + else + return; + emit currentDataChanged(val); + if (panel) + emit panel->modified(); } protected: - int * field = nullptr; - GenericPanel * panel = nullptr; + int *field = nullptr; + GenericPanel *panel = nullptr; int next = 0; bool lock = false; + bool hasModel = false; + RawSource *rawSource = nullptr; + RawSwitch *rawSwitch = nullptr; }; - -#endif // _AUTOCOMBOBOX_H_ diff --git a/companion/src/shared/autodoublespinbox.h b/companion/src/shared/autodoublespinbox.h index 17188243b0..a6466269eb 100644 --- a/companion/src/shared/autodoublespinbox.h +++ b/companion/src/shared/autodoublespinbox.h @@ -18,11 +18,10 @@ * GNU General Public License for more details. */ -#ifndef _AUTODOUBLESPINBOX_H_ -#define _AUTODOUBLESPINBOX_H_ +#pragma once #include -#include "modeledit/modeledit.h" +#include "genericpanel.h" #if __GNUC__ #include #endif @@ -32,23 +31,23 @@ class AutoDoubleSpinBox: public QDoubleSpinBox Q_OBJECT public: - explicit AutoDoubleSpinBox(QWidget *parent = 0): + explicit AutoDoubleSpinBox(QWidget * parent = nullptr): QDoubleSpinBox(parent), - field(NULL), - panel(NULL), + field(nullptr), + panel(nullptr), lock(false) { connect(this, SIGNAL(valueChanged(double)), this, SLOT(onValueChanged(double))); } - void setField(int & field, ModelPanel * panel=NULL) + void setField(int & field, GenericPanel * panel = nullptr) { this->field = &field; this->panel = panel; updateValue(); } - void setField(unsigned int & field, ModelPanel * panel=NULL) + void setField(unsigned int & field, GenericPanel * panel = nullptr) { this->field = (int *)&field; this->panel = panel; @@ -58,7 +57,9 @@ class AutoDoubleSpinBox: public QDoubleSpinBox void updateValue() { if (field) { - setValue(float(*field)/multiplier()); + lock = true; + setValue(float(*field) / multiplier()); + lock = false; } } @@ -81,11 +82,17 @@ class AutoDoubleSpinBox: public QDoubleSpinBox } } + signals: + void currentDataChanged(double value); + protected slots: void onValueChanged(double value) { + if (panel && panel->lock) + return; if (field && !lock) { *field = round(value * multiplier()); + emit currentDataChanged(value); if (panel) { emit panel->modified(); } @@ -93,9 +100,7 @@ class AutoDoubleSpinBox: public QDoubleSpinBox } protected: - int * field; - ModelPanel * panel; - bool lock; + int * field = nullptr; + GenericPanel * panel = nullptr; + bool lock = false; }; - -#endif // _AUTODOUBLESPINBOX_H_ diff --git a/companion/src/shared/autohexspinbox.h b/companion/src/shared/autohexspinbox.h index 7db76d2a3c..40cc24da41 100644 --- a/companion/src/shared/autohexspinbox.h +++ b/companion/src/shared/autohexspinbox.h @@ -18,27 +18,26 @@ * GNU General Public License for more details. */ -#ifndef _AUTOHEXSPINBOX_H_ -#define _AUTOHEXSPINBOX_H_ +#pragma once #include "hexspinbox.h" -#include "modeledit/modeledit.h" +#include "genericpanel.h" class AutoHexSpinBox: public HexSpinBox { Q_OBJECT public: - explicit AutoHexSpinBox(QWidget *parent = 0): + explicit AutoHexSpinBox(QWidget * parent = nullptr): HexSpinBox(parent), - field(NULL), - panel(NULL), + field(nullptr), + panel(nullptr), lock(false) { connect(this, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged(int))); } - void setField(unsigned int & field, ModelPanel * panel=NULL) + void setField(unsigned int & field, GenericPanel * panel = nullptr) { this->field = &field; this->panel = panel; @@ -48,15 +47,23 @@ class AutoHexSpinBox: public HexSpinBox void updateValue() { if (field) { + lock = true; setValue(*field); + lock = false; } } + signals: + void currentDataChanged(int value); + protected slots: void onValueChanged(int value) { + if (panel && panel->lock) + return; if (field && !lock) { *field = value; + emit currentDataChanged(value); if (panel) { emit panel->modified(); } @@ -64,9 +71,7 @@ class AutoHexSpinBox: public HexSpinBox } protected: - unsigned int * field; - ModelPanel * panel; - bool lock; + unsigned int * field = nullptr; + GenericPanel * panel = nullptr; + bool lock = false; }; - -#endif // _AUTOHEXSPINBOX_H_ diff --git a/companion/src/shared/autolineedit.h b/companion/src/shared/autolineedit.h index 36d8489726..b2815796ce 100644 --- a/companion/src/shared/autolineedit.h +++ b/companion/src/shared/autolineedit.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _AUTOLINEEDIT_H_ -#define _AUTOLINEEDIT_H_ +#pragma once #include #include @@ -30,11 +29,11 @@ class AutoLineEdit: public QLineEdit Q_OBJECT public: - explicit AutoLineEdit(QWidget *parent = nullptr, bool updateOnChange = false): + explicit AutoLineEdit(QWidget * parent = nullptr, bool updateOnChange = false): QLineEdit(parent), field(NULL), - strField(NULL), - panel(NULL), + strField(nullptr), + panel(nullptr), lock(false) { if (updateOnChange) @@ -71,9 +70,14 @@ class AutoLineEdit: public QLineEdit lock = false; } + signals: + void currentDataChanged(); + protected slots: void onEdited() { + if (panel && panel->lock) + return; if (lock) return; @@ -84,15 +88,15 @@ class AutoLineEdit: public QLineEdit else return; + emit currentDataChanged(); + if (panel) emit panel->modified(); } protected: char * field; - QString * strField; - GenericPanel * panel; - bool lock; + QString * strField = nullptr; + GenericPanel * panel = nullptr; + bool lock = false; }; - -#endif // _AUTOLINEEDIT_H_ diff --git a/companion/src/shared/autoprecisioncombobox.h b/companion/src/shared/autoprecisioncombobox.h index 4e143f2869..72dd894064 100644 --- a/companion/src/shared/autoprecisioncombobox.h +++ b/companion/src/shared/autoprecisioncombobox.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _AUTOPRECISIONCOMBOBOX_H_ -#define _AUTOPRECISIONCOMBOBOX_H_ +#pragma once #include "genericpanel.h" @@ -124,7 +123,7 @@ class AutoPrecisionComboBox: public QComboBox if (*m_field != val) { *m_field = rangecheckDecimals(val); updateValue(); - emit valueChanged(); + emit currentDataChanged(value); } } @@ -135,7 +134,7 @@ class AutoPrecisionComboBox: public QComboBox if (*m_field != value) { *m_field = rangecheckDecimals(value); updateValue(); - emit valueChanged(); + emit currentDataChanged((int)value); } } @@ -161,7 +160,7 @@ class AutoPrecisionComboBox: public QComboBox } signals: - void valueChanged(); + void currentDataChanged(int index); protected slots: void init() @@ -204,13 +203,13 @@ class AutoPrecisionComboBox: public QComboBox void onCurrentIndexChanged(int index) { - if (index < 0) + if (index < 0 || (m_panel && m_panel->lock) || m_lock) return; - if (m_field && !m_lock) { + if (m_field) { *m_field = itemData(index).toUInt(); + emit currentDataChanged(index); if (m_panel) emit m_panel->modified(); - emit valueChanged(); } } @@ -253,5 +252,3 @@ class AutoPrecisionComboBox: public QComboBox QString m_suffix = ""; bool m_lock = false; }; - -#endif // _AUTOPRECISIONCOMBOBOX_H_ diff --git a/companion/src/shared/autotimeedit.h b/companion/src/shared/autotimeedit.h new file mode 100644 index 0000000000..2ba75d70ec --- /dev/null +++ b/companion/src/shared/autotimeedit.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +#include +#include "genericpanel.h" + +class AutoTimeEdit: public QTimeEdit +{ + Q_OBJECT + + public: + explicit AutoTimeEdit(QWidget * parent = nullptr): + QTimeEdit(parent), + field(nullptr), + panel(nullptr), + lock(false) + { + connect(this, SIGNAL(timeChanged(QTime)), this, SLOT(onTimeChanged(QTime))); + } + + void setField(unsigned int & field, GenericPanel * panel = nullptr) + { + this->field = &field; + this->panel = panel; + updateValue(); + } + + void setMinimumTime(const QTime time) + { + QTimeEdit::setMinimumTime(time); + } + + void setMaximumTime(const QTime time) + { + QTimeEdit::setMaximumTime(time); + } + + void setEnabled(bool enabled) + { + QTimeEdit::setEnabled(enabled); + } + + void updateValue() + { + if (field) { + lock = true; + int hour = *field / 3600; + int min = (*field - (hour * 3600)) / 60; + int sec = (*field - (hour * 3600)) % 60; + setTime(QTime(hour, min, sec)); + lock = false; + } + } + + signals: + void currentDataChanged(unsigned int value); + + protected slots: + void onTimeChanged(QTime time) + { + if (panel && panel->lock) + return; + if (!field || lock) + return; + + unsigned int val = time.hour() * 3600 + time.minute() * 60 + time.second(); + if (*field != val) { + *field = val; + emit currentDataChanged(val); + if (panel) + emit panel->modified(); + } + } + + protected: + unsigned int *field = nullptr; + GenericPanel *panel = nullptr; + bool lock = false; +}; + diff --git a/companion/src/shared/genericpanel.h b/companion/src/shared/genericpanel.h index 5351355b64..88c7f841b4 100644 --- a/companion/src/shared/genericpanel.h +++ b/companion/src/shared/genericpanel.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _GENERICPANEL_H_ -#define _GENERICPANEL_H_ +#pragma once #include @@ -40,6 +39,8 @@ class GenericPanel : public QWidget friend class AutoLineEdit; friend class GVarGroup; friend class AutoPrecisionComboBox; + friend class AutoBitsetCheckBox; + friend class AutoTimeEdit; public: GenericPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware); @@ -65,5 +66,3 @@ class GenericPanel : public QWidget void setFocusFilter(QWidget * w); void disableMouseScrolling(); }; - -#endif // _GENERICPANEL_H_ diff --git a/companion/src/shared/hexspinbox.h b/companion/src/shared/hexspinbox.h index fc404d98a0..204cc8a552 100644 --- a/companion/src/shared/hexspinbox.h +++ b/companion/src/shared/hexspinbox.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _HEXSPINBOX_H_ -#define _HEXSPINBOX_H_ +#pragma once #include @@ -40,5 +39,3 @@ class HexSpinBox : public QSpinBox private: QRegExpValidator *validator; }; - -#endif // _HEXSPINBOX_H_ diff --git a/companion/src/shared/verticalscrollarea.h b/companion/src/shared/verticalscrollarea.h index 36f564dd7c..d409a18ca9 100644 --- a/companion/src/shared/verticalscrollarea.h +++ b/companion/src/shared/verticalscrollarea.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _VERTICALSCROLLAREA_H_ -#define _VERTICALSCROLLAREA_H_ +#pragma once #include @@ -36,6 +35,3 @@ class VerticalScrollArea : public QScrollArea private: GenericPanel * panel; }; - -#endif // _VERTICALSCROLLAREA_H_ - diff --git a/companion/src/simulation/CMakeLists.txt b/companion/src/simulation/CMakeLists.txt index d2d6c77de8..339a649ba4 100644 --- a/companion/src/simulation/CMakeLists.txt +++ b/companion/src/simulation/CMakeLists.txt @@ -13,9 +13,11 @@ set(simulation_SRCS simulateduiwidgetX10.cpp simulateduiwidgetX12.cpp simulateduiwidgetJumperT12.cpp + simulateduiwidgetJumperTLITE.cpp simulateduiwidgetJumperT16.cpp simulateduiwidgetJumperT18.cpp simulateduiwidgetTX12.cpp + simulateduiwidgetT8.cpp simulateduiwidgetTX16S.cpp simulatorinterface.cpp simulatormainwindow.cpp @@ -40,9 +42,11 @@ set(simulation_UIS simulateduiwidgetX10.ui simulateduiwidgetX12.ui simulateduiwidgetJumperT12.ui + simulateduiwidgetJumperTLITE.ui simulateduiwidgetJumperT16.ui simulateduiwidgetJumperT18.ui simulateduiwidgetTX12.ui + simulateduiwidgetT8.ui simulateduiwidgetTX16S.ui simulatormainwindow.ui simulatorstartupdialog.ui diff --git a/companion/src/simulation/simulateduiwidget.h b/companion/src/simulation/simulateduiwidget.h index 66939f429f..f9d92ecd7a 100644 --- a/companion/src/simulation/simulateduiwidget.h +++ b/companion/src/simulation/simulateduiwidget.h @@ -112,10 +112,12 @@ namespace Ui { class SimulatedUIWidgetX10; class SimulatedUIWidgetX12; class SimulatedUIWidgetJumperT12; + class SimulatedUIWidgetJumperTLITE; class SimulatedUIWidgetJumperT16; class SimulatedUIWidgetJumperT18; class SimulatedUIWidgetTX16S; class SimulatedUIWidgetTX12; + class SimulatedUIWidgetT8; } class SimulatedUIWidget9X: public SimulatedUIWidget @@ -242,6 +244,18 @@ class SimulatedUIWidgetJumperT12: public SimulatedUIWidget Ui::SimulatedUIWidgetJumperT12 * ui; }; +class SimulatedUIWidgetJumperTLITE: public SimulatedUIWidget +{ + Q_OBJECT + + public: + explicit SimulatedUIWidgetJumperTLITE(SimulatorInterface * simulator, QWidget * parent = NULL); + virtual ~SimulatedUIWidgetJumperTLITE(); + + private: + Ui::SimulatedUIWidgetJumperTLITE * ui; +}; + class SimulatedUIWidgetJumperT16: public SimulatedUIWidget { Q_OBJECT @@ -278,6 +292,17 @@ class SimulatedUIWidgetTX12: public SimulatedUIWidget Ui::SimulatedUIWidgetTX12 * ui; }; +class SimulatedUIWidgetT8: public SimulatedUIWidget +{ +Q_OBJECT + +public: + explicit SimulatedUIWidgetT8(SimulatorInterface * simulator, QWidget * parent = nullptr); + virtual ~SimulatedUIWidgetT8(); + +private: + Ui::SimulatedUIWidgetT8 * ui; +}; class SimulatedUIWidgetTX16S: public SimulatedUIWidget { diff --git a/companion/src/simulation/simulateduiwidgetJumperTLITE.cpp b/companion/src/simulation/simulateduiwidgetJumperTLITE.cpp new file mode 100644 index 0000000000..2d55408370 --- /dev/null +++ b/companion/src/simulation/simulateduiwidgetJumperTLITE.cpp @@ -0,0 +1,60 @@ +#include "simulateduiwidget.h" +#include "ui_simulateduiwidgetJumperTLITE.h" + +// NOTE: RadioUiAction(NUMBER,...): NUMBER relates to enum EnumKeys in the specific board.h + +SimulatedUIWidgetJumperTLITE::SimulatedUIWidgetJumperTLITE(SimulatorInterface *simulator, QWidget * parent): + SimulatedUIWidget(simulator, parent), + ui(new Ui::SimulatedUIWidgetJumperTLITE) +{ + RadioUiAction * act; + + ui->setupUi(this); + + act = new RadioUiAction(3, QList() << Qt::Key_Up << Qt::Key_PageUp, SIMU_STR_HLP_KEYS_GO_UP, SIMU_STR_HLP_ACT_UP); + addRadioWidget(ui->rightbuttons->addArea(QRect(40, 15, 70, 50), "JumperTLITE/right_top.png", act)); + + act = new RadioUiAction(2, QList() << Qt::Key_Down << Qt::Key_PageDown, SIMU_STR_HLP_KEYS_GO_DN, SIMU_STR_HLP_ACT_DN); + addRadioWidget(ui->rightbuttons->addArea(QRect(47, 65, 70, 50), "JumperTLITE/right_bottom.png", act)); + + act = new RadioUiAction(4, QList() << Qt::Key_Right << Qt::Key_Plus, SIMU_STR_HLP_KEY_RGT % "|" % SIMU_STR_HLP_KEY_PLS, SIMU_STR_HLP_ACT_PLS); + addRadioWidget(ui->bottombuttons->addArea(QRect(150, 73, 80, 30), "JumperTLITE/bottom_right.png", act)); + + act = new RadioUiAction(5, QList() << Qt::Key_Left << Qt::Key_Minus, SIMU_STR_HLP_KEY_LFT % "|" % SIMU_STR_HLP_KEY_MIN, SIMU_STR_HLP_ACT_MIN); + addRadioWidget(ui->bottombuttons->addArea(QRect(24, 73, 80, 30), "JumperTLITE/bottom_left.png", act)); + + m_mouseMidClickAction = new RadioUiAction(1, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_ACTIVATE, SIMU_STR_HLP_ACT_ENT); + addRadioWidget(ui->leftbuttons->addArea(QRect(5, 15, 70, 50), "JumperTLITE/left_top.png", m_mouseMidClickAction)); + + act = new RadioUiAction(0, QList() << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, SIMU_STR_HLP_KEYS_EXIT, SIMU_STR_HLP_ACT_EXIT); + addRadioWidget(ui->leftbuttons->addArea(QRect(10, 65, 70, 50), "JumperTLITE/left_bottom.png", act)); + + //addRadioWidget(ui->leftbuttons->addArea(QRect(10, 65, 70, 50), "JumperTLITE/left_scrnshot.png", m_screenshotAction)); + + m_backlightColors << QColor(215, 243, 255); // X7 Blue + m_backlightColors << QColor(166,247,159); + m_backlightColors << QColor(247,159,166); + m_backlightColors << QColor(255,195,151); + m_backlightColors << QColor(247,242,159); + + setLcd(ui->lcd); + + QString css = "#radioUiWidget {" + "background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1," + "stop:0 rgba(255, 255, 255, 255)," + "stop:0.757062 rgba(241, 238, 238, 255)," + "stop:1 rgba(247, 245, 245, 255));" + "}"; + + QTimer * tim = new QTimer(this); + tim->setSingleShot(true); + connect(tim, &QTimer::timeout, [this, css]() { + emit customStyleRequest(css); + }); + tim->start(100); +} + +SimulatedUIWidgetJumperTLITE::~SimulatedUIWidgetJumperTLITE() +{ + delete ui; +} diff --git a/companion/src/simulation/simulateduiwidgetJumperTLITE.ui b/companion/src/simulation/simulateduiwidgetJumperTLITE.ui new file mode 100644 index 0000000000..407b3954d6 --- /dev/null +++ b/companion/src/simulation/simulateduiwidgetJumperTLITE.ui @@ -0,0 +1,258 @@ + + + SimulatedUIWidgetJumperTLITE + + + + 0 + 0 + 501 + 310 + + + + + 0 + 0 + + + + + 501 + 310 + + + + + 501 + 310 + + + + Jumper T-Lite Simulator + + + background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.757062 rgba(241, 238, 238, 255), stop:1 rgba(247, 245, 245, 255)); + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 122 + 287 + + + + + 122 + 287 + + + + background:url(:/images/simulator/JumperTLITE/left.png); + + + + + + + + 0 + 0 + + + + + 800 + 155 + + + + + 800 + 155 + + + + background-color: rgb(215, 243, 255); + + + + + + + + 0 + 0 + + + + + 122 + 287 + + + + + 122 + 287 + + + + background:url(:/images/simulator/JumperTLITE/right.png) + + + + + + + + 0 + 0 + + + + + 258 + 26 + + + + + 258 + 26 + + + + background:url(:/images/simulator/JumperTLITE/top.png) + + + + + + + + 0 + 0 + + + + + 258 + 106 + + + + + 258 + 106 + + + + background:url(:/images/simulator/JumperTLITE/bottom.png) + + + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + 16777215 + 12 + + + + + 0 + 12 + + + + background-color: rgb(255, 255, 255); + + + + + + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + 16777215 + 10 + + + + background-color: rgb(247, 245, 245); + + + + + + + + + + + LcdWidget + QWidget +
lcdwidget.h
+ 1 +
+ + ButtonsWidget + QWidget +
buttonswidget.h
+ 1 +
+
+ + +
diff --git a/companion/src/simulation/simulateduiwidgetT8.cpp b/companion/src/simulation/simulateduiwidgetT8.cpp new file mode 100644 index 0000000000..ed86889d7b --- /dev/null +++ b/companion/src/simulation/simulateduiwidgetT8.cpp @@ -0,0 +1,67 @@ +#include "simulateduiwidget.h" +#include "ui_simulateduiwidgetT8.h" + +// NOTE: RadioUiAction(NUMBER,...): NUMBER relates to enum EnumKeys in the specific board.h + +SimulatedUIWidgetT8::SimulatedUIWidgetT8(SimulatorInterface *simulator, QWidget * parent): + SimulatedUIWidget(simulator, parent), + ui(new Ui::SimulatedUIWidgetT8) +{ + RadioUiAction * act; + + ui->setupUi(this); + + // add actions in order of appearance on the help menu + + act = new RadioUiAction(5, QList() << Qt::Key_Up, SIMU_STR_HLP_KEY_UP, SIMU_STR_HLP_ACT_MDL); + addRadioWidget(ui->rightbuttons->addArea(QRect(25, 40, 35, 20), "T8/right-mdl.png", act)); + + act = new RadioUiAction(6, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_GO_UP, SIMU_STR_HLP_ACT_UP); + addRadioWidget(ui->rightbuttons->addArea(QRect(25, 90, 35, 20), "T8/right-up.png", act)); + + act = new RadioUiAction(7, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_GO_DN, SIMU_STR_HLP_ACT_DN); + addRadioWidget(ui->rightbuttons->addArea(QRect(25, 135, 35, 20), "T8/right-dn.png", act)); + + act = new RadioUiAction(1, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_ACTIVATE, SIMU_STR_HLP_ACT_ENT); + addRadioWidget(ui->rightbuttons->addArea(QRect(25, 180, 35, 20), "T8/right-ent.png", act)); + + act = new RadioUiAction(4, QList() << Qt::Key_Left, SIMU_STR_HLP_KEY_LFT, SIMU_STR_HLP_ACT_SYS); + addRadioWidget(ui->leftbuttons->addArea(QRect(60, 45, 35, 20), "T8/left-sys.png", act)); + + act = new RadioUiAction(0, QList() << Qt::Key_Down << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace, SIMU_STR_HLP_KEYS_EXIT, SIMU_STR_HLP_ACT_EXIT); + addRadioWidget(ui->leftbuttons->addArea(QRect(60, 85, 35, 20), "T8/left-rtn.png", act)); + + act = new RadioUiAction(3, QList() << Qt::Key_PageDown, SIMU_STR_HLP_KEY_PGDN, SIMU_STR_HLP_ACT_PGDN); + addRadioWidget(ui->leftbuttons->addArea(QRect(60, 135, 35, 20), "T8/left-pagedn.png", act)); + + act = new RadioUiAction(2, QList() << Qt::Key_PageUp, SIMU_STR_HLP_KEY_PGUP, SIMU_STR_HLP_ACT_PGUP); + addRadioWidget(ui->leftbuttons->addArea(QRect(60, 180, 35, 20), "T8/left-pageup.png", act)); + + + m_backlightColors << QColor(215, 243, 255); // X7 Blue + m_backlightColors << QColor(166,247,159); + m_backlightColors << QColor(247,159,166); + m_backlightColors << QColor(255,195,151); + m_backlightColors << QColor(247,242,159); + + setLcd(ui->lcd); + + QString css = "#radioUiWidget {" + "background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1," + "stop:0 rgba(255, 255, 255, 255)," + "stop:0.757062 rgba(241, 238, 238, 255)," + "stop:1 rgba(247, 245, 245, 255));" + "}"; + + QTimer * tim = new QTimer(this); + tim->setSingleShot(true); + connect(tim, &QTimer::timeout, [this, css]() { + emit customStyleRequest(css); + }); + tim->start(100); +} + +SimulatedUIWidgetT8::~SimulatedUIWidgetT8() +{ + delete ui; +} diff --git a/companion/src/simulation/simulateduiwidgetT8.ui b/companion/src/simulation/simulateduiwidgetT8.ui new file mode 100644 index 0000000000..6370888ea1 --- /dev/null +++ b/companion/src/simulation/simulateduiwidgetT8.ui @@ -0,0 +1,258 @@ + + + SimulatedUIWidgetT8 + + + + 0 + 0 + 480 + 300 + + + + + 0 + 0 + + + + + 480 + 300 + + + + + 480 + 300 + + + + Radiomaster T8 Simulator + + + background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.757062 rgba(241, 238, 238, 255), stop:1 rgba(247, 245, 245, 255)); + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 113 + 280 + + + + + 113 + 280 + + + + background:url(:/images/simulator/T8/left.png); + + + + + + + + 0 + 0 + + + + + 254 + 158 + + + + + 254 + 158 + + + + background-color: rgb(215, 243, 255); + + + + + + + + 0 + 0 + + + + + 113 + 280 + + + + + 113 + 280 + + + + background:url(:/images/simulator/T8/right.png) + + + + + + + + 0 + 0 + + + + + 254 + 35 + + + + + 254 + 35 + + + + background:url(:/images/simulator/T8/top.png) + + + + + + + + 0 + 0 + + + + + 254 + 113 + + + + + 254 + 113 + + + + background:url(:/images/simulator/T8/bottom.png) + + + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + 16777215 + 12 + + + + + 0 + 12 + + + + background-color: rgb(255, 255, 255); + + + + + + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + 16777215 + 10 + + + + background-color: rgb(247, 245, 245); + + + + + + + + + + + LcdWidget + QWidget +
lcdwidget.h
+ 1 +
+ + ButtonsWidget + QWidget +
buttonswidget.h
+ 1 +
+
+ + +
diff --git a/companion/src/simulation/simulatorwidget.cpp b/companion/src/simulation/simulatorwidget.cpp index cab7600d44..b4160a579b 100644 --- a/companion/src/simulation/simulatorwidget.cpp +++ b/companion/src/simulation/simulatorwidget.cpp @@ -91,6 +91,9 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface * simulato case Board::BOARD_JUMPER_T12: radioUiWidget = new SimulatedUIWidgetJumperT12(simulator, this); break; + case Board::BOARD_JUMPER_TLITE: + radioUiWidget = new SimulatedUIWidgetJumperTLITE(simulator, this); + break; case Board::BOARD_JUMPER_T16: radioUiWidget = new SimulatedUIWidgetJumperT16(simulator, this); break; @@ -100,6 +103,9 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface * simulato case Board::BOARD_RADIOMASTER_TX12: radioUiWidget = new SimulatedUIWidgetTX12(simulator, this); break; + case Board::BOARD_RADIOMASTER_T8: + radioUiWidget = new SimulatedUIWidgetT8(simulator, this); + break; case Board::BOARD_RADIOMASTER_TX16S: radioUiWidget = new SimulatedUIWidgetTX16S(simulator, this); break; diff --git a/companion/src/translations/companion_fr.ts b/companion/src/translations/companion_fr.ts index 593231b91b..2a6eea9969 100644 --- a/companion/src/translations/companion_fr.ts +++ b/companion/src/translations/companion_fr.ts @@ -95,7 +95,7 @@ Edit Settings - Éditer les paramètres + Éditer les préférences @@ -488,7 +488,7 @@ Manche Droit: Profondeur, Direction Automatic Backup Folder - Dossier de sauvegardes automatiques + Dossier des sauvegardes automatiques @@ -743,58 +743,58 @@ Manche Droit: Profondeur, Direction Boards - + Left Horizontal Gauche Horizontal - + Left Vertical Gauche Vertical - + Right Vertical Droit Vertical - + Right Horizontal Droit Horizontal - + Aux. 1 - + Aux. 2 - - + + Unknown Inconnu - + Rud Dir - + Ele Prf - + Thr Gaz - + Ail @@ -843,127 +843,127 @@ Manche Droit: Profondeur, Direction ChannelsPanel - + Name Nom - + Subtrim Subtrim - + Min - + Max - + Direction - + Curve Courbe - + PPM Center Neutre PPM - + Linear Subtrim Subtrim linéaire - + CH%1 VOIE%1 - + Popup menu available Menu contextuel disponible - + --- - + INV - + Delete Channel. Are you sure? Supprimer la Voie. Êtes-vous sûr? - + Cut Channel. Are you sure? Couper la Voie. Êtes-vous sûr? - + Copy Copier - + Cut Couper - + Paste Coller - + Clear Effacer - + Insert Insérer - + Delete Supprimer - + Move Up Monter - + Move Down Descendre - + Clear All Effacer Tout - + Clear Channel. Are you sure? Effacer la Voie. Êtes-vous sûr? - + Clear all Channels. Are you sure? Effacer toutes les Voies. Êtes-vous sûr? @@ -1118,37 +1118,37 @@ Manche Droit: Profondeur, Direction <p> Le type de radio sélectionnée dans le profil n'existe pas. Utilisez plutôt le type par défaut. </p> <p><b>Veuillez mettre à jour les paramètres de votre profil!</b></p> - + Select or create a file for exported Settings: Sélectionnez ou créez un fichier pour les paramètres exportés: - + Press the 'Retry' button to choose another file. Appuyez sur le bouton 'Réessayer' pour choisir un autre fichier. - + Simulator for this firmware is not yet available Le simulateur n'est pas encore disponible pour ce firmware - + Uknown error during Simulator startup. Erreur inconnue pendant le démarrage du simulateur. - + Simulator Error Erreur Simulateur - + Data Load Error Erreur de chargement des données - + Error occurred while starting simulator. Une erreur s'est produite lors du démarrage du simulateur. @@ -1381,11 +1381,34 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import CurveData - + CV CB + + CurveReference + + + Diff + + + + + Expo + + + + + Func + Fonc + + + + Curve + Courbe + + Curves @@ -1478,112 +1501,112 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import CurvesPanel - + Curve %1 Courbe %1 - + Popup menu available Menu contextuel disponible - + %1 points - + Linear Linéaire - + Single Expo Expo simple - + Symmetrical f(x)=-f(-x) Symétrique f(x)=-f(-x) - + Symmetrical f(x)=f(-x) Symétrique f(x)=f(-x) - + Editing curve %1 Édition de la courbe %1 - + Not enough free points in EEPROM to store the curve. Pas assez de points disponibles en mémoire pour enregistrer la courbe. - + Copy Copier - + Cut Couper - + Paste Coller - + Clear Effacer - + Insert Insérer - + Delete Supprimer - + Move Up Monter - + Move Down Descendre - + Clear All Effacer Tout - + Clear Curve. Are you sure? Effacer la Courbe. Êtes-vous sûr? - + Clear all Curves. Are you sure? Effacer toutes les Courbes. Êtes-vous sûr? - + Cut Curve. Are you sure? Couper la Courbe. Êtes-vous sûr? - + Delete Curve. Are you sure? Supprimer la Courbe. Êtes-vous sûr? @@ -1591,234 +1614,297 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import CustomFunctionData - + GF FG - + SF FS - + Override %1 Remplacer %1 - + Trainer Sticks Manches Écolage - + Trainer RUD Écolage Direction - + Trainer ELE Écolage Profondeur - + Trainer THR Écolage Gaz - + Trainer AIL Écolage Ailerons - + Trainer Channels Écolage Channels - + Instant Trim Trims instantanés - + Play Sound Jouer Son - + Haptic Vibreur - + Reset Remise à zéro - - Set Timer %1 - Définir chrono %1 + + Set %1 + Activer %1 - + Vario - + Play Track Jouer fichier - + Play Both Jouer les deux - + Play Value Lire valeur - - Play Script - Exécuter script + + Lua Script + Script Lua - + + Range Check Int. Module + Test Portée Module Int. + + + + Range Check Ext. Module + Test Portée Module Ext. + + + + Beep 1 + + + + + Beep 2 + + + + + Beep 3 + + + + + Warn 1 + Alerte 1 + + + + Warn 2 + Alerte 2 + + + + Cheep + Piauler + + + + Ratata + + + + + Tick + Tic-tac + + + + Siren + Sirène + + + + Ring + Sonner + + + + Sci Fi + + + + + Robot + + + + + Chirp + Gazouiller + + + + Tada + + + + + Cricket + Criquet + + + + Alarm Clock + Réveil + + + + Value + Valeur + + + + Source + + + + + Global Variable + Variable Globale + + + + Inc/Decrement + Inc/Décrémenter + + + SD Logs Logs SD - + Volume - + Backlight Rétroéclairage - + Screenshot Capture d'écran - + Background Music Musique de fond - + Background Music Pause Pause musique de fond - + Adjust %1 Ajuster %1 - + Set Failsafe Définir Failsafe - - RangeCheck Int. Module - Test portée module interne - - - - RangeCheck Ext. Module - Test portée module externe - - - + Bind Int. Module Bind module interne - + Bind Ext. Module Bind module externe - - Timer1 - Chrono 1 + + Played once, not during startup + Lu une fois, mais pas à la mise en route - - Timer2 - Chrono 2 + + No repeat + Lu une fois - - Timer3 - Chrono 3 + + Repeat %1s + Répéter %1s - + Flight Vol - + Telemetry Télémétrie - - Rotary Encoder - Sélecteur Rotatif - - - - REa - - - - - REb - - - - + s - - - - <font color=red><b>Inconsistent parameter</b></font> - <font color=red><b>Paramètre inconsistant</b></font> - - - - Value - Valeur - - - - played once, not during startup - !1x Lu une fois, mais pas à la mise en route - - - - repeat(%1s) - Répéter chaque %1s - - - + DISABLED DESACTIVE - + CFN FPN @@ -1826,139 +1912,119 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import CustomFunctionsPanel - + Switch Interrupteur - + Action - + Parameters Paramètres - - Enable - Actif - - - + Popup menu available Menu contextuel disponible - + SF%1 FS%1 - + GF%1 FG%1 - + + GV + VG + + + ON - + Error occurred while trying to play sound, possibly the file is already opened. (Err: %1 [%2]) Une erreur s'est produite lors de la lecture du son, le fichier est peut-être déjà ouvert. (Err: %1 [%2]) - + Unable to find or open sound file: %1 Impossible de trouver ou d'ouvrir le fichier son: %1 - + Delete Function. Are you sure? Supprimer la Fonction. Êtes-vous sûr? - + Cut Special Function. Are you sure? Couper la Fonction. Êtes-vous sûr? - + Copy Copier - + Cut Couper - + Paste Coller - + Clear Effacer - + Insert Insérer - + Delete Supprimer - + Move Up Monter - + Move Down Descendre - + Clear All Effacer Tout - - Value - Valeur - - - - Source - Source - - - - GVAR - VG - - - - Increment - Incrément - - - + Clear Function. Are you sure? Effacer la Fonction. Êtes-vous sûr? - + Clear all Functions. Are you sure? Effacer toutes les Fonctions. Êtes-vous sûr? @@ -2126,52 +2192,105 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import Erreur de conversion du champ %1 - + Switch Interrupteur - + Switch L'interrupteur - + cannot be exported on this board! n'est pas supporté sur cette carte ! - + Source - + Source %1 cannot be exported on this board! La source %1 n'est pas supportée sur cette plateforme ! - + OpenTX only accepts %1 points in all curves OpenTX n'accepte que %1 points au maximum entre toutes les courbes - + OpenTx only accepts %1 points in all curves OpenTX n'accepte que %1 points au maximum entre toutes les courbes - - + + OpenTX on this board doesn't accept this function OpenTX ne supporte pas cette fonction sur cette carte - + OpenTX doesn't accept this radio protocol OpenTX ne supporte pas ce protocole radio + + DataHelpers + + + Disabled + Désactivé + + + + Enabled + Activé + + + + OFF + + + + + ON + + + + + False + Faux + + + + True + Vrai + + + + N + + + + + Y + O + + + + No + Non + + + + Yes + Oui + + DebugOutput @@ -2378,12 +2497,12 @@ Vérifier la sélection (M64/M128) ExpoData - + INP ENT - + (@%1) @@ -2398,7 +2517,7 @@ Vérifier la sélection (M64/M128) Flight modes - Phases de vol + Phases de Vol @@ -2500,27 +2619,27 @@ Si vide, la ligne est toujours active. Les 2 - + Edit %1 Éditer %1 - + Popup menu available Menu contextuel disponible - + Clear All Effacer Tout - + Set All Définir Tout - + Invert All Inverser Tout @@ -2609,129 +2728,129 @@ Si vide, la ligne est toujours active. FileSyncDialog - + Synchronize Files Synchroniser les fichiers - + Are you sure you wish to abort the sync? Êtes-vous sûr de vouloir annuler la synchronisation? - + Source Folder: Dosssier "Local": - + Destination Folder: Dossier "Radio": - + %1%2 Both directions, to destination folder first %1%2 Bidirectionnel, en commençant par "Radio" - + %1%2 Both directions, to source folder first %1%2 Bidirectionnel, en commençant par "Local" - + %1 Only from source folder to destination folder %1 Uniquement de "Local" vers "Radio" - + %1 Only from destination folder to source folder %1 Uniquement de "Radio" vers "Local" - + How to handle overwriting files which already exist in the destination folder. Comment gérer l'écrasement des fichiers qui existent déjà dans le dossier de destination. - + Copy only if newer and different (compare contents) Copiez seulement si "plus récent et différent" (comparez le contenu) - + Copy only if newer (do not compare contents) Copier uniquement si "plus récent" (ne pas comparer le contenu) - + Copy only if different (ignore file time stamps) Copier uniquement si "différent" (ignorer l'horodatage des fichiers) - + Always copy (force overwite existing files) Toujours copier (écraser tous les fichiers existants) - + Any size Toutes tailles - + Skip files larger than this size. Enter zero for unlimited. Ignorer tous les fichiers plus grands que cette taille. Entrez 0 pour illimité. - + Minimum reporting level. Events of this type and of higher importance are shown. WARNING: High log rates may make the user interface temporarily unresponsive. Niveau de rapport au minimum. Les événements de ce type et d'une plus grande importance sont indiqués. ATTENTION: un taux de rapport élevé peut rendre l'interface utilisateur temporairement inutilisable. - + Skipped Sauté - + Created Créé - + Updated Mis à jour - + Errors Only Erreur seulement - + Test-run only Essai - + Run as normal but do not actually copy anything. Useful for verifying results before real sync. Exécutez normalement, mais ne rien copier. Utile pour vérifier les résultats avant la synchronisation réelle. - + Log Level: Niveau de rapport: - + Filters: Filtres: - + The "Include" filter will only copy files which match the pattern(s). The "Exclude" filter will skip files matching the filter pattern(s). The Include filter is evaluated first. @@ -2740,148 +2859,148 @@ Le filtre "Exclure" ignorera les fichiers correspondant à la (aux) r Le filtre "Inclure" est évalué en premier. - + One or more file pattern(s) to exclude, separated by commas. Blank means exclude none. ?, *, and [...] wildcards accepted. Une ou plusieurs règle(s) de fichier(s) à exclure, séparés par des virgules. Blanc signifie "exclure aucun".Les métacaractères ?, * et [...] sont acceptés. - + One or more file pattern(s) to include, separated by commas. Blank means include all. ?, *, and [...] wildcards accepted. Une ou plusieurs règle(s) de fichier(s) à inclure, séparés par des virgules. Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont acceptés. - + Include: Inclure: - + Exclude: Exclure: - + Case sensitive Sensible aux majuscules et minuscules - - + + Follow links Suivez les liens - + Include hidden Inclure fichier/dossier caché - + Recursive Récursif - + Skip empty Sauter vide - + Apply filters Appliquer les filtres - + Filter Options: Options des Filtres: - + Folder Options: Options des Dossiers: - - + + Options - + Show extra options Afficher les options supplémentaires - + Reset to defaults Réinitialiser les paramètres par défaut - + Close Fermer - + Sync. Direction: Direction de la synchro.: - + Existing Files: Fichiers existants: - + Max. File Size: Taille Max Fichier: - + MB Mo - + KB ko - + Abort Annuler - + Start Démarrer - + Total: <b>%1</b>; Created: <b>%2</b>; Updated: <b>%3</b>; Skipped: <b>%4</b>; Errors: <font color=%6><b>%5</b></font>; Total: <b>%1</b>; Créé(s): <b>%2</b>; Mis à jour: <b>%3</b>; Sauté(s): <b>%4</b>; Erreur(s): <font color=%6><b>%5</b></font>; - + Current: <b>%1</b> of Courant: <b>%1</b> de - + Source folder not found. Dosssier "Local" non trouvé. - + Destination folder not found. Dosssier "Radio" non trouvé. - + Source and destination folders are the same. Les dossiers "Local" et "Radio" sont les mêmes. @@ -2889,272 +3008,293 @@ Blanc signifie "inclure tous".Les métacaractères ?, * et [...] sont Firmware - + Channel values displayed in us Positions de voies affichées en µs - + No OverrideCH functions available Désactive la fonction spéciale "Remplacer VOIExx" - + Possibility to enable FAI MODE (no telemetry) at field Possibilité d'activer le mode FAI (télémétrie désactivée) sur le terrain - + FAI MODE (no telemetry) always enabled Mode FAI (télémétrie toujours désactivée) - + Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015 Masque le protocole D8. Légalement obligatoire sur les radios Européennes importées après le 1er janvier 2015 - - - + + + + + Disable HELI menu and cyclic mix support Supprimer le menu HELICO et les mixages cycliques - - - + + + + + Disable Global variables Supprimer le support des variables globales - - - + + + + + Enable Lua custom scripts screen Activer l'écran des scripts Lua personnalisés - + Use alternative SQT5 font Utiliser la police alternative SQT5 - - + + Disable RAS (SWR) Désactiver le RAS (SWR). Utile uniquement pour les X9D+ avec un RAS/SWR non fonctionnel - + Pots use in menus navigation Support de la navigation dans les menus avec les POTS - + Enable AFHDS3 support Activer le support du AFHDS3 - + FrSky Taranis X9D+ - + FrSky Taranis X9D+ 2019 - + FrSky Taranis X9D - + Haptic module installed Module vibreur installé - + FrSky Taranis X9E - + Confirmation before radio shutdown Confirmation avant l'arrêt de la radio - + Horus gimbals installed (Hall sensors) Manches Horus à effet HALL installés - + FrSky Taranis X9-Lite - + FrSky Taranis X9-Lite S - + FrSky Taranis X7 / X7S - + FrSky Taranis X7 / X7S Access - + FrSky Taranis X-Lite S/PRO - + FrSky Taranis X-Lite - + FrSky Horus X10 / X10S - - + + Support for ACCESS internal module replacement Prise en charge du module de remplacement interne ACCESS - - - - - + + + + + Support hardware mod: R9M ACCESS Prise en charge du mod hardware: R9M ACCESS - + FrSky Horus X10 Express / X10S Express - + FrSky Horus X12S - + Use ONLY with first DEV pcb version Exclusivement pour les Horus DEV - - + + Support for MULTI internal module Prise en charge du module MULTI interne - - - - Support for bluetooth module - Prise en charge du module Bluetooth - - - - Support internal GPS - Prise en charge du GPS interne - - - - Jumper T18 + + Jumper T-Lite + + + Support for bluetooth module + Prise en charge du module Bluetooth + + + + Radiomaster T8 + + + + + Allow bind using bind key + Autoriser l'appairage avec le bouton"bind" + + + + Support internal GPS + Prise en charge du GPS interne + + + + Jumper T18 + + + + Turnigy 9XR-PRO - + Enable HELI menu and cyclic mix support Activer le menu hélico et les mixages CCPM - + Global variables Variables globales - + Enable non certified firmwares Activer les firmwares non certifiés - + In model setup menus automatically set source by moving the control Sélectionner les sources des mixeurs en bougeant le contrôle désiré - + In model setup menus automatically set switch by moving the control Sélectionner les interrupteurs en bougeant le contrôle désiré - + No graphical check boxes and sliders Pas de cases à cocher et de curseurs graphiques - + Battery graph Graphique de la batterie - + Don't use bold font for highlighting active items Ne pas mettre les lignes actives en gras - + Enable resetting values by pressing up and down at the same time Permet la remise à zéro des valeurs en pressant haut-bas en même temps, valeur min avec gauche/bas, valeur max avec haut/droite, inversion avec gauche/droite - + Radiomaster TX12 - + Radiomaster TX16S / SE / Hall / Masterfire - + 9X with AR9X board 9X avec carte AR9X - + Jumper T12 / T12 Pro - + Jumper T16 / T16+ / T16 Pro - + 9X with Sky9x board 9X avec carte Sky9x @@ -3643,7 +3783,7 @@ Vous utilisez actuellement: FlightModeData - + FM PV @@ -3864,17 +4004,17 @@ Vous utilisez actuellement: FlightModesPanel - + Flight Mode %1 Phase de vol %1 - + (%1) - + (default) (par défaut) @@ -4114,12 +4254,12 @@ p, li { white-space: pre-wrap; } VG - + Own value Valeur indépendante - + Flight mode %1 value Valeur de la phase de vol %1 @@ -4127,7 +4267,7 @@ p, li { white-space: pre-wrap; } GeneralEdit - + Setup Configuration @@ -4144,57 +4284,57 @@ These will be relevant for all models in the same EEPROM. Communs à tous les modèles d'une même EEPROM. - + Trainer Écolage Store calib. and hw settings in selected profile - Sauver étalonnage et paramètres hw dans profil + Sauver paramètres Radio dans profil Retrieve calib. and hw settings from profile - Lire étalonnage et paramètres hw du profil + Lire paramètres Radio depuis profil - + Global Functions Fonctions globales - + Hardware Matériel - + Calibration - + Wrong data in profile, radio calibration was not retrieved Données du profil erronnées, l'étalonnage n'a pas été lu - + Wrong data in profile, Switch/pot config not retrieved Données incorecte, Interrupteurs/Pot non trouvés - + Wrong data in profile, hw related parameters were not retrieved Données du profil erronnées, les paramètres hw n'ont pas été lus - + Do you want to store calibration in %1 profile<br>overwriting existing calibration? Voulez-vous stocker l'étalonnage dans le profil %1<br> et écraser l'étalonnage existant ? - + Calibration and HW parameters saved. Etalonnage et paramètres hw enregistrés avec succès. @@ -4202,7 +4342,7 @@ Communs à tous les modèles d'une même EEPROM. GeneralSettings - + Radio Settings Paramètres de la radio @@ -4672,6 +4812,17 @@ Mode 4: A T E R A G P D + + + Battery warning voltage. +This is the threashhold where the battery warning sounds. + +Acceptable values are 3v..12v + Tension d'alerte de batterie. +Seuil auquel se déclenche l'alarme de batterie. + +Plage de valeurs: 3v...12v + Power Off Delay @@ -4842,17 +4993,6 @@ Mode 4: All Tous - - - Battery warning voltage. -This is the threashhold where the battery warning sounds. - -Acceptable values are 5v..10v - Tension d'alerte de batterie. -Seuil auquel se déclenche l'alarme de batterie. - -Plage de valeurs: 5v...10v - Standard @@ -5638,12 +5778,12 @@ Cette fonction ne peut pas être désactivée sur la radio. Long. cyc - Cyc. longitudinal + Cyclique longitudinal Lateral cyc - Cyc. latéral + Cyclique latéral @@ -5709,177 +5849,177 @@ Cette fonction ne peut pas être désactivée sur la radio. InputsPanel - - - + + + Move Up Monter - - + + Ctrl+Up Ctrl+Haut - - - + + + Move Down Descendre - - + + Ctrl+Down Ctrl+Bas - + Clear All Inputs Effacer toutes les entrées - + Not enough available Inputs! Pas assez d'Entrées disponibles! - + Delete selected Input lines. Are you sure? Supprimer les lignes Entrée sélectionnées. Êtes-vous sûr? - + Cut selected Input lines. Are you sure? Couper les lignes Entrée sélectionnées. Êtes-vous sûr? - + Lines Linéaire - + &Add &Ajouter - + Ctrl+A Ctrl+A - + &Edit &Édition - + Enter Entrée - + &Delete &Supprimer - - + + Delete Supprimer - + &Copy &Copier - + Ctrl+C - + &Cut &Couper - + Ctrl+X - + &Paste &Coller - + Ctrl+V - + Du&plicate Du&pliquer - + Ctrl+U - + Input Entrée - + Insert Insérer - + Clear Effacer - + Clear All Effacer Tout - + Clear all Input lines. Are you sure? Effacer toutes les lignes Entrée. Êtes-vous sûr? - - Clear all lines for the selected Inputs. Are you sure? + + Clear all lines for the selected Input. Are you sure? Effacer toutes les lignes Entrée sélectionnées. Êtes-vous sûr? - - Delete all lines for the selected Inputs. Are you sure? + + Delete all lines for the selected Input. Are you sure? Supprimer toutes les lignes Entrée sélectionnées. Êtes-vous sûr? LimitData - + INV - + NOR - + CH VOIE @@ -5887,7 +6027,7 @@ Cette fonction ne peut pas être désactivée sur la radio. LimitsGroup - + GV VG @@ -6058,72 +6198,72 @@ Cette fonction ne peut pas être désactivée sur la radio. - + (infinite) (infini) - + Delete Logical Switch. Are you sure? Supprimer l'Interrupteur Logique. Êtes-vous sûr? - + Cut Logical Switch. Are you sure? Couper l'Interrupteur Logique. Êtes-vous sûr? - + Copy Copier - + Cut Couper - + Paste Coller - + Clear Effacer - + Insert Insérer - + Delete Supprimer - + Move Up Monter - + Move Down Descendre - + Clear All Effacer Tout - + Clear Logical Switch. Are you sure? Effacer l'Interrupteur Logique. Êtes-vous sûr? - + Clear all Logical Switches. Are you sure? Effacer tous les Interrupteurs Logiques. Êtes-vous sûr? @@ -7386,7 +7526,7 @@ Do you wish to continue? Edit Radio Settings - Éditer paramètres radio + Éditer Paramètres Radio @@ -7401,7 +7541,7 @@ Do you wish to continue? Simulate Radio - Simuler radio + Simuler Radio @@ -7648,12 +7788,12 @@ Enregistrer les changements ? MixData - + MIX - + (@%1) @@ -7850,27 +7990,27 @@ Mixage actif par défaut si non-renseigné. Nom - + DEST -> %1 - + Click to access popup menu Cliquez pour accéder au menu contextuel - + Clear All Effacer Tout - + Set All Définir Tout - + Invert All Inverser Tout @@ -7882,7 +8022,7 @@ Mixage actif par défaut si non-renseigné. Flight modes - Phases de vol + Phases de Vol @@ -7916,136 +8056,136 @@ Mixage actif par défaut si non-renseigné. MixesPanel - - + + Move Up Monter - - + + Ctrl+Up Ctrl+Haut - - + + Move Down Descendre - - + + Ctrl+Down Ctrl+Bas - + Clear Mixes Effacer tous les mixages - + Not enough available mixers! Plus de mixages disponibles ! - + Delete selected Mix lines. Are you sure? Supprimer les lignes Mixeur sélectionnées. Êtes-vous sûr? - + Cut selected Mix lines. Are you sure? Couper les lignes Mixeur sélectionnées. Êtes-vous sûr? - + &Add &Ajouter - + Ctrl+A - + &Edit &Édition - + Enter Entrée - + Ctrl+T - + &Toggle highlight &(Dé)sélectionner - + &Delete &Supprimer - + Delete Supprimer - + &Copy &Copier - + Ctrl+C - + Ctrl+X - + C&ut &Couper - + &Paste &Coller - + Ctrl+V - + Du&plicate &Dupliquer - + Ctrl+U - + Clear Mixes? Effacer tous les mixages ? - + Really clear all the mixes? Êtes-vous sûr de vraiment vouloir effacer tous les mixages ? @@ -8053,15 +8193,20 @@ Mixage actif par défaut si non-renseigné. ModelData - + Model: Modèle: - + Throttle Source Source des gaz + + + THR + GAZ + ModelEdit @@ -8071,32 +8216,32 @@ Mixage actif par défaut si non-renseigné. Simulation - + Heli - Paramètres hélico + Paramètres Hélico - + Inputs Entrées - + Mixes Mixages - + Logical Switches - Inters logiques + Inters Logiques - + Setup Configuration - + Curves Courbes @@ -8106,22 +8251,22 @@ Mixage actif par défaut si non-renseigné. Dialogue - + Flight Modes - Phases de vol + Phases de Vol - + Outputs Sorties - + Special Functions - Fonctions spéciales + Fonctions Spéciales - + Telemetry Télémesure @@ -8220,9 +8365,8 @@ Mixage actif par défaut si non-renseigné. - - - + + OFF @@ -8233,7 +8377,7 @@ Mixage actif par défaut si non-renseigné. - + Mode @@ -8267,13 +8411,13 @@ Mixage actif par défaut si non-renseigné. - + Delay Délai - + Receiver Récepteur @@ -8334,490 +8478,282 @@ Mixage actif par défaut si non-renseigné. - - + + Weight(%1) Ratio(%1) - - + + Switch(%1) Inter(%1) - + MULT! - + Delay(u%1:d%2) Délai(h%1:b%2) - + Slow(u%1:d%2) Ralenti(h%1:b%2) - + Warn(%1) Alerte(%1) - - Offset - Décalage - - - + Flight modes - Phases de vol + Phases de Vol - + Flight mode Phase de vol - + All Tous - + Edge Flanc - + Sticky Bistable - + Timer Chrono - + missing absent - + Duration Durée - + Extended Limits Limites étendues - + Display Checklist Afficher la checklist - + Global Functions Fonctions globales - + Manual Manuel - + Auto - + Failsafe Mode Mode Failsafe - - + + Hold Maintien - + No Pulse Pas d'impulsion - + Not set Non défini - + No pulses Pas d'impulsions - - Silent - Aucun - - - - Beeps - Bips - - - - Voice - Voix - - - - Haptic - Vibreur - - - - Flight - Vol - - - - Manual reset - RAZ manuelle - - - + Step Pas - + Display Affichage - + Extended Étendu - + Never Jamais - + On Change Sur changement - + Always Toujours - - - + + + Source - + Trim idle only Trim ralenti uniquement - + Warning Avertissement - + Reversed Inversé - - Tmr - Chrono - - - + FrSky S.PORT - + FrSky D - + FrSky D (cable) FrSky D (câble) - + Alti Alt - + Alti+ Alt+ - + VSpeed Vitesse verticale - - - + + + A1 - - - + + + A2 - - + + A3 - - + + A4 - - + + FAS - + Cells Velm - - Calculated - Calculé - - - - Add - Addition - - - - Average - Moyenne - - - - + Min - - + Max - - Multiply - Multiplication - - - - Totalise - - - - - Cell - Element LiPo - - - - Consumption - Consommation - - - - Distance - - - - - Lowest - Min - - - - Cell %1 - Elém. %1 - - - - Highest - Max - - - - Delta - - - - - Auto Offset - Offset Auto - - - - 0. - - - - - 0.0 - - - - - 0.00 - - - - - Id - - - - - - Sensor - Capteur - - - - Sources - - - - - GPS - - - - - Blades - Pales - - - - F - - - - - Inst - - - - - Alt - Altitude - - - - Unit - Unité - - - - Prec - - - - - Ratio - - - - - Multi - - - - - Filter - Filtre - - - - Persist - - - - - Positive - - - - - Log - - - - + Numbers Chiffres - + Bars Barres - + Script - + Filename Nom de fichier - + Error: Unable to open or read file! Erreur: Impossible d'ouvrir ou de lire le fichier! - - - Persistent - Persistant - Off @@ -8825,60 +8761,44 @@ Mixage actif par défaut si non-renseigné. - - - - - + + + + None Aucun - - - Name - Nom - - Countdown - Compte à rebours - - - - Minute call - Annonces minutes - - - - - + + FM%1 PV%1 - + FM%1%2 PV%1%2 - + FM%1+%2 PV%1+%2 - - + + NoTrim Pas de trim - + No DR/Expo Pas d'expo/DR - - + + Offset(%1) Décalage(%1) @@ -8893,24 +8813,23 @@ Mixage actif par défaut si non-renseigné. - + Disabled in all flight modes Désactivé pour toutes les phases de vol - + instant immédiat - - - + + Custom Prédéfini - + Standard @@ -9208,12 +9127,12 @@ Mixage actif par défaut si non-renseigné. ModuleData - + Positive - + Negative Négative @@ -9319,42 +9238,42 @@ Mixage actif par défaut si non-renseigné. ModulePanel - + Value Valeur - + Hold Maintien - + No Pulse Pas d'impulsion - + Ask Demander - + Internal Interne - + Internal + External Interne + Externe - + External Externe - + Bind on channel Bind avec VOIE @@ -9362,91 +9281,91 @@ Mixage actif par défaut si non-renseigné. MultiModelPrinter - + Input Entrée - + Weight Ratio - + Long. cyc - Cyc. longitudinal + Cyclique longitudinal - + Lateral cyc - Cyc. latéral + Cyclique latéral - + Collective Source du pas collectif - + Flight modes - Phases de vol + Phases de Vol - - + + Flight mode Phase de vol - + Switch Inter - - + + GV%1 VG%1 - + RE%1 - + Channel Voie - + Direct - + Curve Courbe - + PPM - + Linear Linéaire - + Telemetry Télémétrie - - + + Min @@ -9466,23 +9385,23 @@ Mixage actif par défaut si non-renseigné. Compte à rebours - + Modules - + Outputs Sorties - + Subtrim Subtrim - - + + Max @@ -9493,8 +9412,8 @@ Mixage actif par défaut si non-renseigné. - - + + Name Nom @@ -9549,209 +9468,214 @@ Mixage actif par défaut si non-renseigné. Persistant - + + Start + Démarrer + + + Trainer port Port écolage - + Helicopter Hélicoptère - + Swash Cyclique - - + + Type - + Ring Plateau - + F.In Fondu en entrée - + F.Out Fondu en sortie - + Global vars Variables globales - + Prec - + Popup - + Global Variables Variables globales - + Inputs Entrées - + Mixers Mixages - + Curves Courbes - + L%1 - + Logical Switches - Inters logiques + Inters Logiques - + SF%1 FS%1 - + Special Functions - Fonctions spéciales + Fonctions Spéciales - + Protocol Protocole - + Low Faible - + Critical Critique - + Telemetry audio Audio télémétrie - + Altimetry Altimétrie - - + + Vario source Source vario - + Vario limits > Limites vario > - + Sink max Chute max - + Sink min Chute min - + Climb min Pompe min - + Climb max Pompe max - + Center silent Silence centrer - + Top Bar Barre de titre de l'écran d'accueil - + Volts source Source de la tension - + Altitude source Source de l'altitude - + Parameters Paramètres - + Telemetry Sensors Capteurs Télémétrie - + Telemetry Screens Écrans Télémétrie - + GF%1 FG%1 - + Global Functions Fonctions globales - + Checklist - + Unit Unité - + RSSI Alarms Alarmes RSSI @@ -9830,22 +9754,22 @@ Mixage actif par défaut si non-renseigné. OpenTxEepromInterface - + Unknown error Erreur inconnue - + ... plus %1 errors ... plus %1 erreurs - + Cannot write radio settings Impossible d'écrire les paramètres de la radio - + Cannot write model %1 Impossible d'écrire le modèle %1 @@ -9993,12 +9917,12 @@ Mixage actif par défaut si non-renseigné. QObject - + WARNING ATTENTION - + <p>Importing JumperTX data into OpenTX 2.3 is <b>not supported and dangerous.</b></p> <p>It is unfortunately not possible for us to differentiate JumperTX data from legitimate FrSky X10 data, but <b>You should only continue here if the file you opened comes from a real FrSky X10.</b></p> <p>Do you really want to continue?</p> <p>L'importation de données JumperTX dans OpenTX 2.3 est <b> non prise en charge et dangereuse.</b></p> <p>Il n'est malheureusement pas possible pour nous de différencier les données JumperTX des données légitimes FrSky X10, donc <b>Vous devez continuer uniquement si le fichier que vous avez ouvert provient d’une véritable radio FrSky X10.</b></p> <p>Voulez-vous vraiment continuer?</p> @@ -10006,7 +9930,7 @@ Mixage actif par défaut si non-renseigné. RadioData - + Models Modeles @@ -10350,17 +10274,6 @@ E REb - - - - ??? - - - - - ---- - - I @@ -10389,7 +10302,7 @@ E - + SRC @@ -10581,24 +10494,6 @@ E Notes de version d'OpenTX - - RepeatComboBox - - - Played once, not during startup - 1x Lu une fois, mais pas à la mise en route - - - - No repeat - 1x Lu une fois - - - - %1s - - - RudderPage @@ -10637,146 +10532,322 @@ E SensorData - - + + Raw (-) + Chiffres bruts (-) + + + + V - + A - + mA - + kts - + m/s - + km/h - + mph - + m - + f - + °C - + °F - + % - + mAh - + W - + mW - + dB - + rpms - + g - + ° - + Rad - + hours heures - + minutes - + seconds secondes - + ml/minute - + Hertz - + mS - + uS - + TELE + + + Formula + Formule + + + + Id + + + + + Instance + + + + + + Sensor + Capteur + + + + Sources + + + + + GPS + + + + + Alt + Altitude + + + + Unit + Unité + + + + Precision + Précision + + + + Ratio + + + + + Offset + Décalage + + + + Auto Offset + + + + + Blades + Pales + + + + Multiplier + Multiplicateur + + + + Filter + Filtre + + + + Persist + Persistant + + + + Positive + + + + + Log + + + + + Custom + Prédéfini + + + + Calculated + Calculé + + + + Add + Addition + + + + Average + Moyenne + + + + Minimum + + + + + Maximum + + + + + Multiply + Multiplication + + + + Totalize + Totalisation + + + + Cell + Element LiPo + + + + Consumption + Consommation + + + + Distance + + + + + Lowest + Min + + + + Cell %1 + Elément %1 + + + + Highest + Max + + + + Delta + + + + + (default) + (défaut) + Setup @@ -10960,92 +11031,87 @@ Si cette option est cochée, la voie des gaz est inversée: le ralenti est &apo SetupPanel - + Popup menu available Menu contextuel disponible - + Timer %1 Chrono %1 - - THR - GAZ - - - + Profile Settings Paramètres du profil - + SD structure path not specified or invalid Chemin de la structure SD non spécifié ou invalide - + Copy Copier - + Cut Couper - + Paste Coller - + Clear Effacer - + Insert Insérer - + Delete Supprimer - + Move Up Monter - + Move Down Descendre - + Clear All Effacer Tout - + Clear Timer. Are you sure? Effacer le Chrono. Êtes-vous sûr? - + Clear all Timers. Are you sure? Effacer tous les Chronos. Êtes-vous sûr? - + Cut Timer. Are you sure? Couper le Chrono. Êtes-vous sûr? - + Delete Timer. Are you sure? Supprimer le Chrono. Êtes-vous sûr? @@ -11769,62 +11835,62 @@ La valeur par défaut est configurée dans le profil radio sélectionné.Simulateur Radio (%1) - + Could not determine startup data source. Impossible de déterminer les données source. - + Could not load data, possibly wrong format. Impossible de charger les données, mauvais format. - + Data Load Error Erreur de lecture des données - + Invalid startup data provided. Plese specify a proper file/path. Données de démarrage fournies non valides. Veuillez spécifier un fichier/chemin approprié. - + Simulator Startup Error Erreur de démarrage du simulateur - + Error saving data: could open file for writing: '%1' Erreur de sauvegarde des données: impossible d'écrire le fichier '%1' - + Error saving data: could not get data from simulator interface. Erreur de sauvegarde des données: impossible de récupérer les données depuis l'interface de simulation. - + An unexpected error occurred while attempting to save radio data to file '%1'. Une erreur inattendue s'est produite lors de l'enregistrement des données radio dans le fichier '%1'. - + Data Save Error Erreur de sauvegarde des données - + Cannot open joystick, joystick disabled Impossible d'accéder au Joystick, Joystick désactivé - + Radio firmware error: %1 Erreur firmware radio: %1 - + - Flight Mode %1 (#%2) - Phase de Vol %1 (#%2) @@ -12479,22 +12545,22 @@ Trop d'erreurs, abandon. Type d'écran personnalisé - + None Aucun - + Numbers Chiffres - + Bars Barres - + Script @@ -12522,109 +12588,52 @@ Trop d'erreurs, abandon. TelemetryPanel - + FrSky S.PORT - + FrSky D - + FrSky D (cable) FrSky D (câble) - + Telemetry screen %1 Ecran de télémesure %1 - + Source - + Low Alarm Alarme basse - + Critical Alarm Alarme critique - + Winged Shadow How High - + Winged Shadow How High (not supported) Winged Shadow How High (non supporté) - - Alti - Alt - - - - Alti+ - Alt+ - - - - VSpeed - Vitesse verticale - - - - - - A1 - - - - - - - A2 - - - - - - A3 - - - - - - A4 - - - - - - FAS - - - - - Cells - Velm - - - - --- - - - - + Delete Sensor. Are you sure? Supprimer le Capteur. Êtes-vous sûr? @@ -12642,279 +12651,99 @@ Trop d'erreurs, abandon. - - Custom - Prédéfini - - - - Calculated - Calculé - - - + Id - + Instance - + Rx - - Add - Addition - - - - Average - Moyenne - - - - Min - - - - - Max - - - - - Multiply - Multiplication - - - - Totalize - Totalisation - - - - Cell - Element LiPo - - - - Consumption - Consommation - - - - Dist - Distance - - - + Cells Sensor : Capteur d'éléments: - - - - - - - - + + + + + + + + --- - + GPS Sensor : Capteur GPS: - + Alt. Sensor : Capteur d'altitude: - + Sensor : Capteur: - - V - - - - - A - - - - - mA - - - - - kt - - - - - m/s - - - - - ft/s - - - - - km/h - - - - - mph - - - - - m - - - - - ft - - - - - °C - - - - - °F - - - - - % - - - - - mAh - - - - - W - - - - - mW - - - - - dBm - - - - - g - - - - - ° - - - - - Rad - - - - - mL - - - - - US fl.Oz. - - - - - Raw (-) - Chiffres bruts (-) - - - - RPM - Tours/minute - - - - ml/min - - - - + Precision Précision - + Ratio - + Blades Pales - + Offset Décalage - + Multiplier Multiplicateur - + Auto Offset Offset auto - + Filter Filtre - + Persistent Persistant - + Positive - + Logs @@ -12922,92 +12751,72 @@ Trop d'erreurs, abandon. TelemetrySensorPanel - + TELE%1 - + Popup menu available Menu contextuel disponible - - Lowest - Min - - - - Cell %1 - Elém. %1 - - - - Highest - Max - - - - Delta - - - - + Copy Copier - + Cut Couper - + Paste Coller - + Clear Effacer - + Insert Insérer - + Delete Supprimer - + Move Up Monter - + Move Down Descendre - + Clear All Effacer Tout - + Cut Telemetry Sensor. Are you sure? Couper le capteur de télémétrie. Êtes-vous sûr? - + Clear Telemetry Sensor. Are you sure? Effacer le capteur de télémétrie. Êtes-vous sûr? - + Clear all Telemetry Sensors. Are you sure? Effacez tous les capteurs de télémétrie. Êtes-vous sûr? @@ -13377,12 +13186,17 @@ hh:mm:ss Timer - + Countdown Compte à rebours - + + Start + Démarrer + + + Minute Call Annonces minutes @@ -13390,21 +13204,91 @@ hh:mm:ss TimerData - + TMR - + Timer %1 Chrono %1 - + TMR as in Timer + + + Silent + Aucun + + + + Beeps + Bips + + + + Voice + Voix + + + + Haptic + Vibreur + + + + 5s + + + + + 10s + + + + + 20s + + + + + 30s + + + + + Not persistent + Non persistant + + + + NOT + + + + + Persistent (flight) + Persistant (vol) + + + + Flight + Vol + + + + Persistent (manual reset) + Persistant (RAZ manuelle) + + + + Manual reset + RAZ manuelle + TimerEdit @@ -13431,44 +13315,6 @@ Utilisez CTRL + le défilement de la souris ou les touches PAGE HAUT/PAGE BAS po - - TimerPanel - - - Silent - Aucun - - - - Beeps - Bips - - - - Voice - Voix - - - - Haptic - Vibreur - - - - Not persistent - Non persistant - - - - Persistent (flight) - Persistant (vol) - - - - Persistent (manual reset) - Persistant (RAZ manuelle) - - Trainer diff --git a/companion/src/translations/companion_ja.ts b/companion/src/translations/companion_ja.ts index 2d7d02b4d2..d423959d4e 100644 --- a/companion/src/translations/companion_ja.ts +++ b/companion/src/translations/companion_ja.ts @@ -730,58 +730,58 @@ Mode 4: Boards - + Left Horizontal 左・横 - + Left Vertical 左・縦 - + Right Vertical 右・縦 - + Right Horizontal 右・横 - + Aux. 1 AUX. 1 - + Aux. 2 AUX. 2 - - + + Unknown 不明 - + Rud ラダー - + Ele エレベーター - + Thr スロットル - + Ail エルロン @@ -828,44 +828,44 @@ Mode 4: - Channels + ChannelsPanel - + Name 名称 - + Subtrim サブトリム - + Min 最小 - + Max 最大 - + Direction 方向 - + Curve カーブ - + PPM Center PPM センター - + Linear Subtrim 線形サブトリム @@ -890,67 +890,67 @@ Mode 4: リバース - + Delete Channel. Are you sure? チャンネルを削除します。よろしいですか? - + Cut Channel. Are you sure? チャンネルを切り取ります。よろしいですか? - + Copy コピー - + Cut 切り取り - + Paste 貼り付け - + Clear 消去 - + Insert 挿入 - + Delete 削除 - + Move Up 上へ移動 - + Move Down 下へ移動 - + Clear All すべて消去 - + Clear Channel. Are you sure? チャンネルを消去します。よろしいですか? - + Clear all Channels. Are you sure? チャンネルをすべて消去します。よろしいですか? @@ -1090,37 +1090,37 @@ Mode 4: 送信機と機体モデルの設定 - + Select or create a file for exported Settings: エクスポートした設定ファイルを選択または作成します: - + Press the 'Retry' button to choose another file. 別のファイルを選択するには『再試行』ボタンを押してください。 - + Simulator for this firmware is not yet available このファームウェアのシミュレータはまだ利用できません - + Uknown error during Simulator startup. シミュレータ起動中に不明なエラーが発生しました。 - + Simulator Error シミュレータ エラー - + Data Load Error データロード エラー - + Error occurred while starting simulator. シミュレータ起動中にエラーが発生しました。 @@ -1376,51 +1376,28 @@ If you have a settings backup file, you may import that instead. - CurveGroup + CurveReference - + Diff 差分 - + Expo エクスポ - + Func 機能 - + Curve カーブ - - CurveReference - - - Diff(%1) - 差分(%1) - - - - Expo(%1) - エクスポ(%1) - - - - Function(%1) - 機能(%1) - - - - Curve(%1) - カーブ(%1) - - Curves @@ -1509,113 +1486,116 @@ If you have a settings backup file, you may import that instead. Point size 点のサイズ + + + CurvesPanel - + Curve %1 カーブ %1 - + Popup menu available 利用可能なポップアップメニュー - + %1 points %1 点 - + Linear 線形 - + Single Expo シングルエクスポ - + Symmetrical f(x)=-f(-x) 対称 f(x)=-f(-x) - + Symmetrical f(x)=f(-x) 対称 f(x)=f(-x) - + Editing curve %1 カーブ %1 編集 - + Not enough free points in EEPROM to store the curve. EEPROMにカーブを保存する十分な空き容量がありません。 - + Copy コピー - + Cut 切り取り - + Paste 貼り付け - + Clear 消去 - + Insert 挿入 - + Delete 削除 - + Move Up 上へ移動 - + Move Down 下へ移動 - + Clear All すべて消去 - + Clear Curve. Are you sure? カーブを消去します。よろしいですか? - + Clear all Curves. Are you sure? カーブをすべて消去します。よろしいですか? - + Cut Curve. Are you sure? カーブを切り取ります。よろしいですか? - + Delete Curve. Are you sure? カーブを削除します。よろしいですか? @@ -1689,8 +1669,13 @@ If you have a settings backup file, you may import that instead. - Set Timer %1 - 設定: タイマー %1 + Set %1 + 設定 %1 + + + + Set Failsafe + フェイルセーフ設定 @@ -1750,75 +1735,50 @@ If you have a settings backup file, you may import that instead. Adjust %1 - アジャスト %1 - - - - SetFailsafe Int. Module - 設定: フェイルセーフ 内部モジュール + 調整 %1 - SetFailsafe Ext. Module - 設定: フェイルセーフ 外部モジュール - - - RangeCheck Int. Module レンジチェック 内部モジュール - + RangeCheck Ext. Module レンジチェック 外部モジュール - + Bind Int. Module バインド 内部モジュール - + Bind Ext. Module バインド 外部モジュール - - Timer1 - タイマー1 - - - - Timer2 - タイマー2 - - - - Timer3 - タイマー3 - - - + Flight フライト - + Telemetry テレメトリー - + Rotary Encoder エンコーダ再生 - + REa エンコーダ再生a - + REb エンコーダ再生b @@ -1855,7 +1815,7 @@ If you have a settings backup file, you may import that instead. 無効 - + CFN CFN @@ -1863,139 +1823,139 @@ If you have a settings backup file, you may import that instead. CustomFunctionsPanel - + Switch スイッチ - + Action 実行 - + Parameters パラメータ - + Enable 有効 - + Popup menu available 利用可能なポップアップメニュー - + SF%1 SF%1 - + GF%1 GF%1 - + ON ON - + Error occurred while trying to play sound, possibly the file is already opened. (Err: %1 [%2]) サウンド再生中にエラーが発生しました。おそらくファイルは既に開かれています (Err: %1 [%2]) - + Unable to find or open sound file: %1 音源ファイルが見つからない、または開けません。 %1 - + Delete Function. Are you sure? ファンクションを削除します。よろしいですか? - + Cut Special Function. Are you sure? ファンクションを切り取ります。よろしいですか? - + Clear Function. Are you sure? ファンクションを消去します。よろしいですか? - + Clear all Functions. Are you sure? ファンクションをすべて消去します。よろしいですか? - + Copy コピー - + Cut 切り取り - + Paste 貼り付け - + Clear 消去 - + Insert 挿入 - + Delete 削除 - + Move Up 上へ移動 - + Move Down 下へ移動 - + Clear All すべて消去 - + Value - + Source 選択元 - + GVAR GVAR - + Increment 増加 @@ -2163,48 +2123,48 @@ If you have a settings backup file, you may import that instead. フィールド %1 変換エラー - + Switch スイッチ - + Switch スイッチ - + cannot be exported on this board! このボードにエクスポートできません! - + Source 選択元 - + Source %1 cannot be exported on this board! このボードでは選択元 %1 をエクスポートできません! - + OpenTX only accepts %1 points in all curves OpenTXはすべてのカーブで %1 点のみを許容します - + OpenTx only accepts %1 points in all curves OpenTxはすべてのカーブで %1 点のみを許容します - - + + OpenTX on this board doesn't accept this function このボード上のOpenTXはこの機能を受け付けません - + OpenTX doesn't accept this radio protocol OpenTXはこの送信機プロトコルを受け付けません @@ -2219,18 +2179,18 @@ If you have a settings backup file, you may import that instead. <html><head/><body><p>Enable or disable the filter. If the button won't stay enabled, it is likely there is a syntax error in the Regular Expression entered.</p></body></html> - <html><head/><body><p>フィルタを有効または無効にします。ボタンが有効にならない場合は、入力した正規表現に構文エラーがある可能性があります。</p></body></html> + <html><head/><body><p>フィルターを有効または無効にします。ボタンが有効にならない場合は、入力した正規表現に構文エラーがある可能性があります。</p></body></html> Filter: - フィルタ: + フィルター: <html><head/><body><p>Enter filter text here. Click the help/info button for details about using the filter. </p><p> To <b>remove a remembered entry</b> from the filter list, first choose it, and then press <code>Shift-Delete</code> (or <code>Shift-Backspace</code>) key combination.</p></body></html> - <html><head/><body><p>ここにフィルタテキストを入力してください。フィルタの使用方法の詳細は、help / info ボタンをクリックしてください。</p><p> + <html><head/><body><p>ここにフィルタテキストを入力してください。フィルターの使用方法の詳細は、help / info ボタンをクリックしてください。</p><p> フィルタリストから<b>保存したエントリを削除</b>するには、選択してから<code>Shift+Delete</code> (または<code>Shift+Backspace</code>) キーを押してください。</p></body></html> @@ -2246,12 +2206,12 @@ To <b>remove a remembered entry</b> from the filter list, first cho Filter &Help - フィルタ &ヘルプ + フィルター &ヘルプ Show information about using the filter. - フィルタの使用に関する情報を表示します。 + フィルターの使用に関する情報を表示します。 @@ -2276,22 +2236,22 @@ To <b>remove a remembered entry</b> from the filter list, first cho Enable &Filter - 有効 &フィルタ + 有効 &フィルター Turn the filter on/off. - フィルタをON / OFFします。 + フィルターをON / OFFします。 <html><head><style>kbd {background-color: palette(alternate-base); font-size: large; white-space: nowrap;}</style></head><body><p>The filter supports two syntax types: basic matching with common wildcards as well as full Perl-style (<code>pcre</code>) Regular Expressions.</p><p>By default a filter will only show lines which match (<b>inclusive</b>). To make an <b>exclusive</b> filter which removes matching lines, prefix the filter expression with a <kbd>!</kbd> (exclamation mark).</p><p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). <ul><li>Put the <kbd>/</kbd> or <kbd>^</kbd> after the exclusive <kbd>!</kbd> indicator if you're using one.</li><li>By default the match is case-sensitive. To make it insensitive, add the typical <kbd>/i</kbd> (slash i) operator at the end of your RegEx.</li><li>If you use a caret (^) to denote a RegEx, it will become part of the Reg. Ex. (that is, matches from start of line).</li><li>If the RegEx is invalid, the filter edit field should show a red border and you will not be able to enable the filter.</li><li>A useful resource for testing REs (with a full reference) can be found at <a href="http://www.regexr.com/">http://www.regexr.com/</a></li></ul></p><p>To use <b>basic matching</b> just type any text.<ul><li>Wildcards: <kbd>*</kbd> (asterisk) matches zero or more of any character(s), and <kbd>?</kbd> (question mark) matches any single character.</li><li>The match is always case-insensitive.</li><li>The match always starts from the beginning of a log line. To ignore characters at the start, use a leading <kbd>*</kbd> wildcard.</li><li>A trailing <kbd>*</kbd> is always implied (that is, matches anything to the end of the log line). To avoid this, use a RegEx.</li><li>You can match literal wildcard characters by prefixing them with a <kbd>\</kbd> (backslash) character (eg. "foo\*bar" matches "foo*bar").</li></ul></p><p>After <b>editing text</b>, press ENTER or TAB key (or click anywhere outside the box) to update the filter.</p><p>To <b>remove an entry</b> from the filter selector list, first choose it, and while in the line editor press <kbd>Shift-Delete</kbd> (or <kbd>Shift-Backspace</kbd>) key combination. The default filters cannot be removed. Up to 50 filters are stored.</p></body></html> - <html><head><style>kbd {background-color: palette(alternate-base); font-size: large; white-space: nowrap;}</style></head><body><p>フィルタは2つのシンタックスタイプをサポートしています: 一般的なワイルドカードを用いた完全一致、そして完全なPerlスタイル (<code>pcre</code>) 正規表現です。初期値ではフィルタは一致する (<b>包括的</b>) な行のみを表示します。一致する行を削除する<b>排他的</b>フィルタを作成するには、フィルタ式の先頭に<kbd>!</kbd>(Exclamationマーク)を付けます。</p><p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). <b>正規表現</b> (RegEx)を使用するには、フィルタテキストの先頭に<kbd>/</kbd> (スラッシュ) または<kbd>^</kbd>(アップキャレット)を付けます。<ul><li>既に <kbd>/</kbd> または <kbd>^</kbd> を使用している場合は、 <kbd>!</kbd> の後ろに置きます。</li><li>初期値では大文字と小文字が区別されます。それを鈍感にするには、正規表現の最後に典型的な <kbd>/i</kbd> (スラッシュ+i)演算子を追加します。</li> <li> 正規表現を表すためにキャレット『^』を使用すると、それは正規表現の一部になります。例(つまり、行頭から一致します。)</li> <li> 正規表現が無効な場合、フィルタ編集フィールドには赤い枠が表示されフィルタを有効にすることはできません。</li> <li> 正規表現のテストに役立つリソース(参考文献)は、<a href="http://www.regexr.com/"> http://www.regexr.com/にあります。</a></li> </ul></p><p><b>標準一致 basic matching</b> を使用するには、テキストを入力するだけです。<ul><li>ワイルドカード: <kbd>*</kbd> (アスタリスク)は0個以上の任意の文字に一致し、 <kbd>?</kbd> (クエスチョンマーク) は任意の1文字に一致します。</li><li>この一致では常に大文字と小文字が区別されません。</li><li>一致は常にログの先頭行から始まります。 先頭の文字を無視するには、先頭に<kbd>*</kbd>ワイルドカードを使用します。</li><li>末尾の <kbd>*</kbd> は常に暗黙的に指定されます。(つまり、ログ末尾行までが対象) これを回避するには、正規表現を使用します。</li><li>リテラルワイルドカード文字の前に <kbd>\</kbd> (バックスラッシュ) 文字を付けることで一致させることができます。(例: "foo\*bar"は"foo*bar"と一致)</li></ul></p><p><b>テキスト編集</b>後、EnterまたはTabキーを押して (またはボックスの外側をクリックし) フィルタを更新します。</p><p>フィルタセレクタリストから<b>エントリー削除</b>をするには、まずエントリーを選択しエディタで<kbd>Shift+Delete</kbd> (または<kbd>Shift+Backspace</kbd>) を押します。デフォルトのフィルタは削除できません。また最大50個のフィルタが保存されています。</p></body></html> + <html><head><style>kbd {background-color: palette(alternate-base); font-size: large; white-space: nowrap;}</style></head><body><p>フィルターは2つのシンタックスタイプをサポートしています: 一般的なワイルドカードを用いた完全一致、そして完全なPerlスタイル (<code>pcre</code>) 正規表現です。初期値ではフィルターは一致する (<b>包括的</b>) な行のみを表示します。一致する行を削除する<b>排他的</b>フィルターを作成するには、フィルター式の先頭に<kbd>!</kbd>(Exclamationマーク)を付けます。</p><p>To use <b>Regular Expressions</b> (RegEx), prefix the filter text with a <kbd>/</kbd> (slash) or <kbd>^</kbd> (up caret). <b>正規表現</b> (RegEx)を使用するには、フィルターテキストの先頭に<kbd>/</kbd> (スラッシュ) または<kbd>^</kbd>(アップキャレット)を付けます。<ul><li>既に <kbd>/</kbd> または <kbd>^</kbd> を使用している場合は、 <kbd>!</kbd> の後ろに置きます。</li><li>初期値では大文字と小文字が区別されます。それを鈍感にするには、正規表現の最後に典型的な <kbd>/i</kbd> (スラッシュ+i)演算子を追加します。</li> <li> 正規表現を表すためにキャレット『^』を使用すると、それは正規表現の一部になります。例(つまり、行頭から一致します。)</li> <li> 正規表現が無効な場合、フィルター編集フィールドには赤い枠が表示されフィルターを有効にすることはできません。</li> <li> 正規表現のテストに役立つリソース(参考文献)は、<a href="http://www.regexr.com/"> http://www.regexr.com/にあります。</a></li> </ul></p><p><b>標準一致 basic matching</b> を使用するには、テキストを入力するだけです。<ul><li>ワイルドカード: <kbd>*</kbd> (アスタリスク)は0個以上の任意の文字に一致し、 <kbd>?</kbd> (クエスチョンマーク) は任意の1文字に一致します。</li><li>この一致では常に大文字と小文字が区別されません。</li><li>一致は常にログの先頭行から始まります。 先頭の文字を無視するには、先頭に<kbd>*</kbd>ワイルドカードを使用します。</li><li>末尾の <kbd>*</kbd> は常に暗黙的に指定されます。(つまり、ログ末尾行までが対象) これを回避するには、正規表現を使用します。</li><li>リテラルワイルドカード文字の前に <kbd>\</kbd> (バックスラッシュ) 文字を付けることで一致させることができます。(例: "foo\*bar"は"foo*bar"と一致)</li></ul></p><p><b>テキスト編集</b>後、EnterまたはTabキーを押して (またはボックスの外側をクリックし) フィルターを更新します。</p><p>フィルターセレクタリストから<b>エントリー削除</b>をするには、まずエントリーを選択しエディタで<kbd>Shift+Delete</kbd> (または<kbd>Shift+Backspace</kbd>) を押します。デフォルトのフィルターは削除できません。また最大50個のフィルターが保存されています。</p></body></html> Debug Console Filter Help - デバッグコンソールフィルタ ヘルプ + デバッグコンソールフィルター ヘルプ @@ -2536,27 +2496,27 @@ If blank then the input is considered to be "ON" all the time.ミキサー選択元 - + Edit %1 編集 %1 - + Popup menu available 利用可能なポップアップメニュー - + Clear All すべて消去 - + Set All すべて設定 - + Invert All すべてリバース @@ -2925,255 +2885,293 @@ Blank means include all. ?, *, and [...] wildcards accepted. Firmware - + Channel values displayed in us 表示されるチャンネル値 - + No OverrideCH functions available 使用可能な上書きチャンネル機能はありません - + Possibility to enable FAI MODE (no telemetry) at field フィールドでFAIモード (テレメトリーなし) を有効にする可能性 - + FAI MODE (no telemetry) always enabled FAIモード (テレメトリーなし) を常に有効 - + Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015 2015/01/01以降に販売された送信機に対し、EUでの使用に適さないD8 FrSkyプロトコルサポートを削除 - + Enable non certified firmwares 認定されていないファームウェアを有効にする - - + + + + + Disable HELI menu and cyclic mix support HELIメニューとサイクリックミックスサポートを無効にする - - + + + + + Disable Global variables グローバル変数を無効にする - - + + + + + Enable Lua custom scripts screen Luaカスタムスクリプト画面を有効にする - + Use alternative SQT5 font SQT5 代替フォントを使用する - + Pots use in menus navigation メニューナビゲーションでダイヤルを使用 - + FrSky Taranis X9D+ FrSky Taranis X9D+ - - + + Disable RAS (SWR) RAS (SWR)を無効にする - + FrSky Taranis X9D+ 2019 - + FrSky Taranis X9D FrSky Taranis X9D - + Haptic module installed タッチパネル対応モジュールをインストール - + FrSky Taranis X9E FrSky Taranis X9E - + Confirmation before radio shutdown 送信機シャットダウン前の確認 - + Horus gimbals installed (Hall sensors) Horusジンバル (ホールセンサー) をインストール - + FrSky Taranis X9-Lite FrSky Taranis X9-Lite - + FrSky Taranis X9-Lite S - + FrSky Taranis X7 / X7S FrSky Taranis X7 / X7S - + FrSky Taranis X-Lite S/PRO FrSky Taranis X-Lite S/PRO - + FrSky Taranis X-Lite FrSky Taranis X-Lite - + FrSky Horus X10 / X10S FrSky Horus X10 / X10S - + + + + + + Support hardware mod: R9M ACCESS + ハードウェアモジュールサポート: R9M ACCESS + + + FrSky Horus X12S FrSky Horus X12S - + Use ONLY with first DEV pcb version 初期DEV pcbバージョンでのみ使用 - - + + Support for MULTI internal module MULTI内部モジュールのサポート - - - + + Jumper T-Lite + Jumper T-Lite + + + + + Support for bluetooth module Bluetoothモジュールのサポート - + + Radiomaster TX12 + Radiomaster TX12 + + + + Radiomaster T8 + Radiomaster T8 + + + + Allow bind using bind key + バインドキーを使用したバインドを許可 + + + Radiomaster TX16S / SE / Hall / Masterfire Radiomaster TX16S / SE / Hall / Masterfire - + Jumper T18 Jumper T18 - + Turnigy 9XR-PRO Turnigy 9XR-PRO - + Enable HELI menu and cyclic mix support HELIメニューとサイクリックミックスのサポートを有効にする - + Enable AFHDS3 support AFHDS3サポート 有効 - + Global variables グローバル変数 - + In model setup menus automatically set source by moving the control モデル設定メニューでは、コントローラーを動かし自動的に選択元を設定します - + In model setup menus automatically set switch by moving the control モデル設定メニューでは、コントローラーを動かし自動的にスイッチを設定します - + No graphical check boxes and sliders グラフィカルなチェックボックスとスライダーはありません - + Battery graph バッテリーグラフ - + Don't use bold font for highlighting active items 有効なアイテムを強調表示するために太字フォントを使用しない - + FrSky Taranis X7 / X7S Access FrSky Taranis X7 / X7S ACCESS - - + + Support for ACCESS internal module replacement ACCESS内部モジュール変更のサポート - + Enable resetting values by pressing up and down at the same time 上下に同時に押し、値のリセットを有効にする - + 9X with AR9X board 9X AR9Xボード - + FrSky Horus X10 Express / X10S Express FrSky Horus X10 Express / X10S Express - + Jumper T12 / T12 Pro Jumper T12 / T12 Pro - + Jumper T16 / T16+ / T16 Pro Jumper T16 / T16+ / T16 Pro - + Support internal GPS 内蔵GPSサポート - + 9X with Sky9x board 9X Sky9Xボード @@ -3670,88 +3668,88 @@ You are currently using: FlightModePanel - - + + Popup menu available 利用可能なポップアップメニュー - + Trim disabled トリム 無効 - + Own Trim 独自トリム - + Use Trim from Flight mode %1 フライトモードからトリムを使用してください %1 - + Use Trim from Flight mode %1 + Own Trim as an offset フライトモードからトリムを使用してください %1+オフセット独自トリム - + Rotary Encoder %1 ロータリーエンコーダ %1 - + Name 名称 - + Value source 元値 - + Value - + Unit ユニット - + Prec - + Min 最小 - + Max 最大 - + Popup enabled ポップアップ有効 - + GVAR%1 - + 0._ - + 0.0 0.0 @@ -3767,49 +3765,49 @@ You are currently using: - + Copy コピー - + Cut 切り取り - + Paste 貼り付け - + Insert 挿入 - + Delete 削除 - + Move Up 上へ移動 - + Move Down 下へ移動 - + Clear All すべて消去 @@ -3819,63 +3817,63 @@ You are currently using: フライトモードを消去します。よろしいですか? - + Clear all Flight Modes. Are you sure? フライトモードをすべて消去します。よろしいですか? - + Cut Flight Mode. Are you sure? フライトモードを切り取ります。よろしいですか? - + Delete Flight Mode. Are you sure? フライトモードを削除します。よろしいですか? - + Clear Global Variable across all Flight Modes. Are you sure? すべてのフライトモードのグローバル変数を消去します。よろしいですか? - + Clear Global Variable. Are you sure? グローバル変数を消去します。よろしいですか? - + Cut Global Variable across all Flight Modes. Are you sure? すべてのフライトモードのグローバル変数を切り取ります。よろしいですか? - + Cut Global Variable. Are you sure? グローバル変数を切り取ります。よろしいですか? - + Delete Global Variable. Are you sure? グローバル変数を削除します。よろしいですか? - + Paste to selected Global Variable across all Flight Modes. Are you sure? すべてのフライトモードで選択したグローバル変数を貼り付けます。よろしいですか? - + Clear all Global Variables for all Flight Modes. Are you sure? すべてのフライトモードのすべてのグローバル変数を消去します。よろしいですか? - + Clear all Global Variables for this Flight Mode. Are you sure? このフライトモードのすべてのグローバル変数を消去します。よろしいですか? - + Clear 消去 @@ -3883,17 +3881,17 @@ You are currently using: FlightModesPanel - + Flight Mode %1 フライトモード %1 - + (%1) (%1) - + (default) (初期値) @@ -4133,12 +4131,12 @@ p, li { white-space: pre-wrap; } - + Own value 独自トリム - + Flight mode %1 value フライトモード %1 値 @@ -4168,52 +4166,52 @@ These will be relevant for all models in the same EEPROM. これらは同じEEPROM内のすべてのモデルに関連します。 - + Setup セットアップ - + Global Functions グローバルファンクション - + Trainer トレーナー - + Hardware ハードウェア - + Calibration 校正 - + Wrong data in profile, radio calibration was not retrieved プロファイルデータが正しくなく、送信機校正情報が取得できませんでした - + Wrong data in profile, Switch/pot config not retrieved プロファイルデータが正しくなく、スイッチ/ダイヤル構成が取得できませんでした - + Wrong data in profile, hw related parameters were not retrieved プロファイルデータが正しくなく、HW関連パラメーターが取得できませんでした - + Do you want to store calibration in %1 profile<br>overwriting existing calibration? 既存の校正情報を上書きして %1 プロファイルに校正情報を保存しますか? - + Calibration and HW parameters saved. 校正情報とHWパラメータが保存されました。 @@ -4221,7 +4219,7 @@ These will be relevant for all models in the same EEPROM. GeneralSettings - + Radio Settings 送信機設定 @@ -4306,7 +4304,7 @@ These will be relevant for all models in the same EEPROM. Adjust RTC - 時計調整 + 内蔵時計調整 @@ -4823,7 +4821,7 @@ Acceptable values are 5v..10v Low EEPROM Warning - EEPROM残量警告 + EEPROM 残量警告 @@ -5262,252 +5260,257 @@ Are you sure ? フォーム - + SQ SQ - + SR SR - + LS2 LS2 - + SP SP - + SO SO - + S4 S4 - + RS RS - + SB SB - + PPM 2 PPM 2 - + Antenna アンテナ - + S5 S5 - + OFF OFF - + S-Port Mirror S-Port ミラー - + Telemetry テレメトリー - + SBUS Trainer SBUS トレーナー - + Debug デバッグ - + RTC Batt Check - RTC Battチェック + 内蔵電池チェック - + + S.Port Power + S.Port 出力 + + + Rud ラダー - + PPM 3 PPM 3 - + S1 S1 - + S2 S2 - + S3 S3 - + PPM 1 PPM 1 - + Serial Port シリアルポート - + v v - + PPM Multiplier PPM 乗算 - + Current Offset 現在のオフセット - + PPM 4 PPM 4 - + SA SA - + Ele エレベーター - + Ail エルロン - + Thr スロットル - + SC SC - + LS LS - + SD SD - + Battery Offset バッテリーオフセット - + SE SE - + SF SF - + SG SG - + SH SH - + SI SI - + SJ SJ - + SK SK - + SL SL - + SM SM - + SN SN - + RS2 RS2 - + Bluetooth Bluetooth - + ADC Filter - ADCフィルタ + ADCフィルター - + Device Name: デバイス名: @@ -5516,8 +5519,8 @@ Are you sure ? HardwarePanel - - + + None なし @@ -5537,67 +5540,67 @@ Are you sure ? 3 ポジション - + Pot with detent ダイヤル (ノッチあり) - + Multipos switch マルチPosスイッチ - + Pot without detent ダイヤル (ノッチなし) - + Slider with detent スライダー (ノッチあり) - + OFF OFF - + Enabled 有効 - + Telemetry テレメトリー - + Trainer トレーナー - + Internal 内部 - + Ask 確認 - + Per model Per モデル - + Internal + External 内部 + 外部 - + External 外部 @@ -5723,159 +5726,159 @@ Are you sure ? InputsPanel - - - + + + Move Up 上へ移動 - - + + Ctrl+Up - - - + + + Move Down 下へ移動 - - + + Ctrl+Down - + Clear All Inputs すべての入力項目を消去 - + Not enough available Inputs! 入力項目が不足しています! - + Delete selected Input lines. Are you sure? 選択したInput行を削除します。よろしいですか? - + Cut selected Input lines. Are you sure? 選択したInput行を切り取ります。よろしいですか? - + Lines 直線 - + &Add &追加 - + Ctrl+A - + &Edit &編集 - + Enter Enter - + &Delete &削除 - - + + Delete 削除 - + &Copy &コピー - + Ctrl+C - + &Cut &切り取り - + Ctrl+X - + &Paste &貼り付け - + Ctrl+V - + Du&plicate &複製 - + Ctrl+U - + Input 入力 - + Insert 挿入 - + Clear 消去 - + Clear All すべて消去 - + Clear all Input lines. Are you sure? すべてのInput行を消去します。よろしいですか? - + Clear all lines for the selected Inputs. Are you sure? 選択したすべてのInput行を消去します。よろしいですか? - + Delete all lines for the selected Inputs. Are you sure? 選択したすべてのInput行を削除します。よろしいですか? @@ -5901,7 +5904,7 @@ Are you sure ? LimitsGroup - + GV @@ -6032,112 +6035,112 @@ Are you sure ? LogicalSwitchesPanel - + Function 機能 - + V1 - + V2 - + AND Switch & スイッチ - + Duration 期間 - + Delay 遅延 - + Popup menu available 利用可能なポップアップメニュー - + (instant) (瞬間) - + (infinite) (無制限) - + Delete Logical Switch. Are you sure? 論理スイッチを削除します。よろしいですか? - + Cut Logical Switch. Are you sure? 論理スイッチを切り取ります。よろしいですか? - + Copy コピー - + Cut 切り取り - + Paste 貼り付け - + Clear 消去 - + Insert 挿入 - + Delete 削除 - + Move Up 上へ移動 - + Move Down 下へ移動 - + Clear All すべて消去 - + Clear Logical Switch. Are you sure? 論理スイッチを消去します。よろしいですか? - + Clear all Logical Switches. Are you sure? 論理スイッチをすべて消去します。よろしいですか? @@ -7872,27 +7875,27 @@ If blank then the mix is considered to be "ON" all the time. 空白の場合、ミックスは常に『オン』と見なします。 - + DEST -> %1 - + Click to access popup menu クリックしてポップアップメニューにアクセス - + Clear All すべて消去 - + Set All すべて設定 - + Invert All すべてリバース @@ -7923,136 +7926,136 @@ If blank then the mix is considered to be "ON" all the time. MixesPanel - - + + Move Up 上へ移動 - - + + Ctrl+Up - - + + Move Down 下へ移動 - - + + Ctrl+Down - + Clear Mixes ミキサーを消去 - + Not enough available mixers! ミキサー項目が足りません! - + Delete selected Mix lines. Are you sure? 選択したMix行を削除します。よろしいですか? - + Cut selected Mix lines. Are you sure? 選択したMix行を切り取ります。よろしいですか? - + &Add &追加 - + Ctrl+A - + &Edit &編集 - + Enter Enter - + &Toggle highlight &ハイライト切替 - + Ctrl+T - + &Delete &削除 - + Delete 削除 - + &Copy &コピー - + Ctrl+C - + C&ut &切り取り - + Ctrl+X - + &Paste &貼り付け - + Ctrl+V - + Du&plicate &複製 - + Ctrl+U - + Clear Mixes? ミキサーを消去しますか? - + Really clear all the mixes? すべてのミキサーを本当に消去しますか? @@ -8069,6 +8072,11 @@ If blank then the mix is considered to be "ON" all the time. Throttle Source スロットル値 + + + THR + THR + ModelEdit @@ -8083,52 +8091,52 @@ If blank then the mix is considered to be "ON" all the time. シミュレート - + Setup セットアップ - + Heli ヘリ - + Flight Modes フライトモード - + Inputs 入力 - + Mixes ミキサー - + Outputs 出力 - + Curves カーブ - + Logical Switches 論理スイッチ - + Special Functions スペシャルファンクション - + Telemetry テレメトリー @@ -8183,8 +8191,8 @@ If blank then the mix is considered to be "ON" all the time. - - + + OFF OFF @@ -8225,7 +8233,7 @@ If blank then the mix is considered to be "ON" all the time. - + Mode モード @@ -8259,14 +8267,13 @@ If blank then the mix is considered to be "ON" all the time. - - + Delay 遅延 - + Receiver 受信機 @@ -8358,11 +8365,10 @@ If blank then the mix is considered to be "ON" all the time. - - - - - + + + + None なし @@ -8403,528 +8409,353 @@ If blank then the mix is considered to be "ON" all the time. FM%1+%2 - - - - Weight - ウェイト - - - - - Switch - スイッチ - - + NoTrim トリムなし + Offset(%1) オフセット(%1) - + MULT! 複数! - + No DR/Expo DR/Expoなし - - - Offset - オフセット + + + Weight(%1) + ウェイト(%1) - - Slow - ゆっくり + + + Switch(%1) + スイッチ(%1) - - Warn - 警告 + + Delay(u%1:d%2) + 遅延(u%1:d%2) - + + Slow(u%1:d%2) + 速度低下(u%1:d%2) + + + + Warn(%1) + 警告(%1) + + + Disabled in all flight modes すべてのフライトモードを無効 - + Flight modes フライトモード - + Flight mode フライトモード - + All すべて - + Edge Edge:端 - + instant 簡易 - + Sticky Sticky:追尾 - + Timer タイマー - + missing 間違い - + Duration 期間 - - - + + Custom カスタム - + Standard 標準 - + Extended Limits 拡張制限 - + Display Checklist ディスプレイ チェックリスト - + Global Functions グローバルファンクション - + Manual 手動 - + Auto 自動 - + Failsafe Mode フェイルセーフモード - - + + Hold ホールド - + No Pulse パルスなし - + Not set セットなし - + No pulses パルスなし - + Silent 消音 - + Beeps ビープ - + Voice 音声 - + Haptic タッチパネル - + Flight フライト - + Manual reset 手動リセット - + Step ステップ - + Display ディスプレイ - + Extended 拡張 - + Never なし - + On Change 変更 - + Always 常に - - - + + + Source 選択元 - + Trim idle only トリムアイドルのみ - + Warning 警告 - + Reversed リバース - + Tmr Tmr - + FrSky S.PORT - + FrSky D - + FrSky D (cable) - + Alti - + Alti+ - + VSpeed - - - + + + A1 - - - + + + A2 - - + + A3 - - + + A4 - - + + FAS - + Cells セル - - Calculated - 計算値 - - - - Add - 追加 - - - - Average - 平均 - - - - + Min 最小 - - + Max 最大 - - Multiply - 乗算 - - - - Totalise - 合計 - - - - Cell - セル - - - - Consumption - 消費 - - - - Distance - 距離 - - - - Lowest - より低く - - - - Cell %1 - セル %1 - - - - Highest - より高く - - - - Delta - 差分 - - - - Formula - 定式 - - - - - Id - - - - - Instance - インスタンス - - - - - - - Sensor - センサー - - - - - Sources - 選択元 - - - - - GPS - GPS - - - - Alt. - Alt. - - - - - Blades - ブレード - - - - Multi. - マルチ. - - - - F - - - - - Inst - - - - - Alt - - - - - Unit - - - - - Prec - 精度 - - - - Ratio - レシオ - - - - Multi - マルチ - - - - A/Offset - A/オフセット - - - - Filter - フィルタ - - - - Persist - 持続 - - - - Positive - ノーマル - - - - Log - ログ - - - + Numbers ナンバー - + Bars バー - + Script スクリプト - + Filename ファイル名 - + Error: Unable to open or read file! エラー: ファイルを開けないか、読み取れません! @@ -9019,7 +8850,7 @@ If blank then the mix is considered to be "ON" all the time. Low Power - 低パワー + 低出力 @@ -9320,12 +9151,12 @@ If blank then the mix is considered to be "ON" all the time. 2 W - + Positive ノーマル - + Negative リバース @@ -9333,42 +9164,42 @@ If blank then the mix is considered to be "ON" all the time. ModulePanel - + Value - + Hold ホールド - + No Pulse パルスなし - + Ask 確認 - + Internal 内部 - + Internal + External 内部 + 外部 - + External 外部 - + Bind on channel チャンネルへバインド @@ -9844,22 +9675,22 @@ If blank then the mix is considered to be "ON" all the time. OpenTxEepromInterface - + Unknown error 不明のエラー - + ... plus %1 errors ...追加 %1 エラー - + Cannot write radio settings 送信機設定を書き込めません - + Cannot write model %1 機体モデル %1 を書き込めません @@ -10007,12 +9838,12 @@ If blank then the mix is considered to be "ON" all the time. QObject - + WARNING 警告 - + <p>Importing JumperTX data into OpenTX 2.3 is <b>not supported and dangerous.</b></p> <p>It is unfortunately not possible for us to differentiate JumperTX data from legitimate FrSky X10 data, but <b>You should only continue here if the file you opened comes from a real FrSky X10.</b></p> <p>Do you really want to continue?</p> <p>JumperTXデータをOpenTX 2.3にインポートすることは<b>サポート対象外となり危険な行為です。</b></p> <p>残念ながら、JumperTXデータを正当なFrSky X10データと区別することができませんが、<b>開いたファイルが実際のFrSky X10で生成されたものである場合にのみ、続行する事ができます。</b></p> <p>本当に続行しますか?</p> @@ -10367,17 +10198,6 @@ X REb エンコーダ再生b - - - - ??? - - - - - ---- - - I @@ -10406,7 +10226,7 @@ X - + SRC @@ -10414,22 +10234,22 @@ X RawSwitch - + - + - + - - + ! @@ -10654,146 +10474,327 @@ X SensorData - - + + Formula + 定式 + + + + Id + ID + + + + Instance + インスタンス + + + + + Sensor + センサー + + + + Sources + 選択元 + + + + GPS + GPS + + + + Alt + 高度 + + + + Unit + ユニット + + + + Precision + 精度 + + + + Ratio + レシオ + + + + Offset + オフセット + + + + Auto Offset + 自動オフセット + + + + Blades + ブレード + + + + Multiplier + 乗算 + + + + Filter + フィルター + + + + Persist + 持続 + + + + Positive + ノーマル + + + + Log + ログ + + + + Custom + カスタム + + + + Calculated + 計算値 + + + + Add + 追加 + + + + Average + 平均 + + + + Minimum + 最低値 + + + + Maximum + 最大値 + + + + Multiply + 乗算 + + + + Totalize + 合計 + + + + Cell + セル + + + + Consumption + 消費 + + + + Distance + 距離 + + + + Lowest + より低く + + + + Cell %1 + セル %1 + + + + Highest + より高く + + + + Delta + 差分 + + + + Raw (-) + Raw (-) + + + + V V - + A - + mA - + kts - + m/s - + km/h - + mph - + m - + f - + °C - + °F - + % - + mAh - + W - + mW - + dB - + rpms - + g - + ° - + Rad - + hours - + minutes - + seconds - + ml/minute - + Hertz - + mS - + uS - + TELE + + + Y + Y + + + + N + N + Setup @@ -10975,92 +10976,92 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi SetupPanel - + Popup menu available 利用可能なポップアップメニュー - + Timer %1 タイマー %1 - + THR - + Profile Settings プロファイル設定 - + SD structure path not specified or invalid SDカード保存先パスが指定されていないか無効です - + Copy コピー - + Cut 切り取り - + Paste 貼り付け - + Clear 消去 - + Insert 挿入 - + Delete 削除 - + Move Up 上へ移動 - + Move Down 下へ移動 - + Clear All すべて消去 - + Clear Timer. Are you sure? タイマーを消去します。よろしいですか? - + Clear all Timers. Are you sure? タイマーをすべて消去します。よろしいですか? - + Cut Timer. Are you sure? タイマーを切り取ります。よろしいですか? - + Delete Timer. Are you sure? タイマーを削除します。よろしいですか? @@ -11786,62 +11787,62 @@ The default is configured in the chosen Radio Profile. 送信機シミュレータ (%1) - + Could not determine startup data source. 起動データ元を特定できませんでした。 - + Could not load data, possibly wrong format. データをロードできません、フォーマットが間違っている可能性があります。 - + Data Load Error データロード エラー - + Invalid startup data provided. Plese specify a proper file/path. 無効なスタートアップデータが提供されました。正しいファイル/パスを指定してください。 - + Simulator Startup Error シミュレータ スタートアップ エラー - + Error saving data: could open file for writing: '%1' データ保存エラー: 書き込み用にファイルを開くことができました: 「%1」 - + Error saving data: could not get data from simulator interface. データ保存エラー: シミュレータのインターフェイスからデータを取得できませんでした。 - + An unexpected error occurred while attempting to save radio data to file '%1'. 送信機データをファイル「%1」に保存しようとしたときに予期せぬエラーが発生しました。 - + Data Save Error データ保存 エラー - + Cannot open joystick, joystick disabled スティックが接続不可、もしくはスティックが無効です - + Radio firmware error: %1 送信機 ファームウェア エラー: %1 - + - Flight Mode %1 (#%2) - フライトモード %1 (#%2) @@ -12514,22 +12515,22 @@ Too many errors, giving up. 最大 - + None なし - + Numbers ナンバー - + Bars バー - + Script スクリプト @@ -12537,109 +12538,52 @@ Too many errors, giving up. TelemetryPanel - + Telemetry screen %1 テレメトリースクリーン %1 - + FrSky S.PORT - + FrSky D - + FrSky D (cable) - + Source 信号元 - + Low Alarm 低アラーム - + Critical Alarm クリティカルアラーム - + Winged Shadow How High Winged Shadow How High - + Winged Shadow How High (not supported) Winged Shadow How High (サポートなし) - - Alti - - - - - Alti+ - - - - - VSpeed - - - - - - - A1 - - - - - - - A2 - - - - - - A3 - - - - - - A4 - - - - - - FAS - - - - - Cells - セル - - - - --- - --- - - - + Delete Sensor. Are you sure? テレメトリーセンサーを削除します。よろしいですか? @@ -12657,279 +12601,99 @@ Too many errors, giving up. TELE## - - Custom - カスタム - - - - Calculated - 計算値 - - - + Id ID - + Instance インスタンス - + Rx 受信 - - Add - 追加 - - - - Average - 平均 - - - - Min - 最小 - - - - Max - 最大 - - - - Multiply - 乗算 - - - - Totalize - 合計 - - - - Cell - セル - - - - Consumption - 消費 - - - - Dist - 距離 - - - + Cells Sensor : セル センサー : - - - - - - - - + + + + + + + + --- --- - + GPS Sensor : GPS センサー : - + Alt. Sensor : 高度 センサー : - + Sensor : センサー : - - Raw (-) - Raw (-) - - - - V - V - - - - A - - - - - mA - - - - - kt - - - - - m/s - - - - - ft/s - - - - - km/h - - - - - mph - - - - - m - - - - - ft - - - - - °C - - - - - °F - - - - - % - - - - - mAh - - - - - W - - - - - mW - - - - - dBm - - - - - RPM - - - - - g - - - - - ° - - - - - Rad - - - - - mL - - - - - US fl.Oz. - - - - - ml/min - - - - + Precision 精度 - + Ratio レシオ - + Blades ブレード - + Offset オフセット - + Multiplier 乗算 - + Auto Offset 自動オフセット - + Filter - フィルタ + フィルター - + Persistent 持続 - + Positive ノーマル - + Logs ログ @@ -12937,92 +12701,72 @@ Too many errors, giving up. TelemetrySensorPanel - + TELE%1 - + Popup menu available 利用可能なポップアップメニュー - - Lowest - より低く - - - - Cell %1 - セル %1 - - - - Highest - より高く - - - - Delta - 差分 - - - + Copy コピー - + Cut 切り取り - + Paste 貼り付け - + Clear 消去 - + Insert 挿入 - + Delete 削除 - + Move Up 上へ移動 - + Move Down 下へ移動 - + Clear All すべて消去 - + Cut Telemetry Sensor. Are you sure? テレメトリーセンサーを切り取ります。よろしいですか? - + Clear Telemetry Sensor. Are you sure? テレメトリーセンサーを消去します。よろしいですか? - + Clear all Telemetry Sensors. Are you sure? テレメトリーセンサーのすべてを消去します。よろしいですか? @@ -13391,12 +13135,12 @@ hh:mm:ss Timer - + Countdown カウントダウン - + Minute Call 音声時報 @@ -13857,7 +13601,7 @@ CTRL+スクロールまたはPAGE UP/DOWNキーを押すと、大きなステ Has your helicopter got an adjustable gyro for the tail? - このヘリコプターはテールのアジャストジャイロを実装しましたか? + このヘリコプターはテールのジャイロ調整を実装しましたか? diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/icon.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/icon.png new file mode 100755 index 0000000000..b6b7370479 Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/icon.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/arm.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/arm.png new file mode 100755 index 0000000000..33dcd7d91b Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/arm.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/background.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/background.png new file mode 100755 index 0000000000..e21f7bc812 Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/background.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/beeper.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/beeper.png new file mode 100755 index 0000000000..57c37f2fec Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/beeper.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mark_bg.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mark_bg.png new file mode 100755 index 0000000000..fbe6b0ee2f Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mark_bg.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mode.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mode.png new file mode 100755 index 0000000000..37a1830208 Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/mode.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pagedn.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pagedn.png new file mode 100755 index 0000000000..0733ccfa1f Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pagedn.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pageup.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pageup.png new file mode 100755 index 0000000000..0dbaa5202a Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pageup.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pitch.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pitch.png new file mode 100755 index 0000000000..e691fded26 Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/pitch.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/roll.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/roll.png new file mode 100755 index 0000000000..9110a0d522 Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/roll.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/throttle.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/throttle.png new file mode 100755 index 0000000000..b4f796b0a1 Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/throttle.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/yaw.png b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/yaw.png new file mode 100755 index 0000000000..3fc055bb34 Binary files /dev/null and b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/img/yaw.png differ diff --git a/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/wizard.lua b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/wizard.lua new file mode 100755 index 0000000000..baf8461b54 --- /dev/null +++ b/radio/sdcard/horus/SCRIPTS/WIZARD/multirotor/wizard.lua @@ -0,0 +1,411 @@ +---- ######################################################################### +---- # # +---- # Copyright (C) OpenTX # +-----# # +-----# Credits: graphics by Radiomaster # +-----# # +---- # 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. # +---- # # +---- ######################################################################### + +local VALUE = 0 +local COMBO = 1 + +local edit = false +local page = 1 +local current = 1 +local pages = {} +local fields = {} +local switches = {"SA", "SB", "SC", "SD", "SE", "SF", "SG"} + +-- load common Bitmaps +local ImgMarkBg = Bitmap.open("img/mark_bg.png") +local BackgroundImg = Bitmap.open("img/background.png") +local ImgPageUp = Bitmap.open("img/pageup.png") +local ImgPageDn = Bitmap.open("img/pagedn.png") + + +-- Change display attribute to current field +local function addField(step) + local field = fields[current] + local min, max + if field[3] == VALUE then + min = field[6] + max = field[7] + elseif field[3] == COMBO then + min = 0 + max = #(field[6]) - 1 + end + if (step < 0 and field[5] > min) or (step > 0 and field[5] < max) then + field[5] = field[5] + step + end +end + +-- Select the next or previous page +local function selectPage(step) + page = 1 + ((page + step - 1 + #pages) % #pages) + edit = false + current = 1 +end + +-- Select the next or previous editable field +local function selectField(step) + repeat + current = 1 + ((current + step - 1 + #fields) % #fields) + until fields[current][4]==1 +end + +-- Redraw the current page +local function redrawFieldsPage(event) + + for index = 1, 10, 1 do + local field = fields[index] + if field == nil then + break + end + + local attr = current == (index) and ((edit == true and BLINK or 0) + INVERS) or 0 + attr = attr + TEXT_COLOR + + if field[4] == 1 then + if field[3] == VALUE then + lcd.drawNumber(field[1], field[2], field[5], LEFT + attr) + elseif field[3] == COMBO then + if field[5] >= 0 and field[5] < #(field[6]) then + lcd.drawText(field[1],field[2], field[6][1+field[5]], attr) + end + end + end + end +end + +local function updateField(field) + local value = field[5] +end + +-- Main +local function runFieldsPage(event) + if event == EVT_VIRTUAL_EXIT then -- exit script + return 2 + elseif event == EVT_VIRTUAL_ENTER then -- toggle editing/selecting current field + if fields[current][5] ~= nil then + edit = not edit + if edit == false then + updateField(fields[current]) + end + end + elseif edit then + if event == EVT_VIRTUAL_INC or event == EVT_VIRTUAL_INC_REPT then + addField(1) + elseif event == EVT_VIRTUAL_DEC or event == EVT_VIRTUAL_DEC_REPT then + addField(-1) + end + else + if event == EVT_VIRTUAL_NEXT then + selectField(1) + elseif event == EVT_VIRTUAL_PREV then + selectField(-1) + end + end + redrawFieldsPage(event) + return 0 +end + +-- set visibility flags starting with SECOND field of fields +local function setFieldsVisible(...) + local arg={...} + local cnt = 2 + for i,v in ipairs(arg) do + fields[cnt][4] = v + cnt = cnt + 1 + end +end + +-- draws one letter mark +local function drawMark(x, y, name) + lcd.drawBitmap(ImgMarkBg, x, y) + lcd.drawText(x+8, y+3, name, TEXT_COLOR) +end + + +local ThrottleFields = { + {50, 50, COMBO, 1, 2, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } }, +} + +local ThrottleBackground + +local function runThrottleConfig(event) + lcd.clear() + if ThrottleBackground == nil then + ThrottleBackground = Bitmap.open("img/throttle.png") + end + lcd.drawBitmap(ThrottleBackground, 0, 0) + lcd.drawBitmap(ImgPageDn, 455, 95) + fields = ThrottleFields + lcd.drawText(40, 20, "Assign Throttle channel", TEXT_COLOR) + lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local RollFields = { + {50, 50, COMBO, 1, 0, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } }, +} + +local RollBackground + +local function runRollConfig(event) + lcd.clear() + if RollBackground == nil then + RollBackground = Bitmap.open("img/roll.png") + end + lcd.drawBitmap(RollBackground, 0, 0) + lcd.drawBitmap(ImgPageUp, 0, 95) + lcd.drawBitmap(ImgPageDn, 455, 95) + fields = RollFields + lcd.drawText(40, 20, "Assign Roll channel", TEXT_COLOR) + lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local PitchFields = { + {50, 50, COMBO, 1, 1, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } }, +} + +local PitchBackground + +local function runPitchConfig(event) + lcd.clear() + if PitchBackground == nil then + PitchBackground = Bitmap.open("img/pitch.png") + end + lcd.drawBitmap(PitchBackground, 0, 0) + lcd.drawBitmap(ImgPageUp, 0, 95) + lcd.drawBitmap(ImgPageDn, 455, 95) + fields = PitchFields + lcd.drawText(40, 20, "Assign Pitch channel", TEXT_COLOR) + lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local YawFields = { + {50, 50, COMBO, 1, 3, { "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8" } }, +} + +local YawBackground + +local function runYawConfig(event) + lcd.clear() + if YawBackground == nil then + YawBackground = Bitmap.open("img/yaw.png") + end + lcd.drawBitmap(YawBackground, 0, 0) + lcd.drawBitmap(ImgPageUp, 0, 95) + lcd.drawBitmap(ImgPageDn, 455, 95) + fields = YawFields + lcd.drawText(40, 20, "Assign Yaw channel", TEXT_COLOR) + lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local ArmFields = { + {50, 50, COMBO, 1, 5, { "SA", "SB", "SC", "SD", "SE", "SF"} }, +} + +local ArmBackground + +local function runArmConfig(event) + lcd.clear() + if ArmBackground == nil then + ArmBackground = Bitmap.open("img/arm.png") + end + lcd.drawBitmap(ArmBackground, 0, 0) + lcd.drawBitmap(ImgPageUp, 0, 95) + lcd.drawBitmap(ImgPageDn, 455, 95) + fields = ArmFields + lcd.drawText(40, 20, "Assign Arm switch", TEXT_COLOR) + lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local BeeperFields = { + {50, 50, COMBO, 1, 3, { "SA", "SB", "SC", "SD", "SE", "SF"} }, +} + +local BeeperBackground + +local function runBeeperConfig(event) + lcd.clear() + if BeeperBackground == nil then + BeeperBackground = Bitmap.open("img/beeper.png") + end + lcd.drawBitmap(BeeperBackground, 0, 0) + lcd.drawBitmap(ImgPageUp, 0, 95) + lcd.drawBitmap(ImgPageDn, 455, 95) + fields = BeeperFields + lcd.drawText(40, 20, "Assign Beeper switch", TEXT_COLOR) + lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local ModeFields = { + {50, 50, COMBO, 1, 0, { "SA", "SB", "SC", "SD", "SE", "SF"} }, +} + +local ModeBackground + +local function runModeConfig(event) + lcd.clear() + if ModeBackground == nil then + ModeBackground = Bitmap.open("img/mode.png") + end + lcd.drawBitmap(ModeBackground, 0, 0) + lcd.drawBitmap(ImgPageUp, 0, 95) + lcd.drawBitmap(ImgPageDn, 455, 95) + fields = ModeFields + lcd.drawText(40, 20, "Assign Mode switch", TEXT_COLOR) + lcd.drawFilledRectangle(40, 45, 100, 30, TEXT_BGCOLOR) + fields[1][4]=1 + local result = runFieldsPage(event) + return result +end + +local lineIndex +local function drawNextChanelLine(text, text2) + lcd.drawText(40, lineIndex, text, TEXT_COLOR) + lcd.drawText(242, lineIndex, ": CH" .. text2 + 1, TEXT_COLOR) + lineIndex = lineIndex + 20 +end + +local function drawNextSwitchLine(text, text2) + lcd.drawText(40, lineIndex, text, TEXT_COLOR) + lcd.drawText(242, lineIndex, ": " ..switches[text2 + 1], TEXT_COLOR) + lineIndex = lineIndex + 20 +end + + +local ConfigSummaryFields = { + {110, 250, COMBO, 1, 0, { "No, I need to change something", "Yes, all is well, create the model !"} }, +} + +local ImgSummary + +local function runConfigSummary(event) + lcd.clear() + if ImgSummary == nil then + ImgSummary = Bitmap.open("img/summary.png") + end + fields = ConfigSummaryFields + lcd.drawBitmap(BackgroundImg, 0, 0) + lcd.drawBitmap(ImgPageUp, 0, 95) + lcd.drawBitmap(ImgSummary, 300, 60) + lineIndex = 40 + -- throttle + drawNextChanelLine("Throttle channel", ThrottleFields[1][5]) + -- roll + drawNextChanelLine("Roll channel",RollFields[1][5]) + -- pitch + drawNextChanelLine("Pitch channel",PitchFields[1][5]) + -- yaw + drawNextChanelLine("Yaw channel",YawFields[1][5]) + -- arm + drawNextSwitchLine("Arm switch",ArmFields[1][5]) + -- beeper + drawNextSwitchLine("Beeper switch",BeeperFields[1][5]) + -- mode + drawNextSwitchLine("Mode switch",ModeFields[1][5]) + + local result = runFieldsPage(event) + if(fields[1][5] == 1 and edit == false) then + selectPage(1) + end + return result +end + +local function addMix(channel, input, name, weight, index) + local mix = { source=input, name=name } + if weight ~= nil then + mix.weight = weight + end + if index == nil then + index = 0 + end + model.insertMix(channel, index, mix) +end + +local function createModel(event) + lcd.clear() + lcd.drawBitmap(BackgroundImg, 0, 0) + lcd.drawBitmap(ImgSummary, 300, 60) + model.defaultInputs() + model.deleteMixes() + -- throttle + addMix(ThrottleFields[1][5], MIXSRC_FIRST_INPUT+defaultChannel(2), "Thr") + -- roll + addMix(RollFields[1][5], MIXSRC_FIRST_INPUT+defaultChannel(0), "Roll") + -- pitch + addMix(PitchFields[1][5], MIXSRC_FIRST_INPUT+defaultChannel(1), "Pitch") + -- yaw + addMix(YawFields[1][5], MIXSRC_FIRST_INPUT+defaultChannel(3), "Yaw") + addMix(4, MIXSRC_SA + ArmFields[1][5], "Arm") + addMix(5, MIXSRC_SA + BeeperFields[1][5], "Beeper") + addMix(6, MIXSRC_SA + ModeFields[1][5], "Mode") + + lcd.drawText(70, 90, "Model successfully created !", TEXT_COLOR) + lcd.drawText(100, 130, "Press RTN to exit", TEXT_COLOR) + return 2 +end + +-- Init +local function init() + current, edit = 1, false + pages = { + runThrottleConfig, + runRollConfig, + runPitchConfig, + runYawConfig, + runArmConfig, + runBeeperConfig, + runModeConfig, + runConfigSummary, + createModel, + } +end + +-- Main +local function run(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + elseif event == EVT_VIRTUAL_NEXT_PAGE and page < #pages-1 then + selectPage(1) + elseif event == EVT_VIRTUAL_PREV_PAGE and page > 1 then + killEvents(event); + selectPage(-1) + end + + local result = pages[page](event) + return result +end + +return { init=init, run=run } diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 540af5c102..b8c302f446 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -378,6 +378,10 @@ if(RADIOMASTER_RELEASE) add_definitions(-DRADIOMASTER_RELEASE) endif() +if(RADIOMASTER_RTF_RELEASE) + add_definitions(-DRADIOMASTER_RTF_RELEASE) +endif() + if(TBS_RELEASE) add_definitions(-DTBS_RELEASE) endif() @@ -411,6 +415,7 @@ set(SRC strhelpers.cpp switches.cpp mixer.cpp + mixer_scheduler.cpp stamp.cpp timers.cpp trainer.cpp diff --git a/radio/src/audio.cpp b/radio/src/audio.cpp index 3013fc4495..42a8acae16 100644 --- a/radio/src/audio.cpp +++ b/radio/src/audio.cpp @@ -161,7 +161,7 @@ const char * const unitsFilenames[] = { "hertz", "ms", "us", - "spare4", + "km", "spare5", "spare6", "spare7", diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index 86c41c13f0..25a6d81e3d 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -699,11 +699,11 @@ int cliTrace(const char ** argv) int cliStackInfo(const char ** argv) { - serialPrint("[MAIN] %d available / %d", stackAvailable(), stackSize()); - serialPrint("[MENUS] %d available / %d", menusStack.available(), menusStack.size()); - serialPrint("[MIXER] %d available / %d", mixerStack.available(), mixerStack.size()); - serialPrint("[AUDIO] %d available / %d", audioStack.available(), audioStack.size()); - serialPrint("[CLI] %d available / %d", cliStack.available(), cliStack.size()); + serialPrint("[MAIN] %d available / %d bytes", stackAvailable()*4, stackSize()*4); + serialPrint("[MENUS] %d available / %d bytes", menusStack.available()*4, menusStack.size()); + serialPrint("[MIXER] %d available / %d bytes", mixerStack.available()*4, mixerStack.size()); + serialPrint("[AUDIO] %d available / %d bytes", audioStack.available()*4, audioStack.size()); + serialPrint("[CLI] %d available / %d bytes", cliStack.available()*4, cliStack.size()); return 0; } diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index c37bd3d56c..b11fb6bcc0 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -213,7 +213,11 @@ enum ModuleIndex { }; #endif -#if defined(RADIO_T16) && !defined(INTERNAL_MODULE_MULTI) +#define TRAINER_MODE_MIN() TRAINER_MODE_MASTER_TRAINER_JACK + +#if !defined(HARDWARE_EXTERNAL_MODULE) + #define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE +#elif defined(RADIO_T16) && !defined(INTERNAL_MODULE_MULTI) #if defined(BLUETOOTH) #define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE_BLUETOOTH #else @@ -281,6 +285,7 @@ enum TelemetryProtocol PROTOCOL_TELEMETRY_FLYSKY_IBUS, PROTOCOL_TELEMETRY_HITEC, PROTOCOL_TELEMETRY_HOTT, + PROTOCOL_TELEMETRY_MLINK, PROTOCOL_TELEMETRY_MULTIMODULE, PROTOCOL_TELEMETRY_AFHDS3, PROTOCOL_TELEMETRY_GHOST, @@ -322,8 +327,8 @@ enum TelemetryUnit { UNIT_HERTZ, UNIT_MS, UNIT_US, - UNIT_MAX = UNIT_US, - UNIT_SPARE4, + UNIT_KM, + UNIT_MAX = UNIT_KM, UNIT_SPARE5, UNIT_SPARE6, UNIT_SPARE7, @@ -679,7 +684,7 @@ enum MixSources { MIXSRC_GYRO2, LUA_EXPORT("gyry", "Gyro Y") #endif - MIXSRC_MAX, + MIXSRC_MAX, LUA_EXPORT("max", "MAX") MIXSRC_FIRST_HELI SKIP, MIXSRC_CYC1 = MIXSRC_FIRST_HELI, LUA_EXPORT("cyc1", "Cyclic 1") diff --git a/radio/src/gui/128x64/lcd.h b/radio/src/gui/128x64/lcd.h index d367f0b140..2672f74a64 100644 --- a/radio/src/gui/128x64/lcd.h +++ b/radio/src/gui/128x64/lcd.h @@ -176,8 +176,9 @@ uint8_t * lcdLoadBitmap(uint8_t * dest, const char * filename, uint8_t width, ui #if defined(BOOT) #define BLINK_ON_PHASE (0) #else - #define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6)) #define SLOW_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<7)) + #define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6)) + #define FAST_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<4)) #endif inline pixel_t getPixel(uint8_t x, uint8_t y) diff --git a/radio/src/gui/128x64/model_curve_edit.cpp b/radio/src/gui/128x64/model_curve_edit.cpp index 747df3a556..2677458646 100644 --- a/radio/src/gui/128x64/model_curve_edit.cpp +++ b/radio/src/gui/128x64/model_curve_edit.cpp @@ -165,7 +165,7 @@ void menuModelCurveOne(event_t event) } break; -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_MDL) case EVT_KEY_FIRST(KEY_MODEL): pushMenu(menuChannelsView); killEvents(event); diff --git a/radio/src/gui/128x64/model_input_edit.cpp b/radio/src/gui/128x64/model_input_edit.cpp index f3208f1942..bac85677e7 100644 --- a/radio/src/gui/128x64/model_input_edit.cpp +++ b/radio/src/gui/128x64/model_input_edit.cpp @@ -49,7 +49,7 @@ enum ExposFields { void menuModelExpoOne(event_t event) { -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_MDL) if (event == EVT_KEY_FIRST(KEY_MODEL)) { pushMenu(menuChannelsView); killEvents(event); diff --git a/radio/src/gui/128x64/model_mix_edit.cpp b/radio/src/gui/128x64/model_mix_edit.cpp index f03e34a9cd..671ba55f96 100644 --- a/radio/src/gui/128x64/model_mix_edit.cpp +++ b/radio/src/gui/128x64/model_mix_edit.cpp @@ -85,7 +85,7 @@ void drawOffsetBar(uint8_t x, uint8_t y, MixData * md) void menuModelMixOne(event_t event) { -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_MDL) if (event == EVT_KEY_FIRST(KEY_MODEL)) { pushMenu(menuChannelsView); killEvents(event); diff --git a/radio/src/gui/128x64/model_select.cpp b/radio/src/gui/128x64/model_select.cpp index 0087fef7ca..b202b4079d 100644 --- a/radio/src/gui/128x64/model_select.cpp +++ b/radio/src/gui/128x64/model_select.cpp @@ -203,7 +203,7 @@ void menuModelSelect(event_t event) } break; -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEDN) case EVT_KEY_FIRST(KEY_PAGEUP): chainMenu(menuTabModel[DIM(menuTabModel)-1]); killEvents(event); @@ -212,7 +212,7 @@ void menuModelSelect(event_t event) case EVT_KEY_FIRST(KEY_PAGEDN): chainMenu(menuModelSetup); break; -#elif defined(NAVIGATION_X7) +#elif defined(KEYS_GPIO_REG_PAGE) case EVT_KEY_LONG(KEY_PAGE): chainMenu(menuTabModel[DIM(menuTabModel)-1]); killEvents(event); @@ -244,7 +244,7 @@ void menuModelSelect(event_t event) #endif #endif -#if defined(NAVIGATION_X7) +#if defined(ROTARY_ENCODER) && defined(NAVIGATION_X7) case EVT_ROTARY_LEFT: case EVT_ROTARY_RIGHT: #endif diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index c27e5c387f..65602448ad 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -114,7 +114,7 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2, ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_3, #endif - +#if defined(HARDWARE_EXTERNAL_MODULE) ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL, ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE, #if defined(MULTIMODULE) @@ -132,9 +132,6 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS, ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE, ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM, -#if defined(PCBSKY9X) && defined(REVX) - ITEM_MODEL_SETUP_EXTERNAL_MODULE_OUTPUT_TYPE, -#endif #if defined(AFHDS3) ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_RX_FREQ, ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_ACTUAL_POWER, @@ -154,11 +151,15 @@ enum MenuModelSetupItems { ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_2, ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_3, +#if defined(PCBSKY9X) && defined(REVX) + ITEM_MODEL_SETUP_EXTERNAL_MODULE_OUTPUT_TYPE, +#endif #if defined(PCBSKY9X) ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL, ITEM_MODEL_SETUP_EXTRA_MODULE_CHANNELS, ITEM_MODEL_SETUP_EXTRA_MODULE_BIND, #endif +#endif #if defined(PCBTARANIS) ITEM_MODEL_SETUP_TRAINER_LABEL, @@ -186,13 +187,16 @@ enum MenuModelSetupItems { #define REGISTRATION_ID_ROWS #endif -#if defined(HARDWARE_INTERNAL_MODULE) +#if defined(HARDWARE_INTERNAL_MODULE) && defined(HARDWARE_EXTERNAL_MODULE) #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL ? EXTERNAL_MODULE : INTERNAL_MODULE) #define CURRENT_RECEIVER_EDITED(k) (k - (k >= ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL ? ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1 : ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1)) #elif defined(PCBSKY9X) - #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL ? EXTRA_MODULE : EXTERNAL_MODULE) + #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL ? EXTRA_MODULE : EXTERNAL_MODULE) +#elif defined(HARDWARE_INTERNAL_MODULE) + #define CURRENT_MODULE_EDITED(k) (INTERNAL_MODULE) + #define CURRENT_RECEIVER_EDITED(k) (k - ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1) #else - #define CURRENT_MODULE_EDITED(k) (EXTERNAL_MODULE) + #define CURRENT_MODULE_EDITED(k) (EXTERNAL_MODULE) #define CURRENT_RECEIVER_EDITED(k) (k - ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1) #endif @@ -210,8 +214,8 @@ enum MenuModelSetupItems { #endif #if defined(PCBSKY9X) && defined(REVX) - #define OUTPUT_TYPE_ROW (isModulePPM(EXTERNAL_MODULE) ? (uint8_t)0 : HIDDEN_ROW), -#elif defined(PCBSKY9X) + #define OUTPUT_TYPE_ROW (isModulePPM(EXTERNAL_MODULE) ? (uint8_t)0 : HIDDEN_ROW), // Output type (OpenDrain / PushPull) +#else #define OUTPUT_TYPE_ROW #endif @@ -305,6 +309,27 @@ void onBluetoothConnectMenu(const char * result) } #endif +void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event) +{ + TimerData & timer = g_model.timers[timerIdx]; + lcdDrawTextAlignedLeft(y, STR_BEEPCOUNTDOWN); + lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VBEEPCOUNTDOWN, timer.countdownBeep, (menuHorizontalPosition == 0 ? attr : 0)); + if (timer.countdownBeep != COUNTDOWN_SILENT) { + lcdDrawNumber(MODEL_SETUP_2ND_COLUMN + 6 * FW, y, TIMER_COUNTDOWN_START(timerIdx), (menuHorizontalPosition == 1 ? attr : 0) | LEFT); + lcdDrawChar(lcdLastRightPos, y, 's'); + } + if (attr && s_editMode > 0) { + switch (menuHorizontalPosition) { + case 0: + CHECK_INCDEC_MODELVAR(event, timer.countdownBeep, COUNTDOWN_SILENT, COUNTDOWN_COUNT - 1); + break; + case 1: + timer.countdownStart = -checkIncDecModel(event, -timer.countdownStart, -1, +2); + break; + } + } +} + #include "common/stdlcd/model_setup_pxx1.cpp" #if defined(PXX2) @@ -338,19 +363,53 @@ void onBluetoothConnectMenu(const char * result) #define INTERNAL_MODULE_ROWS #endif +#if defined(HARDWARE_EXTERNAL_MODULE) + #define EXTERNAL_MODULE_ROWS \ + LABEL(ExternalModule), \ + MODULE_TYPE_ROWS(EXTERNAL_MODULE), \ + MULTIMODULE_TYPE_ROWS(EXTERNAL_MODULE) /* PROTOCOL */ \ + MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) /* SUBTYPE */ \ + MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) \ + AFHDS3_PROTOCOL_ROW(EXTERNAL_MODULE) \ + AFHDS3_MODE_ROWS(EXTERNAL_MODULE) \ + MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), \ + IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), /* line reused for PPM: PPM settings */ \ + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), /* RxNum */ \ + AFHDS3_MODULE_ROWS(EXTERNAL_MODULE) \ + MODULE_POWER_ROW(EXTERNAL_MODULE), \ + IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), \ + MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) \ + FAILSAFE_ROWS(EXTERNAL_MODULE), /* ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE */ \ + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), /* Range check and Register buttons */ \ + IF_PXX2_MODULE(EXTERNAL_MODULE, 0), /* Module options */ \ + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), /* Receiver 1 */ \ + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), /* Receiver 2 */ \ + IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), /* Receiver 3 */ +#else + #define EXTERNAL_MODULE_ROWS +#endif + +#if defined(PCBTARANIS) + #define WARN_ROWS \ + SW_WARN_ROWS, /* Switch warning */ \ + POT_WARN_ROWS, /* Pot warning */ +#else + #define WARN_ROWS \ + NUM_SWITCHES - 1, /* Switch warning */ +#endif + void menuModelSetup(event_t event) { int8_t old_editMode = s_editMode; #if defined(PCBTARANIS) int8_t old_posHorz = menuHorizontalPosition; +#endif MENU_TAB({ HEADER_LINE_COLUMNS 0, - TIMER_ROWS, - TIMER_ROWS, - TIMER_ROWS, + TIMERS_ROWS, 0, // Extended limits 1, // Extended trims 0, // Show trims @@ -363,8 +422,7 @@ void menuModelSetup(event_t event) LABEL(PreflightCheck), 0, // Checklist 0, // Throttle warning - SW_WARN_ROWS, // Switch warning - POT_WARN_ROWS, // Pot warning + WARN_ROWS NUM_STICKS + NUM_POTS + NUM_SLIDERS - 1, // Center beeps 0, // Global functions @@ -373,77 +431,14 @@ void menuModelSetup(event_t event) INTERNAL_MODULE_ROWS - LABEL(ExternalModule), - MODULE_TYPE_ROWS(EXTERNAL_MODULE), - MULTIMODULE_TYPE_ROWS(EXTERNAL_MODULE) // PROTOCOL - MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) // SUBTYPE - MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) - AFHDS3_PROTOCOL_ROW(EXTERNAL_MODULE) - AFHDS3_MODE_ROWS(EXTERNAL_MODULE) - MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), - IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), // line reused for PPM: PPM settings - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum - AFHDS3_MODULE_ROWS(EXTERNAL_MODULE) - MODULE_POWER_ROW(EXTERNAL_MODULE), - IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), - MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) - FAILSAFE_ROWS(EXTERNAL_MODULE), //ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons - IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // Module options - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 1 - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 2 - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 3 + EXTERNAL_MODULE_ROWS - TRAINER_ROWS - }); -#else - MENU_TAB({ - HEADER_LINE_COLUMNS - 0, - TIMER_ROWS, - TIMER_ROWS, - TIMER_ROWS, - 0, // Extended limits - 1, // Extended trims - 0, // Show trims - 0, // Trims step - 0, // Throttle reverse - 0, // Throttle trace source - 0, // Throttle trim - 0, // Throttle trim switch - - LABEL(PreflightCheck), - 0, // Checklist - 0, // Throttle warning - NUM_SWITCHES-1, // Switch warning - - NUM_STICKS+NUM_POTS+NUM_SLIDERS-1, // Center beeps - 0, // Global functions - - LABEL(ExternalModule), - MODULE_TYPE_ROWS(EXTERNAL_MODULE), - MULTIMODULE_TYPE_ROWS(EXTERNAL_MODULE) - MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) - MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) - - MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), - IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), // line reused for PPM: PPM settings - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum - 0, // Output type (OpenDrain / PushPull) - MODULE_POWER_ROW(EXTERNAL_MODULE), - IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)), - MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE) - FAILSAFE_ROWS(EXTERNAL_MODULE), - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons - IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // Module options - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 1 - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 2 - IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 3 + OUTPUT_TYPE_ROW EXTRA_MODULE_ROWS + TRAINER_ROWS }); -#endif MENU_CHECK(menuTabModel, MENU_MODEL_SETUP, HEADER_LINE + ITEM_MODEL_SETUP_LINES_COUNT); title(STR_MENU_MODEL_SETUP); @@ -481,7 +476,7 @@ void menuModelSetup(event_t event) } uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); - LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS); + LcdFlags blink = ((s_editMode > 0) ? BLINK|INVERS : INVERS); LcdFlags attr = (sub == k ? blink : 0); switch (k) { @@ -561,8 +556,7 @@ void menuModelSetup(event_t event) case ITEM_MODEL_SETUP_TIMER2_COUNTDOWN_BEEP: case ITEM_MODEL_SETUP_TIMER3_COUNTDOWN_BEEP: { - TimerData * timer = &g_model.timers[k>=ITEM_MODEL_SETUP_TIMER3 ? 2 : (k>=ITEM_MODEL_SETUP_TIMER2 ? 1 : 0)]; - timer->countdownBeep = editChoice(MODEL_SETUP_2ND_COLUMN, y, STR_BEEPCOUNTDOWN, STR_VBEEPCOUNTDOWN, timer->countdownBeep, COUNTDOWN_SILENT, COUNTDOWN_COUNT-1, attr, event); + editTimerCountdown(k>=ITEM_MODEL_SETUP_TIMER3 ? 2 : (k>=ITEM_MODEL_SETUP_TIMER2 ? 1 : 0), y, attr, event); break; } @@ -861,7 +855,7 @@ void menuModelSetup(event_t event) #if !defined(INTERNAL_MODULE_MULTI) case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE: { - lcdDrawTextAlignedLeft(y, INDENT TR_MODE); + lcdDrawText(INDENT_WIDTH, y, STR_MODE); #if defined(INTERNAL_MODULE_PXX1) lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_INTERNAL_MODULE_PROTOCOLS, g_model.moduleData[INTERNAL_MODULE].type, menuHorizontalPosition==0 ? attr : 0); if (isModuleXJT(INTERNAL_MODULE)) @@ -916,14 +910,18 @@ void menuModelSetup(event_t event) break; #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL: lcdDrawTextAlignedLeft(y, STR_EXTERNALRF); break; +#endif #if defined(INTERNAL_MODULE_MULTI) case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE: +#endif lcdDrawTextAlignedLeft(y, INDENT TR_MODE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_EXTERNAL_MODULE_PROTOCOLS, moduleIdx == EXTERNAL_MODULE ? reusableBuffer.moduleSetup.newType : g_model.moduleData[moduleIdx].type, menuHorizontalPosition==0 ? attr : 0); if (isModuleXJT(moduleIdx)) @@ -1017,7 +1015,9 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_PROTOCOL: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL: +#endif { lcdDrawTextAlignedLeft(y, TR_TYPE); int multi_rfProto = g_model.moduleData[moduleIdx].getMultiProtocol(); @@ -1056,7 +1056,9 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE: +#endif { lcdDrawTextAlignedLeft(y, STR_SUBTYPE); lcdDrawMultiSubProtocolString(MODEL_SETUP_2ND_COLUMN, y, moduleIdx, g_model.moduleData[moduleIdx].subType, attr); @@ -1077,7 +1079,7 @@ void menuModelSetup(event_t event) #if defined(AFHDS3) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS_PROTOCOL: - lcdDrawTextAlignedLeft(y, TR_PROTO); + lcdDrawText(INDENT_WIDTH, y, STR_PROTOCOL); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_AFHDS3_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].subType, attr); if (attr && s_editMode > 0 && menuHorizontalPosition == 0) { CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, AFHDS_SUBTYPE_FIRST, AFHDS_SUBTYPE_LAST); @@ -1099,7 +1101,7 @@ void menuModelSetup(event_t event) lcdDrawTextAlignedLeft(y, INDENT TR_MODE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VTRAINERMODES, g_model.trainerData.mode, attr); if (attr) { - g_model.trainerData.mode = checkIncDec(event, g_model.trainerData.mode, 0, TRAINER_MODE_MAX(), EE_MODEL, isTrainerModeAvailable); + g_model.trainerData.mode = checkIncDec(event, g_model.trainerData.mode, TRAINER_MODE_MIN(), TRAINER_MODE_MAX(), EE_MODEL, isTrainerModeAvailable); #if defined(BLUETOOTH) if (checkIncDec_Ret) { bluetooth.state = BLUETOOTH_STATE_OFF; @@ -1186,7 +1188,9 @@ void menuModelSetup(event_t event) #if defined(PCBSKY9X) case ITEM_MODEL_SETUP_EXTRA_MODULE_CHANNELS: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS: +#endif { ModuleData & moduleData = g_model.moduleData[moduleIdx]; lcdDrawTextAlignedLeft(y, STR_CHANNELRANGE); @@ -1312,7 +1316,9 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: +#endif { ModuleData & moduleData = g_model.moduleData[moduleIdx]; if (isModulePPM(moduleIdx)) { @@ -1466,7 +1472,9 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE: +#endif { ModuleData &moduleData = g_model.moduleData[moduleIdx]; lcdDrawTextAlignedLeft(y, STR_FAILSAFE); @@ -1527,44 +1535,41 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS: +#endif { #if defined(MULTIMODULE) if (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx)) { + const char * title = getMultiOptionTitle(moduleIdx); + + lcdDrawText(INDENT_WIDTH, y, title); + if (title == STR_MULTI_RFTUNE) { + lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT); + lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT); + lcdDrawText(lcdLastRightPos, y, ")", LEFT); + } + int optionValue = g_model.moduleData[moduleIdx].multi.optionValue; - - MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol(); - - if (status.isValid()) { - MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); - lcdDrawText(INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]); - if (attr && status.optionDisp == 2) { - lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT); - lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT); - lcdDrawText(lcdLastRightPos, y, ")", LEFT); - } - } - else { - const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto); - if (pdef->optionsstr) { - lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr); - if (attr && pdef->optionsstr == STR_MULTI_RFTUNE) { - lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT); - lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT); - lcdDrawText(lcdLastRightPos, y, ")", LEFT); - } - } - } - int8_t min, max; getMultiOptionValues(multi_proto, min, max); - if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) { + if (title == STR_MULTI_RFPOWER) { + lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_POWER, optionValue, LEFT | attr); + min = 0; + max = 15; + } + else if (title == STR_MULTI_TELEMETRY) { + lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_TELEMETRY_MODE, optionValue, LEFT | attr); + } + else if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) { lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 50 + 5 * optionValue, LEFT | attr); } - else if (multi_proto == MODULE_SUBTYPE_MULTI_FRSKY_R9) { - lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_POWER, optionValue, LEFT | attr); + else if (title == STR_MULTI_WBUS) { + lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_WBUS_MODE, optionValue, LEFT | attr); + min = 0; + max = 1; } else if (multi_proto == MODULE_SUBTYPE_MULTI_DSM2) { optionValue = optionValue & 0x01; @@ -1606,7 +1611,9 @@ void menuModelSetup(event_t event) #if defined(INTERNAL_MODULE_MULTI) case ITEM_MODEL_SETUP_INTERNAL_MODULE_POWER: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER: +#endif { auto & module = g_model.moduleData[moduleIdx]; // Lite FCC / Lite FLEX / Lite Pro Flex @@ -1691,7 +1698,9 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND: +#endif if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) { int8_t value = (g_model.moduleData[moduleIdx].multi.optionValue & 0x02) >> 1; lcdDrawText(INDENT_WIDTH, y, STR_MULTI_SERVOFREQ); @@ -1713,14 +1722,18 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_TELEM: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM: +#endif g_model.moduleData[moduleIdx].multi.disableTelemetry = editCheckBox(g_model.moduleData[moduleIdx].multi.disableTelemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_TELEM, attr, event); break; #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_MAPPING: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING: +#endif g_model.moduleData[moduleIdx].multi.disableMapping = editCheckBox(g_model.moduleData[moduleIdx].multi.disableMapping, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_CH_MAP, attr, event); break; #endif @@ -1746,7 +1759,10 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS: +#endif + { lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS); getModuleStatusString(EXTERNAL_MODULE, reusableBuffer.moduleSetup.msg); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, reusableBuffer.moduleSetup.msg); @@ -1755,7 +1771,10 @@ void menuModelSetup(event_t event) #if defined(HARDWARE_INTERNAL_MODULE) case ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS: #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS: +#endif + { lcdDrawTextAlignedLeft(y, STR_MODULE_SYNC); getModuleSyncStatusString(moduleIdx, reusableBuffer.moduleSetup.msg); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, reusableBuffer.moduleSetup.msg); @@ -1850,11 +1869,13 @@ void menuModelSetup(event_t event) checkModelIdUnique(g_eeGeneral.currModel, EXTRA_MODULE); break; #endif +#if defined(HARDWARE_EXTERNAL_MODULE) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE: case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM: if (menuHorizontalPosition == 0) checkModelIdUnique(g_eeGeneral.currModel, EXTERNAL_MODULE); break; +#endif } } } diff --git a/radio/src/gui/128x64/radio_diagkeys.cpp b/radio/src/gui/128x64/radio_diagkeys.cpp index a3d058c3e3..803ff7eb73 100644 --- a/radio/src/gui/128x64/radio_diagkeys.cpp +++ b/radio/src/gui/128x64/radio_diagkeys.cpp @@ -49,10 +49,15 @@ void menuRadioDiagKeys(event_t event) displayKeyState(i&1? 20*FW : 18*FW, y, TRM_BASE+i); } - if (i <= KEY_MAX) { - y = MENU_HEADER_HEIGHT + 1 + FH*i; + if (i == 7) { + y = MENU_HEADER_HEIGHT + 1 + FH * 6; + lcdDrawTextAtIndex(8, y, STR_VKEYS, i, 0); + displayKeyState(lcdNextPos + 10, y, i); + } + else if (i <= KEY_MAX) { + y = MENU_HEADER_HEIGHT + 1 + FH * i; lcdDrawTextAtIndex(0, y, STR_VKEYS, i, 0); - displayKeyState(5*FW+2, y, i); + displayKeyState(5 * FW + 2, y, i); } #if defined(PCBSKY9X) diff --git a/radio/src/gui/128x64/radio_setup.cpp b/radio/src/gui/128x64/radio_setup.cpp index e8a3cd25bf..dd6252fd0c 100644 --- a/radio/src/gui/128x64/radio_setup.cpp +++ b/radio/src/gui/128x64/radio_setup.cpp @@ -79,13 +79,13 @@ enum { ITEM_RADIO_SETUP_MEMORY_WARNING, ITEM_RADIO_SETUP_ALARM_WARNING, ITEM_RADIO_SETUP_RSSI_POWEROFF_ALARM, - ITEM_RADIO_SETUP_BACKLIGHT_LABEL, - ITEM_RADIO_SETUP_BACKLIGHT_MODE, - ITEM_RADIO_SETUP_BACKLIGHT_DELAY, - ITEM_RADIO_SETUP_BRIGHTNESS, + CASE_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_LABEL) + CASE_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_MODE) + CASE_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_DELAY) + CASE_BACKLIGHT(ITEM_RADIO_SETUP_BRIGHTNESS) CASE_PWM_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_BRIGHTNESS_OFF) CASE_PWM_BACKLIGHT(ITEM_RADIO_SETUP_BACKLIGHT_BRIGHTNESS_ON) - ITEM_RADIO_SETUP_FLASH_BEEP, + CASE_BACKLIGHT(ITEM_RADIO_SETUP_FLASH_BEEP) CASE_SPLASH_PARAM(ITEM_RADIO_SETUP_DISABLE_SPLASH) CASE_PWR_BUTTON_PRESS(ITEM_RADIO_SETUP_PWR_ON_SPEED) CASE_PWR_BUTTON_PRESS(ITEM_RADIO_SETUP_PWR_OFF_SPEED) @@ -152,10 +152,14 @@ void menuRadioSetup(event_t event) CASE_GYRO(0) CASE_GYRO(0) 0, LABEL(ALARMS), 0, CASE_CAPACITY(0) - 0, 0, 0, 0, - LABEL(BACKLIGHT), 0, 0, 0, CASE_PWM_BACKLIGHT(0) + 0, 0, 0, 0, /* ITEM_RADIO_SETUP_INACTIVITY_ALARM ITEM_RADIO_SETUP_MEMORY_WARNING ITEM_RADIO_SETUP_ALARM_WARNING ITEM_RADIO_SETUP_RSSI_POWEROFF_ALARM */ + CASE_BACKLIGHT(LABEL(BACKLIGHT)) + CASE_BACKLIGHT(0) + CASE_BACKLIGHT(0) + CASE_BACKLIGHT(0) CASE_PWM_BACKLIGHT(0) - 0, + CASE_PWM_BACKLIGHT(0) + CASE_BACKLIGHT(0) CASE_SPLASH_PARAM(0) CASE_PWR_BUTTON_PRESS(0) CASE_PWR_BUTTON_PRESS(0) @@ -251,7 +255,7 @@ void menuRadioSetup(event_t event) putsVolts(lcdLastRightPos+FW, y, 120+g_eeGeneral.vBatMax, (menuHorizontalPosition>0 ? attr : 0)|LEFT|NO_UNIT); if (attr && s_editMode>0) { if (menuHorizontalPosition==0) - CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMin, -50, g_eeGeneral.vBatMax+29); // min=4.0V + CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMin, -60, g_eeGeneral.vBatMax+29); // min=3.0V else CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMax, g_eeGeneral.vBatMin-29, +40); // max=16.0V } @@ -424,7 +428,7 @@ void menuRadioSetup(event_t event) case ITEM_RADIO_SETUP_BATTERY_WARNING: lcdDrawText(INDENT_WIDTH, y, STR_BATTERYWARNING); putsVolts(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.vBatWarn, attr|LEFT); - if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatWarn, 40, 120); //4-12V + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatWarn, 30, 120); //3-12V break; case ITEM_RADIO_SETUP_MEMORY_WARNING: @@ -466,6 +470,7 @@ void menuRadioSetup(event_t event) if(attr) g_eeGeneral.inactivityTimer = checkIncDec(event, g_eeGeneral.inactivityTimer, 0, 250, EE_GENERAL); //0..250minutes break; +#if defined(BACKLIGHT_GPIO) case ITEM_RADIO_SETUP_BACKLIGHT_LABEL: lcdDrawTextAlignedLeft(y, STR_BACKLIGHT_LABEL); break; @@ -496,6 +501,7 @@ void menuRadioSetup(event_t event) g_eeGeneral.backlightBright = 100 - b; } break; +#endif #if defined(PWM_BACKLIGHT) case ITEM_RADIO_SETUP_BACKLIGHT_BRIGHTNESS_OFF: diff --git a/radio/src/gui/128x64/view_about.cpp b/radio/src/gui/128x64/view_about.cpp index 02e8e45086..b168f91fb5 100644 --- a/radio/src/gui/128x64/view_about.cpp +++ b/radio/src/gui/128x64/view_about.cpp @@ -42,7 +42,7 @@ enum AboutScreens { #define ABOUT_X 2 #define ABOUT_INDENT 4 -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEDN) #define EVT_KEY_PREVIOUS_VIEW EVT_KEY_BREAK(KEY_PAGEUP) #define EVT_KEY_NEXT_VIEW EVT_KEY_BREAK(KEY_PAGEDN) #elif defined(NAVIGATION_X7) diff --git a/radio/src/gui/128x64/view_channels.cpp b/radio/src/gui/128x64/view_channels.cpp index f71d833c1f..ffb4d9b331 100644 --- a/radio/src/gui/128x64/view_channels.cpp +++ b/radio/src/gui/128x64/view_channels.cpp @@ -26,7 +26,12 @@ constexpr coord_t CHANNEL_GAUGE_OFFSET = CHANNEL_VALUE_OFFSET; constexpr coord_t CHANNEL_BAR_WIDTH = 70; constexpr coord_t CHANNEL_PROPERTIES_OFFSET = CHANNEL_GAUGE_OFFSET + CHANNEL_BAR_WIDTH + 2; -#if defined(NAVIGATION_X7_TX12) +#if defined(RADIO_T8) +#define EVT_KEY_PREVIOUS_VIEW EVT_KEY_BREAK(KEY_PAGEUP) +#define EVT_KEY_NEXT_VIEW EVT_KEY_BREAK(KEY_PAGEDN) +#define EVT_KEY_NEXT_PAGE EVT_KEY_BREAK(KEY_PLUS) +#define EVT_KEY_PREVIOUS_PAGE EVT_KEY_BREAK(KEY_MINUS) +#elif defined(NAVIGATION_X7_TX12) #define EVT_KEY_PREVIOUS_VIEW EVT_KEY_BREAK(KEY_PAGEUP) #define EVT_KEY_NEXT_VIEW EVT_KEY_BREAK(KEY_PAGEDN) #define EVT_KEY_NEXT_PAGE EVT_ROTARY_RIGHT diff --git a/radio/src/gui/128x64/view_main.cpp b/radio/src/gui/128x64/view_main.cpp index 48e6cfbe11..1f7b7eb2bc 100644 --- a/radio/src/gui/128x64/view_main.cpp +++ b/radio/src/gui/128x64/view_main.cpp @@ -102,8 +102,9 @@ void doMainScreenGraphics() if (g_model.throttleReversed && CONVERT_MODE(2) == THR_STICK) calibStickVert = -calibStickVert; drawStick(RBOX_CENTERX, calibratedAnalogs[CONVERT_MODE(3)], calibStickVert); - +#if defined(HARDWARE_POT1) drawPotsBars(); +#endif } #if defined(HARDWARE_NO_TRIMS) @@ -290,7 +291,16 @@ void displayVoltageOrAlarm() #define displayVoltageOrAlarm() displayBattVoltage() #endif -#if defined(NAVIGATION_X7_TX12) +#if defined(RADIO_T8) +#define EVT_KEY_CONTEXT_MENU EVT_KEY_LONG(KEY_ENTER) +#define EVT_KEY_PREVIOUS_VIEW EVT_KEY_BREAK(KEY_PAGEUP) +#define EVT_KEY_NEXT_VIEW EVT_KEY_FIRST(KEY_PAGEDN) +#define EVT_KEY_NEXT_PAGE EVT_KEY_FIRST(KEY_PLUS) +#define EVT_KEY_PREVIOUS_PAGE EVT_KEY_FIRST(KEY_MINUS) +#define EVT_KEY_MODEL_MENU EVT_KEY_LONG(KEY_MODEL) +#define EVT_KEY_GENERAL_MENU EVT_KEY_LONG(KEY_SYS) +#define EVT_KEY_TELEMETRY EVT_KEY_LONG(KEY_PAGEUP) +#elif defined(NAVIGATION_X7_TX12) #define EVT_KEY_CONTEXT_MENU EVT_KEY_LONG(KEY_ENTER) #define EVT_KEY_PREVIOUS_VIEW EVT_KEY_FIRST(KEY_PAGEUP) #define EVT_KEY_NEXT_VIEW EVT_KEY_FIRST(KEY_PAGEDN) @@ -528,6 +538,7 @@ void menuMainView(event_t event) killEvents(event); break; + case EVT_KEY_FIRST(KEY_EXIT): #if defined(GVARS) if (gvarDisplayTimer > 0) { diff --git a/radio/src/gui/128x64/view_statistics.cpp b/radio/src/gui/128x64/view_statistics.cpp index 2b46be36e5..0765cf9b68 100644 --- a/radio/src/gui/128x64/view_statistics.cpp +++ b/radio/src/gui/128x64/view_statistics.cpp @@ -31,7 +31,7 @@ void menuStatisticsView(event_t event) switch (event) { case EVT_KEY_FIRST(KEY_UP): -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEDN) case EVT_KEY_BREAK(KEY_PAGEDN): #elif defined(NAVIGATION_X7) case EVT_KEY_BREAK(KEY_PAGE): @@ -41,7 +41,7 @@ void menuStatisticsView(event_t event) break; case EVT_KEY_FIRST(KEY_DOWN): -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEUP) case EVT_KEY_BREAK(KEY_PAGEUP): killEvents(event); chainMenu(menuStatisticsDebug2); @@ -140,7 +140,7 @@ void menuStatisticsDebug(event_t event) break; case EVT_KEY_FIRST(KEY_UP): -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEDN) case EVT_KEY_BREAK(KEY_PAGEDN): disableVBatBridge(); chainMenu(menuStatisticsDebug2); @@ -153,7 +153,7 @@ void menuStatisticsDebug(event_t event) #endif case EVT_KEY_FIRST(KEY_DOWN): -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEUP) case EVT_KEY_BREAK(KEY_PAGEUP): #elif defined(NAVIGATION_X7) case EVT_KEY_LONG(KEY_PAGE): @@ -278,7 +278,7 @@ void menuStatisticsDebug2(event_t event) break; case EVT_KEY_FIRST(KEY_UP): -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEDN) case EVT_KEY_BREAK(KEY_PAGEDN): #elif defined(NAVIGATION_X7) case EVT_KEY_BREAK(KEY_PAGE): @@ -287,7 +287,7 @@ void menuStatisticsDebug2(event_t event) return; case EVT_KEY_FIRST(KEY_DOWN): -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEUP) case EVT_KEY_BREAK(KEY_PAGEUP): #elif defined(NAVIGATION_X7) case EVT_KEY_LONG(KEY_PAGE): diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index c84580c8b1..0dd9d410d3 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -1294,38 +1294,34 @@ void menuModelSetup(event_t event) #if defined(MULTIMODULE) if (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx)) { + const char * title = getMultiOptionTitle(moduleIdx); + + lcdDrawText(INDENT_WIDTH, y, title); + if (title == STR_MULTI_RFTUNE) { + lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT); + lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT); + lcdDrawText(lcdLastRightPos, y, ")", LEFT); + } + int optionValue = g_model.moduleData[moduleIdx].multi.optionValue; - - MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); - const uint8_t multi_proto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(); - if (status.isValid()) { - lcdDrawText(INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]); - if (attr && status.optionDisp == 2) { - lcdDrawText(MODEL_SETUP_3RD_COLUMN+22, y, "RSSI(", LEFT); - lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT); - lcdDrawText(lcdLastRightPos, y, ")", LEFT); - } - } - else { - const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto); - if (pdef->optionsstr) - lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr); - if (pdef->optionsstr == STR_MULTI_RFTUNE) { - lcdDrawText(MODEL_SETUP_3RD_COLUMN+22, y, "RSSI(", LEFT); - lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT); - lcdDrawText(lcdLastRightPos, y, ")", LEFT); - } - } - + const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol(); int8_t min, max; getMultiOptionValues(multi_proto, min, max); - if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) { - lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 50 + 5 * optionValue, LEFT | attr); - } - else if (multi_proto == MODULE_SUBTYPE_MULTI_FRSKY_R9) { + if (title == STR_MULTI_RFPOWER) { lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_POWER, optionValue, LEFT | attr); } + else if (title == STR_MULTI_TELEMETRY) { + lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_TELEMETRY_MODE, optionValue, LEFT | attr); + } + else if (title == STR_MULTI_WBUS) { + lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_WBUS_MODE, optionValue, LEFT | attr); + min = 0; + max = 1; + } + else if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) { + lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 50 + 5 * optionValue, LEFT | attr); + } else if (multi_proto == MODULE_SUBTYPE_MULTI_DSM2) { optionValue = optionValue & 0x01; editCheckBox(optionValue, MODEL_SETUP_2ND_COLUMN, y, "", LEFT | attr, event); diff --git a/radio/src/gui/colorlcd/model_select_old.cpp b/radio/src/gui/colorlcd/model_select_old.cpp index 44483bf613..cacacddd03 100644 --- a/radio/src/gui/colorlcd/model_select_old.cpp +++ b/radio/src/gui/colorlcd/model_select_old.cpp @@ -191,7 +191,6 @@ bool menuModelWizard(event_t event) uint16_t x = WIZARD_LEFT_SPACING + (wizidx - first) * (WIZARD_SPACING + WIZARD_ICON_X); strcpy(&wizpath[sizeof(WIZARD_PATH)], fno.fname); strcpy(&wizpath[sizeof(WIZARD_PATH) + strlen(fno.fname)], "/icon.png"); - lcdDrawText(x + 10, WIZARD_TEXT_Y, fno.fname); BitmapBuffer * background = BitmapBuffer::load(wizpath); lcd->drawBitmap(x, WIZARD_ICON_Y, background); if(wizidx == wizardSelected ) { @@ -246,6 +245,7 @@ void onModelSelectMenu(const char * result) if (!confirmModelChange()) return; } + // we store the latest changes if any storageFlushCurrentModel(); storageCheck(true); diff --git a/radio/src/gui/common/stdlcd/draw_functions.cpp b/radio/src/gui/common/stdlcd/draw_functions.cpp index 94dd344ca6..dca8346471 100644 --- a/radio/src/gui/common/stdlcd/draw_functions.cpp +++ b/radio/src/gui/common/stdlcd/draw_functions.cpp @@ -171,17 +171,16 @@ void editName(coord_t x, coord_t y, char * name, uint8_t size, event_t event, ui uint8_t cur = editNameCursorPos; if (s_editMode > 0) { int8_t c = name[cur]; - if (c == '\0') - c = ' '; - char v; - if (IS_NEXT_EVENT(event)) { - v = getNextChar(c, cur); - } - else if (IS_PREVIOUS_EVENT(event)) { - v = getPreviousChar(c, cur); - } - else { - v = c; + int8_t v = c; + + if (IS_NEXT_EVENT(event) || IS_PREVIOUS_EVENT(event)) { + if (attr == ZCHAR) { + v = checkIncDec(event, abs(v), 0, ZCHAR_MAX, 0); + if (c <= 0) v = -v; + } + else { + v = checkIncDec(event, abs(v), ' ', 'z', 0); + } } switch (event) { diff --git a/radio/src/gui/common/stdlcd/model_receiver_options.cpp b/radio/src/gui/common/stdlcd/model_receiver_options.cpp index de3547b75d..8516f61cf4 100644 --- a/radio/src/gui/common/stdlcd/model_receiver_options.cpp +++ b/radio/src/gui/common/stdlcd/model_receiver_options.cpp @@ -47,8 +47,7 @@ enum { ITEM_RECEIVER_SETTINGS_PWM_RATE, ITEM_RECEIVER_SETTINGS_TELEMETRY, ITEM_RECEIVER_SETTINGS_TELEMETRY_25MW, - ITEM_RECEIVER_SETTINGS_SPORT_FPORT, - ITEM_RECEIVER_SETTINGS_FPORT2, + ITEM_RECEIVER_SETTINGS_SPORT_MODE, ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED1, ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED2, ITEM_RECEIVER_SETTINGS_PINMAP_FIRST @@ -60,6 +59,15 @@ enum { #define CH_ENABLE_SPORT 4 #define CH_ENABLE_SBUS 5 +bool isSPortModeAvailable(int mode) +{ + uint8_t receiverId = reusableBuffer.hardwareAndSettings.receiverSettings.receiverId; + if (mode == 2 && !IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT2)) { + return false; + } + return true; +} + void menuModelReceiverOptions(event_t event) { const int lim = (g_model.extendedLimits ? (512 * LIMIT_EXT_PERCENT / 100) : 512) * 2; @@ -82,8 +90,7 @@ void menuModelReceiverOptions(event_t event) 0, // PWM rate isModuleR9MAccess(g_moduleIdx) && receiverVariant == PXX2_VARIANT_EU && reusableBuffer.hardwareAndSettings.moduleSettings.txPower > 14 /*25mW*/ ? READONLY_ROW : (uint8_t)0, // Telemetry IF_RECEIVER_CAPABILITY(RECEIVER_CAPABILITY_TELEMETRY_25MW, 0), - IF_RECEIVER_CAPABILITY(RECEIVER_CAPABILITY_FPORT, 0), - IF_RECEIVER_CAPABILITY(RECEIVER_CAPABILITY_FPORT2, 0), + uint8_t((IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT) || IS_RECEIVER_CAPABILITY_ENABLED(RECEIVER_CAPABILITY_FPORT2)) ? 0 : HIDDEN_ROW), uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW), uint8_t(reusableBuffer.hardwareAndSettings.modules[g_moduleIdx].receivers[receiverId].information.capabilityNotSupported ? READONLY_ROW : HIDDEN_ROW), 0 // channels ... @@ -134,11 +141,11 @@ void menuModelReceiverOptions(event_t event) lcdInvertLine(0); if (reusableBuffer.hardwareAndSettings.receiverSettings.state == PXX2_SETTINGS_OK) { - for (uint8_t k=0; k> 1; reusableBuffer.hardwareAndSettings.receiverSettings.dirty = RECEIVER_SETTINGS_DIRTY; } break; + } case ITEM_RECEIVER_SETTINGS_CAPABILITY_NOT_SUPPORTED1: lcdDrawText(LCD_W/2, y+1, STR_MORE_OPTIONS_AVAILABLE, SMLSIZE|CENTERED); diff --git a/radio/src/gui/common/stdlcd/radio_hardware.cpp b/radio/src/gui/common/stdlcd/radio_hardware.cpp index eb90a47050..ff994b0a9f 100644 --- a/radio/src/gui/common/stdlcd/radio_hardware.cpp +++ b/radio/src/gui/common/stdlcd/radio_hardware.cpp @@ -98,8 +98,10 @@ enum { ITEM_RADIO_HARDWARE_STICK2, ITEM_RADIO_HARDWARE_STICK3, ITEM_RADIO_HARDWARE_STICK4, +#if (NUM_POTS + NUM_SLIDERS) > 0 ITEM_RADIO_HARDWARE_LABEL_POTS, ITEM_RADIO_HARDWARE_POT1, +#endif #if defined(HARDWARE_POT2) ITEM_RADIO_HARDWARE_POT2, #endif @@ -195,20 +197,22 @@ enum { ITEM_RADIO_HARDWARE_MAX }; -#if (NUM_POTS + NUM_SLIDERS) == 1 - #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1 +#if (NUM_POTS + NUM_SLIDERS) == 0 + #define POTS_ROWS +#elif (NUM_POTS + NUM_SLIDERS) == 1 + #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, #elif (NUM_POTS + NUM_SLIDERS) == 2 - #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1 + #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, #elif (NUM_POTS + NUM_SLIDERS) == 3 - #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1 + #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, #elif defined(PCBX9D) // TODO defined(STORAGE_POT3) && !defined(STORAGE_POT3) - #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, HIDDEN_ROW, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1 + #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, HIDDEN_ROW, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, #elif (NUM_POTS + NUM_SLIDERS) == 4 - #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1 + #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, #elif (NUM_POTS + NUM_SLIDERS) == 5 - #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1 + #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, #elif (NUM_POTS + NUM_SLIDERS) == 8 - #define POTS_ROWS NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1 + #define POTS_ROWS LABEL(Pots), NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, NAVIGATION_LINE_BY_LINE|1, #endif #if defined(PCBX9E) @@ -238,20 +242,20 @@ enum { #endif #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) -#define EXTERNAL_ANTENNA_ROW 0, -void onHardwareAntennaSwitchConfirm(const char * result) -{ - if (result == STR_OK) { - // Switch to external antenna confirmation - g_eeGeneral.antennaMode = reusableBuffer.radioHardware.antennaMode; - storageDirty(EE_GENERAL); + #define EXTERNAL_ANTENNA_ROW 0, + void onHardwareAntennaSwitchConfirm(const char * result) + { + if (result == STR_OK) { + // Switch to external antenna confirmation + g_eeGeneral.antennaMode = reusableBuffer.radioHardware.antennaMode; + storageDirty(EE_GENERAL); + } + else { + reusableBuffer.radioHardware.antennaMode = g_eeGeneral.antennaMode; + } } - else { - reusableBuffer.radioHardware.antennaMode = g_eeGeneral.antennaMode; - } -} #else -#define EXTERNAL_ANTENNA_ROW + #define EXTERNAL_ANTENNA_ROW #endif #if defined(PCBX9LITE) @@ -262,7 +266,7 @@ void onHardwareAntennaSwitchConfirm(const char * result) #define SWITCH_TYPE_MAX(sw) (SWITCH_3POS) #elif defined(PCBX9E) #define SWITCH_TYPE_MAX(sw) ((MIXSRC_SF - MIXSRC_FIRST_SWITCH == sw || MIXSRC_SH - MIXSRC_FIRST_SWITCH == sw) ? SWITCH_2POS : SWITCH_3POS) -#elif defined(RADIO_TX12) +#elif defined(RADIO_TX12) || defined(RADIO_T8) #define SWITCH_TYPE_MAX(sw) ((MIXSRC_SA - MIXSRC_FIRST_SWITCH == sw || MIXSRC_SD - MIXSRC_FIRST_SWITCH == sw) ? SWITCH_2POS : SWITCH_3POS) #else #define SWITCH_TYPE_MAX(sw) ((MIXSRC_SF - MIXSRC_FIRST_SWITCH == sw || MIXSRC_SH - MIXSRC_FIRST_SWITCH <= sw) ? SWITCH_2POS : SWITCH_3POS) @@ -280,7 +284,7 @@ void onHardwareAntennaSwitchConfirm(const char * result) #define TX_CAPACITY_MEASUREMENT_ROWS #endif -#if (defined(CROSSFIRE) || defined(GHOST)) && SPORT_MAX_BAUDRATE < 400000 +#if (defined(CROSSFIRE) || defined(GHOST)) && (SPORT_MAX_BAUDRATE < 400000 || defined(DEBUG)) #define MAX_BAUD_ROWS 0, #else #define MAX_BAUD_ROWS @@ -326,31 +330,22 @@ void menuRadioHardware(event_t event) 0 /* stick 2 */, 0 /* stick 3 */, 0 /* stick 4 */, - LABEL(Pots), - POTS_ROWS, + POTS_ROWS LABEL(Switches), SWITCHES_ROWS, - 0 /* battery calib */, RTC_ROW TX_CAPACITY_MEASUREMENT_ROWS - MAX_BAUD_ROWS - BLUETOOTH_ROWS - EXTERNAL_ANTENNA_ROW - AUX_SERIAL_ROWS - 0 /* ADC filter */, READONLY_ROW /* RAS */, SPORT_POWER_ROWS 1 /* debugs */, - - 0, - - 0 + 0 /* EEPROM backup */, + 0 /* Factory reset */ }); uint8_t sub = menuVerticalPosition - HEADER_LINE; @@ -399,6 +394,7 @@ void menuRadioHardware(event_t event) editStickHardwareSettings(HW_SETTINGS_COLUMN1, y, k - ITEM_RADIO_HARDWARE_STICK1, event, attr); break; +#if (NUM_POTS + NUM_SLIDERS) > 0 case ITEM_RADIO_HARDWARE_LABEL_POTS: lcdDrawTextAlignedLeft(y, STR_POTS); break; @@ -450,6 +446,7 @@ void menuRadioHardware(event_t event) g_eeGeneral.slidersConfig |= (potType << idx); break; } +#endif #endif case ITEM_RADIO_HARDWARE_LABEL_SWITCHES: diff --git a/radio/src/gui/common/stdlcd/view_telemetry.cpp b/radio/src/gui/common/stdlcd/view_telemetry.cpp index ecdb96aa9d..07a31442cf 100644 --- a/radio/src/gui/common/stdlcd/view_telemetry.cpp +++ b/radio/src/gui/common/stdlcd/view_telemetry.cpp @@ -34,7 +34,7 @@ enum NavigationDirection { #if defined(NAVIGATION_XLITE) #define EVT_KEY_PREVIOUS_VIEW(evt) (evt == EVT_KEY_LONG(KEY_LEFT) && IS_SHIFT_PRESSED()) #define EVT_KEY_NEXT_VIEW(evt) (evt == EVT_KEY_LONG(KEY_RIGHT) && IS_SHIFT_PRESSED()) -#elif defined(NAVIGATION_X7_TX12) +#elif defined(KEYS_GPIO_REG_PAGEDN) #define EVT_KEY_PREVIOUS_VIEW(evt) (evt == EVT_KEY_FIRST(KEY_PAGEUP)) #define EVT_KEY_NEXT_VIEW(evt) (evt == EVT_KEY_FIRST(KEY_PAGEDN)) #elif defined(NAVIGATION_X7) || defined(NAVIGATION_X9D) diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 8dcb466456..316a302cf1 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -1001,9 +1001,15 @@ const char* mm_options_strings::options[] = { STR_MULTI_SERVOFREQ, STR_MULTI_MAX_THROW, STR_MULTI_RFCHAN, - STR_MULTI_RFPOWER + STR_MULTI_RFPOWER, + STR_MULTI_WBUS }; +const uint8_t getMaxMultiOptions() +{ + return DIM(mm_options_strings::options); +} + const mm_protocol_definition multi_protocols[] = { // Protocol as defined in pulses\modules_constants.h, number of sub_protocols - 1, Failsafe supported, Disable channel mapping supported, Subtype string, Option type {MODULE_SUBTYPE_MULTI_FLYSKY, 4, false, true, STR_SUBTYPE_FLYSKY, nullptr}, @@ -1089,3 +1095,31 @@ const mm_protocol_definition *getMultiProtocolDefinition (uint8_t protocol) return pdef; } #endif + +void editStickHardwareSettings(coord_t x, coord_t y, int idx, event_t event, LcdFlags flags) +{ + lcdDrawTextAtIndex(INDENT_WIDTH, y, STR_VSRCRAW, idx+1, 0); + if (ZEXIST(g_eeGeneral.anaNames[idx]) || (flags && s_editMode > 0)) + editName(x, y, g_eeGeneral.anaNames[idx], LEN_ANA_NAME, event, flags); + else + lcdDrawMMM(x, y, flags); +} + +#if defined(MULTIMODULE) +const char * getMultiOptionTitle(uint8_t moduleIdx) +{ + MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + + if (status.isValid()) { + if (status.optionDisp >= getMaxMultiOptions()) { + status.optionDisp = 1; // Unknown options are defaulted to type 1 (basic option) + } + return mm_options_strings::options[status.optionDisp]; + } + else { + const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol(); + const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto); + return pdef->optionsstr; + } +} +#endif diff --git a/radio/src/gui/gui_common.h b/radio/src/gui/gui_common.h index b8ef67f17e..261caefdbd 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -285,7 +285,7 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx) #define MULTIMODULE_MODULE_ROWS(moduleIdx) (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) && !IS_RX_MULTI(moduleIdx)) ? (uint8_t) 0 : HIDDEN_ROW, (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) && !IS_RX_MULTI(moduleIdx)) ? (uint8_t) 0 : HIDDEN_ROW, MULTI_DISABLE_CHAN_MAP_ROW(moduleIdx), // AUTOBIND, DISABLE TELEM, DISABLE CN.MAP #define MULTIMODULE_TYPE_ROW(moduleIdx) isModuleMultimodule(moduleIdx) ? MULTIMODULE_RFPROTO_COLUMNS(moduleIdx) : HIDDEN_ROW, -#define MULTIMODULE_STATUS_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(moduleIdx) && getMultiSyncStatus(moduleIdx).isValid()) ? TITLE_ROW : HIDDEN_ROW, +#define MULTIMODULE_STATUS_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(moduleIdx) && getModuleSyncStatus(moduleIdx).isValid()) ? TITLE_ROW : HIDDEN_ROW, #define MULTIMODULE_MODE_ROWS(moduleIdx) (g_model.moduleData[moduleIdx].multi.customProto) ? (uint8_t) 3 : MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t)2 : (uint8_t)1 #define MULTIMODULE_TYPE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, #define MULTIMODULE_SUBTYPE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? MULTIMODULE_RFPROTO_COLUMNS(moduleIdx) : HIDDEN_ROW, @@ -325,6 +325,7 @@ inline uint8_t MODULE_OPTION_ROW(uint8_t moduleIdx) { } void editStickHardwareSettings(coord_t x, coord_t y, int idx, event_t event, LcdFlags flags); +const char * getMultiOptionTitle(uint8_t moduleIdx); const char * writeScreenshot(); diff --git a/radio/src/gui/navigation/navigation_9x.cpp b/radio/src/gui/navigation/navigation_9x.cpp index bbc958c63a..5e09cfdd1e 100644 --- a/radio/src/gui/navigation/navigation_9x.cpp +++ b/radio/src/gui/navigation/navigation_9x.cpp @@ -82,7 +82,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla } #endif - if (event==EVT_KEY_FIRST(KEY_RIGHT) || event==EVT_KEY_REPT(KEY_RIGHT) || (s_editMode>0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP)))) { + if ((s_editMode>0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP)))) { do { if (IS_KEY_REPT(event) && (i_flags & INCDEC_REP10)) { newval += min(10, i_max-val); @@ -98,7 +98,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla AUDIO_KEY_ERROR(); } } - else if (event==EVT_KEY_FIRST(KEY_LEFT) || event==EVT_KEY_REPT(KEY_LEFT) || (s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN)))) { + else if ((s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN)))) { do { if (IS_KEY_REPT(event) && (i_flags & INCDEC_REP10)) { newval -= min(10, val-i_min); @@ -136,7 +136,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla #if defined(AUTOSWITCH) else { uint8_t swtch = abs(getMovedSwitch()); - if (swtch) { + if (swtch && !IS_SWITCH_MULTIPOS(swtch)) { newval = switchToMix(swtch); } } diff --git a/radio/src/gui/navigation/navigation_horus.cpp b/radio/src/gui/navigation/navigation_horus.cpp index d62d07810c..9679ab6e78 100644 --- a/radio/src/gui/navigation/navigation_horus.cpp +++ b/radio/src/gui/navigation/navigation_horus.cpp @@ -137,7 +137,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla #if defined(AUTOSWITCH) else { unsigned int swtch = abs(getMovedSwitch()); - if (swtch) { + if (swtch && !IS_SWITCH_MULTIPOS(swtch)) { newval = switchToMix(swtch); } } diff --git a/radio/src/gui/navigation/navigation_x7.cpp b/radio/src/gui/navigation/navigation_x7.cpp index ac4a4bbdd7..ecf00a02b7 100644 --- a/radio/src/gui/navigation/navigation_x7.cpp +++ b/radio/src/gui/navigation/navigation_x7.cpp @@ -56,8 +56,11 @@ void onSwitchLongEnterPress(const char * result) int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_flags, IsValueAvailable isValueAvailable, const CheckIncDecStops &stops) { int newval = val; - +#if defined(ROTARY_ENCODER_NAVIGATION) if (s_editMode>0 && event==EVT_ROTARY_RIGHT) { +#else + if (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_PLUS) || event==EVT_KEY_REPT(KEY_PLUS))) { +#endif newval += min(rotencSpeed, i_max-val); while (isValueAvailable && !isValueAvailable(newval) && newval<=i_max) { newval++; @@ -67,7 +70,11 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla AUDIO_KEY_ERROR(); } } +#if defined(ROTARY_ENCODER_NAVIGATION) else if (s_editMode>0 && event==EVT_ROTARY_LEFT) { +#else + if (s_editMode>0 && (event==EVT_KEY_FIRST(KEY_MINUS) || event==EVT_KEY_REPT(KEY_MINUS))) { +#endif newval -= min(rotencSpeed, val-i_min); while (isValueAvailable && !isValueAvailable(newval) && newval>=i_min) { newval--; @@ -99,7 +106,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla #if defined(AUTOSWITCH) else { unsigned int swtch = abs(getMovedSwitch()); - if (swtch) { + if (swtch && !IS_SWITCH_MULTIPOS(swtch)) { newval = switchToMix(swtch); } } @@ -217,7 +224,7 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t if (menuTab) { int cc = curr; switch (event) { -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEUP) case EVT_KEY_FIRST(KEY_PAGEUP): #else case EVT_KEY_LONG(KEY_PAGE): @@ -232,7 +239,7 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t killEvents(event); break; -#if defined(NAVIGATION_X7_TX12) +#if defined(KEYS_GPIO_REG_PAGEDN) case EVT_KEY_FIRST(KEY_PAGEDN): #else case EVT_KEY_BREAK(KEY_PAGE): @@ -310,12 +317,14 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t } } break; - +#if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_RIGHT: - case EVT_KEY_FIRST(KEY_RIGHT): AUDIO_KEY_PRESS(); // no break - case EVT_KEY_REPT(KEY_RIGHT): +#else + case EVT_KEY_FIRST(KEY_DOWN): + case EVT_KEY_REPT(KEY_DOWN): +#endif if (s_editMode > 0) break; // TODO it was != if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { if (l_posHorz >= 0) { @@ -341,12 +350,14 @@ void check(event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t l_posHorz = POS_HORZ_INIT(l_posVert); break; - +#if defined(ROTARY_ENCODER_NAVIGATION) case EVT_ROTARY_LEFT: - case EVT_KEY_FIRST(KEY_LEFT): AUDIO_KEY_PRESS(); // no break - case EVT_KEY_REPT(KEY_LEFT): +#else + case EVT_KEY_FIRST(KEY_UP): + case EVT_KEY_REPT(KEY_UP): +#endif if (s_editMode > 0) break; // TODO it was != if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { if (l_posHorz >= 0) { diff --git a/radio/src/gui/navigation/navigation_x9d.cpp b/radio/src/gui/navigation/navigation_x9d.cpp index a5d6fc3324..2b3587cba8 100644 --- a/radio/src/gui/navigation/navigation_x9d.cpp +++ b/radio/src/gui/navigation/navigation_x9d.cpp @@ -173,7 +173,7 @@ int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_fla #if defined(AUTOSWITCH) else { unsigned int swtch = abs(getMovedSwitch()); - if (swtch) { + if (swtch && !IS_SWITCH_MULTIPOS(swtch)) { newval = switchToMix(swtch); } } diff --git a/radio/src/gui/navigation/navigation_xlite.cpp b/radio/src/gui/navigation/navigation_xlite.cpp index 9cbafda8ba..61d795e77c 100644 --- a/radio/src/gui/navigation/navigation_xlite.cpp +++ b/radio/src/gui/navigation/navigation_xlite.cpp @@ -29,15 +29,6 @@ horzpos_t menuHorizontalPosition; int8_t checkIncDec_Ret; -#if defined(RADIO_T12) -#define DBLKEYS_PRESSED_RGT_LFT(in) ((in & (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_LEFT)) == (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_LEFT)) -// set to 0 -#define DBLKEYS_PRESSED_UP_DWN(in) ((in & (KEYS_GPIO_PIN_UP + KEYS_GPIO_PIN_DOWN)) == (KEYS_GPIO_PIN_UP + KEYS_GPIO_PIN_DOWN)) -// set to max -#define DBLKEYS_PRESSED_RGT_UP(in) ((in & (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_UP)) == (KEYS_GPIO_PIN_RIGHT + KEYS_GPIO_PIN_UP)) -// set to min -#define DBLKEYS_PRESSED_LFT_DWN(in) ((in & (KEYS_GPIO_PIN_LEFT + KEYS_GPIO_PIN_DOWN)) == (KEYS_GPIO_PIN_LEFT + KEYS_GPIO_PIN_DOWN)) -#else // invert the value #define DBLKEYS_PRESSED_RGT_LFT(in) ((in & ((1< 0 && periodUs < MIN_REFRESH_RATE) { + periodUs = MIN_REFRESH_RATE; + } + else if (periodUs > 0 && periodUs > MAX_REFRESH_RATE) { + periodUs = MAX_REFRESH_RATE; + } + + mixerSchedules[moduleIdx].period = periodUs; +} + +bool mixerSchedulerWaitForTrigger(uint8_t timeoutMs) +{ + RTOS_CLEAR_FLAG(mixerFlag); + return RTOS_WAIT_FLAG(mixerFlag, timeoutMs); +} + +void mixerSchedulerISRTrigger() +{ + RTOS_ISR_SET_FLAG(mixerFlag); +} + +#endif diff --git a/radio/src/mixer_scheduler.h b/radio/src/mixer_scheduler.h new file mode 100644 index 0000000000..601f3fcd7a --- /dev/null +++ b/radio/src/mixer_scheduler.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#ifndef _MIXER_SCHEDULER_H_ +#define _MIXER_SCHEDULER_H_ + +#define MIXER_SCHEDULER_DEFAULT_PERIOD_US 4000u // 4ms + +#define MIN_REFRESH_RATE 1750 /* us */ +#define MAX_REFRESH_RATE 25000 /* us */ + +#if !defined(SIMU) + +// Call once to initialize the mixer scheduler +void mixerSchedulerInit(); + +// Configure and start the scheduler timer +void mixerSchedulerStart(); + +// Stop the scheduler timer +void mixerSchedulerStop(); + +// Set the timer counter to 0 +void mixerSchedulerResetTimer(); + +// Set the scheduling period for a given module +void mixerSchedulerSetPeriod(uint8_t moduleIdx, uint16_t periodUs); + +// Wait for the scheduler timer to trigger +// returns true if timeout, false otherwise +bool mixerSchedulerWaitForTrigger(uint8_t timeoutMs); + +// Enable the timer trigger +void mixerSchedulerEnableTrigger(); + +// Disable the timer trigger +void mixerSchedulerDisableTrigger(); + +// Fetch the current scheduling period +uint16_t getMixerSchedulerPeriod(); + +// Trigger mixer from an ISR +void mixerSchedulerISRTrigger(); + +#else + +#define mixerSchedulerInit() +#define mixerSchedulerStart() +#define mixerSchedulerStop() +#define mixerSchedulerResetTimer() +#define mixerSchedulerSetPeriod(m,p) + +static inline bool mixerSchedulerWaitForTrigger(uint8_t timeout) +{ + simuSleep(timeout); + return false; +} + +#define mixerSchedulerEnableTrigger() +#define mixerSchedulerDisableTrigger() + +#define getMixerSchedulerPeriod() (MIXER_SCHEDULER_DEFAULT_PERIOD_US) +#define mixerSchedulerISRTrigger() + +#endif + +#endif diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index c7baa0e61c..8fcce8cc14 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -344,6 +344,14 @@ void generalDefault() setDefaultOwnerId(); #endif +#if defined(RADIOMASTER_RTF_RELEASE) + // Those settings are for headless radio + g_eeGeneral.USBMode = USB_JOYSTICK_MODE; + g_eeGeneral.disableRtcWarning = 1; + g_eeGeneral.splashMode = 3; // Disable splash + g_eeGeneral.pwrOnSpeed = 1; // 1 second +#endif + g_eeGeneral.chkSum = 0xFFFF; } @@ -518,6 +526,15 @@ void modelDefault(uint8_t id) g_model.switchWarningState |= (1 << (3*i)); } #endif + +#if defined(RADIOMASTER_RTF_RELEASE) + // Those settings are for headless radio + g_model.trainerData.mode = TRAINER_MODE_SLAVE; + g_model.moduleData[INTERNAL_MODULE].type = MODULE_TYPE_MULTIMODULE; + g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY); + g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D8; + g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES; +#endif } bool isInputRecursive(int index) @@ -535,6 +552,8 @@ bool isInputRecursive(int index) } #if defined(AUTOSOURCE) +constexpr int MULTIPOS_STEP_SIZE = (2 * RESX) / XPOTS_MULTIPOS_COUNT; + int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS) { int8_t result = 0; @@ -543,7 +562,7 @@ int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS) static int16_t inputsStates[MAX_INPUTS]; if (min <= MIXSRC_FIRST_INPUT) { for (uint8_t i=0; i 512) { + if (abs(anas[i] - inputsStates[i]) > MULTIPOS_STEP_SIZE) { if (!isInputRecursive(i)) { result = MIXSRC_FIRST_INPUT+i; break; @@ -555,7 +574,7 @@ int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS) static int16_t sourcesStates[NUM_STICKS+NUM_POTS+NUM_SLIDERS+NUM_MOUSE_ANALOGS]; if (result == 0) { for (uint8_t i=0; i 512) { + if (abs(calibratedAnalogs[i] - sourcesStates[i]) > MULTIPOS_STEP_SIZE) { result = MIXSRC_Rud+i; break; } @@ -913,7 +932,7 @@ void checkAll() checkFailsafe(); checkRSSIAlarmsDisabled(); -#if defined(SDCARD) +#if defined(SDCARD) && !defined(RADIOMASTER_RTF_RELEASE) checkSDVersion(); #endif @@ -1449,6 +1468,19 @@ void doMixerCalculations() DEBUG_TIMER_START(debugTimerEvalMixes); evalMixes(tick10ms); DEBUG_TIMER_STOP(debugTimerEvalMixes); +} + +void doMixerPeriodicUpdates() +{ + static tmr10ms_t lastTMR = 0; + + tmr10ms_t tmr10ms = get_tmr10ms(); + + uint8_t tick10ms = (tmr10ms >= lastTMR ? tmr10ms - lastTMR : 1); + // handle tick10ms overrun + // correct overflow handling costs a lot of code; happens only each 11 min; + // therefore forget the exact calculation and use only 1 instead; good compromise + lastTMR = tmr10ms; DEBUG_TIMER_START(debugTimerMixes10ms); if (tick10ms) { @@ -2227,6 +2259,7 @@ uint32_t pwrCheck() #endif event_t evt = getEvent(false); DISPLAY_WARNING(evt); + LED_ERROR_BEGIN(); lcdRefresh(); if (warningResult) { @@ -2236,6 +2269,7 @@ uint32_t pwrCheck() else if (!warningText) { // shutdown has been cancelled pwr_check_state = PWR_CHECK_PAUSED; + LED_ERROR_END(); return e_power_on; } #endif diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 156bd9d3dc..9e25810c5b 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -73,6 +73,12 @@ #define CASE_GYRO(x) #endif +#if defined(BACKLIGHT_GPIO) +#define CASE_BACKLIGHT(x) x, +#else +#define CASE_BACKLIGHT(x) +#endif + #if defined(LUA) #define CASE_LUA(x) x, #else @@ -281,6 +287,12 @@ void memswap(void * a, void * b, uint8_t size); #define IS_MULTIPOS_CALIBRATED(cal) (false) #endif +#if NUM_XPOTS > 0 + #define IS_SWITCH_MULTIPOS(x) (SWSRC_FIRST_MULTIPOS_SWITCH <= (x) && (x) <= SWSRC_LAST_MULTIPOS_SWITCH) +#else + #define IS_SWITCH_MULTIPOS(x) (false) +#endif + #if defined(PWR_BUTTON_PRESS) #define pwrOffPressed() pwrPressed() #else @@ -313,7 +325,7 @@ void memswap(void * a, void * b, uint8_t size); #define MASK_CFN_TYPE uint64_t // current max = 64 function switches #define MASK_FUNC_TYPE uint32_t // current max = 32 functions -typedef struct { +struct CustomFunctionsContext { MASK_FUNC_TYPE activeFunctions; MASK_CFN_TYPE activeSwitches; tmr10ms_t lastFunctionTime[MAX_SPECIAL_FUNCTIONS]; @@ -327,7 +339,7 @@ typedef struct { { memclear(this, sizeof(*this)); } -} CustomFunctionsContext; +}; #include "strhelpers.h" #include "gui.h" @@ -387,6 +399,8 @@ inline bool SPLASH_NEEDED() #define ROTENC_HIGHSPEED 50 #define ROTENC_DELAY_MIDSPEED 32 #define ROTENC_DELAY_HIGHSPEED 16 +#elif defined(RADIO_T8) + constexpr uint8_t rotencSpeed = 1; #endif constexpr uint8_t HEART_TIMER_10MS = 0x01; @@ -441,6 +455,10 @@ extern uint8_t potsPos[NUM_XPOTS]; bool trimDown(uint8_t idx); void readKeysAndTrims(); +#if defined(KEYS_GPIO_REG_BIND) +void bindButtonHandler(event_t event); +#endif + uint16_t evalChkSum(); void alert(const char * title, const char * msg, uint8_t sound); @@ -497,6 +515,7 @@ extern uint32_t nextMixerTime[NUM_MODULES]; void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms); void evalMixes(uint8_t tick10ms); void doMixerCalculations(); +void doMixerPeriodicUpdates(); void scheduleNextMixerCalculation(uint8_t module, uint32_t period_ms); void checkTrims(); @@ -973,7 +992,13 @@ constexpr uint8_t OPENTX_START_NO_CHECKS = 0x04; #if defined(STATUS_LEDS) #define LED_ERROR_BEGIN() ledRed() +#if defined(RADIO_T8) + // Because of green backlit logo, green is preferred on this radio + #define LED_ERROR_END() ledGreen() + #define LED_BIND() ledBlue() +#else #define LED_ERROR_END() ledBlue() +#endif #else #define LED_ERROR_BEGIN() #define LED_ERROR_END() diff --git a/radio/src/options.h b/radio/src/options.h index acadfd129c..4f1a1a0774 100644 --- a/radio/src/options.h +++ b/radio/src/options.h @@ -97,6 +97,9 @@ static const char * const options[] = { #endif #if defined(HARDWARE_EXTERNAL_ACCESS_MOD) "externalaccessmod", +#endif +#if defined(BIND_KEY) + "bindkey", #endif nullptr //sentinel }; diff --git a/radio/src/pulses/afhds3.h b/radio/src/pulses/afhds3.h index 57adf056a9..c309e2e2b7 100644 --- a/radio/src/pulses/afhds3.h +++ b/radio/src/pulses/afhds3.h @@ -94,8 +94,6 @@ struct Data void reset() { -#if !(defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)) - total = 0; pulsesSize = 0; #endif } @@ -121,7 +119,6 @@ struct Data return; } pulses[pulsesSize++] = v; - total += v; } void sendByte(uint8_t b) { @@ -152,14 +149,7 @@ struct Data //add remaining time of frame void flush() { - uint16_t diff = AFHDS3_FRAME_HALF_US - total; - pulses[pulsesSize - 1] += diff; - //ensure 2 ms break - if (pulses[pulsesSize - 1] < 4000) - { - pulses[pulsesSize - 1] = 4050; - } - total += diff; + pulses[pulsesSize - 1] = 60000; } const uint16_t * getData() diff --git a/radio/src/pulses/dsm2.cpp b/radio/src/pulses/dsm2.cpp index 3612f60db1..34a10b3d69 100644 --- a/radio/src/pulses/dsm2.cpp +++ b/radio/src/pulses/dsm2.cpp @@ -76,7 +76,6 @@ void _send_1(uint8_t v) *extmodulePulsesData.dsm2.ptr++ = v - 1; extmodulePulsesData.dsm2.index += 1; - extmodulePulsesData.dsm2.rest -= v; } void sendByteDsm2(uint8_t b) // max 10 changes 0 10 10 10 10 1 @@ -101,9 +100,9 @@ void sendByteDsm2(uint8_t b) // max 10 changes 0 10 10 10 10 1 void putDsm2Flush() { if (extmodulePulsesData.dsm2.index & 1) - *extmodulePulsesData.dsm2.ptr++ = extmodulePulsesData.dsm2.rest; + *extmodulePulsesData.dsm2.ptr++ = 60000; else - *(extmodulePulsesData.dsm2.ptr - 1) = extmodulePulsesData.dsm2.rest; + *(extmodulePulsesData.dsm2.ptr - 1) = 60000; } #endif @@ -119,7 +118,6 @@ void setupPulsesDSM2() extmodulePulsesData.dsm2.serialBitCount = 0 ; #else extmodulePulsesData.dsm2.index = 0; - extmodulePulsesData.dsm2.rest = DSM2_PERIOD * 2000; #endif extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses; diff --git a/radio/src/pulses/modules_constants.h b/radio/src/pulses/modules_constants.h index 15a2c2283b..6fbec157e5 100644 --- a/radio/src/pulses/modules_constants.h +++ b/radio/src/pulses/modules_constants.h @@ -203,6 +203,14 @@ enum MMRFrskySubtypes { MM_RF_FRSKY_SUBTYPE_D16_CLONED }; +enum MMRFrskyX2Subtypes { + MM_RF_FRSKYX2_SUBTYPE_D16, + MM_RF_FRSKYX2_SUBTYPE_D8, + MM_RF_FRSKYX2_SUBTYPE_D16_LBT, + MM_RF_FRSKYX2_SUBTYPE_D16_LBT_8CH, + MM_RF_FRSKYX2_SUBTYPE_D16_CLONED +}; + enum ModuleSubtypeDSM2 { DSM2_PROTO_LP45, DSM2_PROTO_DSM2, diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index 2c92e65ff7..f483d9b6bd 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -42,6 +42,8 @@ struct mm_options_strings { static const char* options[]; }; +const uint8_t getMaxMultiOptions(); + struct mm_protocol_definition { uint8_t protocol; uint8_t maxSubtype; @@ -708,10 +710,6 @@ inline void getMultiOptionValues(int8_t multi_proto, int8_t & min, int8_t & max) min = -1; max = 84; break; - case MODULE_SUBTYPE_MULTI_FRSKY_R9: - min = 0; // 10mW - max = 5; // 300mW - break; default: min = -128; max = 127; diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index dcc7c7f9c3..37364199ae 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -108,15 +108,15 @@ static void sendFailsafeChannels(uint8_t moduleIdx) int16_t failsafeValue = g_model.failsafeChannels[i]; int pulseValue; - if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_HOLD) { + if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_HOLD || failsafeValue == FAILSAFE_CHANNEL_HOLD) { pulseValue = 2047; } - else if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_NOPULSES) { + else if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_NOPULSES || failsafeValue == FAILSAFE_CHANNEL_NOPULSE) { pulseValue = 0; } else { failsafeValue += 2 * PPM_CH_CENTER(g_model.moduleData[moduleIdx].channelsStart + i) - 2 * PPM_CENTER; - pulseValue = limit(1, (failsafeValue * 800 / 1000) + 1024, 2047); + pulseValue = limit(1, (failsafeValue * 800 / 1000) + 1024, 2046); } bits |= pulseValue << bitsavailable; @@ -209,10 +209,8 @@ void setupPulsesMultiExternalModule() extmodulePulsesData.dsm2.serialByte = 0 ; extmodulePulsesData.dsm2.serialBitCount = 0 ; #else - extmodulePulsesData.dsm2.rest = getMultiSyncStatus(EXTERNAL_MODULE).getAdjustedRefreshRate(); extmodulePulsesData.dsm2.index = 0; #endif - extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses; setupPulsesMulti(EXTERNAL_MODULE); diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index d6833bfe9c..128e11976e 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -21,6 +21,7 @@ #include "opentx.h" #include "io/frsky_pxx2.h" #include "pulses/pxx2.h" +#include "mixer_scheduler.h" uint8_t s_pulses_paused = 0; ModuleState moduleState[NUM_MODULES]; @@ -62,7 +63,7 @@ void getModuleSyncStatusString(uint8_t moduleIdx, char * statusText) *statusText = 0; #if defined(MULTIMODULE) if (isModuleMultimodule(moduleIdx)) { - getMultiSyncStatus(moduleIdx).getRefreshString(statusText); + getModuleSyncStatus(moduleIdx).getRefreshString(statusText); } #endif #if defined(AFHDS3) @@ -225,12 +226,14 @@ void enablePulsesExternalModule(uint8_t protocol) #if defined(PXX1) case PROTOCOL_CHANNELS_PXX1_PULSES: extmodulePxx1PulsesStart(); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX_PULSES_PERIOD); break; #endif #if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) case PROTOCOL_CHANNELS_PXX1_SERIAL: extmodulePxx1SerialStart(); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD); break; #endif @@ -238,59 +241,81 @@ void enablePulsesExternalModule(uint8_t protocol) case PROTOCOL_CHANNELS_DSM2_LP45: case PROTOCOL_CHANNELS_DSM2_DSM2: case PROTOCOL_CHANNELS_DSM2_DSMX: +#if defined(PCBSKY9X) extmoduleSerialStart(DSM2_BAUDRATE, DSM2_PERIOD * 2000, false); +#else + extmoduleSerialStart(); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, DSM2_PERIOD); +#endif break; #endif #if defined(CROSSFIRE) case PROTOCOL_CHANNELS_CROSSFIRE: EXTERNAL_MODULE_ON(); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, CROSSFIRE_PERIOD); break; #endif #if defined(GHOST) case PROTOCOL_CHANNELS_GHOST: EXTERNAL_MODULE_ON(); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, GHOST_PERIOD); break; #endif #if defined(PXX2) && defined(EXTMODULE_USART) case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: extmoduleInvertedSerialStart(PXX2_HIGHSPEED_BAUDRATE); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_PERIOD); break; case PROTOCOL_CHANNELS_PXX2_LOWSPEED: extmoduleInvertedSerialStart(PXX2_LOWSPEED_BAUDRATE); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_PERIOD); break; #endif #if defined(MULTIMODULE) case PROTOCOL_CHANNELS_MULTIMODULE: +#if defined(PCBSKY9X) extmoduleSerialStart(MULTIMODULE_BAUDRATE, MULTIMODULE_PERIOD * 2000, true); +#else + extmoduleSerialStart(); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, MULTIMODULE_PERIOD); +#endif break; #endif #if defined(SBUS) case PROTOCOL_CHANNELS_SBUS: +#if defined(PCBSKY9X) extmoduleSerialStart(SBUS_BAUDRATE, SBUS_PERIOD_HALF_US, false); +#else + extmoduleSerialStart(); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, SBUS_PERIOD); +#endif break; #endif #if defined(PPM) case PROTOCOL_CHANNELS_PPM: extmodulePpmStart(); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE)); break; #endif #if defined(AFHDS3) case PROTOCOL_CHANNELS_AFHDS3: extmodulePulsesData.afhds3.init(EXTERNAL_MODULE); - extmoduleSerialStart(AFHDS3_BAUDRATE, AFHDS3_COMMAND_TIMEOUT * 2000, false); + extmoduleSerialStart(/*AFHDS3_BAUDRATE, AFHDS3_COMMAND_TIMEOUT * 2000, false*/); + mixerSchedulerSetPeriod(EXTERNAL_MODULE, AFHDS3_COMMAND_TIMEOUT * 1000 /* us */); break; #endif - default: + // external module stopped, set period to 50ms (necessary for USB Joystick, for instance) + mixerSchedulerSetPeriod(EXTERNAL_MODULE, 50000/*us*/); break; } } @@ -301,14 +326,18 @@ bool setupPulsesExternalModule(uint8_t protocol) #if defined(PXX1) case PROTOCOL_CHANNELS_PXX1_PULSES: extmodulePulsesData.pxx.setupFrame(EXTERNAL_MODULE); +#if defined(PCBSKY9X) scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX_PULSES_PERIOD); +#endif return true; #endif #if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) case PROTOCOL_CHANNELS_PXX1_SERIAL: extmodulePulsesData.pxx_uart.setupFrame(EXTERNAL_MODULE); +#if defined(PCBSKY9X) scheduleNextMixerCalculation(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD); +#endif return true; #endif @@ -316,63 +345,102 @@ bool setupPulsesExternalModule(uint8_t protocol) case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: case PROTOCOL_CHANNELS_PXX2_LOWSPEED: extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE); - scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_PERIOD); +#if defined(PCBSKY9X) + sheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_PERIOD); +#endif return true; #endif #if defined(SBUS) case PROTOCOL_CHANNELS_SBUS: setupPulsesSbus(); +#if defined(PCBSKY9X) scheduleNextMixerCalculation(EXTERNAL_MODULE, SBUS_PERIOD); +#else + // SBUS_PERIOD is not a constant! It can be set from UI + mixerSchedulerSetPeriod(EXTERNAL_MODULE, SBUS_PERIOD); return true; #endif +#endif #if defined(DSM2) case PROTOCOL_CHANNELS_DSM2_LP45: case PROTOCOL_CHANNELS_DSM2_DSM2: case PROTOCOL_CHANNELS_DSM2_DSMX: setupPulsesDSM2(); +#if defined(PCBSKY9X) scheduleNextMixerCalculation(EXTERNAL_MODULE, DSM2_PERIOD); +#endif return true; #endif #if defined(CROSSFIRE) case PROTOCOL_CHANNELS_CROSSFIRE: + { + ModuleSyncStatus& status = getModuleSyncStatus(EXTERNAL_MODULE); + if (status.isValid()) + mixerSchedulerSetPeriod(EXTERNAL_MODULE, status.getAdjustedRefreshRate()); + else + mixerSchedulerSetPeriod(EXTERNAL_MODULE, CROSSFIRE_PERIOD); setupPulsesCrossfire(); +#if defined(PCBSKY9X) scheduleNextMixerCalculation(EXTERNAL_MODULE, CROSSFIRE_PERIOD); +#endif return true; + } #endif #if defined(GHOST) case PROTOCOL_CHANNELS_GHOST: + { + ModuleSyncStatus& status = getModuleSyncStatus(EXTERNAL_MODULE); + if (status.isValid()) + mixerSchedulerSetPeriod(EXTERNAL_MODULE, status.getAdjustedRefreshRate()); + else + mixerSchedulerSetPeriod(EXTERNAL_MODULE, GHOST_PERIOD); setupPulsesGhost(); +#if defined(PCBSKPCBSKY9X) scheduleNextMixerCalculation(EXTERNAL_MODULE, GHOST_PERIOD); +#endif return true; + } #endif #if defined(MULTIMODULE) case PROTOCOL_CHANNELS_MULTIMODULE: + { + ModuleSyncStatus& status = getModuleSyncStatus(EXTERNAL_MODULE); + if (status.isValid()) + mixerSchedulerSetPeriod(EXTERNAL_MODULE, status.getAdjustedRefreshRate()); + else + mixerSchedulerSetPeriod(EXTERNAL_MODULE, MULTIMODULE_PERIOD); setupPulsesMultiExternalModule(); +#if defined(PCBSKY9X) scheduleNextMixerCalculation(EXTERNAL_MODULE, MULTIMODULE_PERIOD); +#endif return true; + } #endif #if defined(PPM) case PROTOCOL_CHANNELS_PPM: setupPulsesPPMExternalModule(); +#if defined(PCBSKY9X) scheduleNextMixerCalculation(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE)); +#endif return true; #endif #if defined(AFHDS3) case PROTOCOL_CHANNELS_AFHDS3: extmodulePulsesData.afhds3.setupFrame(); +#if defined(PCBSKY9X) scheduleNextMixerCalculation(EXTERNAL_MODULE, AFHDS3_COMMAND_TIMEOUT); +#endif return true; #endif default: - scheduleNextMixerCalculation(EXTERNAL_MODULE, 50/*ms*/); return false; } } @@ -386,12 +454,26 @@ static void enablePulsesInternalModule(uint8_t protocol) #if defined(PXX1) && !defined(INTMODULE_USART) case PROTOCOL_CHANNELS_PXX1_PULSES: intmodulePxx1PulsesStart(); +#if defined(INTMODULE_HEARTBEAT) + // use backup trigger (1 ms later) + init_intmodule_heartbeat(); + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000/*us*/); +#else + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); +#endif break; #endif #if defined(PXX1) && defined(INTMODULE_USART) case PROTOCOL_CHANNELS_PXX1_SERIAL: intmodulePxx1SerialStart(); +#if defined(INTMODULE_HEARTBEAT) + // use backup trigger (1 ms later) + init_intmodule_heartbeat(); + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000/*us*/); +#else + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); +#endif break; #endif @@ -399,6 +481,14 @@ static void enablePulsesInternalModule(uint8_t protocol) case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: intmoduleSerialStart(PXX2_HIGHSPEED_BAUDRATE, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b); resetAccessAuthenticationCount(); + +#if defined(INTMODULE_HEARTBEAT) + // use backup trigger (1 ms later) + init_intmodule_heartbeat(); + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD + 1000/*us*/); +#else + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD); +#endif break; #endif @@ -406,17 +496,20 @@ static void enablePulsesInternalModule(uint8_t protocol) case PROTOCOL_CHANNELS_MULTIMODULE: intmodulePulsesData.multi.initFrame(); intmoduleSerialStart(MULTIMODULE_BAUDRATE, true, USART_Parity_Even, USART_StopBits_2, USART_WordLength_9b); - intmoduleTimerStart(MULTIMODULE_PERIOD); + mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD); break; #endif #if defined(INTERNAL_MODULE_PPM) case PROTOCOL_CHANNELS_PPM: intmodulePpmStart(); + mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE)); break; #endif default: + // internal module stopped, set internal period to 0 and start the scheduler + mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); break; } } @@ -427,18 +520,18 @@ bool setupPulsesInternalModule(uint8_t protocol) #if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART) case PROTOCOL_CHANNELS_PXX1_PULSES: intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE); - scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); +#if defined(INTMODULE_HEARTBEAT) + mixerSchedulerResetTimer(); + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1000 /* backup */); +#else + mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); +#endif return true; #endif #if defined(PXX1) && defined(INTMODULE_USART) case PROTOCOL_CHANNELS_PXX1_SERIAL: intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE); -#if defined(INTMODULE_HEARTBEAT) - scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD + 1 /* backup */); -#else - scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); -#endif return true; #endif @@ -447,13 +540,14 @@ bool setupPulsesInternalModule(uint8_t protocol) { bool result = intmodulePulsesData.pxx2.setupFrame(INTERNAL_MODULE); if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER || moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) { - scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_TOOLS_PERIOD); + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_TOOLS_PERIOD); } else { #if defined(INTMODULE_HEARTBEAT) - scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_PERIOD + 1 /* backup */); + mixerSchedulerResetTimer(); + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD + 1000 /* backup */); #else - scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_PERIOD); + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD); #endif } return result; @@ -463,23 +557,32 @@ bool setupPulsesInternalModule(uint8_t protocol) #if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) case PROTOCOL_CHANNELS_PPM: setupPulsesPPMInternalModule(); - scheduleNextMixerCalculation(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE)); + // probably useless, as the interval did not change since "enable" function + mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE)); return true; #endif #if defined(INTERNAL_MODULE_MULTI) case PROTOCOL_CHANNELS_MULTIMODULE: setupPulsesMultiInternalModule(); - scheduleNextMixerCalculation(INTERNAL_MODULE, MULTIMODULE_PERIOD); + mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD); return true; #endif default: - scheduleNextMixerCalculation(INTERNAL_MODULE, 10 /*ms*/); // used for USB sim for example + //mixerSchedulerSetPeriod(INTERNAL_MODULE, 10000 /*us*/); // used for USB sim for example return false; } } +void stopPulsesInternalModule() +{ + if (moduleState[INTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) { + intmoduleStop(); + moduleState[INTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE; + } +} + bool setupPulsesInternalModule() { uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE); @@ -498,6 +601,14 @@ bool setupPulsesInternalModule() } #endif +void stopPulsesExternalModule() +{ + if (moduleState[EXTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) { + extmoduleStop(); + moduleState[EXTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE; + } +} + bool setupPulsesExternalModule() { uint8_t protocol = getRequiredProtocol(EXTERNAL_MODULE); diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index d877accea8..679bfe419a 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -226,21 +226,20 @@ typedef Dsm2SerialPulsesData Dsm2PulsesData; PACK(struct Dsm2TimerPulsesData { pulse_duration_t pulses[MAX_PULSES_TRANSITIONS]; pulse_duration_t * ptr; - uint16_t rest; uint8_t index; }); typedef Dsm2TimerPulsesData Dsm2PulsesData; #endif #define PPM_PERIOD_HALF_US(module) ((g_model.moduleData[module].ppm.frameLength * 5 + 225) * 200) /*half us*/ -#define PPM_PERIOD(module) (PPM_PERIOD_HALF_US(module) / 2000) /*ms*/ +#define PPM_PERIOD(module) (PPM_PERIOD_HALF_US(module) / 2) /*us*/ #define DSM2_BAUDRATE 125000 -#define DSM2_PERIOD 22 /*ms*/ +#define DSM2_PERIOD 22000 /*us*/ #define SBUS_BAUDRATE 100000 #define SBUS_PERIOD_HALF_US ((g_model.moduleData[EXTERNAL_MODULE].sbus.refreshRate * 5 + 225) * 200) /*half us*/ -#define SBUS_PERIOD (SBUS_PERIOD_HALF_US / 2000) /*ms*/ +#define SBUS_PERIOD (SBUS_PERIOD_HALF_US / 2) /*us*/ #define MULTIMODULE_BAUDRATE 100000 -#define MULTIMODULE_PERIOD 7 /*ms*/ +#define MULTIMODULE_PERIOD 7000 /*us*/ #define CROSSFIRE_FRAME_MAXLEN 64 PACK(struct CrossfirePulsesData { @@ -325,8 +324,12 @@ extern TrainerPulsesData trainerPulsesData; #if defined(HARDWARE_INTERNAL_MODULE) bool setupPulsesInternalModule(); +void stopPulsesInternalModule(); #endif +#if defined(HARDWARE_EXTERNAL_MODULE) bool setupPulsesExternalModule(); +void stopPulsesExternalModule(); +#endif void setupPulsesDSM2(); void setupPulsesCrossfire(); void setupPulsesGhost(); @@ -363,7 +366,9 @@ inline void startPulses() setupPulsesInternalModule(); #endif +#if defined(HARDWARE_EXTERNAL_MODULE) setupPulsesExternalModule(); +#endif #if defined(HARDWARE_EXTRA_MODULE) extramodulePpmStart(); diff --git a/radio/src/pulses/pxx.h b/radio/src/pulses/pxx.h index 5d0bfaf051..e852de1808 100644 --- a/radio/src/pulses/pxx.h +++ b/radio/src/pulses/pxx.h @@ -29,20 +29,20 @@ #define PXX2_LOWSPEED_BAUDRATE 230400 #define PXX2_HIGHSPEED_BAUDRATE 450000 -#define PXX2_PERIOD 4 // 4ms -#define PXX2_TOOLS_PERIOD 1 // 1ms +#define PXX2_PERIOD 4000/*us*/ +#define PXX2_TOOLS_PERIOD 1000/*us*/ #define PXX2_FRAME_MAXLENGTH 64 -#define PXX_PULSES_PERIOD 9/*ms*/ -#define EXTMODULE_PXX1_SERIAL_PERIOD 4/*ms*/ +#define PXX_PULSES_PERIOD 9000/*us*/ +#define EXTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/ #define EXTMODULE_PXX1_SERIAL_BAUDRATE 420000 #if defined(PXX_FREQUENCY_HIGH) #define INTMODULE_PXX1_SERIAL_BAUDRATE 450000 - #define INTMODULE_PXX1_SERIAL_PERIOD 4/*ms*/ + #define INTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/ #else #define INTMODULE_PXX1_SERIAL_BAUDRATE 115200 - #define INTMODULE_PXX1_SERIAL_PERIOD 9/*ms*/ + #define INTMODULE_PXX1_SERIAL_PERIOD 9000/*us*/ #endif // Used by the Sky9x family boards @@ -108,7 +108,7 @@ class PwmPxxBitTransport: public PulsesBuffer { void addTail() { // rest min value is 18000 - 200 * 48 = 8400 (4.2ms) - *(ptr - 1) += rest; + *(ptr - 1) = 60000; } }; diff --git a/radio/src/pulses/sbus.cpp b/radio/src/pulses/sbus.cpp index a881730fc5..e44abd6427 100644 --- a/radio/src/pulses/sbus.cpp +++ b/radio/src/pulses/sbus.cpp @@ -55,7 +55,6 @@ static void _send_level(uint8_t v) *extmodulePulsesData.dsm2.ptr++ = v - 1; extmodulePulsesData.dsm2.index+=1; - extmodulePulsesData.dsm2.rest -=v; } void sendByteSbus(uint8_t b) // max 11 changes 0 10 10 10 10 P 1 @@ -113,7 +112,6 @@ void setupPulsesSbus() extmodulePulsesData.dsm2.serialByte = 0; extmodulePulsesData.dsm2.serialBitCount = 0; #else - extmodulePulsesData.dsm2.rest = SBUS_PERIOD_HALF_US; extmodulePulsesData.dsm2.index = 0; #endif diff --git a/radio/src/rtos.h b/radio/src/rtos.h index 0c3cf4ee58..e4bd1aae78 100644 --- a/radio/src/rtos.h +++ b/radio/src/rtos.h @@ -37,7 +37,9 @@ extern "C++" { typedef pthread_t RTOS_TASK_HANDLE; typedef pthread_mutex_t RTOS_MUTEX_HANDLE; + typedef uint32_t RTOS_FLAG_HANDLE; + typedef sem_t * RTOS_EVENT_HANDLE; extern uint64_t simuTimerMicros(void); @@ -77,16 +79,26 @@ extern "C++" { pthread_mutex_unlock(&mutex); } - static inline void RTOS_CREATE_FLAG(uint32_t &flag) + static inline void RTOS_CREATE_FLAG(RTOS_FLAG_HANDLE flag) { - flag = 0; // TODO: real flags (use semaphores?) } - static inline void RTOS_SET_FLAG(uint32_t &flag) + static inline void RTOS_SET_FLAG(RTOS_FLAG_HANDLE flag) { - flag = 1; } + static inline void RTOS_CLEAR_FLAG(RTOS_FLAG_HANDLE flag) + { + } + + static inline bool RTOS_WAIT_FLAG(RTOS_FLAG_HANDLE flag, uint32_t timeout) + { + simuSleep(timeout); + return false; + } + + #define RTOS_ISR_SET_FLAG RTOS_SET_FLAG + template class FakeTaskStack { @@ -147,6 +159,7 @@ template { return (uint32_t)(simuTimerMicros() / 1000); } + #elif defined(RTOS_COOS) #ifdef __cplusplus extern "C" { @@ -156,7 +169,7 @@ template } #endif - #define RTOS_MS_PER_TICK ((CPU_FREQ / CFG_SYSTICK_FREQ) / (CPU_FREQ / 1000)) // RTOS timer tick length in ms (currently 2) + #define RTOS_MS_PER_TICK (1000 / CFG_SYSTICK_FREQ) // RTOS timer tick length in ms (currently 1 for STM32, 2 for others) typedef OS_TID RTOS_TASK_HANDLE; typedef OS_MutexID RTOS_MUTEX_HANDLE; @@ -231,6 +244,17 @@ template #define RTOS_CREATE_FLAG(flag) flag = CoCreateFlag(false, false) #define RTOS_SET_FLAG(flag) (void)CoSetFlag(flag) + #define RTOS_CLEAR_FLAG(flag) (void)CoClearFlag(flag) + #define RTOS_WAIT_FLAG(flag,timeout) (CoWaitForSingleFlag(flag,timeout) == E_TIMEOUT) + + static inline void RTOS_ISR_SET_FLAG(RTOS_FLAG_HANDLE flag) + { + CoEnterISR(); + CoSchedLock(); + isr_SetFlag(flag); + CoSchedUnlock(); + CoExitISR(); + } #ifdef __cplusplus template diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index e25759d0e7..c58261c444 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -146,8 +146,12 @@ const char * getBasename(const char * path); #define OTX_FOURCC 0x3978746F // otx for Taranis X-Lite #elif defined(RADIO_T12) #define OTX_FOURCC 0x3D78746F // otx for Jumper T12 +#elif defined(RADIO_TLITE) + #define OTX_FOURCC 0x4278746F // otx for Jumper TLite #elif defined(RADIO_TX12) #define OTX_FOURCC 0x4178746F // otx for Radiomaster TX12 +#elif defined(RADIO_T8) + #define OTX_FOURCC 0x4378746F // otx for Radiomaster T8 #elif defined(PCBX7) #define OTX_FOURCC 0x3678746F // otx for Taranis X7 / X7S / X7 Express / X7S Express #elif defined(PCBX9LITES) diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp index 613f6a53c0..ee9c8ae45e 100644 --- a/radio/src/simu.cpp +++ b/radio/src/simu.cpp @@ -324,7 +324,7 @@ void OpenTxSim::updateKeysAndSwitches(bool start) KEY_Down, KEY_DOWN, KEY_Right, KEY_RIGHT, KEY_Left, KEY_LEFT, -#elif defined(PCBXLITE) || defined(RADIO_T12) +#elif defined(PCBXLITE) || defined(RADIO_FAMILY_JUMPER_T12) #if defined(KEYS_GPIO_REG_SHIFT) KEY_Shift_L, KEY_SHIFT, #endif @@ -342,6 +342,15 @@ void OpenTxSim::updateKeysAndSwitches(bool start) KEY_Down, KEY_EXIT, KEY_Right, KEY_TELE, KEY_Left, KEY_SYS, +#elif defined(RADIO_T8) + KEY_Page_Up, KEY_PAGEUP, + KEY_Page_Down, KEY_PAGEDN, + KEY_Return, KEY_ENTER, + KEY_Right, KEY_MODEL, + KEY_BackSpace, KEY_EXIT, + KEY_Left, KEY_SYS, + KEY_Up, KEY_PLUS, + KEY_Down, KEY_MINUS, #elif defined(PCBTARANIS) KEY_Page_Up, KEY_MENU, #if defined(KEYS_GPIO_REG_PAGE) diff --git a/radio/src/storage/storage_common.cpp b/radio/src/storage/storage_common.cpp index 0bf0f3b255..b46ea41342 100644 --- a/radio/src/storage/storage_common.cpp +++ b/radio/src/storage/storage_common.cpp @@ -53,6 +53,13 @@ void preModelLoad() } pauseMixerCalculations(); +#if defined(HARDWARE_INTERNAL_MODULE) + stopPulsesInternalModule(); +#endif +#if defined(HARDWARE_EXTERNAL_MODULE) + stopPulsesExternalModule(); +#endif + stopTrainer(); } diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp index 06b14f7a7b..2114c78484 100644 --- a/radio/src/switches.cpp +++ b/radio/src/switches.cpp @@ -519,14 +519,28 @@ swsrc_t getMovedSwitch() swsrc_t result = 0; #if defined(PCBFRSKY) - for (int i=0; i> (i*2); - uint8_t next = (1024+getValue(MIXSRC_SA+i)) / 1024; + swarnstate_t mask = ((swarnstate_t) 0x03 << (i * 2)); + uint8_t prev = (switches_states & mask) >> (i * 2); + uint8_t next = (1024 + getValue(MIXSRC_SA + i)) / 1024; if (prev != next) { - switches_states = (switches_states & (~mask)) | ((swarnstate_t)next << (i*2)); - result = 1+(3*i)+next; + switches_states = (switches_states & (~mask)) | ((swarnstate_t) next << (i * 2)); + result = 1 + (3 * i) + next; + } + } + } + // Multipos + for (int i = 0; i < NUM_XPOTS; i++) { + if (IS_POT_MULTIPOS(POT1 + i)) { + StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[POT1 + i]; + if (IS_MULTIPOS_CALIBRATED(calib)) { + uint8_t prev = potsPos[i] & 0x0F; + uint8_t next = anaIn(POT1 + i) / (2 * RESX / calib->count); + if (prev != next) { + result = SWSRC_LAST_SWITCH + i * XPOTS_MULTIPOS_COUNT + next + 1; + } } } } @@ -683,6 +697,9 @@ void checkSwitches() } int x = SWITCH_WARNING_LIST_X; int y = SWITCH_WARNING_LIST_Y; +#if defined(COLORLCD) + lcdNextPos = SWITCH_WARNING_LIST_X; +#endif int numWarnings = 0; for (int i=0; iSQR2 = (ADC_CHANNEL_BATT << 0) + (ADC_Channel_Vbat << 5); ADC_MAIN->SQR3 = (ADC_CHANNEL_STICK_LH << 0) + (ADC_CHANNEL_STICK_LV << 5) + (ADC_CHANNEL_STICK_RV << 10) + (ADC_CHANNEL_STICK_RH << 15) + (ADC_CHANNEL_POT1 << 20) + (ADC_CHANNEL_POT2 << 25); } +#elif defined(RADIO_T8) || defined(RADIO_TLITE) + ADC_MAIN->SQR2 = (ADC_CHANNEL_BATT << 0) + (ADC_Channel_Vbat << 5); + ADC_MAIN->SQR3 = (ADC_CHANNEL_STICK_LH << 0) + (ADC_CHANNEL_STICK_LV << 5) + (ADC_CHANNEL_STICK_RV << 10) + (ADC_CHANNEL_STICK_RH << 15); #elif defined(PCBX7) ADC_MAIN->SQR2 = (ADC_CHANNEL_BATT << 0) + (ADC_Channel_Vbat << 5); ADC_MAIN->SQR3 = (ADC_CHANNEL_STICK_LH << 0) + (ADC_CHANNEL_STICK_LV << 5) + (ADC_CHANNEL_STICK_RV << 10) + (ADC_CHANNEL_STICK_RH << 15) + (ADC_CHANNEL_POT1 << 20) + (ADC_CHANNEL_POT2 << 25); @@ -136,8 +139,8 @@ void adcInit() ADC_MAIN->SQR3 = (ADC_CHANNEL_STICK_LH << 0) + (ADC_CHANNEL_STICK_LV << 5) + (ADC_CHANNEL_STICK_RV << 10) + (ADC_CHANNEL_STICK_RH << 15) + (ADC_CHANNEL_POT1 << 20) + (ADC_CHANNEL_POT2 << 25); #endif - ADC_MAIN->SMPR1 = (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24); - ADC_MAIN->SMPR2 = (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27); + ADC_MAIN->SMPR1 = ADC_MAIN_SMPR1; + ADC_MAIN->SMPR2 = ADC_MAIN_SMPR2; ADC->CCR = ADC_CCR_VBATE; // Enable vbat sensor diff --git a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp index a4d4f4fccc..b1c6816c46 100644 --- a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp @@ -21,10 +21,6 @@ #include "opentx.h" #include "targets/horus/board.h" -#if defined(SBUS) -extern Fifo trainerSbusFifo; -#endif - #if defined(AUX_SERIAL) uint8_t auxSerialMode = UART_MODE_COUNT; // Prevent debug output before port is setup Fifo auxSerialTxFifo; @@ -35,7 +31,7 @@ AuxSerialRxFifo auxSerialRxFifo __DMA (AUX_SERIAL_DMA_Stream_RX); AuxSerialRxFifo auxSerialRxFifo; #endif -void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t lenght = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1) +void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; @@ -58,7 +54,7 @@ void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t lenght = USART_Wor #endif USART_InitStructure.USART_BaudRate = baudrate; - USART_InitStructure.USART_WordLength = lenght; + USART_InitStructure.USART_WordLength = length; USART_InitStructure.USART_StopBits = stop; USART_InitStructure.USART_Parity = parity; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; @@ -150,12 +146,12 @@ void auxSerialInit(unsigned int mode, unsigned int protocol) break; case UART_MODE_SBUS_TRAINER: - auxSerialSetup(SBUS_BAUDRATE, true, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // 2 stop bits requires USART_WordLength_9b + auxSerialSetup(SBUS_BAUDRATE, true, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // USART_WordLength_9b due to parity bit AUX_SERIAL_POWER_ON(); break; case UART_MODE_LUA: - auxSerialSetup(DEBUG_BAUDRATE, false); + auxSerialSetup(LUA_DEFAULT_BAUDRATE, false); AUX_SERIAL_POWER_ON(); } } @@ -250,7 +246,7 @@ uint8_t aux2SerialMode = UART_MODE_COUNT; // Prevent debug output before port i Fifo aux2SerialTxFifo; AuxSerialRxFifo aux2SerialRxFifo __DMA (AUX2_SERIAL_DMA_Stream_RX); -void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t lenght = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1) +void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; @@ -273,7 +269,7 @@ void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t lenght = USART_Wo #endif USART_InitStructure.USART_BaudRate = baudrate; - USART_InitStructure.USART_WordLength = lenght; + USART_InitStructure.USART_WordLength = length; USART_InitStructure.USART_StopBits = stop; USART_InitStructure.USART_Parity = parity; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; @@ -353,7 +349,7 @@ void aux2SerialInit(unsigned int mode, unsigned int protocol) break; case UART_MODE_LUA: - aux2SerialSetup(DEBUG_BAUDRATE, false); + aux2SerialSetup(LUA_DEFAULT_BAUDRATE, false); AUX2_SERIAL_POWER_ON(); } } diff --git a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt index 4896f90c1a..3ebc31c5ff 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt @@ -88,7 +88,7 @@ set(BOOTLOADER_SRC bin_files.cpp ) -if(PCB STREQUAL X12S OR PCB STREQUAL X10 OR PCB STREQUAL X9E OR (PCB STREQUAL X9D+ AND PCBREV STREQUAL 2019) OR (PCB STREQUAL X7 AND NOT (PCBREV STREQUAL T12)) OR PCB STREQUAL X9LITE OR PCB STREQUAL X9LITES) +if(ROTARY_ENCODER) set(BOOTLOADER_SRC ${BOOTLOADER_SRC} ../../../../../targets/common/arm/stm32/rotary_encoder_driver.cpp diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index 2b9c7152c5..c6d7bac5bc 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -218,8 +218,13 @@ int main() } } +#if defined(RADIO_T8) && !defined(RADIOMASTER_RELEASE) + // Bind button not pressed + if ((~KEYS_GPIO_REG_BIND & KEYS_GPIO_PIN_BIND) == false) { +#else // LHR & RHL trims not pressed simultanously if (readTrims() != BOOTLOADER_KEYS) { +#endif // Start main application jumpTo(APP_START_ADDRESS); } diff --git a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp index 25544c33a0..269b408547 100644 --- a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp +++ b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "mixer_scheduler.h" #if defined(INTMODULE_HEARTBEAT_GPIO) volatile HeartbeatCapture heartbeatCapture; @@ -77,6 +78,8 @@ void check_intmodule_heartbeat() heartbeatCapture.count++; #endif EXTI_ClearITPendingBit(INTMODULE_HEARTBEAT_EXTI_LINE); + + mixerSchedulerISRTrigger(); } } #endif diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp index 56b71d97cd..794c497656 100755 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp @@ -45,12 +45,6 @@ void intmoduleStop() USART_DeInit(INTMODULE_USART); GPIO_ResetBits(INTMODULE_GPIO, INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN); - -#if defined(INTERNAL_MODULE_MULTI) - // stop pulses timer - INTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; - INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; -#endif } void intmodulePxx1SerialStart() @@ -103,28 +97,6 @@ void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable, uint16_t parity, } } -#if defined(INTERNAL_MODULE_MULTI) -void intmoduleTimerStart(uint32_t periodMs) -{ - // Timer - INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; - INTMODULE_TIMER->PSC = INTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz) - INTMODULE_TIMER->ARR = periodMs * 2000; - INTMODULE_TIMER->CCR2 = (periodMs - 1) * 2000; - INTMODULE_TIMER->CCER = TIM_CCER_CC3E; - INTMODULE_TIMER->CCMR2 = 0; - INTMODULE_TIMER->EGR = 1; // Restart - - INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0; // Toggle CC1 o/p - INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt - INTMODULE_TIMER->CR1 |= TIM_CR1_CEN; - - NVIC_EnableIRQ(INTMODULE_TIMER_IRQn); - NVIC_SetPriority(INTMODULE_TIMER_IRQn, 7); -} -#endif - #define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) extern "C" void INTMODULE_USART_IRQHandler(void) { @@ -217,12 +189,3 @@ void intmoduleSendNextFrame() #endif } } - -#if defined(INTERNAL_MODULE_MULTI) -extern "C" void INTMODULE_TIMER_IRQHandler() -{ - INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // clear flag - setupPulsesInternalModule(); - intmoduleSendNextFrame(); -} -#endif diff --git a/radio/src/targets/common/arm/stm32/mixer_scheduler_driver.cpp b/radio/src/targets/common/arm/stm32/mixer_scheduler_driver.cpp new file mode 100644 index 0000000000..7f7b23a1c4 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/mixer_scheduler_driver.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "opentx.h" +#include "mixer_scheduler.h" + +#if !defined(SIMU) + +// Start scheduler with default period +void mixerSchedulerStart() +{ + MIXER_SCHEDULER_TIMER->CR1 &= ~TIM_CR1_CEN; + + MIXER_SCHEDULER_TIMER->CR1 = TIM_CR1_URS; // do not generate interrupt on soft update + MIXER_SCHEDULER_TIMER->PSC = MIXER_SCHEDULER_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz) + MIXER_SCHEDULER_TIMER->CCER = 0; + MIXER_SCHEDULER_TIMER->CCMR1 = 0; + MIXER_SCHEDULER_TIMER->ARR = 2 * getMixerSchedulerPeriod() - 1; + MIXER_SCHEDULER_TIMER->EGR = TIM_EGR_UG; // reset timer + + NVIC_EnableIRQ(MIXER_SCHEDULER_TIMER_IRQn); + NVIC_SetPriority(MIXER_SCHEDULER_TIMER_IRQn, 8); + + MIXER_SCHEDULER_TIMER->SR &= TIM_SR_UIF; // clear interrupt flag + MIXER_SCHEDULER_TIMER->DIER |= TIM_DIER_UIE; // enable interrupt + MIXER_SCHEDULER_TIMER->CR1 |= TIM_CR1_CEN; +} + +void mixerSchedulerStop() +{ + MIXER_SCHEDULER_TIMER->CR1 &= ~TIM_CR1_CEN; + NVIC_DisableIRQ(MIXER_SCHEDULER_TIMER_IRQn); +} + +void mixerSchedulerResetTimer() +{ + mixerSchedulerDisableTrigger(); + MIXER_SCHEDULER_TIMER->CNT = 0; + mixerSchedulerEnableTrigger(); +} + +void mixerSchedulerEnableTrigger() +{ + MIXER_SCHEDULER_TIMER->DIER |= TIM_DIER_UIE; // enable interrupt +} + +void mixerSchedulerDisableTrigger() +{ + MIXER_SCHEDULER_TIMER->DIER &= ~TIM_DIER_UIE; // disable interrupt +} + +extern "C" void MIXER_SCHEDULER_TIMER_IRQHandler(void) +{ + MIXER_SCHEDULER_TIMER->SR &= ~TIM_SR_UIF; // clear flag + mixerSchedulerDisableTrigger(); + + // set next period + MIXER_SCHEDULER_TIMER->ARR = 2 * getMixerSchedulerPeriod() - 1; + + // trigger mixer start + mixerSchedulerISRTrigger(); +} + +#endif diff --git a/radio/src/targets/common/arm/stm32/pwr_driver.cpp b/radio/src/targets/common/arm/stm32/pwr_driver.cpp index 220b5fdfd0..32ff591957 100644 --- a/radio/src/targets/common/arm/stm32/pwr_driver.cpp +++ b/radio/src/targets/common/arm/stm32/pwr_driver.cpp @@ -80,7 +80,7 @@ void pwrInit() GPIO_Init(SD_PRESENT_GPIO, &GPIO_InitStructure); #endif -#if defined(INTMODULE_USART) && defined(TRAINER_MODULE_CPPM_GPIO_PIN) +#if defined(INTMODULE_USART) && defined(TRAINER_MODULE_CPPM) GPIO_SetBits(TRAINER_MODULE_CPPM_GPIO, TRAINER_MODULE_CPPM_GPIO_PIN); GPIO_InitStructure.GPIO_Pin = TRAINER_MODULE_CPPM_GPIO_PIN; GPIO_Init(TRAINER_MODULE_CPPM_GPIO, &GPIO_InitStructure); diff --git a/radio/src/targets/common/arm/stm32/sdio_sd.c b/radio/src/targets/common/arm/stm32/sdio_sd.c index f02916b441..f0f97b97fb 100644 --- a/radio/src/targets/common/arm/stm32/sdio_sd.c +++ b/radio/src/targets/common/arm/stm32/sdio_sd.c @@ -1107,7 +1107,9 @@ OPTIMIZE("O0") SD_Error SD_WaitReadOperation(uint32_t timeout) delay_ms(1); timeout--; } +#if !defined(BOOT) TRACE_SD_CARD_EVENT((timeout == 0), sd_wait_read, (TransferError << 8) + (DMAEndOfTransfer << 1) + TransferEnd); +#endif DMAEndOfTransfer = 0; @@ -1117,7 +1119,9 @@ OPTIMIZE("O0") SD_Error SD_WaitReadOperation(uint32_t timeout) delay_ms(1); timeout--; } +#if !defined(BOOT) TRACE_SD_CARD_EVENT((timeout == 0), sd_wait_read, -1); +#endif if (StopCondition == 1) { errorstatus = SD_StopTransfer(); @@ -1332,8 +1336,10 @@ OPTIMIZE("O0") SD_Error SD_WaitWriteOperation(uint32_t timeout) delay_ms(1); timeout--; } +#if !defined(BOOT) TRACE_SD_CARD_EVENT((timeout == 0), sd_wait_write, (TransferError << 8) + (DMAEndOfTransfer << 1) + TransferEnd); - +#endif + DMAEndOfTransfer = 0; timeout = 100; @@ -1342,7 +1348,9 @@ OPTIMIZE("O0") SD_Error SD_WaitWriteOperation(uint32_t timeout) delay_ms(1); timeout--; } +#if !defined(BOOT) TRACE_SD_CARD_EVENT((timeout == 0), sd_wait_write, -1); +#endif if (StopCondition == 1) { errorstatus = SD_StopTransfer(); @@ -1474,7 +1482,9 @@ OPTIMIZE("O0") void SD_ProcessIRQ(void) SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, DISABLE); +#if !defined(BOOT) TRACE_SD_CARD_EVENT((TransferError != SD_OK), sd_irq, TransferError); +#endif } /** diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 2fe767e568..44f8bc27c2 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -22,6 +22,8 @@ set(LINKER_SCRIPT targets/horus/stm32f4_flash.ld) set(RTC_BACKUP_RAM YES) set(PPM_LIMITS_SYMETRICAL YES) set(USB_SERIAL ON CACHE BOOL "Enable USB serial (CDC)") +set(ROTARY_ENCODER YES) +set(EXTERNAL_MODULE YES) if(BOOTLOADER) set(LINKER_SCRIPT targets/horus/stm32f4_flash_bootloader.ld) @@ -214,6 +216,8 @@ set(TARGET_SRC led_driver.cpp extmodule_driver.cpp trainer_driver.cpp + ../common/arm/stm32/mixer_scheduler_driver.cpp + ../common/arm/stm32/heartbeat_driver.cpp ../common/arm/stm32/timers_driver.cpp ../common/arm/stm32/intmodule_serial_driver.cpp ../common/arm/stm32/rotary_encoder_driver.cpp diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index fb9da0d168..c6f31158aa 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -137,6 +137,7 @@ void boardInit() INTMODULE_RCC_APB1Periph | EXTMODULE_RCC_APB1Periph | I2C_RCC_APB1Periph | + MIXER_SCHEDULER_TIMER_RCC_APB1Periph | GPS_RCC_APB1Periph | BACKLIGHT_RCC_APB1Periph, ENABLE); diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index 05e4d44505..b248791a1b 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -175,14 +175,11 @@ void init_intmodule_heartbeat(); void check_intmodule_heartbeat(); void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable, uint16_t parity, uint16_t stopBits, uint16_t wordLength); -#if defined(INTERNAL_MODULE_MULTI) -void intmoduleTimerStart(uint32_t periodMs); -#endif void intmoduleSendByte(uint8_t byte); void intmoduleSendBuffer(const uint8_t * data, uint8_t size); void intmoduleSendNextFrame(); -void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inverted); +void extmoduleSerialStart(); void extmoduleInvertedSerialStart(uint32_t baudrate); void extmoduleSendBuffer(const uint8_t * data, uint8_t size); void extmoduleSendNextFrame(); @@ -376,7 +373,7 @@ enum Analogs { SLIDER_LAST = SLIDER_FIRST + NUM_SLIDERS - 1, TX_VOLTAGE, #if defined(PCBX12S) - MOUSE1, // TODO why after voltage? + MOUSE1, // after voltage because previous ones come from SPI on X12S MOUSE2, #endif NUM_ANALOGS @@ -639,11 +636,16 @@ void sportUpdatePowerInit(); // Aux serial port driver #if defined(RADIO_TX16S) #define DEBUG_BAUDRATE 400000 + #define LUA_DEFAULT_BAUDRATE 115200 #else #define DEBUG_BAUDRATE 115200 + #define LUA_DEFAULT_BAUDRATE 115200 #endif #if defined(AUX_SERIAL_GPIO) extern uint8_t auxSerialMode; +#if defined __cplusplus +void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t length = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1); +#endif void auxSerialInit(unsigned int mode, unsigned int protocol); void auxSerialPutc(char c); #define auxSerialTelemetryInit(protocol) auxSerialInit(UART_MODE_TELEMETRY, protocol) @@ -663,6 +665,9 @@ void auxSerialPowerOff(); // Aux2 serial port driver #if defined(AUX2_SERIAL) extern uint8_t aux2SerialMode; +#if defined __cplusplus +void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t length = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1); +#endif void aux2SerialInit(unsigned int mode, unsigned int protocol); void aux2SerialPutc(char c); #define aux2SerialTelemetryInit(protocol) aux2SerialInit(UART_MODE_TELEMETRY, protocol) diff --git a/radio/src/targets/horus/extmodule_driver.cpp b/radio/src/targets/horus/extmodule_driver.cpp index 47a40ae02a..e73d5c3d3b 100644 --- a/radio/src/targets/horus/extmodule_driver.cpp +++ b/radio/src/targets/horus/extmodule_driver.cpp @@ -143,7 +143,7 @@ void extmodulePxx1PulsesStart() } #endif -void extmoduleSerialStart(uint32_t /*baudrate*/, uint32_t period_half_us, bool inverted) +void extmoduleSerialStart() { EXTERNAL_MODULE_ON(); @@ -176,10 +176,9 @@ void extmoduleSerialStart(uint32_t /*baudrate*/, uint32_t period_half_us, bool i EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0; #endif - EXTMODULE_TIMER->ARR = period_half_us; - EXTMODULE_TIMER->CCR2 = period_half_us - 4000; + EXTMODULE_TIMER->ARR = 40000; // dummy value until the DMA request kicks in EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - EXTMODULE_TIMER->DIER |= TIM_DIER_UDE | TIM_DIER_CC2IE; + EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; NVIC_EnableIRQ(EXTMODULE_TIMER_DMA_STREAM_IRQn); @@ -342,23 +341,36 @@ void extmoduleSendNextFrame() #if defined(DSM2) case PROTOCOL_CHANNELS_SBUS: -#if defined(PCBX10) || PCBREV >= 13 - EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0); // reverse polarity for Sbus if needed -#else - EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0); // reverse polarity for Sbus if needed -#endif - // no break case PROTOCOL_CHANNELS_DSM2_LP45: case PROTOCOL_CHANNELS_DSM2_DSM2: case PROTOCOL_CHANNELS_DSM2_DSMX: case PROTOCOL_CHANNELS_MULTIMODULE: - EXTMODULE_TIMER->CCR2 = *(extmodulePulsesData.dsm2.ptr - 1) - 4000; // 2mS in advance + + if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) + return; + + if (PROTOCOL_CHANNELS_SBUS == moduleState[EXTERNAL_MODULE].protocol) { +#if defined(PCBX10) || PCBREV >= 13 + EXTMODULE_TIMER->CCER = TIM_CCER_CC3E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC3P : 0); // reverse polarity for Sbus if needed +#else + EXTMODULE_TIMER->CCER = TIM_CCER_CC1E | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? TIM_CCER_CC1P : 0); // reverse polarity for Sbus if needed +#endif + } + + // disable timer + EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; + + // send DMA request EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | EXTMODULE_TIMER_DMA_SIZE | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(extmodulePulsesData.dsm2.pulses); EXTMODULE_TIMER_DMA_STREAM->NDTR = extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses; EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA + + // re-init timer + EXTMODULE_TIMER->EGR = 1; + EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; break; #endif @@ -419,14 +431,20 @@ extern "C" void EXTMODULE_TIMER_DMA_IRQHandler() DMA_ClearITPendingBit(EXTMODULE_TIMER_DMA_STREAM, EXTMODULE_TIMER_DMA_FLAG_TC); - EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt + switch (moduleState[EXTERNAL_MODULE].protocol) { + case PROTOCOL_CHANNELS_PXX1_PULSES: + case PROTOCOL_CHANNELS_PPM: + EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag + EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt + break; + } } extern "C" void EXTMODULE_TIMER_IRQHandler() { EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; + if (setupPulsesExternalModule()) extmoduleSendNextFrame(); } diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 415b88199d..1f8c2f7723 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -331,6 +331,9 @@ #endif #endif +#define ADC_MAIN_SMPR1 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24); +#define ADC_MAIN_SMPR2 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27); + // Power #if defined(RADIO_T18) #define PWR_RCC_AHB1Periph RCC_AHB1Periph_GPIOJ | RCC_AHB1Periph_GPIOB @@ -419,9 +422,9 @@ #define AUX_SERIAL_USART_IRQn USART3_IRQn #define AUX_SERIAL_DMA_Stream_RX DMA1_Stream1 #define AUX_SERIAL_DMA_Channel_RX DMA_Channel_4 - #define AUX_SERIAL_PWR_GPIO GPIOA - #define AUX_SERIAL_PWR_GPIO_PIN GPIO_Pin_15 // PB.00 #if defined(RADIO_TX16S) + #define AUX_SERIAL_PWR_GPIO GPIOA + #define AUX_SERIAL_PWR_GPIO_PIN GPIO_Pin_15 // PA.15 #define TRAINER_BATTERY_COMPARTMENT // allows serial port TTL trainer #endif #else @@ -908,6 +911,13 @@ #define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7 #define TIMER_2MHz_TIMER TIM7 +// Mixer scheduler timer +#define MIXER_SCHEDULER_TIMER_RCC_APB1Periph RCC_APB1Periph_TIM13 +#define MIXER_SCHEDULER_TIMER TIM13 +#define MIXER_SCHEDULER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) +#define MIXER_SCHEDULER_TIMER_IRQn TIM8_UP_TIM13_IRQn +#define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_UP_TIM13_IRQHandler + // Bluetooth #define STORAGE_BLUETOOTH #if defined(BLUETOOTH) diff --git a/radio/src/targets/horus/lcd_driver.cpp b/radio/src/targets/horus/lcd_driver.cpp index f7ca6d1d83..cc4f238185 100644 --- a/radio/src/targets/horus/lcd_driver.cpp +++ b/radio/src/targets/horus/lcd_driver.cpp @@ -151,28 +151,19 @@ static void LCD_NRSTConfig(void) GPIO_Init(LCD_GPIO_NRST, &GPIO_InitStructure); } -static void delay3(uint32_t nCount) -{ - uint32_t index = 0; - for(index = (1000 * 100 * nCount); index != 0; --index) - { - __asm("nop\n"); - } -} - -static void lcdReset() +static void lcd_reset(void) { #if defined(RADIO_T18) // T18 screen has issues if NRST is ever brought low NRST_HIGH(); #else LCD_NRST_HIGH(); - delay3(1); + delay_ms(1); LCD_NRST_LOW(); // RESET(); - delay3(20); + delay_ms(20); LCD_NRST_HIGH(); - delay3(30); + delay_ms(30); #endif } diff --git a/radio/src/targets/horus/startup_stm32f42_43xxx.s b/radio/src/targets/horus/startup_stm32f42_43xxx.s index 68671dc34c..3273244814 100644 --- a/radio/src/targets/horus/startup_stm32f42_43xxx.s +++ b/radio/src/targets/horus/startup_stm32f42_43xxx.s @@ -1,16 +1,16 @@ /** ****************************************************************************** - * @file startup_stm32f40_41xxx.s + * @file startup_stm32f42_43xx.s * @author MCD Application Team * @version V1.3.0 * @date 08-November-2013 - * @brief STM32F40xxx/41xxx Devices vector table for RIDE7 toolchain. + * @brief STM32F42xxx/43xxx Devices vector table for RIDE7 toolchain. * This module performs: * - Set the initial SP * - Set the initial PC == Reset_Handler, * - Set the vector table entries with the exceptions ISR address * - Configure the clock system and the external SRAM mounted on - * STM324xG-EVAL board to be used as data memory (optional, + * STM32F4xG-EVAL board to be used as data memory (optional, * to be enabled by user) * - Branches to main in the C library (which eventually * calls main()). @@ -37,7 +37,7 @@ */ .syntax unified - .cpu cortex-m3 + .cpu cortex-m4 .fpu softvfp .thumb @@ -69,9 +69,9 @@ defined in linker script */ .section .text.Reset_Handler .weak Reset_Handler .type Reset_Handler, %function -Reset_Handler: - - bl pwrResetHandler /*jump to WDT reset handler where soft power control pin is turned on as soon as possible */ +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + bl pwrResetHandler /* jump to WDT reset handler where soft power control pin is turned on as soon as possible */ /* Copy the data segment initializers from flash to SRAM */ movs r1, #0 @@ -113,8 +113,8 @@ LoopPaintMainStack: /* Call the clock system intitialization function.*/ bl SystemInit -/* Call C++ constructors for static objects */ - bl __libc_init_array +/* Call static constructors */ + bl __libc_init_array /* Call the application's entry point.*/ bl main bx lr diff --git a/radio/src/targets/horus/telemetry_driver.cpp b/radio/src/targets/horus/telemetry_driver.cpp index 0288363be6..165e65933f 100644 --- a/radio/src/targets/horus/telemetry_driver.cpp +++ b/radio/src/targets/horus/telemetry_driver.cpp @@ -34,6 +34,7 @@ static void telemetryInitDirPin() GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN; GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure); GPIO_ResetBits(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); diff --git a/radio/src/targets/horus/trainer_driver.cpp b/radio/src/targets/horus/trainer_driver.cpp index ce649c6881..38d25cb457 100644 --- a/radio/src/targets/horus/trainer_driver.cpp +++ b/radio/src/targets/horus/trainer_driver.cpp @@ -20,10 +20,6 @@ #include "opentx.h" -#if defined(SBUS_TRAINER) -Fifo trainerSbusFifo; -#endif - void trainerSendNextFrame(); void init_trainer_ppm() @@ -174,4 +170,4 @@ int sbusGetByte(uint8_t * byte) default: return false; } -} \ No newline at end of file +} diff --git a/radio/src/targets/simu/opentxsimulator.cpp b/radio/src/targets/simu/opentxsimulator.cpp index d501cc2492..0019622644 100644 --- a/radio/src/targets/simu/opentxsimulator.cpp +++ b/radio/src/targets/simu/opentxsimulator.cpp @@ -213,17 +213,7 @@ void OpenTxSimulator::setTrim(unsigned int idx, int value) if (i < 4) // swap axes i = modn12x3[4 * getStickMode() + idx]; uint8_t phase = getTrimFlightMode(getFlightMode(), i); - - if (!setTrimValue(phase, i, value)) { - QTimer *timer = new QTimer(this); - timer->setSingleShot(true); - connect(timer, &QTimer::timeout, [=]() { - emit trimValueChange(idx, 0); - emit outputValueChange(OUTPUT_SRC_TRIM_VALUE, idx, 0); - timer->deleteLater(); - }); - timer->start(350); - } + setTrimValue(phase, i, value); } void OpenTxSimulator::setTrainerInput(unsigned int inputNumber, int16_t value) diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index eacf06bd72..61f5699cb1 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -845,6 +845,12 @@ void rtcSetTime(const struct gtm * t) { } +#if defined(USB_SERIAL) +void usbSerialPutc(uint8_t c) +{ +} +#endif + #if defined(AUX_SERIAL) #if defined(AUX_SERIAL_DMA_Stream_RX) AuxSerialRxFifo auxSerialRxFifo(nullptr); @@ -852,6 +858,11 @@ AuxSerialRxFifo auxSerialRxFifo(nullptr); AuxSerialRxFifo auxSerialRxFifo; #endif uint8_t auxSerialMode; + +void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop) +{ +} + void auxSerialInit(unsigned int mode, unsigned int protocol) { } @@ -872,6 +883,11 @@ void auxSerialStop() #if defined(AUX2_SERIAL) AuxSerialRxFifo aux2SerialRxFifo(nullptr); uint8_t aux2SerialMode; + +void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop) +{ +} + void aux2SerialInit(unsigned int mode, unsigned int protocol) { } diff --git a/radio/src/targets/sky9x/CMakeLists.txt b/radio/src/targets/sky9x/CMakeLists.txt index cad5226a5f..04185fd037 100644 --- a/radio/src/targets/sky9x/CMakeLists.txt +++ b/radio/src/targets/sky9x/CMakeLists.txt @@ -15,6 +15,7 @@ set(PPM_LIMITS_SYMETRICAL YES) set(PXX1 YES) set(AFHDS3 NO) set(GHOST NO) +add_definitions(-DHARDWARE_EXTERNAL_MODULE) add_definitions(-DDISABLE_MULTI_UPDATE) if(PCB STREQUAL 9XRPRO) diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index f63f9ef115..2b561b8611 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -6,6 +6,9 @@ option(AFHDS3 "AFHDS3 TX Module" ON) option(GHOST "Ghost TX Module" ON) option(INTERNAL_MODULE_PPM "Support for PPM internal module" OFF) option(AUTOUPDATE "Auto update internal chips from SD" OFF) +option(BIND_KEY "Enable bind button" OFF) + +set(EXTERNAL_MODULE YES) add_definitions(-DPCBFRSKY) @@ -64,6 +67,7 @@ elseif(PCB STREQUAL X9D+) option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF) option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON) set(FLAVOUR x9d+2019) + set(LUA_EXPORT lua_export_x9d+2019) set(CPU_TYPE STM32F4) set(CPU_TYPE_FULL STM32F407xE) # for size report set(LINKER_SCRIPT targets/taranis/stm32f4_flash.ld) @@ -134,7 +138,21 @@ elseif(PCB STREQUAL X7) set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld) set(LUA_EXPORT lua_export_t12) add_definitions(-DRADIO_T12) + add_definitions(-DRADIO_FAMILY_JUMPER_T12) add_definitions(-DEEPROM_VARIANT=0x4001) + add_definitions(-DMANUFACTURER_JUMPER) + elseif(PCBREV STREQUAL TLITE) + option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" ON) + set(FLAVOUR tlite) + set(NAVIGATION_TYPE 9x) + set(CPU_TYPE STM32F2) + set(CPU_TYPE_FULL STM32F205xE) # for size report + set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld) + set(LUA_EXPORT lua_export_tlite) + add_definitions(-DRADIO_TLITE) + add_definitions(-DRADIO_FAMILY_JUMPER_T12) + add_definitions(-DEEPROM_VARIANT=0x4003) + add_definitions(-DMANUFACTURER_JUMPER) elseif(PCBREV STREQUAL TX12) option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" ON) set(FLAVOUR tx12) @@ -149,6 +167,24 @@ elseif(PCB STREQUAL X7) add_definitions(-DRADIO_TX12) add_definitions(-DEEPROM_VARIANT=0x4002) add_definitions(-DMANUFACTURER_RADIOMASTER) + elseif(PCBREV STREQUAL T8) + option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" ON) + set(EXTERNAL_MODULE NO) + set(AFHDS3 NO) + set(FLAVOUR t8) + set(NAVIGATION_TYPE x7) + set(CPU_TYPE STM32F2) + set(CPU_TYPE_FULL STM32F205xE) # for size report + set(LINKER_SCRIPT targets/taranis/stm32f2_flash.ld) + set(ROTARY_ENCODER NO) + set(LUA_EXPORT lua_export_t8) + set(BLUETOOTH NO) + if(RADIOMASTER_RELEASE) + set(BIND_KEY YES) + endif() + add_definitions(-DRADIO_T8) + add_definitions(-DEEPROM_VARIANT=0x4004) + add_definitions(-DMANUFACTURER_RADIOMASTER) elseif(PCBREV STREQUAL ACCESS) option(INTERNAL_MODULE_PXX1 "Support for PXX1 internal module" OFF) option(INTERNAL_MODULE_PXX2 "Support for PXX2 internal module" ON) @@ -347,6 +383,14 @@ if(ROTARY_ENCODER) ) endif() +if(BIND_KEY) + set(TARGET_SRC + ${TARGET_SRC} + bind_button_driver.cpp + ) + add_definitions(-DBIND_KEY) +endif() + if(USB_CHARGER) set(TARGET_SRC ${TARGET_SRC} usb_charger_driver.cpp) add_definitions(-DUSB_CHARGER) @@ -428,6 +472,8 @@ set(TARGET_SRC set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} ../common/arm/stm32/adc_driver.cpp + ../common/arm/stm32/heartbeat_driver.cpp + ../common/arm/stm32/mixer_scheduler_driver.cpp ) if(PCB STREQUAL XLITE OR PCB STREQUAL XLITES) @@ -476,4 +522,8 @@ if(INTERNAL_MODULE_PPM) add_definitions(-DINTERNAL_MODULE_PPM) endif() +if(EXTERNAL_MODULE) + add_definitions(-DHARDWARE_EXTERNAL_MODULE) +endif() + set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} ${BITMAPS_TARGET}) diff --git a/radio/src/targets/taranis/backlight_driver.cpp b/radio/src/targets/taranis/backlight_driver.cpp index 63a5bfd1ab..7c758f818b 100644 --- a/radio/src/targets/taranis/backlight_driver.cpp +++ b/radio/src/targets/taranis/backlight_driver.cpp @@ -20,7 +20,13 @@ #include "opentx.h" -#if defined(PCBX9E) +#if !defined(BACKLIGHT_GPIO) + // no backlight + void backlightInit() {} + void backlightEnable(uint8_t level) {} + void backlightDisable() {} + uint8_t isBacklightEnabled() {return false;} +#elif defined(PCBX9E) void backlightInit() { GPIO_InitTypeDef GPIO_InitStructure; diff --git a/radio/src/targets/taranis/bind_button_driver.cpp b/radio/src/targets/taranis/bind_button_driver.cpp new file mode 100644 index 0000000000..2d3ca63fc8 --- /dev/null +++ b/radio/src/targets/taranis/bind_button_driver.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "opentx.h" + + +bool setBindProtocolSelection() +{ + int16_t xPos = calibratedAnalogs[CONVERT_MODE(0)]; + int16_t yPos = calibratedAnalogs[CONVERT_MODE(1)]; + + // Center: D8 + if (abs(xPos < 50 && abs(yPos) < 50)) { + g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY); + g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D8; + storageDirty(EE_MODEL); + return true; + } + + // Top left: D16 FCC + if (xPos < -512 && yPos > 512) { + g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY); + g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D16; + g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES; + storageDirty(EE_MODEL); + return true; + } + + // Top right: D16 LBT + if (xPos > 512 && yPos > 512) { + g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKY); + g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKY_SUBTYPE_D16_LBT; + g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES; + storageDirty(EE_MODEL); + return true; + } + + // Bottom left: V2.1 D16 FCC + if (xPos < -512 && yPos < -512) { + g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKYX2); + g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKYX2_SUBTYPE_D16; + g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES; + storageDirty(EE_MODEL); + return true; + } + + // Bottom right: V2.1 D16 LBT + if (xPos > 512 && yPos < -512) { + g_model.moduleData[INTERNAL_MODULE].setMultiProtocol(MODULE_SUBTYPE_MULTI_FRSKYX2); + g_model.moduleData[INTERNAL_MODULE].subType = MM_RF_FRSKYX2_SUBTYPE_D16_LBT; + g_model.moduleData[INTERNAL_MODULE].failsafeMode = FAILSAFE_NOPULSES; + storageDirty(EE_MODEL); + return true; + } + + return false; +} + +void bindButtonHandler(event_t event) +{ + if( !isModuleMultimodule(INTERNAL_MODULE)) + return; + + if (event == EVT_KEY_LONG(KEY_BIND) && getMultiBindStatus(INTERNAL_MODULE) == MULTI_NORMAL_OPERATION) { + if (setBindProtocolSelection()) { + setMultiBindStatus(INTERNAL_MODULE, MULTI_BIND_INITIATED); + moduleState[INTERNAL_MODULE].mode = MODULE_MODE_BIND; + } + } + + if (getMultiBindStatus(INTERNAL_MODULE) == MULTI_BIND_INITIATED) { + if (FAST_BLINK_ON_PHASE) + LED_BIND(); + else + ledOff(); + } + + if (getMultiBindStatus(INTERNAL_MODULE) == MULTI_BIND_FINISHED) { + setMultiBindStatus(INTERNAL_MODULE, MULTI_NORMAL_OPERATION); + moduleState[INTERNAL_MODULE].mode = MODULE_MODE_NORMAL; + LED_ERROR_END(); + } +} diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index d86a82f2d1..69e36d5e88 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -111,6 +111,7 @@ void boardInit() AUX_SERIAL_RCC_APB1Periph | INTMODULE_RCC_APB1Periph | TRAINER_MODULE_RCC_APB1Periph | + MIXER_SCHEDULER_TIMER_RCC_APB1Periph | BT_RCC_APB1Periph | GYRO_RCC_APB1Periph, ENABLE); @@ -272,6 +273,8 @@ void boardOff() #if defined (RADIO_TX12) #define BATTERY_DIVIDER 22830 +#elif defined (RADIO_T8) + #define BATTERY_DIVIDER 50000 #else #define BATTERY_DIVIDER 26214 #endif @@ -344,4 +347,4 @@ void initJackDetect(void) GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(JACK_DETECT_GPIO, &GPIO_InitStructure); } -#endif \ No newline at end of file +#endif diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 6ffff9df9a..8e583be737 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -27,8 +27,8 @@ #include "board_common.h" #include "hal.h" -#if defined(RADIO_TX12) - #define NAVIGATION_X7_TX12 +#if defined(RADIO_TX12) || defined(RADIO_TX12) + #define NAVIGATION_X7_TX12 #endif #if defined(ROTARY_ENCODER_NAVIGATION) @@ -117,7 +117,7 @@ uint32_t isBootloaderStart(const uint8_t * buffer); #define INTERNAL_MODULE_OFF() GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN) #endif -#if !defined(PCBX9LITE) || defined(PCBX9LITES) +#if (defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)) && (!defined(PCBX9LITE) || defined(PCBX9LITES)) #define HARDWARE_INTERNAL_RAS #endif @@ -143,7 +143,7 @@ void intmoduleSendByte(uint8_t byte); void intmoduleSendBuffer(const uint8_t * data, uint8_t size); void intmoduleSendNextFrame(); -void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inverted); +void extmoduleSerialStart(); void extmoduleInvertedSerialStart(uint32_t baudrate); void extmoduleSendBuffer(const uint8_t * data, uint8_t size); void extmoduleSendNextFrame(); @@ -152,7 +152,7 @@ void extmoduleSendInvertedByte(uint8_t byte); // Trainer driver #define SLAVE_MODE() (g_model.trainerData.mode == TRAINER_MODE_SLAVE) -#if defined(PCBX9D) || (defined(PCBX9DP) && PCBREV < 2019) +#if defined(TRAINER_DETECT_GPIO) // Trainer detect is a switch on the jack #define TRAINER_CONNECTED() (GPIO_ReadInputDataBit(TRAINER_DETECT_GPIO, TRAINER_DETECT_GPIO_PIN) == Bit_RESET) #elif defined(PCBXLITES) @@ -270,6 +270,10 @@ enum EnumKeys KEY_COUNT, KEY_MAX = KEY_COUNT - 1, +#if defined(KEYS_GPIO_REG_BIND) + KEY_BIND, +#endif + #if defined(ROTARY_ENCODER_NAVIGATION) KEY_PLUS, KEY_MINUS, @@ -355,7 +359,7 @@ enum EnumSwitchesPositions SW_SE1, SW_SE2, #endif -#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBX7) || defined(PCBXLITES) || defined(PCBX9LITES) +#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || defined(PCBX7) || defined(PCBXLITES) || defined(PCBX9LITES) || defined(RADIO_T8) SW_SF0, SW_SF1, SW_SF2, @@ -365,7 +369,7 @@ enum EnumSwitchesPositions SW_SG1, SW_SG2, #endif -#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || (defined(PCBX7) && !defined(RADIO_TX12)) +#if defined(PCBX9D) || defined(PCBX9DP) || defined(PCBX9E) || (defined(PCBX7) && !defined(RADIO_TX12)) || defined(RADIO_T8) SW_SH0, SW_SH1, SW_SH2, @@ -432,7 +436,12 @@ enum EnumSwitchesPositions #define STORAGE_NUM_SWITCHES 6 #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 2) + (POT_WITHOUT_DETENT << 0) -#elif defined(RADIO_T12) +#elif defined(RADIO_TLITE) + #define NUM_SWITCHES 4 + #define STORAGE_NUM_SWITCHES 8 + #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_2POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0); + #define DEFAULT_POTS_CONFIG (0) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define NUM_SWITCHES 8 #define STORAGE_NUM_SWITCHES NUM_SWITCHES #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 10) + (SWITCH_2POS << 8) + (SWITCH_3POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_3POS << 0) @@ -442,6 +451,11 @@ enum EnumSwitchesPositions #define STORAGE_NUM_SWITCHES NUM_SWITCHES #define DEFAULT_SWITCH_CONFIG (SWITCH_3POS << 10) + (SWITCH_3POS << 8) + (SWITCH_TOGGLE << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_TOGGLE << 0) #define DEFAULT_POTS_CONFIG (POT_WITH_DETENT << 0) + (POT_WITH_DETENT << 2); +#elif defined(RADIO_T8) + #define NUM_SWITCHES 4 + #define STORAGE_NUM_SWITCHES 8 + #define DEFAULT_SWITCH_CONFIG (SWITCH_2POS << 6) + (SWITCH_3POS << 4) + (SWITCH_3POS << 2) + (SWITCH_2POS << 0); + #define DEFAULT_POTS_CONFIG (0) #elif defined(PCBX7ACCESS) #define NUM_SWITCHES 7 #define STORAGE_NUM_SWITCHES 8 @@ -544,6 +558,11 @@ enum Analogs { #define NUM_SLIDERS 0 #define STORAGE_NUM_POTS 1 #define STORAGE_NUM_SLIDERS 0 +#elif defined(RADIO_T8) || defined(RADIO_TLITE) + #define NUM_POTS 0 + #define NUM_SLIDERS 0 + #define STORAGE_NUM_POTS 2 + #define STORAGE_NUM_SLIDERS 0 #elif defined(PCBXLITE) || defined(PCBX7) #define NUM_POTS 2 #define NUM_SLIDERS 0 @@ -644,6 +663,11 @@ extern uint16_t adcValues[NUM_ANALOGS]; #define BATTERY_WARN 66 // 6.6V #define BATTERY_MIN 67 // 6.7V #define BATTERY_MAX 83 // 8.3V +#elif defined(RADIO_T8) || defined(RADIO_TLITE) + // 1S Li-ion / Lipo, LDO for 3.3V + #define BATTERY_WARN 35 // 3.5V + #define BATTERY_MIN 34 // 3.4V + #define BATTERY_MAX 42 // 4.2V #else // NI-MH 7.2V #define BATTERY_WARN 65 // 6.5V @@ -710,6 +734,14 @@ uint8_t isBacklightEnabled(); #define USB_NAME "Radiomaster TX12" #define USB_MANUFACTURER 'R', 'M', '_', 'T', 'X', ' ', ' ', ' ' /* 8 bytes */ #define USB_PRODUCT 'R', 'M', ' ', 'T', 'X', '1', '2', ' ' /* 8 Bytes */ +#elif defined(RADIO_T8) + #define USB_NAME "Radiomaster T8" + #define USB_MANUFACTURER 'R', 'M', '_', 'T', 'X', ' ', ' ', ' ' /* 8 bytes */ + #define USB_PRODUCT 'R', 'M', ' ', 'T', '8', ' ', ' ', ' ' /* 8 Bytes */ +#elif defined(RADIO_TLITE) + #define USB_NAME "Jumper TLite" + #define USB_MANUFACTURER 'J', 'U', 'M', 'P', 'E', 'R', ' ', ' ' /* 8 bytes */ + #define USB_PRODUCT 'T', '-', 'L', 'I', 'T', 'E', ' ', ' ' /* 8 Bytes */ #else #define USB_NAME "FrSky Taranis" #define USB_MANUFACTURER 'F', 'r', 'S', 'k', 'y', ' ', ' ', ' ' /* 8 bytes */ @@ -827,8 +859,12 @@ void hapticOff(); // Aux serial port driver #if defined(AUX_SERIAL_GPIO) #define DEBUG_BAUDRATE 115200 +#define LUA_DEFAULT_BAUDRATE 115200 #define AUX_SERIAL extern uint8_t auxSerialMode; +#if defined __cplusplus +void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t length = USART_WordLength_8b, uint16_t parity = USART_Parity_No, uint16_t stop = USART_StopBits_1); +#endif void auxSerialInit(unsigned int mode, unsigned int protocol); void auxSerialPutc(char c); #define auxSerialTelemetryInit(protocol) auxSerialInit(UART_MODE_TELEMETRY, protocol) @@ -864,8 +900,10 @@ void bluetoothDisable(); #endif // USB Charger +#if defined(USB_CHARGER) void usbChargerInit(); bool usbChargerLed(); +#endif // LED driver void ledInit(); @@ -889,8 +927,8 @@ void ledBlue(); #define IS_LCD_RESET_NEEDED() true #define LCD_CONTRAST_MIN 10 #define LCD_CONTRAST_MAX 30 -#if defined(RADIO_TX12) - #define LCD_CONTRAST_DEFAULT 21 +#if defined(RADIO_TX12) || defined(RADIO_FAMILY_JUMPER_T12) + #define LCD_CONTRAST_DEFAULT 25 #else #define LCD_CONTRAST_DEFAULT 15 #endif diff --git a/radio/src/targets/taranis/extmodule_driver.cpp b/radio/src/targets/taranis/extmodule_driver.cpp index 4287c0f75e..512f16c5d1 100644 --- a/radio/src/targets/taranis/extmodule_driver.cpp +++ b/radio/src/targets/taranis/extmodule_driver.cpp @@ -83,7 +83,7 @@ void extmodulePpmStart() NVIC_SetPriority(EXTMODULE_TIMER_CC_IRQn, 7); } -void extmoduleSerialStart(uint32_t /*baudrate*/, uint32_t period_half_us, bool inverted) +void extmoduleSerialStart() { EXTERNAL_MODULE_ON(); @@ -98,17 +98,18 @@ void extmoduleSerialStart(uint32_t /*baudrate*/, uint32_t period_half_us, bool i GPIO_Init(EXTMODULE_TX_GPIO, &GPIO_InitStructure); EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; - EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS from 30MHz - EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | (inverted ? 0 : EXTMODULE_TIMER_OUTPUT_POLARITY); + EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2 MHz) + + EXTMODULE_TIMER->CCR3 = 0; + EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | EXTMODULE_TIMER_OUTPUT_POLARITY; EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs EXTMODULE_TIMER->CCR1 = 0; EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high EXTMODULE_TIMER->EGR = 1; // Restart EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0; - EXTMODULE_TIMER->ARR = period_half_us; - EXTMODULE_TIMER->CCR2 = 40000; // The first frame will be sent in 20ms + EXTMODULE_TIMER->ARR = 40000; // dummy value until the DMA request kicks in EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - EXTMODULE_TIMER->DIER |= TIM_DIER_UDE | TIM_DIER_CC2IE; + EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; NVIC_EnableIRQ(EXTMODULE_TIMER_DMA_STREAM_IRQn); @@ -214,16 +215,17 @@ void extmodulePxx1PulsesStart() EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; EXTMODULE_TIMER->PSC = EXTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz) + + EXTMODULE_TIMER->CCR3 = 0; EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | EXTMODULE_TIMER_OUTPUT_POLARITY; // polarity, default low EXTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs EXTMODULE_TIMER->CCR1 = 18; EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0; // Force O/P high EXTMODULE_TIMER->EGR = 1; // Restart - EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; - EXTMODULE_TIMER->ARR = 45000; - EXTMODULE_TIMER->CCR2 = 40000; // The first frame will be sent in 20ms + EXTMODULE_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // 0 TOGGLE / 2 PWM1 + EXTMODULE_TIMER->ARR = 40000; EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - EXTMODULE_TIMER->DIER |= TIM_DIER_UDE | TIM_DIER_CC2IE; + EXTMODULE_TIMER->DIER |= TIM_DIER_UDE; EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; NVIC_EnableIRQ(EXTMODULE_TIMER_DMA_STREAM_IRQn); @@ -257,13 +259,23 @@ void extmoduleSendNextFrame() #if defined(PXX1) case PROTOCOL_CHANNELS_PXX1_PULSES: - EXTMODULE_TIMER->CCR2 = extmodulePulsesData.pxx.getLast() - 4000; // 2mS in advance + + if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) + return; + + // disable timer + EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; + EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(extmodulePulsesData.pxx.getData()); EXTMODULE_TIMER_DMA_STREAM->NDTR = extmodulePulsesData.pxx.getSize(); EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA + + // re-init timer + EXTMODULE_TIMER->EGR = 1; + EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; break; #endif @@ -285,34 +297,54 @@ void extmoduleSendNextFrame() #if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO) extmoduleSendBuffer(extmodulePulsesData.afhds3.getData(), extmodulePulsesData.afhds3.getSize()); #else + if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) + return; + const uint16_t* dataPtr = extmodulePulsesData.afhds3.getData(); uint32_t dataSize = extmodulePulsesData.afhds3.getSize(); - EXTMODULE_TIMER->CCR2 = dataPtr[dataSize -1] - 4000; // 2mS in advance EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(dataPtr); EXTMODULE_TIMER_DMA_STREAM->NDTR = dataSize; EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA + + // re-init timer + EXTMODULE_TIMER->EGR = TIM_PSCReloadMode_Immediate; + EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; #endif } break; #endif #if defined(SBUS) || defined(DSM2) || defined(MULTIMODULE) case PROTOCOL_CHANNELS_SBUS: - EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? 0 : EXTMODULE_TIMER_OUTPUT_POLARITY); // reverse polarity for Sbus if needed // no break case PROTOCOL_CHANNELS_DSM2_LP45: case PROTOCOL_CHANNELS_DSM2_DSM2: case PROTOCOL_CHANNELS_DSM2_DSMX: case PROTOCOL_CHANNELS_MULTIMODULE: - EXTMODULE_TIMER->CCR2 = *(extmodulePulsesData.dsm2.ptr - 1) - 4000; // 2mS in advance + + if (EXTMODULE_TIMER_DMA_STREAM->CR & DMA_SxCR_EN) + return; + + // disable timer + EXTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; + + if (PROTOCOL_CHANNELS_SBUS == moduleState[EXTERNAL_MODULE].protocol) { + EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? EXTMODULE_TIMER_OUTPUT_POLARITY : 0); // reverse polarity for Sbus if needed + } + + // send DMA request EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR); EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(extmodulePulsesData.dsm2.pulses); EXTMODULE_TIMER_DMA_STREAM->NDTR = extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses; EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA + + // re-init timer + EXTMODULE_TIMER->EGR = 1; + EXTMODULE_TIMER->CR1 |= TIM_CR1_CEN; break; #endif @@ -373,14 +405,19 @@ extern "C" void EXTMODULE_TIMER_DMA_STREAM_IRQHandler() DMA_ClearITPendingBit(EXTMODULE_TIMER_DMA_STREAM, EXTMODULE_TIMER_DMA_FLAG_TC); - EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt + switch (moduleState[EXTERNAL_MODULE].protocol) { + case PROTOCOL_CHANNELS_PPM: + EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag + EXTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt + break; + } } extern "C" void EXTMODULE_TIMER_CC_IRQHandler() { EXTMODULE_TIMER->DIER &= ~TIM_DIER_CC2IE; // Stop this interrupt EXTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; + if (setupPulsesExternalModule()) { extmoduleSendNextFrame(); } diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 778febeaba..ec046ddf59 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -52,7 +52,7 @@ #define KEYS_GPIO_PIN_LEFT GPIO_Pin_12 // PE.12 #define KEYS_GPIO_REG_RIGHT GPIOE->IDR #define KEYS_GPIO_PIN_RIGHT GPIO_Pin_13 // PE.13 -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define KEYS_GPIO_REG_EXIT GPIOD->IDR #define KEYS_GPIO_PIN_EXIT GPIO_Pin_2 // PD.02 #define KEYS_GPIO_REG_ENTER GPIOE->IDR @@ -80,6 +80,25 @@ #define KEYS_GPIO_PIN_MDL GPIO_Pin_11 // PE.11 #define KEYS_GPIO_REG_TELE GPIOD->IDR #define KEYS_GPIO_PIN_TELE GPIO_Pin_2 // PD.02 +#elif defined(RADIO_T8) + #define KEYS_GPIO_REG_PAGEUP GPIOD->IDR + #define KEYS_GPIO_PIN_PAGEUP GPIO_Pin_3 // PD.03 + #define KEYS_GPIO_REG_PAGEDN GPIOD->IDR + #define KEYS_GPIO_PIN_PAGEDN GPIO_Pin_7 // PD.07 + #define KEYS_GPIO_REG_EXIT GPIOB->IDR + #define KEYS_GPIO_PIN_EXIT GPIO_Pin_3 // PB.03 + #define KEYS_GPIO_REG_ENTER GPIOA->IDR + #define KEYS_GPIO_PIN_ENTER GPIO_Pin_13 // PA.13 + #define KEYS_GPIO_REG_SYS GPIOB->IDR + #define KEYS_GPIO_PIN_SYS GPIO_Pin_4 // PB.04 + #define KEYS_GPIO_REG_MDL GPIOE->IDR + #define KEYS_GPIO_PIN_MDL GPIO_Pin_11 // PE.11 + #define KEYS_GPIO_REG_PLUS GPIOE->IDR + #define KEYS_GPIO_PIN_PLUS GPIO_Pin_9 // PE.09 + #define KEYS_GPIO_REG_MINUS GPIOE->IDR + #define KEYS_GPIO_PIN_MINUS GPIO_Pin_10 // PE.10 + #define KEYS_GPIO_REG_BIND GPIOA->IDR + #define KEYS_GPIO_PIN_BIND GPIO_Pin_10 // PA.10 #elif defined(PCBX7) #define KEYS_GPIO_REG_PAGE GPIOD->IDR #define KEYS_GPIO_PIN_PAGE GPIO_Pin_3 // PD.03 @@ -338,6 +357,11 @@ #define HARDWARE_SWITCH_A #define SWITCHES_GPIO_REG_A GPIOC->IDR #define SWITCHES_GPIO_PIN_A GPIO_Pin_13 // PC.13 +#elif defined(RADIO_T8) + #define STORAGE_SWITCH_A + #define HARDWARE_SWITCH_A + #define SWITCHES_GPIO_REG_A GPIOE->IDR + #define SWITCHES_GPIO_PIN_A GPIO_Pin_14 // PE.14 #elif defined(PCBX7) #define STORAGE_SWITCH_A #define HARDWARE_SWITCH_A @@ -368,6 +392,20 @@ #define SWITCHES_GPIO_PIN_B_L GPIO_Pin_6 // PA.06 #define SWITCHES_GPIO_REG_B_H GPIOA->IDR #define SWITCHES_GPIO_PIN_B_H GPIO_Pin_5 // PA.05 +#elif defined(RADIO_T8) + #define STORAGE_SWITCH_B + #define HARDWARE_SWITCH_B + #define SWITCHES_GPIO_REG_B_L GPIOE->IDR + #define SWITCHES_GPIO_PIN_B_L GPIO_Pin_7 // PE.07 + #define SWITCHES_GPIO_REG_B_H GPIOE->IDR + #define SWITCHES_GPIO_PIN_B_H GPIO_Pin_13 // PE.13 +#elif defined(RADIO_TLITE) + #define STORAGE_SWITCH_B + #define HARDWARE_SWITCH_B + #define SWITCHES_GPIO_REG_B_L GPIOE->IDR + #define SWITCHES_GPIO_PIN_B_L GPIO_Pin_1 // PE.01 + #define SWITCHES_GPIO_REG_B_H GPIOE->IDR + #define SWITCHES_GPIO_PIN_B_H GPIO_Pin_2 // PE.02 #elif defined(PCBX7) #define STORAGE_SWITCH_B #define HARDWARE_SWITCH_B @@ -412,6 +450,18 @@ #define SWITCHES_GPIO_PIN_C_L GPIO_Pin_11 // PD.11 #define SWITCHES_GPIO_REG_C_H GPIOE->IDR #define SWITCHES_GPIO_PIN_C_H GPIO_Pin_0 // PE.00 +#elif defined(RADIO_T8) + #define STORAGE_SWITCH_C + #define HARDWARE_SWITCH_C + #define SWITCHES_GPIO_REG_C_L GPIOE->IDR + #define SWITCHES_GPIO_PIN_C_L GPIO_Pin_2 // PE.02 + #define SWITCHES_GPIO_REG_C_H GPIOE->IDR + #define SWITCHES_GPIO_PIN_C_H GPIO_Pin_1 // PE.01 +#elif defined(RADIO_TLITE) + #define STORAGE_SWITCH_C + #define HARDWARE_SWITCH_C + #define SWITCHES_GPIO_REG_C GPIOE->IDR + #define SWITCHES_GPIO_PIN_C GPIO_Pin_14 // PE.14 #elif defined(PCBX7) #define STORAGE_SWITCH_C #define HARDWARE_SWITCH_C @@ -454,11 +504,21 @@ #define SWITCHES_GPIO_PIN_D_L GPIO_Pin_4 // PB.04 #define SWITCHES_GPIO_REG_D_H GPIOB->IDR #define SWITCHES_GPIO_PIN_D_H GPIO_Pin_5 // PB.05 +#elif defined(RADIO_T8) + #define STORAGE_SWITCH_D + #define HARDWARE_SWITCH_D + #define SWITCHES_GPIO_REG_D GPIOD->IDR + #define SWITCHES_GPIO_PIN_D GPIO_Pin_14 // PD.14 #elif defined(RADIO_TX12) #define STORAGE_SWITCH_D #define HARDWARE_SWITCH_D #define SWITCHES_GPIO_REG_D GPIOE->IDR #define SWITCHES_GPIO_PIN_D GPIO_Pin_8 // PE.08 +#elif defined(RADIO_TLITE) + #define STORAGE_SWITCH_D + #define HARDWARE_SWITCH_D + #define SWITCHES_GPIO_REG_D GPIOD->IDR + #define SWITCHES_GPIO_PIN_D GPIO_Pin_14 // PD.14 #elif defined(PCBX7) #define STORAGE_SWITCH_D #define HARDWARE_SWITCH_D @@ -545,6 +605,9 @@ #define SWITCHES_GPIO_PIN_F_L GPIO_Pin_1 // PE.01 #define SWITCHES_GPIO_REG_F_H GPIOE->IDR #define SWITCHES_GPIO_PIN_F_H GPIO_Pin_2 // PE.02 +#elif defined(RADIO_T8) || defined(RADIO_TLITE) + // no SWF + #define STORAGE_SWITCH_F #elif defined(PCBX7) #define STORAGE_SWITCH_F #define HARDWARE_SWITCH_F @@ -569,7 +632,7 @@ #define HARDWARE_SWITCH_G #define SWITCHES_GPIO_REG_G GPIOC->IDR #define SWITCHES_GPIO_PIN_G GPIO_Pin_2 // PC.02 -#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBX9LITE) +#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBX9LITE) || defined(RADIO_T8) // no SWG #else #define STORAGE_SWITCH_G @@ -592,7 +655,13 @@ #define SWITCHES_GPIO_PIN_H GPIO_Pin_14 // PD.14 #elif defined(PCBXLITE) || defined(PCBX9LITE) // no SWH +#elif defined(RADIO_T8) + #define STORAGE_SWITCH_H + // no SWH #elif defined(RADIO_TX12) +#elif defined(RADIO_TLITE) + // no SWH + #define STORAGE_SWITCH_H #elif defined(PCBX7) #define STORAGE_SWITCH_H #define HARDWARE_SWITCH_H @@ -621,6 +690,10 @@ #define SWITCHES_GPIO_REG_I GPIOC->IDR #define SWITCHES_GPIO_PIN_I GPIO_Pin_13 // PC.13 #define STORAGE_SWITCH_J +#elif defined(RADIO_T8) + #define STORAGE_SWITCH_I + #define STORAGE_SWITCH_J + // no SWI/J #elif defined(RADIO_TX12) #define STORAGE_SWITCH_I #define HARDWARE_SWITCH_I @@ -630,6 +703,11 @@ #define HARDWARE_SWITCH_J #define SWITCHES_GPIO_REG_J GPIOD->IDR #define SWITCHES_GPIO_PIN_J GPIO_Pin_14 // PD.14 +#elif defined(RADIO_TLITE) + // no SWI + #define STORAGE_SWITCH_I + // no SWJ + #define STORAGE_SWITCH_J #elif defined(PCBX7) #define STORAGE_SWITCH_I #define HARDWARE_SWITCH_I @@ -739,7 +817,7 @@ #define KEYS_GPIOB_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5) #define KEYS_GPIOC_PINS (GPIO_Pin_4 | GPIO_Pin_5) #define KEYS_GPIOE_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14) -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE) #define KEYS_GPIOA_PINS GPIO_Pin_5 #define KEYS_GPIOC_PINS (GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3) @@ -752,6 +830,13 @@ #define KEYS_GPIOC_PINS (GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3|GPIO_Pin_13) #define KEYS_GPIOD_PINS (GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_11 | GPIO_Pin_14 | GPIO_Pin_15) #define KEYS_GPIOE_PINS (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 |GPIO_Pin_8| GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15) +#elif defined(RADIO_T8) + #define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE) + #define KEYS_GPIOA_PINS (KEYS_GPIO_PIN_ENTER | KEYS_GPIO_PIN_BIND) + #define KEYS_GPIOB_PINS (KEYS_GPIO_PIN_EXIT | KEYS_GPIO_PIN_SYS) + #define KEYS_GPIOC_PINS (TRIMS_GPIO_PIN_LHR | TRIMS_GPIO_PIN_RVU | TRIMS_GPIO_PIN_RVD) + #define KEYS_GPIOD_PINS (KEYS_GPIO_PIN_PAGEUP | KEYS_GPIO_PIN_PAGEDN | SWITCHES_GPIO_PIN_D | TRIMS_GPIO_PIN_LHL) + #define KEYS_GPIOE_PINS (SWITCHES_GPIO_PIN_C_H | SWITCHES_GPIO_PIN_C_L | TRIMS_GPIO_PIN_RHL | TRIMS_GPIO_PIN_RHR | TRIMS_GPIO_PIN_LVU | TRIMS_GPIO_PIN_LVD | SWITCHES_GPIO_PIN_B_L | KEYS_GPIO_PIN_PLUS | KEYS_GPIO_PIN_MINUS | KEYS_GPIO_PIN_MDL | SWITCHES_GPIO_PIN_B_H | SWITCHES_GPIO_PIN_A) #elif defined(RADIO_X7ACCESS) #define KEYS_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE) #define KEYS_GPIOA_PINS GPIO_Pin_5 @@ -795,6 +880,13 @@ #define ADC_SET_DMA_FLAGS() ADC_DMA->HIFCR = (DMA_HIFCR_CTCIF4 | DMA_HIFCR_CHTIF4 | DMA_HIFCR_CTEIF4 | DMA_HIFCR_CDMEIF4 | DMA_HIFCR_CFEIF4) #define ADC_TRANSFER_COMPLETE() (ADC_DMA->HISR & DMA_HISR_TCIF4) #define ADC_SAMPTIME 2 // sample time = 28 cycles +#if defined(RADIO_TLITE) + #define ADC_MAIN_SMPR1 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + ((ADC_SAMPTIME + 1) << 24); // TLite needs +1 for proper RTC Bat measurement. + #define ADC_MAIN_SMPR2 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27); +#else + #define ADC_MAIN_SMPR1 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24); + #define ADC_MAIN_SMPR2 (ADC_SAMPTIME << 0) + (ADC_SAMPTIME << 3) + (ADC_SAMPTIME << 6) + (ADC_SAMPTIME << 9) + (ADC_SAMPTIME << 12) + (ADC_SAMPTIME << 15) + (ADC_SAMPTIME << 18) + (ADC_SAMPTIME << 21) + (ADC_SAMPTIME << 24) + (ADC_SAMPTIME << 27); +#endif #if defined(PCBX9E) #define HARDWARE_POT1 #define HARDWARE_POT2 @@ -906,6 +998,43 @@ #define ADC_CHANNEL_POT2 ADC_Channel_12 // ADC1_IN12 #define ADC_CHANNEL_BATT ADC_Channel_10 // ADC1_IN10 #define ADC_VREF_PREC2 330 +#elif defined(RADIO_T8) + // No pots + #define ADC_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA2) + #define ADC_RCC_APB1Periph 0 + #define ADC_RCC_APB2Periph RCC_APB2Periph_ADC1 + #define ADC_GPIO_PIN_STICK_RV GPIO_Pin_0 // PA.00 + #define ADC_GPIO_PIN_STICK_RH GPIO_Pin_1 // PA.01 + #define ADC_GPIO_PIN_STICK_LV GPIO_Pin_2 // PA.02 + #define ADC_GPIO_PIN_STICK_LH GPIO_Pin_3 // PA.03 + #define ADC_CHANNEL_STICK_RV ADC_Channel_0 // ADC1_IN0 + #define ADC_CHANNEL_STICK_RH ADC_Channel_1 // ADC1_IN1 + #define ADC_CHANNEL_STICK_LV ADC_Channel_2 // ADC1_IN2 + #define ADC_CHANNEL_STICK_LH ADC_Channel_3 // ADC1_IN3 + #define ADC_GPIO_PIN_BATT GPIO_Pin_0 // PC.00 + #define ADC_GPIOA_PINS (ADC_GPIO_PIN_STICK_RV | ADC_GPIO_PIN_STICK_RH | ADC_GPIO_PIN_STICK_LH | ADC_GPIO_PIN_STICK_LV) + #define ADC_GPIOB_PINS 0 + #define ADC_GPIOC_PINS ADC_GPIO_PIN_BATT + #define ADC_CHANNEL_BATT ADC_Channel_10 + #define ADC_VREF_PREC2 300 +#elif defined(RADIO_TLITE) + #define ADC_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA2) + #define ADC_RCC_APB1Periph 0 + #define ADC_RCC_APB2Periph RCC_APB2Periph_ADC1 + #define ADC_GPIO_PIN_STICK_RV GPIO_Pin_0 // PA.00 + #define ADC_GPIO_PIN_STICK_RH GPIO_Pin_1 // PA.01 + #define ADC_GPIO_PIN_STICK_LV GPIO_Pin_2 // PA.02 + #define ADC_GPIO_PIN_STICK_LH GPIO_Pin_3 // PA.03 + #define ADC_CHANNEL_STICK_RV ADC_Channel_0 // ADC1_IN0 + #define ADC_CHANNEL_STICK_RH ADC_Channel_1 // ADC1_IN1 + #define ADC_CHANNEL_STICK_LV ADC_Channel_2 // ADC1_IN2 + #define ADC_CHANNEL_STICK_LH ADC_Channel_3 // ADC1_IN3 + #define ADC_GPIO_PIN_BATT GPIO_Pin_0 // PC.00 + #define ADC_GPIOA_PINS (ADC_GPIO_PIN_STICK_RV | ADC_GPIO_PIN_STICK_RH | ADC_GPIO_PIN_STICK_LH | ADC_GPIO_PIN_STICK_LV) + #define ADC_GPIOB_PINS 0 + #define ADC_GPIOC_PINS ADC_GPIO_PIN_BATT + #define ADC_CHANNEL_BATT ADC_Channel_10 + #define ADC_VREF_PREC2 330 #elif defined(PCBX7) #define HARDWARE_POT1 #define HARDWARE_POT2 @@ -1033,6 +1162,16 @@ #define LED_BLUE_GPIO_PIN GPIO_Pin_1 // PB.01 #define LED_RED_GPIO GPIOC #define LED_RED_GPIO_PIN GPIO_Pin_4 // PC.04 +#elif defined(RADIO_T8) + #define STATUS_LEDS + #define GPIO_LED_GPIO_ON GPIO_SetBits + #define GPIO_LED_GPIO_OFF GPIO_ResetBits + #define LED_RED_GPIO GPIOC + #define LED_RED_GPIO_PIN GPIO_Pin_4 // PC.04 + #define LED_BLUE_GPIO GPIOC + #define LED_BLUE_GPIO_PIN GPIO_Pin_5 // PC.05 + #define LED_GREEN_GPIO GPIOB + #define LED_GREEN_GPIO_PIN GPIO_Pin_1 // PB.01 #elif defined(PCBX7) #define STATUS_LEDS #define GPIO_LED_GPIO_ON GPIO_SetBits @@ -1158,7 +1297,7 @@ #define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream5_IRQHandler #define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF5 #define INTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) -#elif defined(RADIO_T12) || defined(RADIO_TX12) +#elif (defined(RADIO_FAMILY_JUMPER_T12) && defined(HARDWARE_INTERNAL_MODULE))|| defined(RADIO_TX12) || defined(RADIO_T8) #define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA1) #define INTMODULE_RCC_APB1Periph (RCC_APB1Periph_USART3 | RCC_APB1Periph_TIM2) #define INTMODULE_RCC_APB2Periph 0 @@ -1408,7 +1547,7 @@ #define TELEMETRY_EXTI_IRQn EXTI9_5_IRQn #define TELEMETRY_EXTI_TRIGGER EXTI_Trigger_Rising -#if defined(RADIO_X7) || defined(RADIO_X7ACCESS) || defined(RADIO_TX12) +#if defined(RADIO_X7) || defined(RADIO_X7ACCESS) || defined(RADIO_TX12) || defined(RADIO_T8) #define TELEMETRY_EXTI_REUSE_INTERRUPT_ROTARY_ENCODER #elif defined(PCBXLITE) || defined(PCBX9LITE) || defined(RADIO_X9DP2019) #define TELEMETRY_EXTI_IRQHandler EXTI9_5_IRQHandler @@ -1484,7 +1623,9 @@ // Heartbeat for iXJT / ISRM synchro #define INTMODULE_HEARTBEAT_TRIGGER EXTI_Trigger_Falling -#if defined(PCBXLITE) +#if !defined(HARDWARE_EXTERNAL_MODULE) + // No heartbeat +#elif defined(PCBXLITE) #define INTMODULE_HEARTBEAT #define INTMODULE_HEARTBEAT_RCC_AHB1Periph RCC_AHB1Periph_GPIOD #define INTMODULE_HEARTBEAT_GPIO GPIOD @@ -1584,29 +1725,31 @@ #define TRAINER_MODULE_SBUS_DMA_STREAM EXTMODULE_USART_RX_DMA_STREAM #define TRAINER_MODULE_SBUS_DMA_CHANNEL EXTMODULE_USART_RX_DMA_CHANNEL #else +#if defined(HARDWARE_EXTERNAL_MODULE) #define TRAINER_MODULE_CPPM #define TRAINER_MODULE_SBUS - #define TRAINER_MODULE_RCC_AHB1Periph RCC_AHB1Periph_GPIOC - #define TRAINER_MODULE_RCC_APB2Periph RCC_APB2Periph_USART6 - #define TRAINER_MODULE_RCC_APB1Periph RCC_APB1Periph_TIM3 - #define TRAINER_MODULE_CPPM_TIMER TRAINER_TIMER - #define TRAINER_MODULE_CPPM_GPIO INTMODULE_HEARTBEAT_GPIO - #define TRAINER_MODULE_CPPM_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN - #define TRAINER_MODULE_CPPM_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource - #define TRAINER_MODULE_CPPM_INTERRUPT_ENABLE TIM_DIER_CC2IE - #define TRAINER_MODULE_CPPM_INTERRUPT_FLAG TIM_SR_CC2IF - #define TRAINER_MODULE_CPPM_CCMR1 (TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_CC2S_0) - #define TRAINER_MODULE_CPPM_CCER TIM_CCER_CC2E - #define TRAINER_MODULE_CPPM_COUNTER_REGISTER TRAINER_TIMER->CCR2 - #define TRAINER_MODULE_CPPM_TIMER_IRQn TRAINER_TIMER_IRQn - #define TRAINER_MODULE_CPPM_GPIO_AF GPIO_AF_TIM3 - #define TRAINER_MODULE_SBUS_GPIO_AF GPIO_AF_USART6 - #define TRAINER_MODULE_SBUS_USART USART6 - #define TRAINER_MODULE_SBUS_GPIO INTMODULE_HEARTBEAT_GPIO - #define TRAINER_MODULE_SBUS_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN - #define TRAINER_MODULE_SBUS_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource - #define TRAINER_MODULE_SBUS_DMA_STREAM DMA2_Stream1 - #define TRAINER_MODULE_SBUS_DMA_CHANNEL DMA_Channel_5 +#endif + #define TRAINER_MODULE_RCC_AHB1Periph RCC_AHB1Periph_GPIOC + #define TRAINER_MODULE_RCC_APB2Periph RCC_APB2Periph_USART6 + #define TRAINER_MODULE_RCC_APB1Periph RCC_APB1Periph_TIM3 + #define TRAINER_MODULE_CPPM_TIMER TRAINER_TIMER + #define TRAINER_MODULE_CPPM_GPIO INTMODULE_HEARTBEAT_GPIO + #define TRAINER_MODULE_CPPM_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN + #define TRAINER_MODULE_CPPM_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource + #define TRAINER_MODULE_CPPM_INTERRUPT_ENABLE TIM_DIER_CC2IE + #define TRAINER_MODULE_CPPM_INTERRUPT_FLAG TIM_SR_CC2IF + #define TRAINER_MODULE_CPPM_CCMR1 (TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_CC2S_0) + #define TRAINER_MODULE_CPPM_CCER TIM_CCER_CC2E + #define TRAINER_MODULE_CPPM_COUNTER_REGISTER TRAINER_TIMER->CCR2 + #define TRAINER_MODULE_CPPM_TIMER_IRQn TRAINER_TIMER_IRQn + #define TRAINER_MODULE_CPPM_GPIO_AF GPIO_AF_TIM3 + #define TRAINER_MODULE_SBUS_GPIO_AF GPIO_AF_USART6 + #define TRAINER_MODULE_SBUS_USART USART6 + #define TRAINER_MODULE_SBUS_GPIO INTMODULE_HEARTBEAT_GPIO + #define TRAINER_MODULE_SBUS_GPIO_PIN INTMODULE_HEARTBEAT_GPIO_PIN + #define TRAINER_MODULE_SBUS_GPIO_PinSource INTMODULE_HEARTBEAT_EXTI_PinSource + #define TRAINER_MODULE_SBUS_DMA_STREAM DMA2_Stream1 + #define TRAINER_MODULE_SBUS_DMA_CHANNEL DMA_Channel_5 #endif // USB @@ -1672,6 +1815,10 @@ #define BACKLIGHT_CCMR1 TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 // Channel 1, PWM #define BACKLIGHT_CCER TIM_CCER_CC1E #define BACKLIGHT_COUNTER_REGISTER BACKLIGHT_TIMER->CCR1 +#elif defined(RADIO_T8) + #define BACKLIGHT_RCC_AHB1Periph 0 + #define BACKLIGHT_RCC_APB1Periph 0 + #define BACKLIGHT_RCC_APB2Periph 0 #elif defined(PCBX7) #define BACKLIGHT_RCC_AHB1Periph RCC_AHB1Periph_GPIOD #define BACKLIGHT_RCC_APB1Periph RCC_APB1Periph_TIM4 @@ -1699,7 +1846,7 @@ #define KEYS_BACKLIGHT_RCC_AHB1Periph 0 // LCD driver -#if defined(RADIO_TX12) || defined(RADIO_T12) +#if defined(RADIO_TX12) || defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_T8) #define LCD_VERTICAL_INVERT #endif #if defined(PCBX9E) @@ -1894,12 +2041,16 @@ #define AUDIO_SPEAKER_ENABLE_GPIO_PIN GPIO_Pin_14 // PD.14 #define HEADPHONE_TRAINER_SWITCH_GPIO GPIOD #define HEADPHONE_TRAINER_SWITCH_GPIO_PIN GPIO_Pin_9 // PD.09 -#elif defined(RADIO_TX12) +#elif defined(AUDIO_MUTE_GPIO) #define AUDIO_RCC_AHB1Periph (RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA1) #define AUDIO_MUTE_GPIO GPIOE #define AUDIO_MUTE_GPIO_PIN GPIO_Pin_12 // PE.12 - #define AUDIO_UNMUTE_DELAY 150 // ms #define AUDIO_MUTE_DELAY 500 // ms +#if defined(RADIO_TLITE) + #define AUDIO_UNMUTE_DELAY 250 // ms +#else + #define AUDIO_UNMUTE_DELAY 150 // ms +#endif #else #define AUDIO_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA1) #endif @@ -2020,7 +2171,7 @@ #define BT_USART_IRQn USART3_IRQn // #define BT_DMA_Stream_RX DMA1_Stream1 // #define BT_DMA_Channel_RX DMA_Channel_4 -#elif defined(PCBX9D) || defined(PCBX9DP) || defined(RADIO_T12) || defined(RADIO_TX12) +#elif defined(PCBX9D) || defined(PCBX9DP) || defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_TX12) || defined(RADIO_T8) #define STORAGE_BLUETOOTH #define BT_RCC_AHB1Periph 0 #define BT_RCC_APB1Periph 0 @@ -2041,4 +2192,11 @@ #define TIMER_2MHz_RCC_APB1Periph RCC_APB1Periph_TIM7 #define TIMER_2MHz_TIMER TIM7 +// Mixer scheduler timer +#define MIXER_SCHEDULER_TIMER_RCC_APB1Periph RCC_APB1Periph_TIM13 +#define MIXER_SCHEDULER_TIMER TIM13 +#define MIXER_SCHEDULER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) +#define MIXER_SCHEDULER_TIMER_IRQn TIM8_UP_TIM13_IRQn +#define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_UP_TIM13_IRQHandler + #endif // _HAL_H_ diff --git a/radio/src/targets/taranis/intmodule_pulses_driver.cpp b/radio/src/targets/taranis/intmodule_pulses_driver.cpp index e71768eacb..9afacfda8d 100644 --- a/radio/src/targets/taranis/intmodule_pulses_driver.cpp +++ b/radio/src/targets/taranis/intmodule_pulses_driver.cpp @@ -42,21 +42,23 @@ void intmoduleSendNextFrame() #if defined(PXX1) case PROTOCOL_CHANNELS_PXX1_PULSES: { - uint32_t last = intmodulePulsesData.pxx.getLast(); - if (heartbeatCapture.valid) { - if (getTmr2MHz() - heartbeatCapture.timestamp > HEARBEAT_OFFSET) - last -= 21; - else - last += 19; - intmodulePulsesData.pxx.setLast(last); - } - INTMODULE_TIMER->CCR2 = last - 4000; // 2mS in advance + if (INTMODULE_DMA_STREAM->CR & DMA_SxCR_EN) + return; + + //disable timer + INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; + + //INTMODULE_TIMER->CCR2 = last - 4000; // 2mS in advance INTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA INTMODULE_DMA_STREAM->CR |= INTMODULE_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; INTMODULE_DMA_STREAM->PAR = CONVERT_PTR_UINT(&INTMODULE_TIMER->ARR); INTMODULE_DMA_STREAM->M0AR = CONVERT_PTR_UINT(intmodulePulsesData.pxx.getData()); INTMODULE_DMA_STREAM->NDTR = intmodulePulsesData.pxx.getSize(); INTMODULE_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA + + // re-init timer + INTMODULE_TIMER->EGR = 1; + INTMODULE_TIMER->CR1 |= TIM_CR1_CEN; break; } #endif @@ -97,17 +99,16 @@ void intmodulePxx1PulsesStart() INTMODULE_TIMER->CR1 &= ~TIM_CR1_CEN; INTMODULE_TIMER->PSC = INTMODULE_TIMER_FREQ / 2000000 - 1; // 0.5uS (2Mhz) - INTMODULE_TIMER->ARR = 18000; + INTMODULE_TIMER->CCER = TIM_CCER_CC3E | TIM_CCER_CC3NE; INTMODULE_TIMER->BDTR = TIM_BDTR_MOE; // Enable outputs INTMODULE_TIMER->CCR3 = 16; INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_0; // Force O/P high INTMODULE_TIMER->EGR = 1; // Restart - INTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update - INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2; + INTMODULE_TIMER->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3PE; + INTMODULE_TIMER->ARR = 40000; INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - INTMODULE_TIMER->CCR2 = 16000; // The first frame will be sent in 20ms - INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt + INTMODULE_TIMER->DIER |= TIM_DIER_UDE; // Enable DMA on update INTMODULE_TIMER->CR1 |= TIM_CR1_CEN; NVIC_EnableIRQ(INTMODULE_DMA_STREAM_IRQn); @@ -157,8 +158,12 @@ extern "C" void INTMODULE_DMA_STREAM_IRQHandler() DMA_ClearITPendingBit(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC); - INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag - INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt + switch (moduleState[INTERNAL_MODULE].protocol) { + case PROTOCOL_CHANNELS_PPM: + INTMODULE_TIMER->SR &= ~TIM_SR_CC2IF; // Clear flag + INTMODULE_TIMER->DIER |= TIM_DIER_CC2IE; // Enable this interrupt + break; + } } extern "C" void INTMODULE_TIMER_CC_IRQHandler() diff --git a/radio/src/targets/taranis/keys_driver.cpp b/radio/src/targets/taranis/keys_driver.cpp index 6883740c49..bca5e3e97a 100644 --- a/radio/src/targets/taranis/keys_driver.cpp +++ b/radio/src/targets/taranis/keys_driver.cpp @@ -88,6 +88,10 @@ uint32_t readKeys() result |= 1 << KEY_SHIFT; #endif +#if defined(KEYS_GPIO_PIN_BIND) + if (~KEYS_GPIO_REG_BIND & KEYS_GPIO_PIN_BIND) + result |= 1 << KEY_BIND; +#endif // if (result != 0) TRACE("readKeys(): result=0x%02x", result); return result; @@ -200,10 +204,16 @@ uint32_t switchState(uint8_t index) uint32_t xxx = 0; switch (index) { -#if defined(RADIO_TX12) + +#if defined(RADIO_TX12) || defined(RADIO_T8) ADD_2POS_CASE(A); ADD_3POS_CASE(B, 1); ADD_3POS_CASE(C, 2); +#elif defined(RADIO_TLITE) + ADD_3POS_CASE(A, 0); + ADD_3POS_CASE(B, 1); + ADD_2POS_CASE(C); + ADD_2POS_CASE(D); #else ADD_3POS_CASE(A, 0); ADD_3POS_CASE(B, 1); @@ -235,6 +245,10 @@ uint32_t switchState(uint8_t index) ADD_2POS_CASE(D); ADD_3POS_CASE(E, 4); ADD_3POS_CASE(F, 5); +#elif defined(RADIO_T8) + ADD_2POS_CASE(D); +#elif defined(RADIO_TLITE) + // Only 4 switches #elif defined(PCBX7) ADD_3POS_CASE(D, 3); ADD_2POS_CASE(F); diff --git a/radio/src/targets/taranis/lcd_driver_spi.cpp b/radio/src/targets/taranis/lcd_driver_spi.cpp index e1efa8e15a..07924671c2 100644 --- a/radio/src/targets/taranis/lcd_driver_spi.cpp +++ b/radio/src/targets/taranis/lcd_driver_spi.cpp @@ -20,7 +20,7 @@ #include "opentx.h" -#if defined(RADIO_T12) || defined(RADIO_TX12) +#if defined(RADIO_FAMILY_JUMPER_T12) || defined(RADIO_TX12) || defined(RADIO_T8) #define LCD_CONTRAST_OFFSET -10 #else #define LCD_CONTRAST_OFFSET 160 diff --git a/radio/src/targets/taranis/usb_charger_driver.cpp b/radio/src/targets/taranis/usb_charger_driver.cpp index 7e92c6dbcd..78cc3d6a60 100644 --- a/radio/src/targets/taranis/usb_charger_driver.cpp +++ b/radio/src/targets/taranis/usb_charger_driver.cpp @@ -33,5 +33,9 @@ void usbChargerInit() bool usbChargerLed() { +#if defined(SIMU) + return true; +#else return (GPIO_ReadInputDataBit(USB_CHARGER_GPIO, USB_CHARGER_GPIO_PIN) == Bit_RESET && usbPlugged()); +#endif } diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp index 16e120784e..a051cc5098 100644 --- a/radio/src/tasks.cpp +++ b/radio/src/tasks.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "mixer_scheduler.h" RTOS_TASK_HANDLE menusTaskId; RTOS_DEFINE_STACK(menusStack, MENUS_STACK_SIZE); @@ -32,16 +33,6 @@ RTOS_DEFINE_STACK(audioStack, AUDIO_STACK_SIZE); RTOS_MUTEX_HANDLE audioMutex; RTOS_MUTEX_HANDLE mixerMutex; -enum TaskIndex { - MENU_TASK_INDEX, - MIXER_TASK_INDEX, - AUDIO_TASK_INDEX, - CLI_TASK_INDEX, - BLUETOOTH_TASK_INDEX, - TASK_INDEX_COUNT, - MAIN_TASK_INDEX = 255 -}; - void stackPaint() { menusStack.paint(); @@ -75,13 +66,30 @@ bool isForcePowerOffRequested() bool isModuleSynchronous(uint8_t moduleIdx) { - uint8_t protocol = moduleState[moduleIdx].protocol; - if (protocol == PROTOCOL_CHANNELS_PXX2_HIGHSPEED || protocol == PROTOCOL_CHANNELS_PXX2_LOWSPEED || protocol == PROTOCOL_CHANNELS_CROSSFIRE || protocol == PROTOCOL_CHANNELS_GHOST || protocol == PROTOCOL_CHANNELS_NONE) - return true; -#if defined(INTMODULE_USART) || defined(EXTMODULE_USART) - if (protocol == PROTOCOL_CHANNELS_PXX1_SERIAL) - return true; + switch(moduleState[moduleIdx].protocol) { + case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: + case PROTOCOL_CHANNELS_PXX2_LOWSPEED: + case PROTOCOL_CHANNELS_CROSSFIRE: + case PROTOCOL_CHANNELS_GHOST: + case PROTOCOL_CHANNELS_AFHDS3: + case PROTOCOL_CHANNELS_NONE: + +#if defined(MULTIMODULE) + case PROTOCOL_CHANNELS_MULTIMODULE: #endif +#if defined(INTMODULE_USART) || defined(EXTMODULE_USART) + case PROTOCOL_CHANNELS_PXX1_SERIAL: +#endif + // case PROTOCOL_CHANNELS_PPM: + case PROTOCOL_CHANNELS_PXX1_PULSES: +#if defined(DSM2) + case PROTOCOL_CHANNELS_SBUS: + case PROTOCOL_CHANNELS_DSM2_LP45: + case PROTOCOL_CHANNELS_DSM2_DSM2: + case PROTOCOL_CHANNELS_DSM2_DSMX: +#endif + return true; + } return false; } @@ -106,6 +114,11 @@ TASK_FUNCTION(mixerTask) { s_pulses_paused = true; + mixerSchedulerInit(); +#if !defined(PCBSKY9X) + mixerSchedulerStart(); +#endif + while (true) { #if defined(SBUS_TRAINER) // SBUS trainer @@ -120,7 +133,18 @@ TASK_FUNCTION(mixerTask) bluetooth.wakeup(); #endif - RTOS_WAIT_TICKS(1); + // run mixer at least every 30ms + bool timeout = mixerSchedulerWaitForTrigger(30); + +#if defined(DEBUG_MIXER_SCHEDULER) + GPIO_SetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); +#endif + +#if !defined(PCBSKY9X) + // re-enable trigger + mixerSchedulerEnableTrigger(); +#endif #if defined(SIMU) if (pwrCheck() == e_power_off) { @@ -132,29 +156,22 @@ TASK_FUNCTION(mixerTask) } #endif - uint32_t now = RTOS_GET_MS(); - uint8_t runMask = 0; - - if (now >= nextMixerTime[0]) { - runMask |= (1 << 0); - } - -#if NUM_MODULES >= 2 - if (now >= nextMixerTime[1]) { - runMask |= (1 << 1); - } -#endif - - if (!runMask) { - continue; // go back to sleep - } - if (!s_pulses_paused) { uint16_t t0 = getTmr2MHz(); DEBUG_TIMER_START(debugTimerMixer); RTOS_LOCK_MUTEX(mixerMutex); + doMixerCalculations(); + +#if defined(PCBSKY9X) + sendSynchronousPulses(1 << EXTERNAL_MODULE); +#else + sendSynchronousPulses((1 << INTERNAL_MODULE) | (1 << EXTERNAL_MODULE)); +#endif + + doMixerPeriodicUpdates(); + DEBUG_TIMER_START(debugTimerMixerCalcToUsage); DEBUG_TIMER_SAMPLE(debugTimerMixerIterval); RTOS_UNLOCK_MUTEX(mixerMutex); @@ -183,7 +200,13 @@ TASK_FUNCTION(mixerTask) if (t0 > maxMixerDuration) maxMixerDuration = t0; - sendSynchronousPulses(runMask); + // TODO: + // - check the cause of timeouts when switching + // between protocols with multi-proto RF +#if defined(DEBUG) + if (timeout) + serialPrint("mix sched timeout!"); +#endif } } } diff --git a/radio/src/telemetry/crossfire.cpp b/radio/src/telemetry/crossfire.cpp index b81a7487e0..56ae0e5365 100644 --- a/radio/src/telemetry/crossfire.cpp +++ b/radio/src/telemetry/crossfire.cpp @@ -184,6 +184,25 @@ void processCrossfireTelemetryFrame() break; } + case RADIO_ID: + if (telemetryRxBuffer[3] == 0xEA // radio address + && telemetryRxBuffer[5] == 0x10 // timing correction frame + ) { + + uint32_t update_interval; + int32_t offset; + if (getCrossfireTelemetryValue<4>(6, (int32_t&)update_interval) && getCrossfireTelemetryValue<4>(10, offset)) { + + // values are in 10th of micro-seconds + update_interval /= 10; + offset /= 10; + + TRACE("[XF] Rate: %d, Lag: %d", update_interval, offset); + getModuleSyncStatus(EXTERNAL_MODULE).update(update_interval, offset); + } + } + break; + #if defined(LUA) default: if (luaInputTelemetryFifo && luaInputTelemetryFifo->hasSpace(telemetryRxBufferCount-2) ) { diff --git a/radio/src/telemetry/crossfire.h b/radio/src/telemetry/crossfire.h index 347104980f..f8249e5f84 100644 --- a/radio/src/telemetry/crossfire.h +++ b/radio/src/telemetry/crossfire.h @@ -102,12 +102,12 @@ const uint8_t CROSSFIRE_FRAME_PERIODS[] = { 4, 16, }; -#if SPORT_MAX_BAUDRATE < 400000 -#define CROSSFIRE_BAUDRATE CROSSFIRE_BAUDRATES[g_eeGeneral.telemetryBaudrate] -#define CROSSFIRE_PERIOD CROSSFIRE_FRAME_PERIODS[g_eeGeneral.telemetryBaudrate] +#if SPORT_MAX_BAUDRATE < 400000 || defined(DEBUG) +#define CROSSFIRE_BAUDRATE CROSSFIRE_BAUDRATES[g_eeGeneral.telemetryBaudrate] +#define CROSSFIRE_PERIOD (CROSSFIRE_PERIODS[g_eeGeneral.telemetryBaudrate] * 1000) #else #define CROSSFIRE_BAUDRATE 400000 -#define CROSSFIRE_PERIOD 4 // 4ms +#define CROSSFIRE_PERIOD 4000 /* us; 250 Hz */ #endif #define CROSSFIRE_TELEM_MIRROR_BAUDRATE 115200 diff --git a/radio/src/telemetry/ghost.cpp b/radio/src/telemetry/ghost.cpp index 098e9c990b..8b949b69aa 100755 --- a/radio/src/telemetry/ghost.cpp +++ b/radio/src/telemetry/ghost.cpp @@ -43,12 +43,19 @@ enum GHOST_ID_TOTAL_LATENCY = 0x0007, // Tx-side total latency GHOST_ID_VTX_FREQ = 0x0008, // Vtx Frequency (in MHz) GHOST_ID_VTX_POWER = 0x0009, // Vtx Power (in mW) - GHOST_ID_VTX_CHAN = 0x000a, // Vtx Channel - GHOST_ID_VTX_BAND = 0x000b, // Vtx Band + GHOST_ID_VTX_CHAN = 0x000A, // Vtx Channel + GHOST_ID_VTX_BAND = 0x000B, // Vtx Band - GHOST_ID_PACK_VOLTS = 0x000c, // Battery Pack Voltage - GHOST_ID_PACK_AMPS = 0x000d, // Battery Pack Current - GHOST_ID_PACK_MAH = 0x000e, // Battery Pack mAh consumed + GHOST_ID_PACK_VOLTS = 0x000C, // Battery Pack Voltage + GHOST_ID_PACK_AMPS = 0x000D, // Battery Pack Current + GHOST_ID_PACK_MAH = 0x000E, // Battery Pack mAh consumed + + GHOST_ID_GPS_LAT = 0x000F, // GPS Latitude + GHOST_ID_GPS_LONG = 0x0010, // GPS Longitude + GHOST_ID_GPS_ALT = 0x0011, // GPS Altitude + GHOST_ID_GPS_HDG = 0x0012, // GPS Heading + GHOST_ID_GPS_GSPD = 0x0013, // GPS Ground Speed + GHOST_ID_GPS_SATS = 0x0014 // GPS Satellite Count }; const GhostSensor ghostSensors[] = { @@ -70,6 +77,13 @@ const GhostSensor ghostSensors[] = { {GHOST_ID_PACK_AMPS, ZSTR_CURR, UNIT_AMPS, 2}, {GHOST_ID_PACK_MAH, ZSTR_CAPACITY, UNIT_MAH, 0}, + {GHOST_ID_GPS_LAT, ZSTR_GPS, UNIT_GPS_LATITUDE, 0}, + {GHOST_ID_GPS_LONG, ZSTR_GPS, UNIT_GPS_LONGITUDE, 0}, + {GHOST_ID_GPS_GSPD, ZSTR_GSPD, UNIT_KMH, 1}, + {GHOST_ID_GPS_HDG, ZSTR_HDG, UNIT_DEGREE, 3}, + {GHOST_ID_GPS_ALT, ZSTR_ALT, UNIT_METERS, 0}, + {GHOST_ID_GPS_SATS, ZSTR_SATELLITES, UNIT_RAW, 0}, + {0x00, NULL, UNIT_RAW, 0}, }; @@ -88,7 +102,11 @@ void processGhostTelemetryValue(uint8_t index, int32_t value) return; const GhostSensor * sensor = getGhostSensor(index); - setTelemetryValue(PROTOCOL_TELEMETRY_GHOST, sensor->id, 0, 0, value, sensor->unit, sensor->precision); + uint16_t id = sensor->id; + if (id == GHOST_ID_GPS_LONG) { + id = GHOST_ID_GPS_LAT; + } + setTelemetryValue(PROTOCOL_TELEMETRY_GHOST, id, 0, 0, value, sensor->unit, sensor->precision); } void processGhostTelemetryValueString(const GhostSensor * sensor, const char * str) @@ -105,16 +123,19 @@ bool checkGhostTelemetryFrameCRC() return (crc == telemetryRxBuffer[len + 1]); } +// hifirst uint16_t getTelemetryValue_u16(uint8_t index) { return (telemetryRxBuffer[index] << 8) | telemetryRxBuffer[index + 1]; } +// lofirst uint16_t getTelemetryValue_u16le(uint8_t index) { return (telemetryRxBuffer[index + 1] << 8) | telemetryRxBuffer[index]; } +// hifirst uint32_t getTelemetryValue_s32(uint8_t index) { uint32_t val = 0; @@ -123,6 +144,15 @@ uint32_t getTelemetryValue_s32(uint8_t index) return val; } +// lofirst +uint32_t getTelemetryValue_s32le(uint8_t index) +{ + uint32_t val = 0; + for (int i = 0; i < 4; ++i) + val <<= 8, val |= telemetryRxBuffer[index + 3 - i]; + return val; +} + void processGhostTelemetryFrame() { if (!checkGhostTelemetryFrameCRC()) { @@ -132,6 +162,19 @@ void processGhostTelemetryFrame() uint8_t id = telemetryRxBuffer[2]; switch(id) { + case GHST_DL_OPENTX_SYNC: + { + uint32_t update_interval = getTelemetryValue_s32(3); + int32_t offset = getTelemetryValue_s32(7); + + // values are in units of 100ns + update_interval /= 10; + offset /= 10; + + getModuleSyncStatus(EXTERNAL_MODULE).update(update_interval, offset); + } + break; + case GHST_DL_LINK_STAT: { #if defined(BLUETOOTH) @@ -213,15 +256,40 @@ void processGhostTelemetryFrame() case GHST_DL_PACK_STAT: { #if defined(BLUETOOTH) if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { - bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount); - } + bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount); + } #endif processGhostTelemetryValue(GHOST_ID_PACK_VOLTS, getTelemetryValue_u16le(3)); processGhostTelemetryValue(GHOST_ID_PACK_AMPS, getTelemetryValue_u16le(5)); processGhostTelemetryValue(GHOST_ID_PACK_MAH, getTelemetryValue_u16le(7) * 10); - break; } + + case GHST_DL_GPS_PRIMARY: { +#if defined(BLUETOOTH) + if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { + bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount); + } +#endif + processGhostTelemetryValue(GHOST_ID_GPS_LAT, getTelemetryValue_s32le(3) / 10); + processGhostTelemetryValue(GHOST_ID_GPS_LONG, getTelemetryValue_s32le(7) / 10); + processGhostTelemetryValue(GHOST_ID_GPS_ALT, (int16_t) getTelemetryValue_u16le(11)); + break; + } + + case GHST_DL_GPS_SECONDARY: { +#if defined(BLUETOOTH) + if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { + bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount); + } +#endif + processGhostTelemetryValue(GHOST_ID_GPS_HDG, getTelemetryValue_u16le(5) / 10); + + // ground speed is passed via GHST as cm/s, converted to km/h for OpenTx + processGhostTelemetryValue(GHOST_ID_GPS_GSPD, (getTelemetryValue_u16le(3) * 36 + 50) / 100); + processGhostTelemetryValue(GHOST_ID_GPS_SATS, telemetryRxBuffer[7]); + break; + } } } @@ -272,6 +340,9 @@ void ghostSetDefault(int index, uint8_t id, uint8_t subId) const GhostSensor * sensor = getGhostSensor(id); if (sensor) { TelemetryUnit unit = sensor->unit; + if (unit == UNIT_GPS_LATITUDE || unit == UNIT_GPS_LONGITUDE) { + unit = UNIT_GPS; + } uint8_t prec = min(2, sensor->precision); telemetrySensor.init(sensor->name, unit, prec); } diff --git a/radio/src/telemetry/ghost.h b/radio/src/telemetry/ghost.h index 0a3195835e..36f493b9fa 100755 --- a/radio/src/telemetry/ghost.h +++ b/radio/src/telemetry/ghost.h @@ -44,6 +44,8 @@ #define GHST_DL_VTX_STAT 0x22 #define GHST_DL_PACK_STAT 0x23 #define GHST_DL_MENU_DESC 0x24 +#define GHST_DL_GPS_PRIMARY 0x25 +#define GHST_DL_GPS_SECONDARY 0x26 #define GHST_RC_CTR_VAL_12BIT 0x7C0 // 0x3e0 << 1 #define GHST_RC_CTR_VAL_8BIT 0x7C @@ -113,7 +115,7 @@ enum GhostTelemetryBaudrates }; #endif #define GHOST_BAUDRATE 400000 -#define GHOST_PERIOD 4 +#define GHOST_PERIOD 4000 /* us */ enum GhostLineFlags { diff --git a/radio/src/telemetry/mlink.cpp b/radio/src/telemetry/mlink.cpp new file mode 100644 index 0000000000..a7cdccb92b --- /dev/null +++ b/radio/src/telemetry/mlink.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) OpenTX + * + * 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 "opentx.h" + +struct MLinkSensor +{ + const uint16_t id; + const char * name; + const TelemetryUnit unit; + const uint8_t precision; +}; + +const MLinkSensor mlinkSensors[] = { + {MLINK_RX_VOLTAGE, ZSTR_BATT, UNIT_VOLTS, 1}, + {MLINK_VOLTAGE, ZSTR_VFAS, UNIT_VOLTS, 1}, + {MLINK_CURRENT, ZSTR_CURR, UNIT_AMPS, 1}, + {MLINK_VARIO, ZSTR_VSPD, UNIT_METERS_PER_SECOND, 1}, + {MLINK_SPEED, ZSTR_SPEED, UNIT_KMH, 1}, + {MLINK_RPM, ZSTR_RPM, UNIT_RPMS, 0}, + {MLINK_TEMP, ZSTR_TEMP1, UNIT_CELSIUS, 1}, + {MLINK_HEADING, ZSTR_HDG, UNIT_DEGREE, 1}, + {MLINK_ALT, ZSTR_ALT , UNIT_METERS, 0}, + {MLINK_FUEL, ZSTR_FUEL, UNIT_PERCENT, 0}, + {MLINK_CAPACITY, ZSTR_CAPACITY, UNIT_MAH, 0}, + {MLINK_FLOW, ZSTR_FLOW, UNIT_MILLILITERS, 0}, + {MLINK_DISTANCE, ZSTR_DIST, UNIT_KM, 1}, + {MLINK_LQI, ZSTR_RSSI, UNIT_RAW, 0}, + {MLINK_LOSS, ZSTR_LOSS, UNIT_RAW, 0}, + {MLINK_TX_RSSI, ZSTR_TX_RSSI, UNIT_RAW, 0}, + {MLINK_TX_LQI, ZSTR_TX_QUALITY, UNIT_RAW, 0}, +}; + +const MLinkSensor * getMLinkSensor(uint16_t id) +{ + for (const MLinkSensor * sensor = mlinkSensors; sensor->id; sensor++) { + if (id == sensor->id) + return sensor; + } + return nullptr; +} + +void processMLinkPacket(const uint8_t * packet) +{ + const uint8_t * data = packet + 2; + + // Multi telem + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TX_RSSI, 0, 0, (packet[0] * 100) / 31, UNIT_RAW, 0); + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TX_LQI, 0, 0, packet[1], UNIT_RAW, 0); + + // M-Link telem + if (data[0] == 0x13) { // Telemetry type RX-9 + for (uint8_t i = 1; i < 5; i += 3) { //2 sensors per packet + int32_t val = (int16_t )(data[i + 2] << 8 | data[i + 1]); + val = val >> 1; // remove alarm flag + uint8_t adress = (data[i] & 0xF0) >> 4; + switch (data[i] & 0x0F) { + case MLINK_VOLTAGE: + if ((data[i] & 0xF0) == 0x00){ + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_RX_VOLTAGE, 0, adress, val, UNIT_VOLTS, 1); + } + else { + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_VOLTAGE, 0, adress, val, UNIT_VOLTS, 1); + } + break; + case MLINK_CURRENT: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_CURRENT, 0, adress, val, UNIT_AMPS, 1); + break; + case MLINK_VARIO: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_VARIO, 0, adress, val, UNIT_METERS_PER_SECOND, 1); + break; + case MLINK_SPEED: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_SPEED, 0, adress, val, UNIT_KMH, 1); + break; + case MLINK_RPM: + if (val < 0) { + val = -val * 10; + } + else { + val = val * 100; + } + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_RPM, 0, adress, val, UNIT_RPMS, 0); + break; + case MLINK_TEMP: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_TEMP, 0, adress, val, UNIT_CELSIUS, 1); + break; + case MLINK_HEADING: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_HEADING, 0, adress, val, UNIT_DEGREE, 1); + break; + case MLINK_ALT: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_ALT, 0, adress, val, UNIT_METERS, 0); + break; + case MLINK_FUEL: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_FUEL, 0, adress, val, UNIT_PERCENT, 0); + break; + case MLINK_CAPACITY: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_CAPACITY, 0, adress, val, UNIT_MAH, 0); + break; + case MLINK_FLOW: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_FLOW, 0, adress, val, UNIT_MILLILITERS, 0); + break; + case MLINK_DISTANCE: + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_DISTANCE, 0, adress, val, UNIT_KM, 1); + break; + case MLINK_LQI: + uint8_t mlinkRssi = data[i + 1] >> 1; + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_LQI, 0, 0, mlinkRssi, UNIT_RAW, 0); + telemetryData.rssi.set(mlinkRssi); + if (mlinkRssi > 0) { + telemetryStreaming = TELEMETRY_TIMEOUT10ms; + } + break; + } + } + } + else if (packet[2] == 0x03) { // Telemetry type RX-5 + uint16_t mlinkRssi = (packet[4] * 100) / 35; + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_LQI, 0, 0, mlinkRssi, UNIT_RAW, 0); + telemetryData.rssi.set(mlinkRssi); + if (mlinkRssi > 0) { + telemetryStreaming = TELEMETRY_TIMEOUT10ms; + } + setTelemetryValue(PROTOCOL_TELEMETRY_MLINK, MLINK_LOSS, 0, 0, packet[7], UNIT_RAW, 0); + } +} + +void mlinkSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance) +{ + TelemetrySensor &telemetrySensor = g_model.telemetrySensors[index]; + telemetrySensor.id = id; + telemetrySensor.subId = subId; + telemetrySensor.instance = instance; + + const MLinkSensor * sensor = getMLinkSensor(id); + if (sensor) { + TelemetryUnit unit = sensor->unit; + uint8_t prec = min(2, sensor->precision); + telemetrySensor.init(sensor->name, unit, prec); + if (unit == UNIT_RPMS) { + telemetrySensor.custom.ratio = 1; + telemetrySensor.custom.offset = 1; + } + } + else { + telemetrySensor.init(id); + } + + storageDirty(EE_MODEL); +} diff --git a/radio/src/telemetry/mlink.h b/radio/src/telemetry/mlink.h new file mode 100644 index 0000000000..eb5da955e1 --- /dev/null +++ b/radio/src/telemetry/mlink.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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. + */ + +#pragma once + +enum { + MLINK_VOLTAGE = 1, + MLINK_CURRENT = 2, + MLINK_VARIO = 3, + MLINK_SPEED = 4, + MLINK_RPM = 5, + MLINK_TEMP = 6, + MLINK_HEADING = 7, + MLINK_ALT = 8, + MLINK_FUEL = 9, + MLINK_LQI = 10, + MLINK_CAPACITY = 11, + MLINK_FLOW = 12, + MLINK_DISTANCE = 13, + MLINK_RX_VOLTAGE = 16, // out of range ID for specific RxBt treatment + MLINK_LOSS = 17, // out of range ID for handling number of loss + MLINK_TX_RSSI = 18, // out of range ID for handling Telemetry RSSi reported by multi + MLINK_TX_LQI = 19, // out of range ID for handling Telemetry LQI reported by multi +}; + +void processMLinkTelemetryData(uint8_t data, uint8_t* rxBuffer, uint8_t& rxBufferCount); +void mlinkSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance); + +// Used by multi protocol +void processMLinkPacket(const uint8_t *packet); diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index 409ce057ea..b9972e240d 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -42,6 +42,7 @@ enum MultiPacketTypes : uint8_t FlyskyIBusTelemetryAC, MultiRxChannels, HottTelemetry, + MLinkTelemetry }; enum MultiBufferState : uint8_t @@ -63,7 +64,6 @@ enum MultiBufferState : uint8_t #if defined(INTERNAL_MODULE_MULTI) static MultiModuleStatus multiModuleStatus[NUM_MODULES] = {MultiModuleStatus(), MultiModuleStatus()}; -static MultiModuleSyncStatus multiSyncStatus[NUM_MODULES] = {MultiModuleSyncStatus(), MultiModuleSyncStatus()}; static uint8_t multiBindStatus[NUM_MODULES] = {MULTI_BIND_NONE, MULTI_BIND_NONE}; static MultiBufferState multiTelemetryBufferState[NUM_MODULES]; @@ -74,11 +74,6 @@ MultiModuleStatus &getMultiModuleStatus(uint8_t module) return multiModuleStatus[module]; } -MultiModuleSyncStatus &getMultiSyncStatus(uint8_t module) -{ - return multiSyncStatus[module]; -} - uint8_t getMultiBindStatus(uint8_t module) { return multiBindStatus[module]; @@ -111,7 +106,6 @@ uint8_t intTelemetryRxBufferCount; #else // !INTERNAL_MODULE_MULTI static MultiModuleStatus multiModuleStatus; -static MultiModuleSyncStatus multiSyncStatus; static uint8_t multiBindStatus = MULTI_BIND_NONE; static MultiBufferState multiTelemetryBufferState; @@ -122,11 +116,6 @@ MultiModuleStatus& getMultiModuleStatus(uint8_t) return multiModuleStatus; } -MultiModuleSyncStatus& getMultiSyncStatus(uint8_t) -{ - return multiSyncStatus; -} - uint8_t getMultiBindStatus(uint8_t) { return multiBindStatus; @@ -254,23 +243,14 @@ static void processMultiStatusPacket(const uint8_t * data, uint8_t module, uint8 static void processMultiSyncPacket(const uint8_t * data, uint8_t module) { - MultiModuleSyncStatus &status = getMultiSyncStatus(module); + ModuleSyncStatus &status = getModuleSyncStatus(module); - status.lastUpdate = get_tmr10ms(); - status.interval = data[4]; - status.target = data[5]; -#if !defined(PPM_PIN_SERIAL) - auto oldlag = status.inputLag; - (void) oldlag; -#endif + uint16_t refreshRate = data[0] << 8 | data[1]; + int16_t inputLag = data[2] << 8 | data[3]; - status.calcAdjustedRefreshRate(data[0] << 8 | data[1], data[2] << 8 | data[3]); - -#if !defined(PPM_PIN_SERIAL) - TRACE("MP ADJ: rest: %d, lag %04d, diff: %04d target: %d, interval: %d, Refresh: %d, intAdjRefresh: %d, adjRefresh %d\r\n", - module == EXTERNAL_MODULE ? extmodulePulsesData.dsm2.rest : 0, - status.inputLag, oldlag - status.inputLag, status.target, status.interval, status.refreshRate, status.adjustedRefreshRate / 50, - status.getAdjustedRefreshRate()); + status.update(refreshRate, inputLag); +#if defined(DEBUG) + serialPrint("MP ADJ: R %d, L %04d", refreshRate, inputLag); #endif } @@ -379,6 +359,13 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) TRACE("[MP] Received HoTT telemetry len %d < 14", len); break; + case MLinkTelemetry: + if (len > 6) + processMLinkPacket(data); + else + TRACE("[MP] Received M-Link telemetry len %d < 6", len); + break; + case FrSkyHubTelemetry: if (len >= 4) frskyDProcessPacket(data); @@ -434,104 +421,6 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) } } -#define MIN_REFRESH_RATE 5500 - -void MultiModuleSyncStatus::calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag) -{ - // Check how far off we are from our target, positive means we are too slow, negative we are too fast - int lagDifference = newInputLag - inputLag; - - // The refresh rate that we target - // Below is least common multiple of MIN_REFRESH_RATE and requested rate - uint16_t targetRefreshRate = (uint16_t) (newRefreshRate * ((MIN_REFRESH_RATE / (newRefreshRate - 1)) + 1)); - - // Overflow, reverse sample - if (lagDifference < -targetRefreshRate / 2) - lagDifference = -lagDifference; - - - // Reset adjusted refresh if rate has changed - if (newRefreshRate != refreshRate) { - refreshRate = newRefreshRate; - adjustedRefreshRate = targetRefreshRate; - if (adjustedRefreshRate >= 30000) - adjustedRefreshRate /= 2; - - // Our refresh rate in ps - adjustedRefreshRate *= 1000; - return; - } - - // Caluclate how many samples went into the reported input Lag (*10) - int numsamples = interval * 10000 / targetRefreshRate; - - // Convert lagDifference to ps - lagDifference = lagDifference * 1000; - - // Calculate the time we intentionally were late/early - if (inputLag > target * 10 + 30) - lagDifference += numsamples * 500; - else if (inputLag < target * 10 - 30) - lagDifference -= numsamples * 500; - - // Caculate the time in ps each frame is to slow (positive), fast(negative) - int perframeps = lagDifference * 10 / numsamples; - - if (perframeps > 20000) - perframeps = 20000; - - if (perframeps < -20000) - perframeps = -20000; - - adjustedRefreshRate = (adjustedRefreshRate + perframeps); - - // Safeguards - if (adjustedRefreshRate < MIN_REFRESH_RATE * 1000) - adjustedRefreshRate = MIN_REFRESH_RATE * 1000; - if (adjustedRefreshRate > 30 * 1000 * 1000) - adjustedRefreshRate = 30 * 1000 * 1000; - - inputLag = newInputLag; -} - -static uint8_t counter; - -const uint16_t MultiModuleSyncStatus::getAdjustedRefreshRate() -{ - if (!isValid() || refreshRate == 0) - return 18000; - - counter = (uint8_t) (counter + 1 % 10); - uint16_t rate = (uint16_t) ((adjustedRefreshRate + counter * 50) / 500); - // Check how far off we are from our target, positive means we are too slow, negative we are too fast - if (inputLag > target * 10 + 30) - return (uint16_t) (rate - 1); - else if (inputLag < target * 10 - 30) - return (uint16_t) (rate + 1); - else - return rate; -} - -void MultiModuleSyncStatus::getRefreshString(char * statusText) -{ - if (!isValid()) { - return; - } - - char * tmp = statusText; -#if defined(DEBUG) - *tmp++ = 'L'; - tmp = strAppendUnsigned(tmp, inputLag, 5); - tmp = strAppend(tmp, "us R "); - tmp = strAppendUnsigned(tmp, (uint32_t) (adjustedRefreshRate / 1000), 5); - tmp = strAppend(tmp, STR_US); -#else - tmp = strAppend(tmp, "Sync at "); - tmp = strAppendUnsigned(tmp, (uint32_t) (adjustedRefreshRate / 1000000)); - tmp = strAppend(tmp, " ms"); -#endif -} - void MultiModuleStatus::getStatusString(char * statusText) const { if (!isValid()) { diff --git a/radio/src/telemetry/multi.h b/radio/src/telemetry/multi.h index 9c256ffb1c..c97d70fab6 100644 --- a/radio/src/telemetry/multi.h +++ b/radio/src/telemetry/multi.h @@ -94,28 +94,6 @@ void processMultiTelemetryData(uint8_t data, uint8_t module); #define MULTI_SCANNER_MAX_CHANNEL 249 -// This should be put into the Module definition if other modules gain this functionality -struct MultiModuleSyncStatus { - uint32_t adjustedRefreshRate = 9000 * 1000; // in ps - tmr10ms_t lastUpdate; - uint16_t refreshRate; - uint16_t inputLag; - uint8_t interval; - uint8_t target; - - inline bool isValid() const - { - return (get_tmr10ms() - lastUpdate < 100); - } - - void getRefreshString(char * refreshText); - const uint16_t getAdjustedRefreshRate(); - void calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag); -}; - -MultiModuleSyncStatus& getMultiSyncStatus(uint8_t module); - - struct MultiModuleStatus { uint8_t major; diff --git a/radio/src/telemetry/telemetry.cpp b/radio/src/telemetry/telemetry.cpp index 3979ecb0e7..c32cd491c0 100644 --- a/radio/src/telemetry/telemetry.cpp +++ b/radio/src/telemetry/telemetry.cpp @@ -21,6 +21,7 @@ #include "opentx.h" #include "multi.h" #include "pulses/afhds3.h" +#include "mixer_scheduler.h" uint8_t telemetryStreaming = 0; uint8_t telemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE]; // Receive buffer. 9 bytes (full packet), worst case 18 bytes with byte-stuffing (+1) @@ -373,3 +374,86 @@ OutputTelemetryBuffer outputTelemetryBuffer __DMA; #if defined(LUA) Fifo * luaInputTelemetryFifo = NULL; #endif + +#if defined(HARDWARE_INTERNAL_MODULE) +static ModuleSyncStatus moduleSyncStatus[NUM_MODULES]; + +ModuleSyncStatus &getModuleSyncStatus(uint8_t moduleIdx) +{ + return moduleSyncStatus[moduleIdx]; +} +#else +static ModuleSyncStatus moduleSyncStatus; + +ModuleSyncStatus &getModuleSyncStatus(uint8_t moduleIdx) +{ + return moduleSyncStatus; +} +#endif + +ModuleSyncStatus::ModuleSyncStatus() +{ + memset(this, 0, sizeof(ModuleSyncStatus)); +} + +void ModuleSyncStatus::update(uint16_t newRefreshRate, uint16_t newInputLag) +{ + if (!newRefreshRate) + return; + + if (newRefreshRate < MIN_REFRESH_RATE) + newRefreshRate = newRefreshRate * (MIN_REFRESH_RATE / (newRefreshRate + 1)); + else if (newRefreshRate > MAX_REFRESH_RATE) + newRefreshRate = MAX_REFRESH_RATE; + + refreshRate = newRefreshRate; + inputLag = newInputLag; + currentLag = newInputLag; + lastUpdate = get_tmr10ms(); + + TRACE("[SYNC] update rate = %dus; lag = %dus",refreshRate,currentLag); +} + +uint16_t ModuleSyncStatus::getAdjustedRefreshRate() +{ + int16_t lag = currentLag; + int32_t newRefreshRate = refreshRate; + + if (lag == 0) { + return refreshRate; + } + + newRefreshRate += lag; + + if (newRefreshRate < MIN_REFRESH_RATE) { + newRefreshRate = MIN_REFRESH_RATE; + } + else if (newRefreshRate > MAX_REFRESH_RATE) { + newRefreshRate = MAX_REFRESH_RATE; + } + + currentLag -= newRefreshRate - refreshRate; + TRACE("[SYNC] mod rate = %dus; lag = %dus",newRefreshRate,currentLag); + + return (uint16_t)newRefreshRate; +} + +void ModuleSyncStatus::getRefreshString(char * statusText) +{ + if (!isValid()) { + return; + } + + char * tmp = statusText; +#if defined(DEBUG) + *tmp++ = 'L'; + tmp = strAppendUnsigned(tmp, inputLag, 5); + tmp = strAppend(tmp, "us R "); + tmp = strAppendUnsigned(tmp, (uint32_t) (refreshRate / 1000), 5); + tmp = strAppend(tmp, "us"); +#else + tmp = strAppend(tmp, "Sync at "); + tmp = strAppendUnsigned(tmp, (uint32_t) (refreshRate / 1000000)); + tmp = strAppend(tmp, " ms"); +#endif +} diff --git a/radio/src/telemetry/telemetry.h b/radio/src/telemetry/telemetry.h index bafb0dc075..f2a3fc98a0 100644 --- a/radio/src/telemetry/telemetry.h +++ b/radio/src/telemetry/telemetry.h @@ -34,6 +34,7 @@ #include "hitec.h" #include "hott.h" #include "multi.h" + #include "mlink.h" #endif #include "myeeprom.h" #if defined(MULTIMODULE) || defined(AFHDS3) @@ -291,4 +292,33 @@ extern Fifo * luaInputTelemetryFifo; void processPXX2Frame(uint8_t module, const uint8_t *frame); +// Module pulse synchronization +struct ModuleSyncStatus +{ + // feedback input: last received values + uint16_t refreshRate; // in us + int16_t inputLag; // in us + + tmr10ms_t lastUpdate; // in 10ms + int16_t currentLag; // in us + + inline bool isValid() { + // 2 seconds + return (get_tmr10ms() - lastUpdate < 200); + } + + // Set feedback from RF module + void update(uint16_t newRefreshRate, uint16_t newInputLag); + + // Get computed settings for scheduler + uint16_t getAdjustedRefreshRate(); + + // Status string for the UI + void getRefreshString(char* refreshText); + + ModuleSyncStatus(); +}; + +ModuleSyncStatus& getModuleSyncStatus(uint8_t moduleIdx); + #endif // _TELEMETRY_H_ diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index e88807062a..b439bd6786 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -559,6 +559,10 @@ int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, ui case PROTOCOL_TELEMETRY_HOTT: hottSetDefault(index, id, subId, instance); break; + + case PROTOCOL_TELEMETRY_MLINK: + mlinkSetDefault(index, id, subId, instance); + break; #endif #if defined(LUA) diff --git a/radio/src/tests/fonts_480x272.png b/radio/src/tests/fonts_480x272.png index abd3e1f72f..94d4237b5e 100644 Binary files a/radio/src/tests/fonts_480x272.png and b/radio/src/tests/fonts_480x272.png differ diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 00029ebb2e..4d4075bb56 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -86,6 +86,7 @@ ISTR(SPORT_UPDATE_POWER_MODES); ISTR(CRSF_BAUDRATE); ISTR(PPM_POL); ISTR(SBUS_INVERSION_VALUES); +ISTR(SPORT_MODES); #if defined(PCBSKY9X) && defined(REVX) ISTR(VOUTPUT_TYPE); @@ -98,6 +99,8 @@ ISTR(VSWASHTYPE); #if defined(MULTIMODULE) ISTR(MULTI_PROTOCOLS); ISTR(MULTI_POWER); +ISTR(MULTI_TELEMETRY_MODE); +ISTR(MULTI_WBUS_MODE); #endif #if defined(BLUETOOTH) @@ -832,6 +835,7 @@ const char STR_BIND_OK[] = TR_BIND_OK; const char STR_MULTI_CUSTOM[] = TR_MULTI_CUSTOM; const char STR_MULTI_RFTUNE[] = TR_MULTI_RFTUNE; const char STR_MULTI_RFPOWER[] = TR_MULTI_RFPOWER; +const char STR_MULTI_WBUS[] = TR_MULTI_WBUS; const char STR_MULTI_TELEMETRY[] = TR_MULTI_TELEMETRY; const char STR_MULTI_VIDFREQ[] = TR_MULTI_VIDFREQ; const char STR_MULTI_OPTION[] = TR_MULTI_OPTION; @@ -957,3 +961,4 @@ const char STR_ABOUT_PARENTS_3[] = TR_ABOUT_PARENTS_3; const char STR_ABOUT_PARENTS_4[] = TR_ABOUT_PARENTS_4; const char STR_AUTH_FAILURE[] = TR_AUTH_FAILURE; +const char STR_PROTOCOL[] = TR_PROTOCOL; diff --git a/radio/src/translations.h b/radio/src/translations.h index 04fd1d9f2d..755c6bca45 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -171,6 +171,9 @@ extern const char STR_SBUS_INVERSION_VALUES[]; extern const char STR_MULTI_PROTOCOLS[]; extern const char STR_MULTI_POWER[]; +extern const char STR_MULTI_TELEMETRY_MODE[]; +extern const char STR_MULTI_WBUS_MODE[]; +extern const char STR_SPORT_MODES[]; extern const char STR_AFHDS3_ONE_TO_ONE_TELEMETRY[]; extern const char STR_AFHDS3_ONE_TO_MANY[]; @@ -426,6 +429,7 @@ extern const char STR_MULTI_OPTION[]; extern const char STR_MULTI_VIDFREQ[]; extern const char STR_MULTI_RFTUNE[]; extern const char STR_MULTI_RFPOWER[]; +extern const char STR_MULTI_WBUS[]; extern const char STR_MULTI_TELEMETRY[]; extern const char STR_MULTI_AUTOBIND[]; extern const char STR_DISABLE_CH_MAP[]; @@ -1096,6 +1100,7 @@ extern const char STR_ABOUT_PARENTS_3[]; extern const char STR_ABOUT_PARENTS_4[]; extern const char STR_AUTH_FAILURE[]; +extern const char STR_PROTOCOL[]; #define CHR_HOUR TR_CHR_HOUR #define CHR_INPUT TR_CHR_INPUT diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index df4680df01..c235a77b53 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -263,7 +263,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\010") #define TR_VUNITSSYSTEM TR("Metr.\0""Imper.", "Metrické""Imperial") #define LEN_VTELEMUNIT "\003" -#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" +#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -291,12 +291,15 @@ #if defined(PCBHORUS) #define LEN_VKEYS "\005" #define TR_VKEYS "PGUP\0""PGDN\0""ENTER""MDL\0 ""RTN\0 ""TELE\0""SYS\0 " -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Dolů\0""Nhoru""Vprvo""Vlevo" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Mínus" @@ -450,7 +453,7 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Výstup" #endif -#define TR_PROTO INDENT "Protokol" +#define TR_PROTOCOL "Protokol" #define TR_PPMFRAME INDENT "PPM modulace" #define TR_REFRESHRATE TR(INDENT "Obnovit", INDENT "Obn. frekv.") #define STR_WARN_BATTVOLTAGE TR(INDENT "Výstup VBAT: ", INDENT "Varování: výstupní hodnota VBAT: ") @@ -661,6 +664,7 @@ #define TR_RECEIVER "Přijímač" #define TR_MULTI_RFTUNE TR(INDENT "Ladění frek", INDENT "Jemné ladění frek. RF") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetrie" #define TR_MULTI_VIDFREQ TR(INDENT "Freq. videa", INDENT "Frekvence videa") #define TR_RF_POWER INDENT "Výkon RF" @@ -809,7 +813,7 @@ #define TR_NO_MODELS_ON_SD "žádný model" BREAKSPACE "na SD" #define TR_NO_BITMAPS_ON_SD "žádné obrázky" BREAKSPACE "na SD" #define TR_NO_SCRIPTS_ON_SD "žádný skript" BREAKSPACE "na SD" -#define TR_SCRIPT_SYNTAX_ERROR "Syntaktická chyba skriptu" +#define TR_SCRIPT_SYNTAX_ERROR TR("Syntaktická chyba", "Syntaktická chyba skriptu") #define TR_SCRIPT_PANIC "Script zmaten" #define TR_SCRIPT_KILLED "Script ukončen" #define TR_SCRIPT_ERROR "Neznámá chyba" @@ -1410,3 +1414,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index 6edf51683b..901f1a1108 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -266,7 +266,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\012") #define TR_VUNITSSYSTEM TR("Metrik""Imper.", "Metrisch\0 ""Imperial\0 ") #define LEN_VTELEMUNIT "\003" - #define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" + #define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -297,12 +297,15 @@ #elif defined(PCBXLITE) #define LEN_VKEYS "\005" #define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" @@ -455,8 +458,8 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Output" #endif -#define TR_PROTO TR(INDENT "Protok.", INDENT "Protokoll") - #define TR_PPMFRAME INDENT "PPM-Frame" +#define TR_PROTOCOL TR("Protok.", "Protokoll") +#define TR_PPMFRAME INDENT "PPM-Frame" #define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate") #define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ") #define TR_WARN_5VOLTS "Warning: output level is 5 volts" @@ -667,6 +670,7 @@ #define TR_RECEIVER "Empfänger" #define TR_MULTI_RFTUNE TR(INDENT "RF Freq.", INDENT "RF Freq. Feintuning") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetry" #define TR_MULTI_VIDFREQ TR(INDENT "Vid. Freq.", INDENT "Video Frequenz") #define TR_RF_POWER INDENT "RF Power" @@ -814,7 +818,7 @@ #define TR_NO_MODELS_ON_SD "Kein Modelle" BREAKSPACE "auf SD" #define TR_NO_BITMAPS_ON_SD "Keine Bitmaps" BREAKSPACE "auf SD" #define TR_NO_SCRIPTS_ON_SD "Keine Skripte" BREAKSPACE "auf SD" -#define TR_SCRIPT_SYNTAX_ERROR "Skript Syntaxfehler" +#define TR_SCRIPT_SYNTAX_ERROR TR("Syntaxfehler", "Skript Syntaxfehler") #define TR_SCRIPT_PANIC "Skript Panik" #define TR_SCRIPT_KILLED "Skript beendet" #define TR_SCRIPT_ERROR "Unbekannter Fehler" @@ -1420,3 +1424,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 946ad558e2..084dba46c4 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -266,7 +266,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\010") #define TR_VUNITSSYSTEM TR("Metric""Imper.", "Metric\0 ""Imperial") #define LEN_VTELEMUNIT "\003" -#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" +#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -297,12 +297,15 @@ #elif defined(PCBXLITE) #define LEN_VKEYS "\005" #define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" @@ -454,7 +457,7 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Output" #endif -#define TR_PROTO TR(INDENT "Proto", INDENT "Protocol") +#define TR_PROTOCOL TR("Proto", "Protocol") #define TR_PPMFRAME INDENT "PPM frame" #define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate") #define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ") @@ -665,6 +668,7 @@ #define TR_RECEIVER "Receiver" #define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetry" #define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency") #define TR_RF_POWER "RF Power" @@ -818,7 +822,7 @@ #define TR_NO_MODELS_ON_SD "No models" BREAKSPACE "on SD" #define TR_NO_BITMAPS_ON_SD "No bitmaps" BREAKSPACE "on SD" #define TR_NO_SCRIPTS_ON_SD "No scripts" BREAKSPACE "on SD" -#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" +#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error") #define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_KILLED "Script killed" #define TR_SCRIPT_ERROR "Unknown error" @@ -1424,3 +1428,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 564e7ef1a5..34065eeb42 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -263,7 +263,7 @@ #define LEN_VUNITSSYSTEM "\010" #define TR_VUNITSSYSTEM "Métrico\0""Imperial" #define LEN_VTELEMUNIT "\003" -#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" +#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -294,12 +294,15 @@ #elif defined(PCBXLITE) #define LEN_VKEYS "\005" #define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" @@ -453,7 +456,7 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Output" #endif -#define TR_PROTO TR(INDENT"Proto",INDENT"Protocolo") +#define TR_PROTOCOL TR("Proto", "Protocolo") #define TR_PPMFRAME INDENT "Trama PPM" #define TR_REFRESHRATE TR(INDENT "Refresco", INDENT "Velocidad refresco") #define STR_WARN_BATTVOLTAGE TR(INDENT "Salida es VBAT: ", INDENT "Aviso: señal salida es VBAT: ") @@ -668,6 +671,7 @@ #define TR_RECEIVER "Receptor" #define TR_MULTI_RFTUNE TR("Sint.freq.", "RF Freq. sint.fina") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetría" #define TR_MULTI_VIDFREQ TR("Freq.vídeo", "Frecuencia vídeo") #define TR_RF_POWER "RF Power" @@ -816,7 +820,7 @@ #define TR_NO_MODELS_ON_SD "Sin modelos en SD" #define TR_NO_BITMAPS_ON_SD "Sin imágenes en SD" #define TR_NO_SCRIPTS_ON_SD "No scripts en SD" -#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" +#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error") #define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_KILLED "Script killed" #define TR_SCRIPT_ERROR "Error desconocido" @@ -1418,3 +1422,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 7459d89098..ab2d5bafe5 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -284,7 +284,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\010") #define TR_VUNITSSYSTEM TR("Metric""Imper.", "Metric\0 ""Imperial") #define LEN_VTELEMUNIT "\003" -#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" +#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -315,12 +315,15 @@ #elif defined(PCBXLITE) #define LEN_VKEYS "\005" #define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" @@ -467,7 +470,7 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Output" #endif -#define TR_PROTO TR(INDENT "Proto", INDENT "Protocol") +#define TR_PROTOCOL TR("Proto", "Protocol") #define TR_PPMFRAME TR("PPM frame", INDENT "PPM frame") #define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate") #define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ") @@ -682,6 +685,7 @@ #define TR_RECEIVER "Receiver" #define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetry" #define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency") #define TR_RF_POWER "RF Power" @@ -830,7 +834,7 @@ #define TR_NO_MODELS_ON_SD "No Models on SD" #define TR_NO_BITMAPS_ON_SD "No Bitmaps on SD" #define TR_NO_SCRIPTS_ON_SD "No Scripts on SD" -#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" +#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error") #define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_KILLED "Script killed" #define TR_SCRIPT_ERROR "Unknown error" @@ -1424,3 +1428,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index a49f803ac6..2d46264777 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -286,7 +286,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\012") #define TR_VUNITSSYSTEM TR("Métr.\0""Impér.", "Métriques\0""Impériales") #define LEN_VTELEMUNIT "\003" -#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" +#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -317,12 +317,15 @@ #elif defined(PCBXLITE) #define LEN_VKEYS "\005" #define TR_VKEYS "Shift""Exit\0""Enter""Bas\0 ""Haut\0""Droit""Gauch" -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Moins" @@ -473,8 +476,8 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Sortie" #endif -#define TR_PROTO TR(INDENT "Proto.", INDENT "Protocole") - #define TR_PPMFRAME INDENT "Trame PPM" +#define TR_PROTOCOL TR("Proto.", "Protocole") +#define TR_PPMFRAME INDENT "Trame PPM" #define TR_REFRESHRATE INDENT "Période" #define STR_WARN_BATTVOLTAGE TR(INDENT "Signal est VBAT: ", INDENT "ATTENTION: signal est à VBAT: ") #define TR_WARN_5VOLTS "Warning: output level is 5 volts" @@ -688,6 +691,7 @@ #define TR_RECEIVER "Récept." #define TR_MULTI_RFTUNE TR(INDENT "Ajust.fréq", INDENT "Ajustement fréq.") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Télémétrie" #define TR_MULTI_VIDFREQ TR(INDENT "Fréq. vidéo", INDENT "Fréquence vidéo") #define TR_RF_POWER TR("Puiss. RF", "Puissance RF") @@ -835,7 +839,7 @@ #define TR_NO_MODELS_ON_SD "Aucun modèle SD" #define TR_NO_BITMAPS_ON_SD "Aucun Bitmap SD" #define TR_NO_SCRIPTS_ON_SD "Aucun Script SD" -#define TR_SCRIPT_SYNTAX_ERROR "Erreur syntaxe script" +#define TR_SCRIPT_SYNTAX_ERROR TR("Erreur syntaxe", "Erreur syntaxe script") #define TR_SCRIPT_PANIC "Script bloqué" #define TR_SCRIPT_KILLED "Script interrompu" #define TR_SCRIPT_ERROR "Erreur inconnue" @@ -1449,3 +1453,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index 9842dc7edf..c13fd5dbaf 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -290,7 +290,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\011") #define TR_VUNITSSYSTEM TR("Metric""Imper.", "Metriche\0""Imperiali") #define LEN_VTELEMUNIT "\003" -#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" +#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -321,12 +321,15 @@ #elif defined(PCBXLITE) #define LEN_VKEYS "\005" #define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" @@ -474,12 +477,12 @@ #define TR_TTRIM TR("Trim Mot.", INDENT "Trim Motore") #define TR_TTRIM_SW TR("T-Trim-Sw", INDENT "Trim switch") #define TR_BEEPCTR TR("Beep al c.", "Beep al centro") -#define TR_USE_GLOBAL_FUNCS "Usa Funz. Globali" +#define TR_USE_GLOBAL_FUNCS TR("Funz. Glob.", "Usa Funz. Globali") #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Uscita" #endif -#define TR_PROTO TR(INDENT "Protoc.", INDENT "Protocollo") - #define TR_PPMFRAME INDENT "Frame PPM" +#define TR_PROTOCOL TR("Protoc.", "Protocollo") +#define TR_PPMFRAME INDENT "Frame PPM" #define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate") #define STR_WARN_BATTVOLTAGE TR(INDENT "Uscita VBAT: ", INDENT "Att.: livel. uscita VBAT: ") #define TR_WARN_5VOLTS "Attenzione: il livello d'uscita è 5 Volts" @@ -688,6 +691,7 @@ #define TR_RECEIVER "Ricevente" #define TR_MULTI_RFTUNE TR("Tune RF", "Tune fine Freq. RF") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetria" #define TR_MULTI_VIDFREQ TR("Freq. video", "Frequenza video") #define TR_RF_POWER "Potenza RF" @@ -836,7 +840,7 @@ #define TR_NO_MODELS_ON_SD "No Model." BREAKSPACE "su SD" #define TR_NO_BITMAPS_ON_SD "No Immag." BREAKSPACE "su SD" #define TR_NO_SCRIPTS_ON_SD "No Scripts" BREAKSPACE "su SD" -#define TR_SCRIPT_SYNTAX_ERROR "Script errore sintassi" +#define TR_SCRIPT_SYNTAX_ERROR TR("Errore sintassi", "Script errore sintassi") #define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_KILLED "Script fermato" #define TR_SCRIPT_ERROR "Errore sconosciuto" @@ -903,28 +907,28 @@ #define TR_FLASH_EXTERNAL_MODULE TR("Prog. modulo est.", "Programma modulo esterno") #define TR_FLASH_INTERNAL_MULTI TR("Prog. MULTI int.", "Programma MULTI interno") #define TR_FLASH_EXTERNAL_MULTI TR("Prog. MULTI est.", "Programma MULTI esterno") -#define TR_FIRMWARE_UPDATE_ERROR TR(INDENT "Errore agg. FW",INDENT "Errore aggiornamento firmware") +#define TR_FIRMWARE_UPDATE_ERROR TR(INDENT "Errore agg. FW",INDENT "Errore aggiornamento firmware") #define TR_FIRMWARE_UPDATE_SUCCESS "Aggiornamento" BREAKSPACE "riuscito" -#define TR_WRITING "Scrittura..." -#define TR_CONFIRM_FORMAT "Confermi formattazione?" -#define TR_INTERNALRF "Modulo interno" +#define TR_WRITING "Scrittura..." +#define TR_CONFIRM_FORMAT "Confermi formattazione?" +#define TR_INTERNALRF "Modulo interno" #define TR_INTERNAL_MODULE TR("Modulo int.", "Modulo interno") #define TR_EXTERNAL_MODULE TR("Modulo est.", "Modulo esterno") #define TR_OPENTX_UPGRADE_REQUIRED "OpenTX richiede aggiornamento" #define TR_TELEMETRY_DISABLED TR("Telem. off", "Telem. disabilitata") #define TR_MORE_OPTIONS_AVAILABLE "Altre opzioni assenti" #define TR_NO_MODULE_INFORMATION "Nessuna info del modulo" -#define TR_EXTERNALRF "Modulo esterno" -#define TR_FAILSAFE "Modo failsafe" -#define TR_FAILSAFESET TR(INDENT "FAILSAFE", INDENT "IMPOSTAZIONI FAILSAFE") +#define TR_EXTERNALRF "Modulo esterno" +#define TR_FAILSAFE TR(INDENT "Failsafe", INDENT "Modo failsafe") +#define TR_FAILSAFESET TR(INDENT "FAILSAFE", INDENT "IMPOSTAZIONI FAILSAFE") #define TR_REG_ID "Reg. ID" #define TR_OWNER_ID "Owner ID" #define TR_PINMAPSET "PINMAP" -#define TR_HOLD "Hold" +#define TR_HOLD "Hold" #define TR_HOLD_UPPERCASE "HOLD" -#define TR_NONE "None" +#define TR_NONE "None" #define TR_NONE_UPPERCASE "NONE" -#define TR_MENUSENSOR "SENSORE" +#define TR_MENUSENSOR "SENSORE" #define TR_POWERMETER_PEAK "Picco" #define TR_POWERMETER_POWER "Potenza" #define TR_POWERMETER_ATTN "Att." @@ -968,7 +972,7 @@ #define TR_SPEAKER INDENT "Speaker" #define TR_BUZZER INDENT "Buzzer" #define TR_BYTES "Bytes" -#define TR_MODULE_BIND "[Bind]" +#define TR_MODULE_BIND TR("[Bnd]","[Bind]") #define TR_POWERMETER_ATTN_NEEDED "Attenuatore necessario" #define TR_PXX2_SELECT_RX "Seleziona RX..." #define TR_PXX2_DEFAULT "" @@ -980,8 +984,8 @@ #define TR_RECEIVER_RESET "Resetto RX?" #define TR_SHARE "Condividere" #define TR_BIND "Bind" -#define TR_REGISTER TR("Reg", "Registrare") -#define TR_MODULE_RANGE "[Range]" +#define TR_REGISTER TR("Reg", "Registrare") +#define TR_MODULE_RANGE TR("[Rng]","[Range]") #define TR_RECEIVER_OPTIONS TR("OPZIONI RX", "OPZIONI RICEVENTE") #define TR_DEL_BUTTON BUTTON(TR("Canc.", "Cancella")) #define TR_RESET_BTN "[Reset]" @@ -1006,7 +1010,7 @@ #define TR_TOPLCDTIMER "Timer LCD Sup." #define TR_UNIT "Unita" #define TR_TELEMETRY_NEWSENSOR INDENT "Aggiungi nuovo sensore" -#define TR_CHANNELRANGE INDENT "Numero Canali" +#define TR_CHANNELRANGE TR(INDENT "Num Canali", INDENT "Numero Canali") #define TR_RXFREQUENCY TR("Rx Freqency", "Rx Servo Frequency") #define TR_AFHDS3_RX_FREQ TR("Freq. RX", "Frequenza RX") #define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetria") @@ -1438,3 +1442,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index 6d2acdc7c4..aa03b5f81c 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -267,7 +267,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\010") #define TR_VUNITSSYSTEM TR("Mtrsch""Engels", "Metrisch\0 ""Engels\0 ") #define LEN_VTELEMUNIT "\003" -#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" +#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -295,12 +295,15 @@ #if defined(PCBHORUS) #define LEN_VKEYS "\005" #define TR_VKEYS "PGUP\0""PGDN\0""ENTER""MDL\0 ""RTN\0 ""TELE\0""SYS\0 " -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" @@ -454,8 +457,8 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Output" #endif -#define TR_PROTO TR(INDENT "Proto", INDENT "Protocol") - #define TR_PPMFRAME INDENT "PPM frame" +#define TR_PROTOCOL TR("Proto", "Protocol") +#define TR_PPMFRAME INDENT "PPM frame" #define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate") #define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ") #define TR_WARN_5VOLTS "Warning: output level is 5 volts" @@ -671,6 +674,7 @@ #define TR_RECEIVER "Receiver" #define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetry" #define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency") #define TR_RF_POWER "RF Power" @@ -819,7 +823,7 @@ #define TR_NO_MODELS_ON_SD "Geen Modellen" BREAKSPACE "op SD" #define TR_NO_BITMAPS_ON_SD "Geen Bitmaps" BREAKSPACE "op SD" #define TR_NO_SCRIPTS_ON_SD "Geen Scripts" BREAKSPACE "op SD" -#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" +#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error") #define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_KILLED "Script killed" #define TR_SCRIPT_ERROR "Unknown error" @@ -1425,3 +1429,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index ef15f99220..8e86bca94d 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -284,7 +284,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\010") /*8 decimal*/ #define TR_VUNITSSYSTEM TR("Metr. ""Imper.", "Metryczn""Imperial") #define LEN_VTELEMUNIT "\003" -#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" +#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -315,12 +315,15 @@ #elif defined(PCBXLITE) #define LEN_VKEYS "\005" #define TR_VKEYS "Shift""Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" @@ -474,8 +477,8 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Wyjście" #endif -#define TR_PROTO TR(INDENT "Proto", INDENT "Protokół") - #define TR_PPMFRAME INDENT "Ramka PPM" +#define TR_PROTOCOL TR("Proto", "Protokół") +#define TR_PPMFRAME INDENT "Ramka PPM" #define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate") #define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ") #define TR_WARN_5VOLTS "Warning: output level is 5 volts" @@ -685,6 +688,7 @@ #define TR_RECEIVER INDENT "Receiver" #define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetry" #define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency") #define TR_RF_POWER "RF Power" @@ -833,7 +837,7 @@ #define TR_NO_MODELS_ON_SD "Brak modelu na SD" #define TR_NO_BITMAPS_ON_SD "Brak obrazków na SD" #define TR_NO_SCRIPTS_ON_SD "Brak skryptów na SD" -#define TR_SCRIPT_SYNTAX_ERROR "Skrypt:syntax error" +#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Skrypt:syntax error") #define TR_SCRIPT_PANIC "Skrypt:panic" #define TR_SCRIPT_KILLED "Skrypt:killed" #define TR_SCRIPT_ERROR "Nieznany błąd" @@ -1168,21 +1172,21 @@ #define TR_ABOUT_MARTIN_2 "Projekty graficzne" #if defined(MANUFACTURER_FRSKY) - #define TR_ABOUT_HARDWARE_1 "FrSky" - #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware" - #define TR_ABOUT_HARDWARE_3 "Współautor firmware" + #define TR_ABOUT_HARDWARE_1 "FrSky" + #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware" + #define TR_ABOUT_HARDWARE_3 "Współautor firmware" #elif defined(MANUFACTURER_RADIOMASTER) - #define TR_ABOUT_HARDWARE_1 "Radiomaster" - #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware" - #define TR_ABOUT_HARDWARE_3 "Współautor firmware" + #define TR_ABOUT_HARDWARE_1 "Radiomaster" + #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware" + #define TR_ABOUT_HARDWARE_3 "Współautor firmware" #elif defined(MANUFACTURER_JUMPER) - #define TR_ABOUT_HARDWARE_1 "JumperRC" - #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware" - #define TR_ABOUT_HARDWARE_3 "Współautor firmware" + #define TR_ABOUT_HARDWARE_1 "JumperRC" + #define TR_ABOUT_HARDWARE_2 "Proucent/projektant Hardware" + #define TR_ABOUT_HARDWARE_3 "Współautor firmware" #else - #define TR_ABOUT_HARDWARE_1 "Brent Nelson" - #define TR_ABOUT_HARDWARE_2 "Sky9x designer/výrobce" - #define TR_ABOUT_HARDWARE_3 "" + #define TR_ABOUT_HARDWARE_1 "Brent Nelson" + #define TR_ABOUT_HARDWARE_2 "Sky9x designer/výrobce" + #define TR_ABOUT_HARDWARE_3 "" #endif #define TR_ABOUT_PARENTS_1 "Projekty macierzyste" @@ -1434,3 +1438,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index 60a0db1e03..0909fbd6a6 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -280,7 +280,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\010") #define TR_VUNITSSYSTEM TR("Metric""Imper.", "Metric\0 ""Imperial") #define LEN_VTELEMUNIT "\003" - #define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" + #define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -308,12 +308,15 @@ #if defined(PCBHORUS) #define LEN_VKEYS "\005" #define TR_VKEYS "PGUP\0""PGDN\0""ENTER""MDL\0 ""RTN\0 ""TELE\0""SYS\0 " -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" @@ -471,7 +474,7 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Output" #endif -#define TR_PROTO INDENT"Proto" +#define TR_PROTOCOL "Proto" #define TR_PPMFRAME "PPM frame" #define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate") #define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ") @@ -687,6 +690,7 @@ #define TR_SYNCMENU "Sync [MENU]" #define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetry" #define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency") #define TR_RF_POWER "RF Power" @@ -834,7 +838,7 @@ #define TR_NO_MODELS_ON_SD "Sem Modelo no SD" #define TR_NO_BITMAPS_ON_SD "No Bitmaps on SD" #define TR_NO_SCRIPTS_ON_SD "No Scripts on SD" -#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" +#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error") #define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_KILLED "Script killed" #define TR_SCRIPT_ERROR "Unknown error" @@ -1277,7 +1281,7 @@ #define TR_MENU_INVERT "Invert" #define TR_JITTER_FILTER "ADC Filter" #define TR_RTC_CHECK TR("Check RTC", "Check RTC voltage") -#define TR_AUTH_FAILURE "Auth-failure" +#define TR_AUTH_FAILURE "Auth-failure" #define ZSTR_VFR "VFR" #define ZSTR_RSSI "RSSI" @@ -1434,3 +1438,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 4f869131bb..417d4f7df9 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -284,7 +284,7 @@ #define LEN_VUNITSSYSTEM TR("\006", "\010") #define TR_VUNITSSYSTEM TR("Metri.""Imper.", "Metriska""Imperial") #define LEN_VTELEMUNIT "\003" -#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0" +#define TR_VTELEMUNIT "-\0 ""V\0 ""A\0 ""mA\0""kts""m/s""f/s""kmh""mph""m\0 ""ft\0""@C\0""@F\0""%\0 ""mAh""W\0 ""mW\0""dB\0""rpm""g\0 ""@\0 ""rad""ml\0""fOz""mlm""Hz\0""mS\0""uS\0""km\0" #define STR_V (STR_VTELEMUNIT+1) #define STR_A (STR_VTELEMUNIT+4) @@ -312,12 +312,15 @@ #if defined(PCBHORUS) #define LEN_VKEYS "\005" #define TR_VKEYS "PGUP\0""PGDN\0""ENTER""MDL\0 ""RTN\0 ""TELE\0""SYS\0 " -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Down\0""Up\0 ""Right""Left\0" #elif defined(RADIO_TX12) #define LEN_VKEYS "\005" #define TR_VKEYS "Exit\0""Enter""Up\0 ""Down\0""SYS\0 ""MDL\0 ""TELE\0" +#elif defined(RADIO_T8) + #define LEN_VKEYS "\005" + #define TR_VKEYS "RTN\0 ""ENTER""PGUP\0""PGDN\0""SYS\0 ""MDL\0 ""UP\0 ""DOWN\0" #elif defined(PCBTARANIS) #define LEN_VKEYS "\005" #define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" @@ -476,8 +479,8 @@ #if defined(PCBSKY9X) && defined(REVX) #define TR_OUTPUT_TYPE INDENT "Output" #endif -#define TR_PROTO TR(INDENT "Proto", INDENT "Protokoll") - #define TR_PPMFRAME INDENT "PPM-paket" +#define TR_PROTOCOL TR("Proto", "Protokoll") +#define TR_PPMFRAME INDENT "PPM-paket" #define TR_REFRESHRATE TR(INDENT "Refresh", INDENT "Refresh rate") #define STR_WARN_BATTVOLTAGE TR(INDENT "Output is VBAT: ", INDENT "Warning: output level is VBAT: ") #define TR_WARN_5VOLTS "Warning: output level is 5 volts" @@ -688,6 +691,7 @@ #define TR_SYNCMENU "Synk [MENU]" #define TR_MULTI_RFTUNE TR("Freq tune", "RF Freq. fine tune") #define TR_MULTI_RFPOWER "RF power" +#define TR_MULTI_WBUS "Output" #define TR_MULTI_TELEMETRY "Telemetry" #define TR_MULTI_VIDFREQ TR("Vid. freq.", "Video frequency") #define TR_RF_POWER "RF Power" @@ -836,7 +840,7 @@ #define TR_NO_MODELS_ON_SD "Ingen modell i SD" #define TR_NO_BITMAPS_ON_SD "Ikoner saknas på SD" #define TR_NO_SCRIPTS_ON_SD "Programkod saknas på SD" -#define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" +#define TR_SCRIPT_SYNTAX_ERROR TR("Syntax error", "Script syntax error") #define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_KILLED "Script killed" #define TR_SCRIPT_ERROR "Unknown error" @@ -1437,3 +1441,6 @@ #define ZSTR_SERVO_VOLTAGE "SrvV" #define ZSTR_SERVO_TEMPERATURE "SrvT" #define ZSTR_SERVO_STATUS "SrvS" +#define ZSTR_LOSS "Loss" +#define ZSTR_SPEED "Spd " +#define ZSTR_FLOW "Flow" diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index a8dd02e353..bbd753897e 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -41,7 +41,7 @@ #elif defined(PCBXLITE) #define TR_POTS_VSRCRAW STR_CHAR_POT"S1\0" STR_CHAR_POT"S2\0" #define TR_SW_VSRCRAW STR_CHAR_SWITCH"SA\0" STR_CHAR_SWITCH"SB\0" STR_CHAR_SWITCH"SC\0" STR_CHAR_SWITCH"SD\0" STR_CHAR_SWITCH"SE\0" STR_CHAR_SWITCH"SF\0" -#elif defined(RADIO_T12) +#elif defined(RADIO_FAMILY_JUMPER_T12) #define TR_POTS_VSRCRAW STR_CHAR_POT"S1\0" STR_CHAR_POT"S2\0" #define TR_SW_VSRCRAW STR_CHAR_SWITCH"SA\0" STR_CHAR_SWITCH"SB\0" STR_CHAR_SWITCH"SC\0" STR_CHAR_SWITCH"SD\0" STR_CHAR_SWITCH"SG\0" STR_CHAR_SWITCH"SH\0" STR_CHAR_SWITCH"SI\0" STR_CHAR_SWITCH"SJ\0" #elif defined(RADIO_TX12) @@ -123,6 +123,9 @@ #define LEN_R9M_PXX2_RF_PROTOCOLS "\006" #define TR_R9M_PXX2_RF_PROTOCOLS "ACCESS""FCC\0 ""EU\0 ""Flex" +#define LEN_SPORT_MODES "\014" +#define TR_SPORT_MODES "S.PORT\0 ""F.PORT\0 ""FBUS(FPORT2)" + #define LEN_R9M_REGION "\006" #define TR_R9M_REGION "FCC\0 ""EU\0 ""868MHz""915MHz" @@ -145,7 +148,13 @@ #define TR_MULTI_PROTOCOLS "FlySky\0""Hubsan\0""FrSky\0 ""Hisky\0 ""V2x2\0 ""DSM\0 ""Devo\0 ""YD717\0 ""KN\0 ""SymaX\0 ""SLT\0 ""CX10\0 ""CG023\0 ""Bayang\0""ESky\0 ""MT99XX\0""MJXq\0 ""Shenqi\0""FY326\0 ""Futaba\0""J6 Pro\0""FQ777\0 ""Assan\0 ""Hontai\0""OpenLrs""FlSky2A""Q2x2\0 ""Walkera""Q303\0 ""GW008\0 ""DM002\0 ""Cabell\0""Esky150""H8 3D\0 ""Corona\0""CFlie\0 ""Hitec\0 ""WFly\0 ""Bugs\0 ""BugMini""Traxxas""NCC1701""E01X\0 ""V911S\0 ""GD00X\0 ""V761\0 ""KF606\0 ""Redpine""Potensi""ZSX\0 ""Height\0""Scanner""FrSkyRX""FS2A_RX""HoTT\0 ""FX816\0 ""BayanRX""Pelikan""Tiger\0 ""XK\0 ""XN297DU""FrSkyX2""FrSkyR9""Propel\0""FrSkyL\0""Skyartc""ESky-v2""DSM RX\0""JJRC345""Q90C\0 ""Kyosho\0""RadLink""ExpLRS\0""Realacc""OMP\0 ""M-Link\0""Wfly 2\0""E016Hv2" #define LEN_MULTI_POWER "\005" -#define TR_MULTI_POWER "10mW\0""25mW\0""50mW\0""100mW""200mW""300mW""500mW""1W\0 ""2W\0 " +#define TR_MULTI_POWER "1.6mW""2.0mW""2.5mW""3.2mW""4.0mW""5.0mW""6.3mW""7.9mW""10mW\0""13mW\0""16mW\0""20mW\0""25mW\0""32mW\0""40mW\0""50mW\0" + +#define LEN_MULTI_WBUS_MODE "\004" +#define TR_MULTI_WBUS_MODE "WBUS""PPM\0" + +#define LEN_MULTI_TELEMETRY_MODE "\007" +#define TR_MULTI_TELEMETRY_MODE "Off\0 ""On\0 ""Off+Aux""On+Aux\0" #define LEN_AFHDS3_PROTOCOLS "\x008" #define TR_AFHDS3_PROTOCOLS "PWM/IBUS""PWM/SBUS""PPM/IBUS""PPM/SBUS" diff --git a/radio/util/build-firmware.py b/radio/util/build-firmware.py index 66d9f053db..5d577092ce 100755 --- a/radio/util/build-firmware.py +++ b/radio/util/build-firmware.py @@ -138,6 +138,11 @@ def main(): cmake_options["PCB"] = "X12S" firmware_options = options_horus_x12s maxsize = 2 * 1024 * 1024 + elif board_name == "tlite": + cmake_options["PCB"] = "X7" + cmake_options["PCBREV"] = "TLITE" + firmware_options = options_jumper_tlite + maxsize = 65536 * 8 elif board_name == "t12": cmake_options["PCB"] = "X7" cmake_options["PCBREV"] = "T12" @@ -148,6 +153,11 @@ def main(): cmake_options["PCBREV"] = "TX12" firmware_options = options_radiomaster_tx12 maxsize = 65536 * 8 + elif board_name == "t8": + cmake_options["PCB"] = "X7" + cmake_options["PCBREV"] = "T8" + firmware_options = options_radiomaster_t8 + maxsize = 65536 * 8 elif board_name == "t16": cmake_options["PCB"] = "X10" cmake_options["PCBREV"] = "T16" diff --git a/radio/util/fwoptions.py b/radio/util/fwoptions.py index f4438db442..2349bdd189 100755 --- a/radio/util/fwoptions.py +++ b/radio/util/fwoptions.py @@ -207,6 +207,18 @@ options_horus_x10express = { "flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None), } +options_jumper_tlite = { + "noheli": ("HELI", "NO", "YES"), + "ppmus": ("PPM_UNIT", "US", "PERCENT_PREC1"), + "lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"), + "nogvars": ("GVARS", "NO", "YES"), + "faimode": ("FAI", "YES", None), + "faichoice": ("FAI", "CHOICE", None), + "nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"), + "flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None), +} + + options_jumper_t12 = { "noheli": ("HELI", "NO", "YES"), "ppmus": ("PPM_UNIT", "US", "PERCENT_PREC1"), @@ -244,6 +256,7 @@ options_jumper_t18 = { "nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"), "flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None), "bluetooth": ("BLUETOOTH", "YES", "NO"), + "externalaccessmod": ("HARDWARE_EXTERNAL_ACCESS_MOD", "YES", "NO"), } options_radiomaster_tx12 = { @@ -258,6 +271,17 @@ options_radiomaster_tx12 = { "afhds3": ("AFHDS3", "YES", "NO") } +options_radiomaster_t8 = { + "noheli": ("HELI", "NO", "YES"), + "ppmus": ("PPM_UNIT", "US", "PERCENT_PREC1"), + "lua": ("LUA", "YES", "NO_MODEL_SCRIPTS"), + "nogvars": ("GVARS", "NO", "YES"), + "faimode": ("FAI", "YES", None), + "faichoice": ("FAI", "CHOICE", None), + "nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"), + "bindkey": ("BIND_KEY", "NO", "YES"), +} + options_radiomaster_tx16s = { "noheli": ("HELI", "NO", "YES"), "ppmus": ("PPM_UNIT", "US", "PERCENT_PREC1"), diff --git a/radio/util/tts_en.py b/radio/util/tts_en.py index 616abe5161..6230aafe93 100755 --- a/radio/util/tts_en.py +++ b/radio/util/tts_en.py @@ -41,6 +41,7 @@ for i, (s, f) in enumerate([("volt", "volt0"), ("volts", "volt1"), ("hertz", "hertz0"), ("hertz", "hertz1"), ("milisecond", "ms0"), ("miliseconds", "ms1"), ("microsecond", "us0"), ("microseconds", "us1"), + ("kilometer", "km0"), ("kilometers", "km1"), ("hour", "hour0"), ("hours", "hour1"), ("minute", "minute0"), ("minutes", "minute1"), ("second", "second0"), ("seconds", "second1"), diff --git a/radio/util/tts_fr.py b/radio/util/tts_fr.py index 9dc046fa50..eba461d72d 100755 --- a/radio/util/tts_fr.py +++ b/radio/util/tts_fr.py @@ -39,6 +39,10 @@ for i, (s, f) in enumerate([("volts", "volt0"), ("millilitres", "ml0"), ("onces", "founce0"), ("millilitre minute", "mlpm0"), + ("microsecond", "us0"), + ("milisecond", "ms0"), + ("hertz", "hertz0"), + ("kilometre", "km0"), ("heure", "hour0"), ("minute", "minute0"), ("seconde", "second0"), diff --git a/tools/boards.py b/tools/boards.py new file mode 100755 index 0000000000..72e367cb36 --- /dev/null +++ b/tools/boards.py @@ -0,0 +1,69 @@ +#!/usr/bin/python3 + +boards = { + "XLITE": { + "PCB": "XLITE", + }, + "XLITES": { + "PCB": "XLITES", + }, + "X9LITE": { + "PCB": "X9LITE", + }, + "X9LITES": { + "PCB": "X9LITES", + }, + "X9D": { + "PCB": "X9D", + }, + "X9D+": { + "PCB": "X9D+", + }, + "X9D+2019": { + "PCB": "X9D+", + "PCBREV": "2019", + }, + "X9E": { + "PCB": "X9E", + }, + "X7": { + "PCB": "X7", + }, + "X7ACCESS": { + "PCB": "X7", + "PCBREV": "ACCESS", + }, + "X10": { + "PCB": "X10", + }, + "X10EXPRESS": { + "PCB": "X10", + "PCBREV": "EXPRESS", + }, + "X12S": { + "PCB": "X12S", + }, + "T16": { + "PCB": "X10", + "PCBREV": "T16", + "INTERNAL_MODULE_MULTI": "YES" + }, + "T18": { + "PCB": "X10", + "PCBREV": "T18", + "INTERNAL_MODULE_MULTI": "YES" + }, + "TX16S": { + "PCB": "X10", + "PCBREV": "TX16S", + "INTERNAL_MODULE_MULTI": "YES" + }, + "T12": { + "PCB": "X7", + "PCBREV": "T12", + }, + "TX12": { + "PCB": "X7", + "PCBREV": "TX12", + }, +} diff --git a/tools/build-imrc.py b/tools/build-imrc.py new file mode 100755 index 0000000000..e0c8cf0612 --- /dev/null +++ b/tools/build-imrc.py @@ -0,0 +1,65 @@ +#!/usr/bin/python3 + +import argparse +import datetime +import os +from builtins import NotADirectoryError +import shutil +import tempfile + +from boards import * + +translations = [ + "EN" +] + + +def timestamp(): + return datetime.datetime.now().strftime("%Y%m%d") + + +def build(board, translation, srcdir): + cmake_options = " ".join(["-D%s=%s" % (key, value) for key, value in boards[board].items()]) + cwd = os.getcwd() + if not os.path.exists("output"): + os.mkdir("output") + path = tempfile.mkdtemp() + os.chdir(path) + command = "cmake %s -DTRANSLATIONS=%s -DIMRC_RELEASE=YES -DGHOST=YES %s" % (cmake_options, translation, srcdir) + print(command) + os.system(command) + os.system("make firmware -j16") + os.chdir(cwd) + index = 0 + while 1: + suffix = "" if index == 0 else "_%d" % index + filename = "output/ghost_firm_%s_%s_%s%s.bin" % (board.lower(), translation.lower(), timestamp(), suffix) + if not os.path.exists(filename): + shutil.copy("%s/firmware.bin" % path, filename) + break + index += 1 + shutil.rmtree(path) + + +def dir_path(string): + if os.path.isdir(string): + return string + else: + raise NotADirectoryError(string) + + +def main(): + parser = argparse.ArgumentParser(description="Build Ghost firmware") + parser.add_argument("-b", "--boards", action="append", help="Destination boards", required=True) + parser.add_argument("-t", "--translations", action="append", help="Translations", required=True) + parser.add_argument("srcdir", type=dir_path) + + args = parser.parse_args() + + for board in (boards.keys() if "ALL" in args.boards else args.boards): + for translation in (translations if "ALL" in args.translations else args.translations): + build(board, translation, args.srcdir) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tools/build-jumper.py b/tools/build-jumper.py index 6e7f3d7334..2df2aa46d5 100755 --- a/tools/build-jumper.py +++ b/tools/build-jumper.py @@ -9,6 +9,11 @@ import tempfile boards = { + "TLITE": { + "PCB": "X7", + "PCBREV": "TLITE", + "DEFAULT_MODE": "2", + }, "T12": { "PCB": "X7", "PCBREV": "T12", @@ -53,7 +58,7 @@ def build(board, translation, srcdir): command = "cmake %s -DTRANSLATIONS=%s -DJUMPER_RELEASE=YES %s" % (cmake_options, translation, srcdir) print(command) os.system(command) - os.system("make firmware -j6") + os.system("make firmware -j16") os.chdir(cwd) index = 0 while 1: diff --git a/tools/build-radiomaster.py b/tools/build-radiomaster.py index 985bc705ae..5644635375 100755 --- a/tools/build-radiomaster.py +++ b/tools/build-radiomaster.py @@ -28,6 +28,18 @@ boards = { "PCB": "X7", "PCBREV": "TX12", "DEFAULT_MODE": "2", + }, + "T8_1": { + "PCB": "X7", + "PCBREV": "T8", + "DEFAULT_MODE": "1", + "RADIOMASTER_RTF_RELEASE": "YES", + }, + "T8_2": { + "PCB": "X7", + "PCBREV": "T8", + "DEFAULT_MODE": "2", + "RADIOMASTER_RTF_RELEASE": "YES", } } diff --git a/tools/build-tbs.py b/tools/build-tbs.py index 3c5cb2d1cd..4d469c6086 100755 --- a/tools/build-tbs.py +++ b/tools/build-tbs.py @@ -7,60 +7,7 @@ from builtins import NotADirectoryError import shutil import tempfile - -boards = { - "XLITE": { - "PCB": "XLITE", - }, - "XLITES": { - "PCB": "XLITES", - }, - "X9LITE": { - "PCB": "X9LITE", - }, - "X9LITES": { - "PCB": "X9LITES", - }, - "X9D": { - "PCB": "X9D+", - }, - "X9D+": { - "PCB": "X9D+", - }, - "X9D+2019": { - "PCB": "X9D+", - "PCBREV": "2019", - }, - "X9E": { - "PCB": "X9E", - }, - "X7": { - "PCB": "X7", - }, - "X7ACCESS": { - "PCB": "X7", - "PCBREV": "ACCESS", - }, - "X10": { - "PCB": "X10", - }, - "X10EXPRESS": { - "PCB": "X10", - "PCBREV": "EXPRESS", - }, - "X12S": { - "PCB": "X12S", - }, - "T16": { - "PCB": "X10", - "PCBREV": "T16", - "INTERNAL_MODULE_MULTI": "YES" - }, - "T12": { - "PCB": "X7", - "PCBREV": "T12", - }, -} +from boards import * translations = [ "EN" @@ -78,15 +25,15 @@ def build(board, translation, srcdir): os.mkdir("output") path = tempfile.mkdtemp() os.chdir(path) - command = "cmake %s -DTRANSLATIONS=%s -DTBS_RELEASE=YES -DTEST_BUILD_WARNING=YES %s" % (cmake_options, translation, srcdir) + command = "cmake %s -DTRANSLATIONS=%s -DTBS_RELEASE=YES %s" % (cmake_options, translation, srcdir) print(command) os.system(command) - os.system("make firmware -j6") + os.system("make firmware -j16") os.chdir(cwd) index = 0 while 1: suffix = "" if index == 0 else "_%d" % index - filename = "output/firmware_%s_%s_%s%s.bin" % (board.lower(), translation.lower(), timestamp(), suffix) + filename = "output/tbs_firm_%s_%s_%s%s.bin" % (board.lower(), translation.lower(), timestamp(), suffix) if not os.path.exists(filename): shutil.copy("%s/firmware.bin" % path, filename) break diff --git a/tools/commit-tests.sh b/tools/commit-tests.sh index 793b0f3d2e..0233ac883a 100755 --- a/tools/commit-tests.sh +++ b/tools/commit-tests.sh @@ -157,6 +157,33 @@ if [[ " TX12 X7 ALL " =~ \ ${FLAVOR}\ ]] ; then make -j"${CORES}" tests-radio fi +if [[ " T8 X7 ALL " =~ \ ${FLAVOR}\ ]] ; then + # OpenTX on T8 + rm -rf ./* + cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=TX12 -DHELI=YES -DGVARS=YES "${SRCDIR}" + make -j"${CORES}" ${FIRMARE_TARGET} + make -j"${CORES}" libsimulator + make -j"${CORES}" tests-radio +fi + +if [[ " TLITE X7 ALL " =~ \ ${FLAVOR}\ ]] ; then + # OpenTX on TLITE + rm -rf ./* + cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=TLITE -DHELI=YES -DGVARS=YES "${SRCDIR}" + make -j"${CORES}" ${FIRMARE_TARGET} + make -j"${CORES}" libsimulator + make -j"${CORES}" tests-radio +fi + +if [[ " TX12 X7 ALL " =~ \ ${FLAVOR}\ ]] ; then + # OpenTX on TX12 + rm -rf ./* + cmake "${COMMON_OPTIONS}" -DPCB=X7 -DPCBREV=TX12 -DHELI=YES -DGVARS=YES "${SRCDIR}" + make -j"${CORES}" ${FIRMARE_TARGET} + make -j"${CORES}" libsimulator + make -j"${CORES}" tests-radio +fi + if [[ " XLITE ALL " =~ \ ${FLAVOR}\ ]] ; then # OpenTX on X-Lite rm -rf ./* || true