1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-23 16:25:16 +03:00

Merge with latest 2.3

This commit is contained in:
Bertrand Songis 2021-04-06 09:40:48 +02:00
commit 5d131093ef
No known key found for this signature in database
GPG key ID: F189F79290FEC50F
141 changed files with 5095 additions and 3762 deletions

View file

@ -16,6 +16,8 @@ addons:
- libmpc3
- libfox-1.6-dev
- libgtest-dev
- lib32stdc++6
- libclang-common-6.0-dev
- clang-6.0
- python3-pip

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -39,6 +39,8 @@
#include <QLineEdit>
#include <QMenu>
#include <QSpinBox>
#include <QMessageBox>
#include <QPushButton>
FileSyncDialog::FileSyncDialog(QWidget * parent, const SyncProcess::SyncOptions & syncOptions) :
QDialog(parent),

View file

@ -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

View file

@ -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<void *>(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);
}

View file

@ -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 <QtCore>
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;
};

View file

@ -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("<font color=red><b>Inconsistent parameter</b></font>");
return playSoundToString(param);
}
else if (func == FuncPlayHaptic) {
CustomFunctionData::populateHapticParams(qs);
if (param >= 0 && param < (int)qs.count())
return qs.at(param);
else
return tr("<font color=red><b>Inconsistent parameter</b></font>");
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("<font color=red><b>Inconsistent parameter</b></font>");
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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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<void *>(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<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);
}
/*
* FlightModeData
*/
void FlightModeData::clear(const int phaseIdx)
{
memset(reinterpret_cast<void *>(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)

View file

@ -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 <QtCore>
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;
};

View file

@ -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"

View file

@ -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 <QtCore>
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<void *>(this), 0, sizeof(SwashRingData)); }
};

View file

@ -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);
}

View file

@ -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 <QtCore>
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<void *>(this), 0, sizeof(ExpoData)); }
bool isEmpty() const;
};

View file

@ -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 <QtCore>
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<void *>(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<void *>(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<void *>(this), 0, sizeof(SwashRingData)); }
};
#endif // IO_DATA_H

View file

@ -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);
}

View file

@ -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 <QtCore>
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<void *>(this), 0, sizeof(MixData)); }
bool isEmpty() const;
};

View file

@ -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:
if (lsd->val1 != 0) {
updateSourceIntRef(lsd->val1);
if (lsd->val1 == 0)
clearlsd = true;
}
break;
case LS_FAMILY_STICKY:
case LS_FAMILY_VBOOL:
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)
if (lsd->val1 == 0 && lsd->val2 == 0 && ((lsd->val1 != oldval1 && oldval2 == 0) || (lsd->val2 != oldval2 && oldval1 == 0)))
clearlsd = true;
break;
case LS_FAMILY_EDGE:
if (lsd->val1 != 0) {
updateSwitchIntRef(lsd->val1);
if (lsd->val1 == 0)
clearlsd = true;
}
break;
case LS_FAMILY_VCOMP:
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)
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));
}

View file

@ -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 <QtCore>
@ -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<void *>(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

View file

@ -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<void *>(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);
}

View file

@ -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 <QtCore>
#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;
};

View file

@ -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));

View file

@ -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 <QtCore>
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_

View file

@ -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()
{

View file

@ -20,7 +20,7 @@
#pragma once
#include "helpersdata.h"
#include "datahelpers.h"
#include <QtCore>
@ -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();

View file

@ -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<void *>(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;
}

View file

@ -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 <QtCore>
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();
};

View file

