diff --git a/.travis.yml b/.travis.yml index 6ddb599b5..909cf534d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,8 @@ addons: - libmpc3 - libfox-1.6-dev - libgtest-dev + - lib32stdc++6 + - libclang-common-6.0-dev - clang-6.0 - python3-pip diff --git a/CREDITS.txt b/CREDITS.txt index 384f48bbd..d05842991 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -2126,3 +2126,101 @@ 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 diff --git a/companion/src/datamodels/compounditemmodels.cpp b/companion/src/datamodels/compounditemmodels.cpp index 039e90244..2f04a34fb 100644 --- a/companion/src/datamodels/compounditemmodels.cpp +++ b/companion/src/datamodels/compounditemmodels.cpp @@ -46,6 +46,8 @@ QString AbstractItemModel::idToString(const int value) return "CustomFuncResetParam"; case IMID_TeleSource: return "TeleSource"; + case IMID_RssiSource: + return "RssiSource"; case IMID_CurveRefType: return "CurveRefType"; case IMID_CurveRefFunc: @@ -109,7 +111,6 @@ RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSett 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_ROTARY_ENCODER, RawSource::SourcesGroup, firmware->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)); @@ -170,7 +171,6 @@ RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSett addItems(SWITCH_TYPE_TELEMETRY, -1); addItems(SWITCH_TYPE_FLIGHT_MODE, -firmware->getCapability(FlightModes)); addItems(SWITCH_TYPE_VIRTUAL, -firmware->getCapability(LogicalSwitches)); - addItems(SWITCH_TYPE_ROTARY_ENCODER, -firmware->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)); @@ -181,7 +181,6 @@ RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSett 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, firmware->getCapability(RotaryEncoders)); addItems(SWITCH_TYPE_VIRTUAL, firmware->getCapability(LogicalSwitches)); addItems(SWITCH_TYPE_FLIGHT_MODE, firmware->getCapability(FlightModes)); addItems(SWITCH_TYPE_TELEMETRY, 1); @@ -420,7 +419,7 @@ CustomFuncActionItemModel::CustomFuncActionItemModel(const GeneralSettings * con void CustomFuncActionItemModel::setDynamicItemData(QStandardItem * item, const int value) const { - item->setText(CustomFunctionData(AssignFunc(value)).funcToString(modelData)); + item->setText(CustomFunctionData::funcToString((AssignFunc)value, modelData)); item->setData(CustomFunctionData::isFuncAvailable(value), IMDR_Available); } @@ -445,9 +444,9 @@ CustomFuncResetParamItemModel::CustomFuncResetParamItemModel(const GeneralSettin AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType) { setId(IMID_CustomFuncResetParam); - setUpdateMask(IMUE_TeleSensors); + setUpdateMask(IMUE_TeleSensors | IMUE_Timers); - for (int i = 0; i < CustomFunctionData::resetParamCount(modelData); i++) { + for (int i = 0; i < CustomFunctionData::resetParamCount(); i++) { QStandardItem * modelItem = new QStandardItem(); modelItem->setData(i, IMDR_Id); setDynamicItemData(modelItem, i); @@ -457,10 +456,8 @@ CustomFuncResetParamItemModel::CustomFuncResetParamItemModel(const GeneralSettin void CustomFuncResetParamItemModel::setDynamicItemData(QStandardItem * item, const int value) const { - CustomFunctionData cfd = CustomFunctionData(AssignFunc::FuncReset); - cfd.param = value; - item->setText(cfd.paramToString(modelData)); - item->setData(CustomFunctionData::isResetParamAvailable(modelData, value), IMDR_Available); + item->setText(CustomFunctionData::resetToString(value, modelData)); + item->setData(CustomFunctionData::isResetParamAvailable(value, modelData), IMDR_Available); } void CustomFuncResetParamItemModel::update(const int event) @@ -488,7 +485,7 @@ TelemetrySourceItemModel::TelemetrySourceItemModel(const GeneralSettings * const if (!modelData) return; - setUpdateMask(IMUE_TeleSensors); + setUpdateMask(IMUE_TeleSensors | IMUE_Modules); const int count = firmware->getCapability(Sensors); for (int i = -count; i <= count; ++i) { @@ -519,6 +516,49 @@ void TelemetrySourceItemModel::update(const int event) } } +// +// 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 // @@ -624,6 +664,9 @@ void CompoundItemModelFactory::addItemModel(const int id) 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; @@ -674,6 +717,16 @@ AbstractItemModel * CompoundItemModelFactory::getItemModel(const int id) const 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) { diff --git a/companion/src/datamodels/compounditemmodels.h b/companion/src/datamodels/compounditemmodels.h index de32fc902..d5a7c5f27 100644 --- a/companion/src/datamodels/compounditemmodels.h +++ b/companion/src/datamodels/compounditemmodels.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef COMPOUNDITEMMODELS_H -#define COMPOUNDITEMMODELS_H +#pragma once #include "rawsource.h" #include "rawswitch.h" @@ -44,6 +43,7 @@ class AbstractItemModel: public QStandardItemModel IMID_CustomFuncAction, IMID_CustomFuncResetParam, IMID_TeleSource, + IMID_RssiSource, IMID_CurveRefType, IMID_CurveRefFunc, IMID_ReservedCount, @@ -78,8 +78,9 @@ class AbstractItemModel: public QStandardItemModel 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_LogicalSwitches | IMUE_Scripts | IMUE_TeleSensors | IMUE_Timers | IMUE_Modules }; Q_ENUM(ItemModelUpdateEvent) @@ -305,6 +306,21 @@ class TelemetrySourceItemModel: public AbstractDynamicItemModel 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 @@ -347,6 +363,7 @@ class CompoundItemModelFactory 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; @@ -361,5 +378,3 @@ class CompoundItemModelFactory private: void setSourceId(AbstractItemModel * itemModel); }; - -#endif // COMPOUNDITEMMODELS_H diff --git a/companion/src/dialogs/filesyncdialog.cpp b/companion/src/dialogs/filesyncdialog.cpp index 3927a3ffd..30026c931 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 bf05bc44d..b79d8fd42 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}") @@ -30,7 +37,6 @@ string(REPLACE ".cpp" ".h" firmwares_HDRS "${firmwares_SRCS}") list(APPEND firmwares_HDRS eepromimportexport.h moduledata.h - helpersdata.h ) set(firmwares_QT diff --git a/companion/src/firmwares/curvedata.cpp b/companion/src/firmwares/curvedata.cpp new file mode 100644 index 000000000..c32eac4cc --- /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 000000000..cb083375e --- /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/customfunctiondata.cpp b/companion/src/firmwares/customfunctiondata.cpp index d4942c60c..98157cae2 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,12 +47,19 @@ 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); } QString CustomFunctionData::funcToString(const ModelData * model) const +{ + 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)); @@ -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) @@ -94,9 +112,9 @@ QString CustomFunctionData::funcToString(const ModelData * model) const 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) @@ -106,53 +124,6 @@ QString CustomFunctionData::funcToString(const ModelData * model) const } } -void CustomFunctionData::populateResetParams(const ModelData * model, QComboBox * b, unsigned int value = 0) -{ - int val = 0; - Firmware * firmware = Firmware::getCurrentVariant(); - - for (int i = 0; i < CPN_MAX_TIMERS; i++, val++) { - if (i < firmware->getCapability(Timers)) { - RawSource item = RawSource(SOURCE_TYPE_SPECIAL, i + SOURCE_TYPE_SPECIAL_TIMER1_IDX); - b->addItem(item.toString(model), 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; @@ -163,31 +134,16 @@ QString CustomFunctionData::paramToString(const ModelData * model) const 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)) { @@ -200,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 ""; @@ -217,15 +171,20 @@ 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); } } @@ -246,7 +205,7 @@ QString CustomFunctionData::enabledToString() const } // static -bool CustomFunctionData::isFuncAvailable(int index) +bool CustomFunctionData::isFuncAvailable(const int index) { Firmware * fw = getCurrentFirmware(); @@ -265,7 +224,7 @@ bool CustomFunctionData::isFuncAvailable(int index) } // static -int CustomFunctionData::funcContext(int index) +int CustomFunctionData::funcContext(const int index) { int ret = AllFunctionContexts; @@ -276,16 +235,42 @@ int CustomFunctionData::funcContext(int index) return ret; } + // static -int CustomFunctionData::resetParamCount(const ModelData * model) +QString CustomFunctionData::resetToString(const int value, const ModelData * model) { - QComboBox cb; - CustomFunctionData::populateResetParams(model, &cb); - return cb.count(); + 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 -bool CustomFunctionData::isResetParamAvailable(const ModelData * model, int index) +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(); @@ -295,20 +280,121 @@ bool CustomFunctionData::isResetParamAvailable(const ModelData * model, int inde else return false; } - else if (index < CPN_MAX_TIMERS + firmware->getCapability(RotaryEncoders)) + else if (index < CPN_MAX_TIMERS + 2) return true; - else if (model && index < CPN_MAX_TIMERS + firmware->getCapability(RotaryEncoders) + firmware->getCapability(Sensors)) - return model->sensorData[index - CPN_MAX_TIMERS - firmware->getCapability(RotaryEncoders)].isAvailable(); + else if (model && index < resetParamCount()) + return model->sensorData[index - (CPN_MAX_TIMERS + 2)].isAvailable(); return false; } -void CustomFunctionData::convert(RadioDataConversionState & cstate) +QString CustomFunctionData::harpicToString() const { - 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(); + 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 9e597441f..d5a08a96f 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,6 +31,7 @@ class Firmware; class ModelData; class GeneralSettings; class RadioDataConversionState; +class AbstractStaticItemModel; enum AssignFunc { FuncOverrideCH1 = 0, @@ -78,7 +78,8 @@ 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 { @@ -102,25 +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 = nullptr) 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); - static bool isFuncAvailable(int index); - static int funcContext(int index); - static int resetParamCount(const ModelData * model); - static bool isResetParamAvailable(const ModelData * model, int index); - 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 000000000..8ae759a1b --- /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/helpersdata.h b/companion/src/firmwares/datahelpers.h similarity index 64% rename from companion/src/firmwares/helpersdata.h rename to companion/src/firmwares/datahelpers.h index 29273e5f0..ccd3b0f64 100644 --- a/companion/src/firmwares/helpersdata.h +++ b/companion/src/firmwares/datahelpers.h @@ -24,8 +24,6 @@ class FieldRange { - Q_DECLARE_TR_FUNCTIONS(FieldRange) - public: FieldRange(): decimals(0), @@ -48,3 +46,24 @@ class FieldRange 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 a958750d8..c0a268e96 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 000000000..8578d04e5 --- /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/heli_data.cpp b/companion/src/firmwares/heli_data.cpp new file mode 100644 index 000000000..b1fb7b36e --- /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 000000000..734b29928 --- /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 000000000..9b9ecfe20 --- /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 000000000..27b6b6282 --- /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 b70b174ea..000000000 --- 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 000000000..ac2893a4d --- /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 000000000..dc81298f0 --- /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 7657e2798..679e90f5f 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))) @@ -1478,3 +1474,79 @@ bool ModelData::isThrTraceSrcAvailable(const GeneralSettings * generalSettings, 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 847997d94..f834a0779 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,35 +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 countdownStart; - unsigned int direction; - 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 { @@ -290,6 +266,14 @@ class ModelData { 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); @@ -346,5 +330,3 @@ class ModelData { void sortMixes(); void updateResetParam(CustomFunctionData * cfd); }; - -#endif // MODELDATA_H diff --git a/companion/src/firmwares/output_data.cpp b/companion/src/firmwares/output_data.cpp new file mode 100644 index 000000000..d5cc585ee --- /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 000000000..423f03e49 --- /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 8054e5b1a..c833281fd 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 29d29e4eb..d289f1846 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/sensordata.cpp b/companion/src/firmwares/sensordata.cpp index a87dc6d21..ae602bd0d 100644 --- a/companion/src/firmwares/sensordata.cpp +++ b/companion/src/firmwares/sensordata.cpp @@ -19,8 +19,6 @@ */ #include "sensordata.h" - -#include "radiodata.h" #include "modeldata.h" #include "eeprominterface.h" #include "compounditemmodels.h" @@ -35,7 +33,7 @@ void SensorData::updateUnit() QString SensorData::nameToString(int index) const { - return RadioData::getElementName(tr("TELE"), index + 1, label); + return DataHelpers::getElementName(tr("TELE"), index + 1, label); } QString SensorData::getOrigin(const ModelData * model) const @@ -171,7 +169,7 @@ QString SensorData::paramsToString(const ModelData * model) const 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(boolToString(autoOffset))); + 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 @@ -180,15 +178,15 @@ QString SensorData::paramsToString(const ModelData * model) const } if (mask & SENSOR_ISCONFIGURABLE) - str.append(QString(FMT_LABEL_VALUE).arg(tr("Filter")).arg(boolToString(filter))); + 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(boolToString(persistent))); + 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(boolToString(onlyPositive))); + 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(boolToString(logs))); + str.append(QString(FMT_LABEL_VALUE).arg(tr("Log")).arg(DataHelpers::boolToString(logs, DataHelpers::BOOL_FMT_YN))); return str; } @@ -427,6 +425,28 @@ bool SensorData::isSourceAvailable(const ModelData * model, const int index) return false; } +#define RSSI_ID 0xF101 + +// static +bool SensorData::isRssiSensorAvailable(const ModelData * model, const int value) +{ + if (value == 0) + return true; + else { + const SensorData &sensor = model->sensorData[abs(value) - 1]; + return (sensor.isAvailable() && sensor.id == RSSI_ID); + } +} + +// static +QString SensorData::rssiSensorToString(const ModelData * model, const int value) +{ + if (value == 0) + return tr("(default)"); + else + return sourceToString(model, value); +} + // static AbstractStaticItemModel * SensorData::typeItemModel() { diff --git a/companion/src/firmwares/sensordata.h b/companion/src/firmwares/sensordata.h index 5e888d749..8a032cec5 100644 --- a/companion/src/firmwares/sensordata.h +++ b/companion/src/firmwares/sensordata.h @@ -20,7 +20,7 @@ #pragma once -#include "helpersdata.h" +#include "datahelpers.h" #include @@ -205,7 +205,8 @@ class SensorData { static QString cellIndexToString(const int value); static QString unitToString(const int value); static QString precToString(const int value); - static QString boolToString(const bool value) { return value ? tr("Y") : tr("N"); } + static bool isRssiSensorAvailable(const ModelData * model, const int value); + static QString rssiSensorToString(const ModelData * model, const int value); static AbstractStaticItemModel * typeItemModel(); static AbstractStaticItemModel * formulaItemModel(); diff --git a/companion/src/firmwares/timerdata.cpp b/companion/src/firmwares/timerdata.cpp new file mode 100644 index 000000000..9034ed7e0 --- /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 000000000..07cc1eedd --- /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/generalsetup.ui b/companion/src/generaledit/generalsetup.ui index 7353b9c4b..422eddc7d 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 020f1b45b..c1cd7de79 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 107ca2aa0..8bb1cc6b8 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/modeledit/channels.cpp b/companion/src/modeledit/channels.cpp index 27374a8c4..806ea144e 100644 --- a/companion/src/modeledit/channels.cpp +++ b/companion/src/modeledit/channels.cpp @@ -22,42 +22,31 @@ #include "helpers.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,18 +73,19 @@ 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, CompoundItemModelFactory * sharedItemModels): ModelPanel(parent, model, generalSettings, firmware), sharedItemModels(sharedItemModels) @@ -103,8 +93,12 @@ ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSetting chnCapability = firmware->getCapability(Outputs); int channelNameMaxLen = firmware->getCapability(ChannelsName); - curveFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_Curve)); - connectItemModelEvents(curveFilteredModel); + 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 << "#"; @@ -146,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); @@ -165,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]); } @@ -213,7 +207,7 @@ ChannelsPanel::~ChannelsPanel() delete centerSB[i]; delete symlimitsChk[i]; } - delete curveFilteredModel; + 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,39 +431,19 @@ 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::connectItemModelEvents(const FilteredItemModel * itemModel) @@ -494,4 +466,5 @@ void ChannelsPanel::onItemModelUpdateComplete() void ChannelsPanel::updateItemModels() { sharedItemModels->update(AbstractItemModel::IMUE_Channels); + emit modified(); } diff --git a/companion/src/modeledit/channels.h b/companion/src/modeledit/channels.h index 2a65f497a..5d7600718 100644 --- a/companion/src/modeledit/channels.h +++ b/companion/src/modeledit/channels.h @@ -18,8 +18,7 @@ * GNU General Public License for more details. */ -#ifndef _CHANNELS_H_ -#define _CHANNELS_H_ +#pragma once #include "helpers.h" #include "modeledit.h" @@ -27,7 +26,7 @@ #include class CompoundItemModelFactory; -class FilteredItemModel; +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,7 +58,8 @@ class ChannelsPanel : public ModelPanel Q_OBJECT public: - ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels); + ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, + CompoundItemModelFactory * sharedItemModels); virtual ~ChannelsPanel(); public slots: @@ -89,7 +91,6 @@ class ChannelsPanel : public ModelPanel 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]; @@ -101,9 +102,7 @@ class ChannelsPanel : public ModelPanel int selectedIndex; int chnCapability; CompoundItemModelFactory *sharedItemModels; - FilteredItemModel *curveFilteredModel; void updateItemModels(); void connectItemModelEvents(const FilteredItemModel * itemModel); + FilteredItemModelFactory *dialogFilteredItemModels; }; - -#endif // _CHANNELS_H_ diff --git a/companion/src/modeledit/customfunctions.cpp b/companion/src/modeledit/customfunctions.cpp index 5c15bd538..c773e90e5 100644 --- a/companion/src/modeledit/customfunctions.cpp +++ b/companion/src/modeledit/customfunctions.cpp @@ -19,53 +19,11 @@ */ #include "customfunctions.h" -#include "filtereditemmodels.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, CompoundItemModelFactory * sharedItemModels): GenericPanel(parent, model, generalSettings, firmware), @@ -77,18 +35,41 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, lock = true; fswCapability = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions); - rawSwitchFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch), - model ? RawSwitch::SpecialFunctionsContext : RawSwitch::GlobalFunctionsContext); - connectItemModelEvents(rawSwitchFilteredModel); + 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 FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource)); - connectItemModelEvents(rawSourceAllModel); + tabFilterFactory = new FilteredItemModelFactory(); - rawSourceInputsModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), RawSource::InputSourceGroups); - connectItemModelEvents(rawSourceInputsModel); + funcActionsId = tabFilterFactory->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_CustomFuncAction), + model ? CustomFunctionData::AllFunctionContexts : CustomFunctionData::GlobalFunctionsContext), + "Function Actions"); + connectItemModelEvents(tabFilterFactory->getItemModel(funcActionsId)); - rawSourceGVarsModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), RawSource::GVarsGroup); - connectItemModelEvents(rawSourceGVarsModel); + 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)); @@ -118,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++) { @@ -135,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(); @@ -168,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]); @@ -207,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); @@ -225,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); @@ -250,10 +220,8 @@ CustomFunctionsPanel::~CustomFunctionsPanel() { if (mediaPlayer) stopSound(mediaPlayerCurrent); - delete rawSwitchFilteredModel; - delete rawSourceAllModel; - delete rawSourceInputsModel; - delete rawSourceGVarsModel; + delete tabModelFactory; + delete tabFilterFactory; } void CustomFunctionsPanel::onMediaPlayerStateChanged(QMediaPlayer::State state) @@ -333,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) @@ -363,11 +330,6 @@ void CustomFunctionsPanel::functionEdited() } } -void CustomFunctionsPanel::onRepeatModified() -{ - emit modified(); -} - void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified) { CustomFunctionData & cfn = functions[i]; @@ -414,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) @@ -468,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) @@ -493,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(); @@ -577,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); } @@ -653,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; } } @@ -828,7 +757,7 @@ bool CustomFunctionsPanel::moveUpAllowed() const return selectedIndex > 0; } -void CustomFunctionsPanel::connectItemModelEvents(const FilteredItemModel * itemModel) +void CustomFunctionsPanel::connectItemModelEvents(FilteredItemModel * itemModel) { connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &CustomFunctionsPanel::onItemModelAboutToBeUpdated); connect(itemModel, &FilteredItemModel::updateComplete, this, &CustomFunctionsPanel::onItemModelUpdateComplete); diff --git a/companion/src/modeledit/customfunctions.h b/companion/src/modeledit/customfunctions.h index e41baf672..87775246d 100644 --- a/companion/src/modeledit/customfunctions.h +++ b/companion/src/modeledit/customfunctions.h @@ -18,38 +18,19 @@ * 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 CompoundItemModelFactory; -class FilteredItemModel; 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 @@ -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); @@ -87,8 +67,6 @@ class CustomFunctionsPanel : public GenericPanel 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,12 +74,20 @@ class CustomFunctionsPanel : public GenericPanel bool moveUpAllowed() const; void swapData(int idx1, int idx2); void resetCBsAndRefresh(int idx); - void connectItemModelEvents(const FilteredItemModel * itemModel); + void connectItemModelEvents(FilteredItemModel * itemModel); - FilteredItemModel * rawSwitchFilteredModel; - FilteredItemModel * rawSourceAllModel; - FilteredItemModel * rawSourceInputsModel; - FilteredItemModel * rawSourceGVarsModel; + 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; @@ -115,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 808cff7ba..be549144c 100644 --- a/companion/src/modeledit/expodialog.cpp +++ b/companion/src/modeledit/expodialog.cpp @@ -50,8 +50,11 @@ 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); + 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)); curveRefFilteredItemModels = new CurveRefFilteredFactory(sharedItemModels, firmware->getCapability(HasInputDiff) ? 0 : FilteredItemModel::PositiveFilter); @@ -92,7 +95,7 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G if (firmware->getCapability(VirtualInputs)) { ui->inputName->setMaxLength(firmware->getCapability(InputsLength)); id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), - (RawSource::InputSourceGroups & ~ RawSource::NoneGroup & ~RawSource::InputsGroup)), + (RawSource::InputSourceGroups & ~RawSource::NoneGroup & ~RawSource::InputsGroup) | RawSource::TelemGroup), "RawSource"); ui->sourceCB->setModel(dialogFilteredItemModels->getItemModel(id)); ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(ed->srcRaw.toValue())); diff --git a/companion/src/modeledit/inputs.cpp b/companion/src/modeledit/inputs.cpp index f48d7d916..1f7fd2b0b 100644 --- a/companion/src/modeledit/inputs.cpp +++ b/companion/src/modeledit/inputs.cpp @@ -351,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; @@ -368,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(); @@ -573,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(); @@ -589,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++) { diff --git a/companion/src/modeledit/mixerdialog.cpp b/companion/src/modeledit/mixerdialog.cpp index 67b01f8f6..6cc39ffd1 100644 --- a/companion/src/modeledit/mixerdialog.cpp +++ b/companion/src/modeledit/mixerdialog.cpp @@ -49,15 +49,19 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, this->setWindowTitle(tr("DEST -> %1").arg(RawSource(SOURCE_TYPE_CH, md->destCh - 1).toString(&model, &generalSettings))); id = dialogFilteredItemModels->registerItemModel(new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSource), - ((RawSource::InputSourceGroups | RawSource::ScriptsGroup) & ~ RawSource::NoneGroup)), + (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, 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)); - 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); curveRefFilteredItemModels = new CurveRefFilteredFactory(sharedItemModels, firmware->getCapability(HasMixerExpo) ? 0 : FilteredItemModel::PositiveFilter); curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, md->curve, model, diff --git a/companion/src/modeledit/mixes.cpp b/companion/src/modeledit/mixes.cpp index 3d95bd04d..023888760 100644 --- a/companion/src/modeledit/mixes.cpp +++ b/companion/src/modeledit/mixes.cpp @@ -354,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 @@ -371,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; diff --git a/companion/src/modeledit/modeledit.cpp b/companion/src/modeledit/modeledit.cpp index 3577be7ae..146bc01f0 100644 --- a/companion/src/modeledit/modeledit.cpp +++ b/companion/src/modeledit/modeledit.cpp @@ -62,6 +62,7 @@ ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmw 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); diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp index ae8635f09..de6609591 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 "filtereditemmodels.h" #include "appdata.h" #include "modelprinter.h" #include "multiprotocols.h" @@ -31,54 +30,53 @@ #include -TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, - QWidget * prevFocus, FilteredItemModel * 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); - connectItemModelEvents(rawSwitchFilteredModel); + 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); - ui->countdownStart->addItem("5s", 1); - ui->countdownStart->addItem("10s", 0); - ui->countdownStart->addItem("20s", -1); - ui->countdownStart->addItem("30s", -2); disableMouseScrolling(); QWidget::setTabOrder(prevFocus, ui->name); @@ -102,33 +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; + if (timer.countdownBeep == TimerData::COUNTDOWNBEEP_SILENT) { + ui->countdownStartLabel->setEnabled(false); + ui->countdownStart->setEnabled(false); + } + else { + ui->countdownStartLabel->setEnabled(true); + ui->countdownStart->setEnabled(true); + } - 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'))); + ui->persistent->updateValue(); + ui->persistentValue->setText(timer.pvalueToString()); } - ui->countdownBeep->updateValue(); - ui->minuteBeep->setChecked(timer.minuteBeep); - ui->persistent->updateValue(); - ui->countdownStart->updateValue(); lock = false; } @@ -137,57 +129,6 @@ QWidget * TimerPanel::getLastFocus() return ui->persistent; } -void TimerPanel::on_countdownBeep_currentIndexChanged(int index) -{ - if(index == TimerData::COUNTDOWN_SILENT) - ui->countdownStart->hide(); - else - ui->countdownStart->show(); -} - -void TimerPanel::on_value_editingFinished() -{ - 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(); - } - } -} - -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::connectItemModelEvents(const FilteredItemModel * itemModel) { connect(itemModel, &FilteredItemModel::aboutToBeUpdated, this, &TimerPanel::onItemModelAboutToBeUpdated); @@ -197,12 +138,27 @@ void TimerPanel::connectItemModelEvents(const FilteredItemModel * itemModel) void TimerPanel::onItemModelAboutToBeUpdated() { lock = true; + modelsUpdateCnt++; } 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; } /******************************************************************************/ @@ -710,6 +666,7 @@ void ModulePanel::onProtocolChanged(int index) module.protocol = ui->protocol->itemData(index).toInt(); module.channelsCount = module.getMaxChannelCount(); update(); + emit updateItemModels(); emit modified(); } } @@ -810,6 +767,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; } @@ -1035,16 +993,26 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge { ui->setupUi(this); - rawSwitchFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_RawSwitch), RawSwitch::TimersContext); - connectItemModelEvents(rawSwitchFilteredModel); + lock = true; - thrSourceFilteredModel = new FilteredItemModel(sharedItemModels->getItemModel(AbstractItemModel::IMID_ThrSource)); - connectItemModelEvents(thrSourceFilteredModel); + 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(); - lock = true; - memset(modules, 0, sizeof(modules)); QRegExp rx(CHAR_FOR_NAMES_REGEX); @@ -1124,7 +1092,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); @@ -1160,6 +1128,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(); @@ -1265,6 +1236,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); } @@ -1290,8 +1262,8 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge SetupPanel::~SetupPanel() { delete ui; - delete rawSwitchFilteredModel; - delete thrSourceFilteredModel; + delete panelFilteredModels; + delete panelItemModels; } void SetupPanel::on_extendedLimits_toggled(bool checked) @@ -1325,14 +1297,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) { @@ -1391,28 +1355,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(); @@ -1440,7 +1382,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); @@ -1811,4 +1753,10 @@ void SetupPanel::onItemModelUpdateComplete() void SetupPanel::updateItemModels() { 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 692f26ea5..955f2189b 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 CompoundItemModelFactory; -class FilteredItemModel; - namespace Ui { class Setup; class Timer; @@ -40,21 +38,18 @@ class TimerPanel : public ModelPanel Q_OBJECT public: - TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, - QWidget *prevFocus, FilteredItemModel * 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_countdownBeep_currentIndexChanged(int index); - void on_name_editingFinished(); + void onNameChanged(); void onItemModelAboutToBeUpdated(); void onItemModelUpdateComplete(); + void onCountdownBeepChanged(int index); signals: void nameChanged(); @@ -63,6 +58,7 @@ class TimerPanel : public ModelPanel TimerData & timer; Ui::Timer * ui; void connectItemModelEvents(const FilteredItemModel * itemModel); + int modelsUpdateCnt; }; class ModulePanel : public ModelPanel @@ -81,6 +77,7 @@ class ModulePanel : public ModelPanel signals: void channelsRangeChanged(); void failsafeModified(unsigned index); + void updateItemModels(); private slots: void setupFailsafes(); @@ -146,7 +143,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); @@ -176,6 +172,7 @@ class SetupPanel : public ModelPanel void onTimerNameChanged(); void onItemModelAboutToBeUpdated(); void onItemModelUpdateComplete(); + void onModuleUpdateItemModels(); private: Ui::Setup *ui; @@ -183,12 +180,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; @@ -198,10 +194,8 @@ class SetupPanel : public ModelPanel bool moveTimerUpAllowed() const; void swapTimerData(int idx1, int idx2); CompoundItemModelFactory * sharedItemModels; - FilteredItemModel * rawSwitchFilteredModel; - FilteredItemModel * thrSourceFilteredModel; void updateItemModels(); void connectItemModelEvents(const FilteredItemModel * itemModel); + CompoundItemModelFactory * panelItemModels; + FilteredItemModelFactory * panelFilteredModels; }; - -#endif // _SETUP_H_ diff --git a/companion/src/modeledit/setup.ui b/companion/src/modeledit/setup.ui index 8b2409191..ee0ec28a3 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 11f566b45..67b929bdb 100644 --- a/companion/src/modeledit/setup_timer.ui +++ b/companion/src/modeledit/setup_timer.ui @@ -9,7 +9,7 @@ 0 0 - 675 + 874 33 @@ -33,7 +33,7 @@ 0 - + 80 @@ -43,7 +43,7 @@ - + true @@ -56,7 +56,7 @@ - + @@ -68,11 +68,18 @@ + + + + Start + + + - + Minute Call @@ -109,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 8cda220a9..bb32790b8 100644 --- a/companion/src/modeledit/telemetry.cpp +++ b/companion/src/modeledit/telemetry.cpp @@ -35,6 +35,7 @@ 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): @@ -111,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())); @@ -696,6 +697,11 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin 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); @@ -813,12 +819,14 @@ 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_TELEPOSSRC)); + ui->rssiSourceCB->setModel(panelFilteredItemModels->getItemModel(FIM_RSSISOURCE)); ui->rssiSourceCB->setField(model->rssiSource, this); ui->rssiSourceCB->show(); diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp index 282f53550..1d7df4f93 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) { diff --git a/companion/src/modelprinter.h b/companion/src/modelprinter.h index ea2eab2d8..8be56bd64 100644 --- a/companion/src/modelprinter.h +++ b/companion/src/modelprinter.h @@ -67,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); @@ -104,13 +102,8 @@ 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); diff --git a/companion/src/multimodelprinter.cpp b/companion/src/multimodelprinter.cpp index 17cb30be4..0ebef1884 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(); diff --git a/companion/src/shared/CMakeLists.txt b/companion/src/shared/CMakeLists.txt index 2fbbafbf9..ffd5942bf 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 ea86db956..af831948e 100644 --- a/companion/src/shared/autobitsetcheckbox.h +++ b/companion/src/shared/autobitsetcheckbox.h @@ -34,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) { @@ -42,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(); @@ -104,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); diff --git a/companion/src/shared/autocheckbox.h b/companion/src/shared/autocheckbox.h index f5b233fed..1c1a7207c 100644 --- a/companion/src/shared/autocheckbox.h +++ b/companion/src/shared/autocheckbox.h @@ -21,23 +21,23 @@ #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; @@ -51,26 +51,31 @@ class AutoCheckBox: public QCheckBox 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; }; diff --git a/companion/src/shared/autocombobox.h b/companion/src/shared/autocombobox.h index 784abaefa..ca6054555 100644 --- a/companion/src/shared/autocombobox.h +++ b/companion/src/shared/autocombobox.h @@ -22,14 +22,23 @@ #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))); } @@ -69,16 +78,38 @@ class AutoComboBox: public QComboBox } } - 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(); } @@ -103,10 +134,18 @@ class AutoComboBox: public QComboBox void updateValue() { - if (!field) + if (!field && !rawSource && !rawSwitch) return; + lock = true; - setCurrentIndex(findData(*field)); + + if (field) + setCurrentIndex(findData(*field)); + else if (rawSource) + setCurrentIndex(findData(rawSource->toValue())); + else if (rawSwitch) + setCurrentIndex(findData(rawSwitch->toValue())); + lock = false; } @@ -118,21 +157,37 @@ class AutoComboBox: public QComboBox { if (panel && panel->lock) return; - if (index > -1) { - const int val = itemData(index).toInt(); - if (field && !lock) { - *field = val; - if (panel) - emit panel->modified(); - } - emit currentDataChanged(val); + if (lock || index < 0) + return; + + bool ok; + const int val = itemData(index).toInt(&ok); + if (!ok) + return; + + if (field && *field != val) { + *field = val; } + 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; }; diff --git a/companion/src/shared/autodoublespinbox.h b/companion/src/shared/autodoublespinbox.h index 6560b6ea2..a6466269e 100644 --- a/companion/src/shared/autodoublespinbox.h +++ b/companion/src/shared/autodoublespinbox.h @@ -21,7 +21,7 @@ #pragma once #include -#include "modeledit/modeledit.h" +#include "genericpanel.h" #if __GNUC__ #include #endif @@ -31,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; @@ -57,7 +57,9 @@ class AutoDoubleSpinBox: public QDoubleSpinBox void updateValue() { if (field) { - setValue(float(*field)/multiplier()); + lock = true; + setValue(float(*field) / multiplier()); + lock = false; } } @@ -80,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(); } @@ -92,7 +100,7 @@ class AutoDoubleSpinBox: public QDoubleSpinBox } protected: - int * field; - ModelPanel * panel; - bool lock; + int * field = nullptr; + GenericPanel * panel = nullptr; + bool lock = false; }; diff --git a/companion/src/shared/autohexspinbox.h b/companion/src/shared/autohexspinbox.h index d7df46bd6..40cc24da4 100644 --- a/companion/src/shared/autohexspinbox.h +++ b/companion/src/shared/autohexspinbox.h @@ -21,23 +21,23 @@ #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; @@ -47,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(); } @@ -63,7 +71,7 @@ class AutoHexSpinBox: public HexSpinBox } protected: - unsigned int * field; - ModelPanel * panel; - bool lock; + unsigned int * field = nullptr; + GenericPanel * panel = nullptr; + bool lock = false; }; diff --git a/companion/src/shared/autolineedit.h b/companion/src/shared/autolineedit.h index 0f888e6df..b2815796c 100644 --- a/companion/src/shared/autolineedit.h +++ b/companion/src/shared/autolineedit.h @@ -29,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) @@ -76,7 +76,9 @@ class AutoLineEdit: public QLineEdit protected slots: void onEdited() { - if ((panel && panel->lock) || lock) + if (panel && panel->lock) + return; + if (lock) return; if (field) @@ -86,15 +88,15 @@ class AutoLineEdit: public QLineEdit else return; + emit currentDataChanged(); + if (panel) emit panel->modified(); - - emit currentDataChanged(); } protected: char * field; - QString * strField; - GenericPanel * panel; - bool lock; + QString * strField = nullptr; + GenericPanel * panel = nullptr; + bool lock = false; }; diff --git a/companion/src/shared/autoprecisioncombobox.h b/companion/src/shared/autoprecisioncombobox.h index e93059199..72dd89406 100644 --- a/companion/src/shared/autoprecisioncombobox.h +++ b/companion/src/shared/autoprecisioncombobox.h @@ -123,7 +123,7 @@ class AutoPrecisionComboBox: public QComboBox if (*m_field != val) { *m_field = rangecheckDecimals(val); updateValue(); - emit valueChanged(); + emit currentDataChanged(value); } } @@ -134,7 +134,7 @@ class AutoPrecisionComboBox: public QComboBox if (*m_field != value) { *m_field = rangecheckDecimals(value); updateValue(); - emit valueChanged(); + emit currentDataChanged((int)value); } } @@ -160,7 +160,7 @@ class AutoPrecisionComboBox: public QComboBox } signals: - void valueChanged(); + void currentDataChanged(int index); protected slots: void init() @@ -203,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(); } } diff --git a/companion/src/shared/autotimeedit.h b/companion/src/shared/autotimeedit.h new file mode 100644 index 000000000..2ba75d70e --- /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 bbb9b7254..88c7f841b 100644 --- a/companion/src/shared/genericpanel.h +++ b/companion/src/shared/genericpanel.h @@ -39,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); diff --git a/companion/src/translations/companion_fr.ts b/companion/src/translations/companion_fr.ts index 89a6734e2..7f5c0618d 100644 --- a/companion/src/translations/companion_fr.ts +++ b/companion/src/translations/companion_fr.ts @@ -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,7 +1381,7 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import CurveData - + CV CB @@ -1614,219 +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 %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 - + + Played once, not during startup + Lu une fois, mais pas à la mise en route + + + + No repeat + Lu une fois + + + + 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 @@ -1834,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? @@ -2386,12 +2444,12 @@ Vérifier la sélection (M64/M128) ExpoData - + INP ENT - + (@%1) @@ -2513,22 +2571,22 @@ Si vide, la ligne est toujours active. Éditer %1 - + Popup menu available Menu contextuel disponible - + Clear All Effacer Tout - + Set All Définir Tout - + Invert All Inverser Tout @@ -3672,7 +3730,7 @@ Vous utilisez actuellement: FlightModeData - + FM PV @@ -4143,12 +4201,12 @@ p, li { white-space: pre-wrap; } VG - + Own value Valeur indépendante - + Flight mode %1 value Valeur de la phase de vol %1 @@ -4701,6 +4759,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 @@ -4871,17 +4940,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 @@ -5739,27 +5797,27 @@ 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 @@ -5784,113 +5842,113 @@ Cette fonction ne peut pas être désactivée sur la radio. 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? Effacer toutes les lignes Entrée sélectionnées. Êtes-vous sûr? - + Delete all lines for the selected Inputs. Are you sure? Supprimer toutes les lignes Entrée sélectionnées. Êtes-vous sûr? @@ -5898,17 +5956,17 @@ Cette fonction ne peut pas être désactivée sur la radio. LimitData - + INV - + NOR - + CH VOIE @@ -5916,7 +5974,7 @@ Cette fonction ne peut pas être désactivée sur la radio. LimitsGroup - + GV VG @@ -7677,12 +7735,12 @@ Enregistrer les changements ? MixData - + MIX - + (@%1) @@ -7884,22 +7942,22 @@ Mixage actif par défaut si non-renseigné. - + 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 @@ -7946,25 +8004,25 @@ Mixage actif par défaut si non-renseigné. MixesPanel - + Move Up Monter - + Ctrl+Up Ctrl+Haut - + Move Down Descendre - + Ctrl+Down Ctrl+Bas @@ -7989,92 +8047,92 @@ Mixage actif par défaut si non-renseigné. 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 ? @@ -8105,32 +8163,32 @@ Mixage actif par défaut si non-renseigné. Simulation - + Heli Paramètres hélico - + Inputs Entrées - + Mixes Mixages - + Logical Switches Inters logiques - + Setup Configuration - + Curves Courbes @@ -8140,22 +8198,22 @@ Mixage actif par défaut si non-renseigné. Dialogue - + Flight Modes Phases de vol - + Outputs Sorties - + Special Functions Fonctions spéciales - + Telemetry Télémesure @@ -8399,11 +8457,6 @@ Mixage actif par défaut si non-renseigné. Warn(%1) Alerte(%1) - - - Offset - Décalage - Flight modes @@ -8557,8 +8610,8 @@ Mixage actif par défaut si non-renseigné. - - + + Source @@ -8598,252 +8651,89 @@ Mixage actif par défaut si non-renseigné. 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! @@ -8861,9 +8751,8 @@ Mixage actif par défaut si non-renseigné. - - - + + None Aucun @@ -8939,7 +8828,6 @@ Mixage actif par défaut si non-renseigné. - Custom Prédéfini @@ -9353,42 +9241,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 @@ -10027,12 +9915,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> @@ -10604,24 +10492,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 @@ -10660,226 +10530,332 @@ 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 - - Custom - Prédéfini + + Formula + Formule - - Calculated - Calculé - - - - Add - Addition - - - - Average - Moyenne - - - - Minimum + + Id - - Maximum + + Instance + + + + + + Sensor + Capteur + + + + Sources - Multiply - Multiplication + GPS + - - Totalize - Totalisation + + Alt + Altitude - - Cell - Element LiPo - - - - Consumption - Consommation + + Unit + Unité - Distance + 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) + + + + Y + O + + + + N + + Setup @@ -11063,92 +11039,92 @@ 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? @@ -12582,22 +12558,22 @@ Trop d'erreurs, abandon. Type d'écran personnalisé - + None Aucun - + Numbers Chiffres - + Bars Barres - + Script @@ -12625,52 +12601,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é) - + Delete Sensor. Are you sure? Supprimer le Capteur. Êtes-vous sûr? @@ -12688,279 +12664,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 @@ -12968,72 +12764,72 @@ Trop d'erreurs, abandon. TelemetrySensorPanel - + TELE%1 - + Popup menu available Menu contextuel disponible - + 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? @@ -13403,12 +13199,12 @@ hh:mm:ss Timer - + Countdown Compte à rebours - + Minute Call Annonces minutes diff --git a/companion/src/translations/companion_ja.ts b/companion/src/translations/companion_ja.ts index 2d7d02b4d..d423959d4 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/src/CMakeLists.txt b/radio/src/CMakeLists.txt index b3a8c1fdb..b71d572ba 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -382,6 +382,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 702ec044e..04ff8a8b2 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 cb72b8076..8d64e7972 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 8348f75bd..1c5fdc1ea 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -278,6 +278,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, @@ -318,8 +319,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, diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 52f71689e..52a28d497 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -130,9 +130,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, @@ -152,6 +149,9 @@ 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, @@ -212,8 +212,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 @@ -389,12 +389,22 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event) #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 @@ -412,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 @@ -424,54 +433,12 @@ void menuModelSetup(event_t event) EXTERNAL_MODULE_ROWS - TRAINER_ROWS - }); -#else - MENU_TAB({ - HEADER_LINE_COLUMNS - 0, - TIMERS_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_MENUSETUP); @@ -1582,40 +1549,35 @@ 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[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; diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 2e719c756..db9ccc996 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -1304,38 +1304,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/480x272/model_setup.cpp b/radio/src/gui/480x272/model_setup.cpp index 5cc428906..a181a458f 100644 --- a/radio/src/gui/480x272/model_setup.cpp +++ b/radio/src/gui/480x272/model_setup.cpp @@ -1688,34 +1688,33 @@ bool menuModelSetup(event_t event) { #if defined(MULTIMODULE) if (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx)) { + const char * title = getMultiOptionTitle(moduleIdx); + + lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, title); + if (title == STR_MULTI_RFTUNE) { + lcdDrawNumber(LCD_W - 10, y, TELEMETRY_RSSI(), RIGHT, 0, "RSSI(", ")"); + } + 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()) { - lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]); - if (attr && status.optionDisp == 2) { - lcdDrawNumber(LCD_W - 10, y, TELEMETRY_RSSI(), RIGHT, 0, "RSSI(", ")"); - } - } - else { - const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto); - if (pdef->optionsstr) { - lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, pdef->optionsstr); - if (attr && pdef->optionsstr == STR_MULTI_RFTUNE) { - lcdDrawNumber(LCD_W - 10, y, TELEMETRY_RSSI(), RIGHT, 0, "RSSI(", ")"); - } - } - } - 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); + 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 (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; @@ -1727,6 +1726,7 @@ bool menuModelSetup(event_t event) else lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, optionValue, LEFT | attr); } + if (attr) { CHECK_INCDEC_MODELVAR(event, optionValue, min, max); if (checkIncDec_Ret) { diff --git a/radio/src/gui/common/stdlcd/draw_functions.cpp b/radio/src/gui/common/stdlcd/draw_functions.cpp index 056a66b08..c7d9142ed 100644 --- a/radio/src/gui/common/stdlcd/draw_functions.cpp +++ b/radio/src/gui/common/stdlcd/draw_functions.cpp @@ -145,7 +145,7 @@ void editName(coord_t x, coord_t y, char * name, uint8_t size, event_t event, ui if (c <= 0) v = -v; } else { - v = checkIncDec(event, abs(v), '0', 'z', 0); + v = checkIncDec(event, abs(v), ' ', 'z', 0); } } diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 368aac163..1bd84b21e 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -994,9 +994,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}, @@ -1091,3 +1097,22 @@ void editStickHardwareSettings(coord_t x, coord_t y, int idx, event_t event, Lcd 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 0d43a65c9..43c489d5f 100644 --- a/radio/src/gui/gui_common.h +++ b/radio/src/gui/gui_common.h @@ -306,7 +306,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, @@ -346,6 +346,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/lua/CMakeLists.txt b/radio/src/lua/CMakeLists.txt index 138c8b60a..589b5d1c1 100644 --- a/radio/src/lua/CMakeLists.txt +++ b/radio/src/lua/CMakeLists.txt @@ -24,6 +24,7 @@ if(PYTHONINTERP_FOUND) add_lua_export_target(xlite ${LUA_INCLUDES} -DPCBTARANIS -DPCBXLITE) add_lua_export_target(xlites ${LUA_INCLUDES} -DPCBTARANIS -DPCBXLITES -DPCBXLITE -DGYRO) add_lua_export_target(x9d ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9D -DPCBX9) + add_lua_export_target(x9d+2019 ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9D -DPCBX9 -DRADIO_X9DP2019) add_lua_export_target(x9e ${LUA_INCLUDES} -DPCBTARANIS -DPCBX9E -DPCBX9) add_lua_export_target(x10 ${LUA_INCLUDES} -DPCBHORUS -DPCBX10) add_lua_export_target(x12s ${LUA_INCLUDES} -DPCBHORUS -DPCBX12S) diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 18b8c0fb8..3c6f20d42 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -54,6 +54,8 @@ #include "lua/lua_exports_xlites.inc" #elif defined(PCBXLITE) #include "lua/lua_exports_xlite.inc" +#elif defined(RADIO_X9DP2019) + #include "lua/lua_exports_x9d+2019.inc" #elif defined(PCBTARANIS) #include "lua/lua_exports_x9d.inc" #endif @@ -1409,7 +1411,10 @@ Get RSSI value as well as low and critical RSSI alarm levels (in dB) */ static int luaGetRSSI(lua_State * L) { - lua_pushunsigned(L, min((uint8_t)99, TELEMETRY_RSSI())); + if (TELEMETRY_STREAMING()) + lua_pushunsigned(L, min((uint8_t)99, TELEMETRY_RSSI())); + else + lua_pushunsigned(L, 0); lua_pushunsigned(L, g_model.rssiAlarms.getWarningRssi()); lua_pushunsigned(L, g_model.rssiAlarms.getCriticalRssi()); return 3; @@ -2036,6 +2041,7 @@ const luaR_value_entry opentxConstants[] = { {"UNIT_KMH", UNIT_KMH }, {"UNIT_MPH", UNIT_MPH }, {"UNIT_METERS", UNIT_METERS }, + {"UNIT_KM", UNIT_KM }, {"UNIT_FEET", UNIT_FEET }, {"UNIT_CELSIUS", UNIT_CELSIUS }, {"UNIT_FAHRENHEIT", UNIT_FAHRENHEIT }, diff --git a/radio/src/mixer_scheduler.cpp b/radio/src/mixer_scheduler.cpp new file mode 100644 index 000000000..dcf95383b --- /dev/null +++ b/radio/src/mixer_scheduler.cpp @@ -0,0 +1,82 @@ +/* + * 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) + +// Global trigger flag +RTOS_FLAG_HANDLE mixerFlag; + +// Mixer schedule +struct MixerSchedule { + + // period in us + volatile uint16_t period; +}; + +static MixerSchedule mixerSchedules[NUM_MODULES]; + +uint16_t getMixerSchedulerPeriod() +{ +#if defined(HARDWARE_INTERNAL_MODULE) + if (mixerSchedules[INTERNAL_MODULE].period) { + return mixerSchedules[INTERNAL_MODULE].period; + } +#endif +#if defined(HARDWARE_EXTERNAL_MODULE) + if (mixerSchedules[EXTERNAL_MODULE].period) { + return mixerSchedules[EXTERNAL_MODULE].period; + } +#endif + return MIXER_SCHEDULER_DEFAULT_PERIOD_US; +} + +void mixerSchedulerInit() +{ + RTOS_CREATE_FLAG(mixerFlag); + memset(mixerSchedules, 0, sizeof(mixerSchedules)); +} + +void mixerSchedulerSetPeriod(uint8_t moduleIdx, uint16_t periodUs) +{ + if (periodUs > 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 000000000..601f3fcd7 --- /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 7e89312dc..68e6eb3bb 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -1445,6 +1445,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) { diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 3f759a439..4e80328c0 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -320,7 +320,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]; @@ -334,7 +334,7 @@ typedef struct { { memclear(this, sizeof(*this)); } -} CustomFunctionsContext; +}; #include "strhelpers.h" #include "gui.h" @@ -501,6 +501,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(); diff --git a/radio/src/pulses/afhds3.h b/radio/src/pulses/afhds3.h index fab057854..5eef56a4b 100644 --- a/radio/src/pulses/afhds3.h +++ b/radio/src/pulses/afhds3.h @@ -94,9 +94,6 @@ struct Data void reset() { -#if !(defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)) - total = 0; -#endif pulsesSize = 0; } #if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO) @@ -118,7 +115,6 @@ struct Data return; } pulses[pulsesSize++] = v; - total += v; } void sendByte(uint8_t b) { @@ -149,14 +145,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 3612f60db..34a10b3d6 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_helpers.h b/radio/src/pulses/modules_helpers.h index 0272a3825..b2bd77de4 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; @@ -671,10 +673,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 6c6471c9c..37364199a 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -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 8f58f2b55..d29eb6504 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 + 2 /* backup */); + mixerSchedulerResetTimer(); + mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD + 2000 /* 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 84ecee015..e9f65a9d2 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -216,21 +216,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 { @@ -315,8 +314,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(); @@ -353,7 +356,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 5d0bfaf05..e852de180 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 a881730fc..e44abd642 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 6e42ebf30..f9f112399 100644 --- a/radio/src/rtos.h +++ b/radio/src/rtos.h @@ -36,7 +36,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); @@ -76,16 +78,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 { @@ -146,6 +158,7 @@ template { return (uint32_t)(simuTimerMicros() / 1000); } + #elif defined(RTOS_COOS) #ifdef __cplusplus extern "C" { @@ -155,7 +168,7 @@ template } #endif - #define RTOS_MS_PER_TICK ((CFG_CPU_FREQ / CFG_SYSTICK_FREQ) / (CFG_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; @@ -230,7 +243,18 @@ 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 class TaskStack diff --git a/radio/src/storage/storage_common.cpp b/radio/src/storage/storage_common.cpp index 40bac6a67..857cdd1a6 100644 --- a/radio/src/storage/storage_common.cpp +++ b/radio/src/storage/storage_common.cpp @@ -53,11 +53,11 @@ void preModelLoad() } pauseMixerCalculations(); -#if defined(INTMODULE_PWR_GPIO) - INTERNAL_MODULE_OFF(); +#if defined(HARDWARE_INTERNAL_MODULE) + stopPulsesInternalModule(); #endif -#if defined(EXTMODULE_PWR_GPIO) - EXTERNAL_MODULE_OFF(); +#if defined(HARDWARE_EXTERNAL_MODULE) + stopPulsesExternalModule(); #endif stopTrainer(); diff --git a/radio/src/targets/common/arm/CMakeLists.txt b/radio/src/targets/common/arm/CMakeLists.txt index 16169ff24..e725bc68c 100644 --- a/radio/src/targets/common/arm/CMakeLists.txt +++ b/radio/src/targets/common/arm/CMakeLists.txt @@ -148,7 +148,7 @@ endif() if(MULTIMODULE) add_definitions(-DMULTIMODULE) - set(SRC ${SRC} pulses/multi.cpp telemetry/spektrum.cpp telemetry/hitec.cpp telemetry/hott.cpp telemetry/multi.cpp io/multi_firmware_update.cpp) + set(SRC ${SRC} pulses/multi.cpp telemetry/spektrum.cpp telemetry/hitec.cpp telemetry/hott.cpp telemetry/mlink.cpp telemetry/multi.cpp io/multi_firmware_update.cpp) endif() if(CROSSFIRE) 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 9cc558b51..86082f7f8 100644 --- a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp @@ -124,7 +124,7 @@ 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; diff --git a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp index 25544c33a..269b40854 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 56b71d97c..794c49765 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 000000000..7f7b23a1c --- /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/sdio_sd.c b/radio/src/targets/common/arm/stm32/sdio_sd.c index f02916b44..f0f97b97f 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 6f64dae51..40454fde3 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -246,6 +246,7 @@ 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 diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index cb379e6fe..0f3f9df4a 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 8550d1517..2b71dab39 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -180,14 +180,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(); @@ -381,7 +378,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 diff --git a/radio/src/targets/horus/extmodule_driver.cpp b/radio/src/targets/horus/extmodule_driver.cpp index 47a40ae02..e73d5c3d3 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 81639e73a..22a646a2d 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -420,9 +420,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 @@ -905,6 +905,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 751aa88cd..97ecc5a61 100644 --- a/radio/src/targets/horus/lcd_driver.cpp +++ b/radio/src/targets/horus/lcd_driver.cpp @@ -141,29 +141,19 @@ static void LCD_NRSTConfig(void) GPIO_Init(LCD_GPIO_NRST, &GPIO_InitStructure); } -// TODO delay function -static void delay3(uint32_t nCount) -{ - uint32_t index = 0; - for(index = (1000 * 100 * nCount); index != 0; --index) - { - __asm("nop\n"); - } -} - static void lcd_reset(void) { #if defined(RADIO_T18) // T18 screen has issues if NRST is ever brought low NRST_HIGH(); #else NRST_HIGH(); - delay3(1); + delay_ms(1); NRST_LOW(); // RESET(); - delay3(20); + delay_ms(20); 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 e87226bf2..ad8a89264 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,7 +113,7 @@ LoopPaintMainStack: /* Call the clock system intitialization function.*/ bl SystemInit -/* Call C++ constructors for static objects */ +/* Call static constructors */ bl __libc_init_array /* Call the application's entry point.*/ bl main diff --git a/radio/src/targets/horus/telemetry_driver.cpp b/radio/src/targets/horus/telemetry_driver.cpp index 0288363be..165e65933 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/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index 54779f137..162dc5c38 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -63,6 +63,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) @@ -449,6 +450,7 @@ set(TARGET_SRC ../common/arm/stm32/audio_dac_driver.cpp ../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) diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index bec585b25..69e36d5e8 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); @@ -346,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 21d34f36e..8e583be73 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -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(); diff --git a/radio/src/targets/taranis/extmodule_driver.cpp b/radio/src/targets/taranis/extmodule_driver.cpp index 4287c0f75..512f16c5d 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 d80f9e197..5c00b3052 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -2185,4 +2185,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 e71768eac..9afacfda8 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/tasks.cpp b/radio/src/tasks.cpp index fc2df74c7..a051cc509 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); @@ -65,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; } @@ -96,6 +114,11 @@ TASK_FUNCTION(mixerTask) { s_pulses_paused = true; + mixerSchedulerInit(); +#if !defined(PCBSKY9X) + mixerSchedulerStart(); +#endif + while (true) { #if defined(SBUS_TRAINER) // SBUS trainer @@ -110,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) { @@ -122,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); @@ -173,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 b46cc2b44..64dba983d 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 5e7d59c78..23d39947e 100644 --- a/radio/src/telemetry/crossfire.h +++ b/radio/src/telemetry/crossfire.h @@ -99,15 +99,15 @@ const uint32_t CROSSFIRE_BAUDRATES[] = { 115200, }; const uint8_t CROSSFIRE_PERIODS[] = { - 4, + 4, 16, }; #if SPORT_MAX_BAUDRATE < 400000 || defined(DEBUG) #define CROSSFIRE_BAUDRATE CROSSFIRE_BAUDRATES[g_eeGeneral.telemetryBaudrate] -#define CROSSFIRE_PERIOD CROSSFIRE_PERIODS[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 098e9c990..8b949b69a 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 0a3195835..36f493b9f 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 000000000..a7cdccb92 --- /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 000000000..eb5da955e --- /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 b1b86eb0a..d71cdad34 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_NORMAL_OPERATION, MULTI_NORMAL_OPERATION}; 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_NORMAL_OPERATION; 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, "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 e9b9ada15..ca9d3fc79 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 47b14d381..700bf535a 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) @@ -375,3 +376,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 6599db749..c70cc5fb9 100644 --- a/radio/src/telemetry/telemetry.h +++ b/radio/src/telemetry/telemetry.h @@ -33,6 +33,7 @@ #include "hitec.h" #include "hott.h" #include "multi.h" + #include "mlink.h" #endif #if defined(MULTIMODULE) || defined(AFHDS3) #include "flysky_ibus.h" @@ -289,4 +290,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 e88807062..b439bd678 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/translations.cpp b/radio/src/translations.cpp index 071ee2815..7cc5977d7 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -98,6 +98,8 @@ ISTR(INPUTNAMES); #if defined(MULTIMODULE) ISTR(MULTI_PROTOCOLS); ISTR(MULTI_POWER); +ISTR(MULTI_TELEMETRY_MODE); +ISTR(MULTI_WBUS_MODE); #endif #if defined(BLUETOOTH) @@ -707,6 +709,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; diff --git a/radio/src/translations.h b/radio/src/translations.h index b5b4ea47d..0ec58fe8e 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -161,6 +161,8 @@ extern const char STR_R9M_PXX2_RF_PROTOCOLS[]; extern const char STR_DSM_PROTOCOLS[]; 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[]; #if defined(AFHDS3) @@ -403,6 +405,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[]; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index bfb2e3006..f042c994e 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -261,7 +261,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) @@ -640,6 +640,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_RFPOWER "Výkon RF" @@ -1382,3 +1383,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 6c906b49e..05b377a40 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -264,7 +264,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) @@ -642,6 +642,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_RFPOWER "RF Power" @@ -1389,3 +1390,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 d61d940ad..7abf4a509 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -264,7 +264,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) @@ -641,6 +641,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_RFPOWER "RF Power" @@ -1386,3 +1387,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 353aab18f..6d19f41df 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -261,7 +261,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) @@ -643,6 +643,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_RFPOWER "RF Power" @@ -1385,3 +1386,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 025a3fd71..1e31139b1 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -282,7 +282,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) @@ -659,6 +659,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_RFPOWER "RF Power" @@ -1393,3 +1394,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 247a4f2fc..06f7159a0 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -284,7 +284,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) @@ -662,6 +662,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_RFPOWER TR("Puiss. RF", "Puissance RF") @@ -1410,3 +1411,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 d7878777b..cdd3dfc94 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -285,7 +285,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) @@ -463,7 +463,7 @@ #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 @@ -661,6 +661,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_RFPOWER "Potenza RF" @@ -872,28 +873,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." @@ -935,7 +936,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 "" @@ -947,8 +948,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]" @@ -971,7 +972,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_AFHDS3_RX_FREQ TR("Freq. RX", "Frequenza RX") #define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetria") #define TR_AFHDS3_ONE_TO_MANY "Multicast" @@ -1403,3 +1404,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 93fec41bf..4aad255b2 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -265,7 +265,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) @@ -647,6 +647,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_RFPOWER "RF Power" @@ -1395,3 +1396,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 ba6192553..8923a5bd0 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -282,7 +282,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) @@ -660,6 +660,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_RFPOWER "RF Power" @@ -1402,3 +1403,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 faa4c95bb..9b82bfdfa 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -278,7 +278,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) @@ -662,6 +662,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_RFPOWER "RF Power" @@ -1401,3 +1402,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 03a3d883f..1b13ffb8f 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -279,7 +279,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) @@ -660,6 +660,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_RFPOWER "RF Power" @@ -1402,3 +1403,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 74735bc7f..a758b1a31 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -134,7 +134,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/fwoptions.py b/radio/util/fwoptions.py index 4ce915426..2349bdd18 100755 --- a/radio/util/fwoptions.py +++ b/radio/util/fwoptions.py @@ -256,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 = { diff --git a/radio/util/tts_en.py b/radio/util/tts_en.py index 616abe516..6230aafe9 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 9dc046fa5..eba461d72 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 000000000..72e367cb3 --- /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 000000000..e0c8cf061 --- /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-tbs.py b/tools/build-tbs.py index 3c5cb2d1c..4d469c608 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