@ -1527,7 +1527,7 @@ Mode 4:
<string>Battery warning voltage.
This is the threashhold where the battery warning sounds.
Acceptable values are 5v..10v</string>
Acceptable values are 3v..12v</string>
</property>
<property name="prefix">
<string notr="true"/>
@ -1539,7 +1539,7 @@ Acceptable values are 5v..10v</string>
<number>1</number>
</property>
<property name="minimum">
<double>4.000000000000000</double>
<double>3.000000000000000</double>
</property>
<property name="maximum">
<double>12.000000000000000</double>
@ -1679,7 +1679,7 @@ Acceptable values are 5v..10v</string>
<number>1</number>
</property>
<property name="minimum">
<double>4.000000000000000</double>
<double>3.000000000000000</double>
</property>
<property name="maximum">
<double>16.000000000000000</double>
@ -1708,7 +1708,7 @@ Acceptable values are 5v..10v</string>
<number>1</number>
</property>
<property name="minimum">
<double>4.000000000000000</double>
<double>3.000000000000000</double>
</property>
<property name="maximum">
<double>16.000000000000000</double>

View file

@ -32,6 +32,7 @@
#include "simulatorinterface.h"
#include "simulatormainwindow.h"
#include "storage/sdcard.h"
#include "filtereditemmodels.h"
#include <QFileDialog>
#include <QLabel>
@ -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)
{
if (!lock) {
weightCB->setVisible(state);
if (weightSB)
weightSB->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);
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<mini) {
if (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)
{

View file

@ -18,8 +18,7 @@
* GNU General Public License for more details.
*/
#ifndef _HELPERS_H_
#define _HELPERS_H_
#pragma once
#include "eeprominterface.h"
#include <QCheckBox>
@ -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<QString> & set, const QString & current);
void getFileComboBoxValue(QComboBox * b, char * dest, int length);
@ -234,5 +235,3 @@ private:
};
extern Stopwatch gStopwatch;
#endif // _HELPERS_H_

View file

@ -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();
}

View file

@ -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 <QtCore>
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_

View file

@ -19,53 +19,11 @@
*/
#include "customfunctions.h"
#include "filtereditemmodels.h"
#include "helpers.h"
#include "appdata.h"
#include <TimerEdit>
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);

View file

@ -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 <QMediaPlayer>
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<QString> tracksSet;
QSet<QString> 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_

View file

@ -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()));

View file

@ -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,14 +580,16 @@ 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 (!ed->isEmpty()) {
if ((int)ed->chn == inputIdx)
model->removeInput(i);
}
}
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, inputIdx);
update();
updateItemModels();
@ -589,16 +598,18 @@ 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 (!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++) {
strncpy(model->inputNames[i], model->inputNames[i + 1], sizeof(model->inputNames[i]) - 1);

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

@ -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 <QDir>
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;
ui->mode->setCurrentIndex(ui->mode->findData(timer.mode.toValue()));
ui->value->setTime(QTime(hour, min, sec));
if (timer.countdownBeep == TimerData::COUNTDOWNBEEP_SILENT) {
ui->countdownStartLabel->setEnabled(false);
ui->countdownStart->setEnabled(false);
}
else {
ui->countdownStartLabel->setEnabled(true);
ui->countdownStart->setEnabled(true);
}
if (firmware->getCapability(PermTimers)) {
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();
}
/******************************************************************************/
@ -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);
}

View file

@ -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<QCheckBox *> startupSwitchesCheckboxes;
QVector<QCheckBox *> potWarningCheckboxes;
QVector<QCheckBox *> 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_

View file

@ -604,7 +604,7 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="throttleSource">
<widget class="AutoComboBox" name="throttleSource">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>

View file

@ -9,7 +9,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>675</width>
<width>874</width>
<height>33</height>
</rect>
</property>
@ -33,7 +33,7 @@
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="name">
<widget class="AutoLineEdit" name="name">
<property name="minimumSize">
<size>
<width>80</width>
@ -43,7 +43,7 @@
</widget>
</item>
<item>
<widget class="QTimeEdit" name="value">
<widget class="AutoTimeEdit" name="value">
<property name="accelerated">
<bool>true</bool>
</property>
@ -56,7 +56,7 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="mode"/>
<widget class="AutoComboBox" name="mode"/>
</item>
<item>
<widget class="QLabel" name="countdownBeepLabel">
@ -68,11 +68,18 @@
<item>
<widget class="AutoComboBox" name="countdownBeep"/>
</item>
<item>
<widget class="QLabel" name="countdownStartLabel">
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
<item>
<widget class="AutoComboBox" name="countdownStart"/>
</item>
<item>
<widget class="QCheckBox" name="minuteBeep">
<widget class="AutoCheckBox" name="minuteBeep">
<property name="text">
<string>Minute Call</string>
</property>
@ -109,6 +116,21 @@
<extends>QComboBox</extends>
<header>autocombobox.h</header>
</customwidget>
<customwidget>
<class>AutoLineEdit</class>
<extends>QLineEdit</extends>
<header>autolineedit.h</header>
</customwidget>
<customwidget>
<class>AutoCheckBox</class>
<extends>QCheckBox</extends>
<header>autocheckbox.h</header>
</customwidget>
<customwidget>
<class>AutoTimeEdit</class>
<extends>QTimeEdit</extends>
<header>autotimeedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View file

@ -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<QString> scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/TELEMETRY", QStringList() << "*.lua", 8);
QSet<QString> 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();

View file

@ -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) {

View file

@ -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);

View file

@ -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; i<firmware->getCapability(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();

View file

@ -16,6 +16,7 @@ set(shared_HDRS
genericpanel.h
hexspinbox.h
autoprecisioncombobox.h
autotimeedit.h
)
qt5_wrap_cpp(shared_SRCS ${shared_HDRS})

View file

@ -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);

View file

@ -21,23 +21,23 @@
#pragma once
#include <QCheckBox>
#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;
}
}
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;
};

View file

@ -22,14 +22,23 @@
#include <QComboBox>
#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;
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) {
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();
}
emit currentDataChanged(val);
}
}
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;
};

View file

@ -21,7 +21,7 @@
#pragma once
#include <QDoubleSpinBox>
#include "modeledit/modeledit.h"
#include "genericpanel.h"
#if __GNUC__
#include <math.h>
#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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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();
}
}

View file

@ -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 <QTimeEdit>
#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;
};

View file

@ -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);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -382,6 +382,7 @@ set(SRC
strhelpers.cpp
switches.cpp
mixer.cpp
mixer_scheduler.cpp
stamp.cpp
timers.cpp
trainer.cpp

View file

@ -161,7 +161,7 @@ const char * const unitsFilenames[] = {
"hertz",
"ms",
"us",
"spare4",
"km",
"spare5",
"spare6",
"spare7",

View file

@ -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;
}

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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

View file

@ -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();

View file

@ -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)

View file

@ -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)
{
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 },

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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();

View file

@ -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()

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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<pulse_duration_t, 200> {
void addTail()
{
// rest min value is 18000 - 200 * 48 = 8400 (4.2ms)
*(ptr - 1) += rest;
*(ptr - 1) = 60000;
}
};

View file

@ -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

View file

@ -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<int SIZE>
class FakeTaskStack
{
@ -146,6 +158,7 @@ template<int SIZE>
{
return (uint32_t)(simuTimerMicros() / 1000);
}
#elif defined(RTOS_COOS)
#ifdef __cplusplus
extern "C" {
@ -155,7 +168,7 @@ template<int SIZE>
}
#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,6 +243,17 @@ template<int SIZE>
#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<int SIZE>

View file

@ -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();

View file

@ -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)

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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,7 +1336,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, (TransferError << 8) + (DMAEndOfTransfer << 1) + TransferEnd);
#endif
DMAEndOfTransfer = 0;
@ -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
}
/**

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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:
case PROTOCOL_CHANNELS_DSM2_LP45:
case PROTOCOL_CHANNELS_DSM2_DSM2:
case PROTOCOL_CHANNELS_DSM2_DSMX:
case PROTOCOL_CHANNELS_MULTIMODULE:
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
// 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
}
// 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);
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();
}

View file

@ -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)

Some files were not shown because too many files have changed in this diff Show more