1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-13 11:29:51 +03:00

Merge with latest 2.3

This commit is contained in:
Bertrand Songis 2021-01-12 17:16:15 +01:00
commit a02bf3aa0c
No known key found for this signature in database
GPG key ID: F189F79290FEC50F
118 changed files with 7785 additions and 6935 deletions

View file

@ -6,7 +6,7 @@ set(VERSION_REVISION "0")
set(VERSION_SUFFIX $ENV{OPENTX_VERSION_SUFFIX}) set(VERSION_SUFFIX $ENV{OPENTX_VERSION_SUFFIX})
set(VERSION_FAMILY ${VERSION_MAJOR}.${VERSION_MINOR}) set(VERSION_FAMILY ${VERSION_MAJOR}.${VERSION_MINOR})
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}${VERSION_SUFFIX}) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}${VERSION_SUFFIX})
set(SDCARD_REVISION "0034") set(SDCARD_REVISION "0035")
set(SDCARD_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}V${SDCARD_REVISION}) set(SDCARD_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}V${SDCARD_REVISION})
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)

View file

@ -1,6 +1,7 @@
[Main developers] [Main developers]
Bertrand Songis (bsongis) Bertrand Songis (bsongis)
André Bernet (kilrah) André Bernet (kilrah)
JC D. (3djc)
Michael Blandford Michael Blandford
Damjan Adamic (projectkk2glider) Damjan Adamic (projectkk2glider)
Franck Aguerre (jivarofad) Franck Aguerre (jivarofad)
@ -9,6 +10,7 @@ Martin Hotař (mhotar)
Maxim (Max) Paperno (mpaperno) Maxim (Max) Paperno (mpaperno)
Arne Schwabe (schwabe) Arne Schwabe (schwabe)
Daniel Gorbea (dgatf) Daniel Gorbea (dgatf)
Neil Horne (elecpower)
[Translators] [Translators]
[fr] Sebastien Charpentier (LapinFou) [fr] Sebastien Charpentier (LapinFou)
@ -1942,3 +1944,152 @@ Miklos Turcsin
Edward Skerness Edward Skerness
Stefano Perinetti Stefano Perinetti
Toni Marchante Toni Marchante
Stuart Olson
Peter Campbell
Keith Wood
Leo Duflou
Michael Florey
Gerhard Weixelbaumer
Peter K Lehotsky
Elisha Jones
Joerg Sattler
paul42
Pascal Heg
Bjorn Sorenssen
Chris Payne
Pascal Afflard
Robert Boboryko
Chris Whitehead
David Bradley
Ian Lever
Phillip Barber
Jan Bronee
N Haasnoot
Rick Smith
Randall Grant
Patrick Degouy
Piotr Zdanowski
David Gardner
TMac FPV
Bernard Thompson
Mark Sutton
Darren J Crane
Michael Keyes
Magnus Borg
David Lorentzen
Antony Smith
Aleksandr Sarkisov
Johannes Kuhne
Kathleen Cilluffo
David Hoffmann
Alan Porter
Arlé Mooldijk
Tenbones
Kim Bitsch Lauridsen
Arthur Costerus
Peter Harvey
John Simpson
Landy de los Santos
Graham Ridley
Schenk Peter
Joseph Rex
Richard Honeywell
Roy Nixon
Andrew Shewan
David Bradley
Alan Micklethwaite
Susan Siegel
Stephen Evans
William Hallman
Franck Michel
László Gajcsi (monthly)
Danny Koch
Robert Martin
Gavin Meerwald
Frédéric Maix
Frank Steinberg
Kevin Berkefeld
Marccos Colon
Kerry Reynolds
Kim Jeppesen
Arthur Peters
Andrew Lowes
Anthony Hallo
Bill Hill
Gerard Falaise
Kevin Raynor
Lorenzo gh
Jan Landeweer
David Bland
Manuel Spoerri
Jeff Jacobs
David Thorne
Maddox Philip
James Jewitt
Justin Digby
John Magnuson (monthly)
Holger Lippert
Hubert Huber
David Blum
Noam Kfir
Mats gårdstad friberg
Jesper Frickmann
Alan Bunker
Emanuel Kircher
Barry Andersen
Gabriel Formanek
Timothy Justiniano
Kelvin Garcia Urbina
Jan Lau
Choon Wei Jonathan Tan
Daniel Navas
Ray Moss
Markus Frielingsdorf
Michael Hirschauer
Jesse Frey
Philipp Koch
Robert Rubio
Dennis G Miller
Leonardo Garcia Osuna
Antonio Carrasco Pastor
Musa Pinar
Jens Moder
Josef de Beer
Chad Mofford
Pim Pouw
Kenth Jonsson
Gordon Westfall
Jean-Michel Saves
Roberto Orsello
Luboš Konvalinka
Lawrence Dorn
Michael Dittmann
Bernd Schmiedel
Raoul Piccioli
Uwe Probst
Glendon Satchell
Trevor Collins
Horst Grashauser
Miguel José Cárdenas Herrera
Mike Jennings
José Bernardo
Carlos Dangle
Gordon Evans
Pablo Peinado Abad
Carl Payne
Adam Sosnowski
Гасак Сергей
SaltCtyRacingFPV
Georg Bernhardt
James Mildenhall
Dave Plummer
Ivan Mokris
Patrick Daniels
Stuart Olson
Cory Znebel
Andrey Yarovoy
Christian Pons
Burt Pickard-Richardson
Michal Mesaros
Conrad Young
Martin Mathes

View file

@ -71,6 +71,7 @@
#define CPN_STR_APP_SETTINGS_FILTER CPN_STR_APP_SETTINGS_FILES % " (*.ini)" #define CPN_STR_APP_SETTINGS_FILTER CPN_STR_APP_SETTINGS_FILES % " (*.ini)"
#define CPN_STR_UNKNOWN_ITEM "???" #define CPN_STR_UNKNOWN_ITEM "???"
#define CPN_STR_NONE_ITEM "----"
#define CPN_STR_SW_INDICATOR_UP QCoreApplication::translate("RawSwitch", "\xE2\x86\x91") // Switch up position indicator: Up arrow, or similar. #define CPN_STR_SW_INDICATOR_UP QCoreApplication::translate("RawSwitch", "\xE2\x86\x91") // Switch up position indicator: Up arrow, or similar.
#define CPN_STR_SW_INDICATOR_DN QCoreApplication::translate("RawSwitch", "\xE2\x86\x93") // Switch down position indicator: Down arrow, or similar. #define CPN_STR_SW_INDICATOR_DN QCoreApplication::translate("RawSwitch", "\xE2\x86\x93") // Switch down position indicator: Down arrow, or similar.

View file

@ -30,7 +30,7 @@ RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSett
Firmware * fw = getCurrentFirmware(); Firmware * fw = getCurrentFirmware();
addItems(SOURCE_TYPE_NONE, RawSource::NoneGroup, 1); addItems(SOURCE_TYPE_NONE, RawSource::NoneGroup, 1);
for (int i=0; i < fw->getCapability(LuaScripts); i++) for (int i = 0; i < fw->getCapability(LuaScripts); i++)
addItems(SOURCE_TYPE_LUA_OUTPUT, RawSource::ScriptsGroup, fw->getCapability(LuaOutputsPerScript), i * 16); addItems(SOURCE_TYPE_LUA_OUTPUT, RawSource::ScriptsGroup, fw->getCapability(LuaOutputsPerScript), i * 16);
addItems(SOURCE_TYPE_VIRTUAL_INPUT, RawSource::InputsGroup, fw->getCapability(VirtualInputs)); addItems(SOURCE_TYPE_VIRTUAL_INPUT, RawSource::InputsGroup, fw->getCapability(VirtualInputs));
addItems(SOURCE_TYPE_STICK, RawSource::SourcesGroup, board.getCapability(Board::MaxAnalogs)); addItems(SOURCE_TYPE_STICK, RawSource::SourcesGroup, board.getCapability(Board::MaxAnalogs));
@ -43,7 +43,7 @@ RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSett
addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, fw->getCapability(TrainerInputs)); addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, fw->getCapability(TrainerInputs));
addItems(SOURCE_TYPE_CH, RawSource::SourcesGroup, fw->getCapability(Outputs)); addItems(SOURCE_TYPE_CH, RawSource::SourcesGroup, fw->getCapability(Outputs));
addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, 5); addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, 5);
addItems(SOURCE_TYPE_TELEMETRY, RawSource::TelemGroup, CPN_MAX_SENSORS * 3); addItems(SOURCE_TYPE_TELEMETRY, RawSource::TelemGroup, fw->getCapability(Sensors) * 3);
addItems(SOURCE_TYPE_GVAR, RawSource::GVarsGroup, fw->getCapability(Gvars)); addItems(SOURCE_TYPE_GVAR, RawSource::GVarsGroup, fw->getCapability(Gvars));
} }
@ -67,10 +67,14 @@ void RawSourceItemModel::addItems(const RawSourceType & type, const int group, c
} }
} }
void RawSourceItemModel::update() const void RawSourceItemModel::update()
{ {
for (int i=0; i < rowCount(); ++i) emit dataAboutToBeUpdated();
for (int i = 0; i < rowCount(); ++i)
setDynamicItemData(item(i), RawSource(item(i)->data(ItemIdRole).toInt())); setDynamicItemData(item(i), RawSource(item(i)->data(ItemIdRole).toInt()));
emit dataUpdateComplete();
} }
@ -86,7 +90,7 @@ RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSett
// Descending switch direction: NOT (!) switches // Descending switch direction: NOT (!) switches
addItems(SWITCH_TYPE_ACT, -1); addItems(SWITCH_TYPE_ACT, -1);
addItems(SWITCH_TYPE_SENSOR, -CPN_MAX_SENSORS); addItems(SWITCH_TYPE_SENSOR, -fw->getCapability(Sensors));
addItems(SWITCH_TYPE_TELEMETRY, -1); addItems(SWITCH_TYPE_TELEMETRY, -1);
addItems(SWITCH_TYPE_FLIGHT_MODE, -fw->getCapability(FlightModes)); addItems(SWITCH_TYPE_FLIGHT_MODE, -fw->getCapability(FlightModes));
addItems(SWITCH_TYPE_VIRTUAL, -fw->getCapability(LogicalSwitches)); addItems(SWITCH_TYPE_VIRTUAL, -fw->getCapability(LogicalSwitches));
@ -105,7 +109,7 @@ RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSett
addItems(SWITCH_TYPE_VIRTUAL, fw->getCapability(LogicalSwitches)); addItems(SWITCH_TYPE_VIRTUAL, fw->getCapability(LogicalSwitches));
addItems(SWITCH_TYPE_FLIGHT_MODE, fw->getCapability(FlightModes)); addItems(SWITCH_TYPE_FLIGHT_MODE, fw->getCapability(FlightModes));
addItems(SWITCH_TYPE_TELEMETRY, 1); addItems(SWITCH_TYPE_TELEMETRY, 1);
addItems(SWITCH_TYPE_SENSOR, CPN_MAX_SENSORS); addItems(SWITCH_TYPE_SENSOR, fw->getCapability(Sensors));
addItems(SWITCH_TYPE_ON, 1); addItems(SWITCH_TYPE_ON, 1);
addItems(SWITCH_TYPE_ONE, 1); addItems(SWITCH_TYPE_ONE, 1);
addItems(SWITCH_TYPE_ACT, 1); addItems(SWITCH_TYPE_ACT, 1);
@ -166,8 +170,95 @@ void RawSwitchItemModel::addItems(const RawSwitchType & type, int count)
} }
} }
void RawSwitchItemModel::update() const void RawSwitchItemModel::update()
{ {
for (int i=0; i < rowCount(); ++i) emit dataAboutToBeUpdated();
for (int i = 0; i < rowCount(); ++i)
setDynamicItemData(item(i), RawSwitch(item(i)->data(ItemIdRole).toInt())); setDynamicItemData(item(i), RawSwitch(item(i)->data(ItemIdRole).toInt()));
emit dataUpdateComplete();
}
//
// CurveItemModel
//
CurveItemModel::CurveItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) :
AbstractRawItemDataModel(generalSettings, modelData, parent)
{
const int count = getCurrentFirmware()->getCapability(NumCurves);
for (int i = -count ; i <= count; ++i) {
QStandardItem * modelItem = new QStandardItem();
modelItem->setData(i, ItemIdRole);
int flags;
if (i < 0)
flags = DataGroups::NegativeGroup;
else if (i > 0)
flags = DataGroups::PositiveGroup;
else
flags = DataGroups::NoneGroup;
modelItem->setData(flags, ItemFlagsRole);
setDynamicItemData(modelItem, i);
appendRow(modelItem);
}
}
void CurveItemModel::setDynamicItemData(QStandardItem * item, int index) const
{
item->setText(CurveReference(CurveReference::CURVE_REF_CUSTOM, index).toString(modelData, false));
item->setData(true, IsAvailableRole);
}
void CurveItemModel::update()
{
emit dataAboutToBeUpdated();
for (int i = 0; i < rowCount(); ++i)
setDynamicItemData(item(i), item(i)->data(ItemIdRole).toInt());
emit dataUpdateComplete();
}
//
// CommonItemModels
//
CommonItemModels::CommonItemModels(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent) :
QObject(parent)
{
m_rawSourceItemModel = new RawSourceItemModel(generalSettings, modelData, parent);
m_rawSwitchItemModel = new RawSwitchItemModel(generalSettings, modelData, parent);
m_curveItemModel = new CurveItemModel(generalSettings, modelData, parent);
}
CommonItemModels::~CommonItemModels()
{
}
void CommonItemModels::update(const RadioModelObjects radioModelObjects)
{
switch (radioModelObjects) {
case RMO_CHANNELS:
case RMO_INPUTS:
case RMO_TELEMETRY_SENSORS:
case RMO_TIMERS:
m_rawSourceItemModel->update();
break;
case RMO_FLIGHT_MODES:
case RMO_GLOBAL_VARIABLES:
case RMO_LOGICAL_SWITCHES:
m_rawSourceItemModel->update();
m_rawSwitchItemModel->update();
break;
case RMO_CURVES:
m_curveItemModel->update();
break;
case RMO_SCRIPTS:
// no need to refresh
break;
default:
qDebug() << "Unknown RadioModelObject:" << radioModelObjects;
}
} }

View file

@ -36,6 +36,13 @@ class AbstractRawItemDataModel: public QStandardItemModel
enum DataRoles { ItemIdRole = Qt::UserRole, ItemTypeRole, ItemFlagsRole, IsAvailableRole }; enum DataRoles { ItemIdRole = Qt::UserRole, ItemTypeRole, ItemFlagsRole, IsAvailableRole };
Q_ENUM(DataRoles) Q_ENUM(DataRoles)
enum DataGroups {
NoneGroup = 0x01,
NegativeGroup = 0x02,
PositiveGroup = 0x04
};
Q_ENUM(DataGroups)
explicit AbstractRawItemDataModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr) : explicit AbstractRawItemDataModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr) :
QStandardItemModel(parent), QStandardItemModel(parent),
generalSettings(generalSettings), generalSettings(generalSettings),
@ -43,7 +50,11 @@ class AbstractRawItemDataModel: public QStandardItemModel
{} {}
public slots: public slots:
virtual void update() const = 0; virtual void update() = 0;
signals:
void dataAboutToBeUpdated();
void dataUpdateComplete();
protected: protected:
const GeneralSettings * generalSettings; const GeneralSettings * generalSettings;
@ -58,7 +69,7 @@ class RawSourceItemModel: public AbstractRawItemDataModel
explicit RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr); explicit RawSourceItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr);
public slots: public slots:
void update() const override; void update() override;
protected: protected:
void setDynamicItemData(QStandardItem * item, const RawSource & src) const; void setDynamicItemData(QStandardItem * item, const RawSource & src) const;
@ -73,7 +84,7 @@ class RawSwitchItemModel: public AbstractRawItemDataModel
explicit RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr); explicit RawSwitchItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr);
public slots: public slots:
void update() const override; void update() override;
protected: protected:
void setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const; void setDynamicItemData(QStandardItem * item, const RawSwitch & rsw) const;
@ -81,4 +92,49 @@ class RawSwitchItemModel: public AbstractRawItemDataModel
}; };
class CurveItemModel: public AbstractRawItemDataModel
{
Q_OBJECT
public:
explicit CurveItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr);
public slots:
void update() override;
protected:
void setDynamicItemData(QStandardItem * item, int index) const;
};
class CommonItemModels: public QObject
{
Q_OBJECT
public:
enum RadioModelObjects {
RMO_CHANNELS,
RMO_CURVES,
RMO_FLIGHT_MODES,
RMO_GLOBAL_VARIABLES,
RMO_INPUTS,
RMO_LOGICAL_SWITCHES,
RMO_SCRIPTS,
RMO_TELEMETRY_SENSORS,
RMO_TIMERS
};
Q_ENUM(RadioModelObjects)
explicit CommonItemModels(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr);
~CommonItemModels();
void update(const RadioModelObjects radioModelObjects);
RawSourceItemModel * rawSourceItemModel() const { return m_rawSourceItemModel; }
RawSwitchItemModel * rawSwitchItemModel() const { return m_rawSwitchItemModel; }
CurveItemModel * curveItemModel() const { return m_curveItemModel; }
private:
RawSourceItemModel *m_rawSourceItemModel;
RawSwitchItemModel *m_rawSwitchItemModel;
CurveItemModel *m_curveItemModel;
};
#endif // RAWITEMDATAMODELS_H #endif // RAWITEMDATAMODELS_H

View file

@ -19,7 +19,6 @@
*/ */
#include "rawitemfilteredmodel.h" #include "rawitemfilteredmodel.h"
#include "rawitemdatamodels.h"
RawItemFilteredModel::RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent) : RawItemFilteredModel::RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent) :
QSortFilterProxyModel(parent), QSortFilterProxyModel(parent),
@ -30,6 +29,12 @@ RawItemFilteredModel::RawItemFilteredModel(QAbstractItemModel * sourceModel, int
setFilterFlags(flags); setFilterFlags(flags);
setDynamicSortFilter(true); setDynamicSortFilter(true);
setSourceModel(sourceModel); setSourceModel(sourceModel);
AbstractRawItemDataModel * itemModel = qobject_cast<AbstractRawItemDataModel *>(sourceModel);
if (itemModel) {
connect(itemModel, &AbstractRawItemDataModel::dataAboutToBeUpdated, this, &RawItemFilteredModel::onDataAboutToBeUpdated);
connect(itemModel, &AbstractRawItemDataModel::dataUpdateComplete, this, &RawItemFilteredModel::onDataUpdateComplete);
}
} }
void RawItemFilteredModel::setFilterFlags(int flags) void RawItemFilteredModel::setFilterFlags(int flags)
@ -56,19 +61,17 @@ bool RawItemFilteredModel::filterAcceptsRow(int sourceRow, const QModelIndex & s
void RawItemFilteredModel::update() const void RawItemFilteredModel::update() const
{ {
AbstractRawItemDataModel * model = qobject_cast<AbstractRawItemDataModel *>(sourceModel()); AbstractRawItemDataModel * itemModel = qobject_cast<AbstractRawItemDataModel *>(sourceModel());
if (model) if (itemModel)
model->update(); itemModel->update();
} }
void RawItemFilteredModel::onDataAboutToBeUpdated()
RawSourceFilterItemModel::RawSourceFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int flags, QObject * parent) :
RawItemFilteredModel(new RawSourceItemModel(generalSettings, modelData, parent), flags, parent)
{ {
emit dataAboutToBeUpdated();
} }
void RawItemFilteredModel::onDataUpdateComplete()
RawSwitchFilterItemModel::RawSwitchFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int context, QObject * parent) :
RawItemFilteredModel(new RawSwitchItemModel(generalSettings, modelData, parent), context, parent)
{ {
emit dataUpdateComplete();
} }

View file

@ -21,54 +21,43 @@
#ifndef RAWITEMFILTEREDMODEL_H #ifndef RAWITEMFILTEREDMODEL_H
#define RAWITEMFILTEREDMODEL_H #define RAWITEMFILTEREDMODEL_H
#include "rawitemdatamodels.h"
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
class GeneralSettings; class GeneralSettings;
class ModelData; class ModelData;
class RawSourceItemModel;
class RawSwitchItemModel;
class RawItemFilteredModel: public QSortFilterProxyModel class RawItemFilteredModel: public QSortFilterProxyModel
{ {
Q_OBJECT Q_OBJECT
public: public:
enum DataFilters {
AllFilter = AbstractRawItemDataModel::NegativeGroup | AbstractRawItemDataModel::NoneGroup | AbstractRawItemDataModel::PositiveGroup,
AllExcludeNoneFilter = AllFilter &~ AbstractRawItemDataModel::NoneGroup,
NegativeFilter = AbstractRawItemDataModel::NegativeGroup | AbstractRawItemDataModel::NoneGroup,
NegativeExcludeNoneFilter = AbstractRawItemDataModel::NegativeGroup,
PositiveFilter = AbstractRawItemDataModel::PositiveGroup | AbstractRawItemDataModel::NoneGroup,
PositiveExcludeNoneFilter = AbstractRawItemDataModel::PositiveGroup
};
Q_ENUM(DataFilters)
explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent = nullptr); explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, int flags, QObject * parent = nullptr);
explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, QObject * parent = nullptr) : RawItemFilteredModel(sourceModel, 0, parent) {} explicit RawItemFilteredModel(QAbstractItemModel * sourceModel, QObject * parent = nullptr) : RawItemFilteredModel(sourceModel, 0, parent) {}
public slots: public slots:
void setFilterFlags(int flags); void setFilterFlags(int flags);
void update() const; void update() const;
void onDataAboutToBeUpdated();
void onDataUpdateComplete();
signals:
void dataAboutToBeUpdated();
void dataUpdateComplete();
protected: protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override; bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const override;
int filterFlags; int filterFlags;
}; };
// The specialized "convenience" types below can go away once centralalized RawSource/RawSwitch item models are established.
// These proxy classes will automatically create a source model of the corresponding type.
class RawSwitchFilterItemModel: public RawItemFilteredModel
{
Q_OBJECT
public:
using RawItemFilteredModel::RawItemFilteredModel;
explicit RawSwitchFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int context, QObject * parent = nullptr);
};
class RawSourceFilterItemModel: public RawItemFilteredModel
{
Q_OBJECT
public:
using RawItemFilteredModel::RawItemFilteredModel;
explicit RawSourceFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, int flags, QObject * parent = nullptr);
explicit RawSourceFilterItemModel(const GeneralSettings * const generalSettings, const ModelData * const modelData, QObject * parent = nullptr) :
RawSourceFilterItemModel(generalSettings, modelData, 0, parent) {}
};
#endif // RAWITEMFILTEREDMODEL_H #endif // RAWITEMFILTEREDMODEL_H

View file

@ -32,8 +32,14 @@ list(APPEND firmwares_HDRS
moduledata.h moduledata.h
) )
set(firmwares_QT
curvereference.h
)
qt5_wrap_cpp(firmwares_SRCS ${firmwares_QT})
add_library(firmwares ${firmwares_SRCS} ${firmwares_HDRS}) add_library(firmwares ${firmwares_SRCS} ${firmwares_HDRS})
target_link_libraries(firmwares ${CPN_COMMON_LIB} Qt5::Core Qt5::Xml Qt5::Widgets) target_link_libraries(firmwares ${CPN_COMMON_LIB} datamodels Qt5::Core Qt5::Xml Qt5::Widgets)
target_include_directories(firmwares target_include_directories(firmwares
PRIVATE PRIVATE
${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}

View file

@ -191,7 +191,20 @@ SwitchInfo Boards::getSwitchInfo(Board::Type board, int index)
if (index < DIM(switches)) if (index < DIM(switches))
return switches[index]; return switches[index];
} }
else if (IS_TARANIS_X7(board)) { else if (board == BOARD_TARANIS_X7_ACCESS) {
const Board::SwitchInfo switches[] = {
{SWITCH_3POS, "SA"},
{SWITCH_3POS, "SB"},
{SWITCH_3POS, "SC"},
{SWITCH_3POS, "SD"},
{SWITCH_2POS, "SF"},
{SWITCH_TOGGLE, "SH"},
{SWITCH_2POS, "SI"}
};
if (index < DIM(switches))
return switches[index];
}
else if (board == BOARD_TARANIS_X7) {
const Board::SwitchInfo switches[] = { const Board::SwitchInfo switches[] = {
{SWITCH_3POS, "SA"}, {SWITCH_3POS, "SA"},
{SWITCH_3POS, "SB"}, {SWITCH_3POS, "SB"},
@ -350,7 +363,9 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return 5; return 5;
else if (board == Board::BOARD_TARANIS_X9LITES) else if (board == Board::BOARD_TARANIS_X9LITES)
return 7; return 7;
else if (IS_TARANIS_X7(board)) else if (board == BOARD_TARANIS_X7_ACCESS)
return 7;
else if (board == BOARD_TARANIS_X7)
return 8; return 8;
else if (IS_FAMILY_T12(board)) else if (IS_FAMILY_T12(board))
return 8; return 8;

View file

@ -19,45 +19,293 @@
*/ */
#include "curvereference.h" #include "curvereference.h"
#include "adjustmentreference.h"
#include "helpers.h"
#include "modeldata.h"
#include "rawitemfilteredmodel.h"
#include "helpers.h" // for Helpers::getAdjustmentString() const QString CurveReference::toString(const ModelData * model, bool verbose) const
#include "radiodata.h" // for ModelData
QString CurveReference::toString(const ModelData * model, bool verbose) const
{ {
if (value == 0) { if (value == 0)
return "----"; return CPN_STR_NONE_ITEM;
}
QString ret; QString ret;
unsigned idx = abs(value) - 1; unsigned idx = abs(value) - 1;
switch(type) { switch(type) {
case CURVE_REF_DIFF: case CURVE_REF_DIFF:
ret = tr("Diff(%1)").arg(Helpers::getAdjustmentString(value, model));
break;
case CURVE_REF_EXPO: case CURVE_REF_EXPO:
ret = tr("Expo(%1)").arg(Helpers::getAdjustmentString(value, model)); ret = AdjustmentReference(value).toString(model);
break; break;
case CURVE_REF_FUNC: case CURVE_REF_FUNC:
ret = QString("x>0" "x<0" "|x|" "f>0" "f<0" "|f|").mid(3*(value-1), 3); ret = functionToString(value);
if (verbose)
ret = tr("Function(%1)").arg(ret);
break; break;
case CURVE_REF_CUSTOM:
default:
if (model) if (model)
ret = model->curves[idx].nameToString(idx); ret = model->curves[idx].nameToString(idx);
else else
ret = CurveData().nameToString(idx); ret = CurveData().nameToString(idx);
if (verbose)
ret = tr("Curve(%1)").arg(ret);
if (value < 0) if (value < 0)
ret.prepend(CPN_STR_SW_INDICATOR_REV); ret.prepend(CPN_STR_SW_INDICATOR_REV);
break; break;
default:
return CPN_STR_UNKNOWN_ITEM;
} }
if (verbose)
ret = tr(qPrintable(QString(typeToString(type) + "(%1)").arg(ret)));
return ret; return ret;
} }
const bool CurveReference::isValueNumber() const
{
return (type == CURVE_REF_DIFF || type == CURVE_REF_EXPO) && AdjustmentReference(value).type == AdjustmentReference::ADJUST_REF_VALUE;
}
// static
int CurveReference::getDefaultValue(const CurveRefType type, const bool isGVar)
{
if (isGVar && (type == CURVE_REF_DIFF || type == CURVE_REF_EXPO))
return AdjustmentReference(AdjustmentReference::ADJUST_REF_GVAR, 1).toValue();
else if (type == CURVE_REF_FUNC)
return 1;
else
return 0;
}
// static
QString CurveReference::typeToString(const CurveRefType type)
{
const QStringList strl = { "Diff", "Expo" , "Func", "Curve" };
int idx = (int)type;
if (idx < 0 || idx >= strl.count())
return CPN_STR_UNKNOWN_ITEM;
return strl.at(idx);
}
constexpr int MAX_CURVE_REF_FUNC { 6 };
// static
QString CurveReference::functionToString(const int value)
{
const QStringList strl = { "x>0", "x<0", "|x|", "f>0", "f<0", "|f|" };
int idx = value - 1;
if (idx < 0 || idx >= strl.count())
return CPN_STR_UNKNOWN_ITEM;
return strl.at(idx);
}
/*
* CurveReferenceUIManager
*/
constexpr int CURVE_REF_UI_HIDE_DIFF { 0x01 };
constexpr int CURVE_REF_UI_HIDE_EXPO { 0x02 };
constexpr int CURVE_REF_UI_HIDE_NEGATIVE_CURVES { 0x04 };
// static
bool CurveReferenceUIManager::firsttime { true };
int CurveReferenceUIManager::flags { 0 };
bool CurveReferenceUIManager::hasCapabilityGvars { false };
int CurveReferenceUIManager::numCurves { 0 };
RawItemFilteredModel * CurveReferenceUIManager::curveItemModel { nullptr };
QStandardItemModel * CurveReferenceUIManager::tempModel { nullptr };
CurveReferenceUIManager::CurveReferenceUIManager(QComboBox * curveValueCB, CurveReference & curve, const ModelData & model,
RawItemFilteredModel * curveItemModel, QObject * parent) :
QObject(parent),
curveTypeCB(nullptr),
curveGVarCB(nullptr),
curveValueSB(nullptr),
curveValueCB(curveValueCB),
curve(curve),
model(model),
lock(false)
{
init(curveItemModel);
}
CurveReferenceUIManager::CurveReferenceUIManager(QComboBox * curveTypeCB, QCheckBox * curveGVarCB, QSpinBox * curveValueSB,
QComboBox * curveValueCB, CurveReference & curve, const ModelData & model,
RawItemFilteredModel * curveItemModel, QObject * parent) :
QObject(parent),
curveTypeCB(curveTypeCB),
curveGVarCB(curveGVarCB),
curveValueSB(curveValueSB),
curveValueCB(curveValueCB),
curve(curve),
model(model),
lock(false)
{
init(curveItemModel);
}
CurveReferenceUIManager::~CurveReferenceUIManager()
{
delete tempModel;
}
void CurveReferenceUIManager::init(RawItemFilteredModel * curveModel)
{
tempModel = new QStandardItemModel();
if (firsttime) {
firsttime = false;
Firmware * fw = getCurrentFirmware();
hasCapabilityGvars = fw->getCapability(Gvars);
numCurves = fw->getCapability(NumCurves);
curveItemModel = curveModel;
if (!fw->getCapability(HasInputDiff))
flags |= (CURVE_REF_UI_HIDE_DIFF | CURVE_REF_UI_HIDE_NEGATIVE_CURVES);
if (!fw->getCapability(HasMixerExpo))
flags |= CURVE_REF_UI_HIDE_EXPO;
}
if (curveTypeCB) {
populateTypeCB(curveTypeCB, curve);
connect(curveTypeCB, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int)));
}
if (curveGVarCB)
connect(curveGVarCB, SIGNAL(stateChanged(int)), this, SLOT(gvarCBChanged(int)));
if (curveValueSB) {
curveValueSB->setMinimum(-100);
curveValueSB->setMaximum(100);
connect(curveValueSB, SIGNAL(editingFinished()), this, SLOT(valueSBChanged()));
}
curveValueCB->setSizeAdjustPolicy(QComboBox::AdjustToContents);
curveValueCB->setMaxVisibleItems(10);
connect(curveValueCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valueCBChanged()));
update();
}
#define CURVE_REF_UI_GVAR_SHOW (1<<0)
#define CURVE_REF_UI_VALUE_SHOW (1<<1)
#define CURVE_REF_UI_REF_SHOW (1<<2)
void CurveReferenceUIManager::update()
{
lock = true;
int widgetsMask = 0;
if (curve.type == CurveReference::CURVE_REF_DIFF || curve.type == CurveReference::CURVE_REF_EXPO) {
if (hasCapabilityGvars)
widgetsMask |= CURVE_REF_UI_GVAR_SHOW;
if (curve.isValueNumber()) {
curveGVarCB->setChecked(false);
curveValueSB->setValue(curve.value);
widgetsMask |= CURVE_REF_UI_VALUE_SHOW;
}
else {
curveGVarCB->setChecked(true);
widgetsMask |= CURVE_REF_UI_REF_SHOW;
}
}
else {
widgetsMask |= CURVE_REF_UI_REF_SHOW;
}
if(curveTypeCB) {
curveTypeCB->setCurrentIndex(curveTypeCB->findData(curve.type));
curveTypeCB->show();
}
if(curveGVarCB)
curveGVarCB->setVisible(widgetsMask & CURVE_REF_UI_GVAR_SHOW);
if(curveValueSB)
curveValueSB->setVisible(widgetsMask & CURVE_REF_UI_VALUE_SHOW);
if(curveValueCB) {
if (curve.isValueReference())
populateValueCB(curveValueCB, curve, &model);
curveValueCB->setVisible(widgetsMask & CURVE_REF_UI_REF_SHOW);
}
lock = false;
}
void CurveReferenceUIManager::gvarCBChanged(int state)
{
if (!lock) {
curve.value = CurveReference::getDefaultValue(curve.type, state);
update();
}
}
void CurveReferenceUIManager::typeChanged(int value)
{
if (!lock) {
CurveReference::CurveRefType type = (CurveReference::CurveRefType)curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt();
curve = CurveReference(type, CurveReference::getDefaultValue(type));
update();
}
}
void CurveReferenceUIManager::valueSBChanged()
{
if (!lock) {
curve.value = curveValueSB->value();
update();
}
}
void CurveReferenceUIManager::valueCBChanged()
{
if (!lock) {
curve.value = curveValueCB->itemData(curveValueCB->currentIndex()).toInt();
update();
}
}
// static
void CurveReferenceUIManager::populateTypeCB(QComboBox * cb, const CurveReference & curveRef)
{
if (cb) {
cb->clear();
for (int i = 0; i <= CurveReference::MAX_CURVE_REF_TYPE; i++) {
if ((curveRef.type == CurveReference::CURVE_REF_DIFF && !(flags & CURVE_REF_UI_HIDE_DIFF)) ||
(curveRef.type == CurveReference::CURVE_REF_EXPO && !(flags & CURVE_REF_UI_HIDE_EXPO)) ||
(curveRef.type != CurveReference::CURVE_REF_DIFF && curveRef.type != CurveReference::CURVE_REF_EXPO))
cb->addItem(CurveReference::typeToString((CurveReference::CurveRefType)i), i);
}
cb->setCurrentIndex(cb->findData((int)curveRef.type));
}
}
// static
void CurveReferenceUIManager::populateValueCB(QComboBox * cb, const CurveReference & curveRef, const ModelData * model)
{
if (cb) {
cb->setModel(tempModel); // do not want to clear/alter the shared curves model and set to nullptr is invalid
switch (curveRef.type) {
case CurveReference::CURVE_REF_DIFF:
case CurveReference::CURVE_REF_EXPO:
cb->clear();
Helpers::populateGVCB(*cb, curveRef.value, *model);
break;
case CurveReference::CURVE_REF_FUNC:
cb->clear();
for (int i = 1; i <= MAX_CURVE_REF_FUNC; i++) {
cb->addItem(CurveReference::functionToString(i), i);
}
break;
case CurveReference::CURVE_REF_CUSTOM:
cb->setModel(curveItemModel);
break;
default:
break;
}
cb->setCurrentIndex(cb->findData(curveRef.value));
}
}

View file

@ -22,35 +22,101 @@
#define CURVEREFERENCE_H #define CURVEREFERENCE_H
#include <QtCore> #include <QtCore>
#include <QComboBox>
#include <QCheckBox>
#include <QSpinBox>
#include <QStandardItemModel>
class ModelData; class ModelData;
class RawItemFilteredModel;
class CurveReference { class CurveReference {
Q_DECLARE_TR_FUNCTIONS(CurveReference) Q_DECLARE_TR_FUNCTIONS(CurveReference)
public: public:
enum CurveRefType { enum CurveRefType {
CURVE_REF_DIFF, CURVE_REF_DIFF,
CURVE_REF_EXPO, CURVE_REF_EXPO,
CURVE_REF_FUNC, CURVE_REF_FUNC,
CURVE_REF_CUSTOM CURVE_REF_CUSTOM,
MAX_CURVE_REF_TYPE = CURVE_REF_CUSTOM
};
enum CurveRefGroups {
NoneGroup = 0x001,
NegativeGroup = 0x002,
PositiveGroup = 0x004,
AllCurveRefGroups = NoneGroup | NegativeGroup | PositiveGroup,
PositiveCurveRefGroups = AllCurveRefGroups &~ NegativeGroup
}; };
CurveReference() { clear(); } CurveReference() { clear(); }
CurveReference(CurveRefType type, int value) : type(type), value(value) { ; }
CurveReference(CurveRefType type, int value):
type(type),
value(value)
{
}
void clear() { memset(this, 0, sizeof(CurveReference)); } void clear() { memset(this, 0, sizeof(CurveReference)); }
const bool isEmpty() const { return type == CURVE_REF_DIFF && value == 0; }
const bool isSet() const { return !isEmpty(); }
const bool isValueNumber() const;
const bool isValueReference() const { return !isValueNumber(); }
const QString toString(const ModelData * model = nullptr, bool verbose = true) const;
CurveRefType type; CurveRefType type;
int value; int value;
QString toString(const ModelData * model = NULL, bool verbose = true) const; bool operator == ( const CurveReference & other) const {
bool isSet() const { return type != CURVE_REF_DIFF || value != 0; } return (this->type == other.type) && (this->value == other.value);
}
bool operator != ( const CurveReference & other) const {
return (this->type != other.type) || (this->value != other.value);
}
static int getDefaultValue(const CurveRefType type, const bool isGVar = false);
static QString typeToString(const CurveRefType type);
static QString functionToString(const int value);
};
class CurveReferenceUIManager : public QObject {
Q_OBJECT
public:
CurveReferenceUIManager(QComboBox *curveValueCB, CurveReference & curve, const ModelData & model,
RawItemFilteredModel * curveItemModel, QObject * parent = nullptr);
CurveReferenceUIManager(QComboBox *curveTypeCB, QCheckBox *curveGVarCB, QSpinBox *curveValueSB, QComboBox *curveValueCB,
CurveReference & curve, const ModelData & model, RawItemFilteredModel * curveItemModel, QObject * parent = nullptr);
virtual ~CurveReferenceUIManager();
void init(RawItemFilteredModel * curveModel);
void update();
protected slots:
void gvarCBChanged(int);
void typeChanged(int);
void valueSBChanged();
void valueCBChanged();
protected:
QComboBox *curveTypeCB;
QCheckBox *curveGVarCB;
QSpinBox *curveValueSB;
QComboBox *curveValueCB;
CurveReference & curve;
const ModelData & model;
bool lock;
static bool firsttime;
static int flags;
static bool hasCapabilityGvars;
static int numCurves;
static RawItemFilteredModel * curveItemModel;
static QStandardItemModel * tempModel;
static void populateTypeCB(QComboBox * cb, const CurveReference & curveRef);
static void populateValueCB(QComboBox * cb, const CurveReference & curveRef, const ModelData * model = nullptr);
}; };
#endif // CURVEREFERENCE_H #endif // CURVEREFERENCE_H

View file

@ -91,10 +91,8 @@ QString CustomFunctionData::funcToString(const ModelData * model) const
return tr("Background Music Pause"); return tr("Background Music Pause");
else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast) else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast)
return tr("Adjust %1").arg(RawSource(SOURCE_TYPE_GVAR, func-FuncAdjustGV1).toString(model)); return tr("Adjust %1").arg(RawSource(SOURCE_TYPE_GVAR, func-FuncAdjustGV1).toString(model));
else if (func == FuncSetFailsafeInternalModule) else if (func == FuncSetFailsafe)
return tr("SetFailsafe Int. Module"); return tr("Set Failsafe");
else if (func == FuncSetFailsafeExternalModule)
return tr("SetFailsafe Ext. Module");
else if (func == FuncRangeCheckInternalModule) else if (func == FuncRangeCheckInternalModule)
return tr("RangeCheck Int. Module"); return tr("RangeCheck Int. Module");
else if (func == FuncRangeCheckExternalModule) else if (func == FuncRangeCheckExternalModule)
@ -126,20 +124,15 @@ void CustomFunctionData::populateResetParams(const ModelData * model, QComboBox
b->addItem(tr("REa"), val++); b->addItem(tr("REa"), val++);
b->addItem(tr("REb"), val++); b->addItem(tr("REb"), val++);
} }
if ((int)value < b->count()) {
b->setCurrentIndex(value);
}
if (model) { if (model) {
for (unsigned i=0; i<CPN_MAX_SENSORS; ++i) { for (int i = 0; i < firmware->getCapability(Sensors); ++i) {
if (model->sensorData[i].isAvailable()) { if (model->sensorData[i].isAvailable()) {
RawSource item = RawSource(SOURCE_TYPE_TELEMETRY, 3*i); RawSource item = RawSource(SOURCE_TYPE_TELEMETRY, 3 * i);
b->addItem(item.toString(model), val+i); b->addItem(item.toString(model), val + i);
if (value == val+i) {
b->setCurrentIndex(b->count()-1);
}
} }
} }
} }
b->setCurrentIndex(b->findData(value));
} }
void CustomFunctionData::populatePlaySoundParams(QStringList & qs) void CustomFunctionData::populatePlaySoundParams(QStringList & qs)

View file

@ -62,8 +62,7 @@ enum AssignFunc {
FuncBackgroundMusicPause, FuncBackgroundMusicPause,
FuncAdjustGV1, FuncAdjustGV1,
FuncAdjustGVLast = FuncAdjustGV1+CPN_MAX_GVARS-1, FuncAdjustGVLast = FuncAdjustGV1+CPN_MAX_GVARS-1,
FuncSetFailsafeInternalModule, FuncSetFailsafe,
FuncSetFailsafeExternalModule,
FuncRangeCheckInternalModule, FuncRangeCheckInternalModule,
FuncRangeCheckExternalModule, FuncRangeCheckExternalModule,
FuncBindInternalModule, FuncBindInternalModule,

View file

@ -723,11 +723,15 @@ int ModelData::updateReference()
updateAssignFunc(cfd); updateAssignFunc(cfd);
if (!cfd->isEmpty()) { if (!cfd->isEmpty()) {
updateSwitchRef(cfd->swtch); updateSwitchRef(cfd->swtch);
if (cfd->func == FuncVolume || cfd->func == FuncBacklight || cfd->func == FuncPlayValue || (cfd->func >= FuncAdjustGV1 && cfd->func <= FuncAdjustGVLast && (cfd->adjustMode == FUNC_ADJUST_GVAR_GVAR || cfd->adjustMode == FUNC_ADJUST_GVAR_SOURCE))) { if (cfd->func == FuncVolume || cfd->func == FuncBacklight || cfd->func == FuncPlayValue ||
(cfd->func >= FuncAdjustGV1 && cfd->func <= FuncAdjustGVLast && (cfd->adjustMode == FUNC_ADJUST_GVAR_GVAR || cfd->adjustMode == FUNC_ADJUST_GVAR_SOURCE))) {
updateSourceIntRef(cfd->param); updateSourceIntRef(cfd->param);
if (cfd->param == 0) if (cfd->param == 0)
cfd->clear(); cfd->clear();
} }
else if (cfd->func == FuncReset) {
updateResetParam(cfd);
}
} }
} }
} }
@ -847,7 +851,7 @@ void ModelData::updateTypeIndexRef(R & curRef, const T type, const int idxAdj, c
newRef.clear(); newRef.clear();
else { else {
newRef.type = (T)defType; newRef.type = (T)defType;
newRef.index = defIndex + idxAdj; newRef.index = defIndex;
} }
break; break;
case REF_UPD_ACT_SHIFT: case REF_UPD_ACT_SHIFT:
@ -904,7 +908,7 @@ void ModelData::updateTypeValueRef(R & curRef, const T type, const int idxAdj, c
newRef.clear(); newRef.clear();
else { else {
newRef.type = (T)defType; newRef.type = (T)defType;
newRef.value = defValue + idxAdj; newRef.value = defValue;
} }
break; break;
case REF_UPD_ACT_SHIFT: case REF_UPD_ACT_SHIFT:
@ -972,7 +976,7 @@ void ModelData::updateAssignFunc(CustomFunctionData * cfd)
{ {
const int invalidateRef = -1; const int invalidateRef = -1;
int newRef = (int)cfd->func; int newRef = (int)cfd->func;
int idxAdj; int idxAdj = 0;
switch (updRefInfo.type) switch (updRefInfo.type)
{ {
@ -989,7 +993,7 @@ void ModelData::updateAssignFunc(CustomFunctionData * cfd)
case REF_UPD_TYPE_TIMER: case REF_UPD_TYPE_TIMER:
if (cfd->func < FuncSetTimer1 || cfd->func > FuncSetTimer3) // TODO refactor to FuncSetTimerLast if (cfd->func < FuncSetTimer1 || cfd->func > FuncSetTimer3) // TODO refactor to FuncSetTimerLast
return; return;
idxAdj = FuncSetTimer1 - 2; // reverse earlier offset requiured for rawsource idxAdj = FuncSetTimer1 - 2; // reverse earlier offset required for rawsource
break; break;
default: default:
return; return;
@ -1374,3 +1378,64 @@ void ModelData::sortMixes()
memcpy(&mixData[0], &sortedMixData[0], CPN_MAX_MIXERS * sizeof(MixData)); memcpy(&mixData[0], &sortedMixData[0], CPN_MAX_MIXERS * sizeof(MixData));
} }
void ModelData::updateResetParam(CustomFunctionData * cfd)
{
if (cfd->func != FuncReset)
return;
const int invalidateRef = -1;
int newRef = cfd->param;
int idxAdj = 0;
Firmware *firmware = getCurrentFirmware();
switch (updRefInfo.type)
{
case REF_UPD_TYPE_SENSOR:
idxAdj = 5/*3 Timers + Flight + Telemetery*/ + firmware->getCapability(RotaryEncoders);
if (cfd->param < idxAdj || cfd->param > (idxAdj + firmware->getCapability(Sensors)))
return;
break;
default:
return;
}
switch (updRefInfo.action)
{
case REF_UPD_ACT_CLEAR:
if (newRef != (updRefInfo.index1 + idxAdj))
return;
newRef = invalidateRef;
break;
case REF_UPD_ACT_SHIFT:
if (newRef < (updRefInfo.index1 + idxAdj))
return;
newRef += updRefInfo.shift;
if (newRef < (updRefInfo.index1 + idxAdj) || newRef > (updRefInfo.maxindex + idxAdj))
newRef = invalidateRef;
break;
case REF_UPD_ACT_SWAP:
if (newRef == updRefInfo.index1 + idxAdj)
newRef = updRefInfo.index2 + idxAdj;
else if (newRef == updRefInfo.index2 + idxAdj)
newRef = updRefInfo.index1 + idxAdj;
break;
default:
qDebug() << "Error - unhandled action:" << updRefInfo.action;
return;
}
if (newRef == invalidateRef) {
cfd->clear();
//qDebug() << "Function cleared";
updRefInfo.updcnt++;
}
else if (cfd->param != newRef) {
//qDebug() << "Updated reference:" << cfd->param << " -> " << newRef;
cfd->param = newRef;
updRefInfo.updcnt++;
}
}

View file

@ -338,6 +338,7 @@ class ModelData {
value = swtch.toValue(); value = swtch.toValue();
} }
void sortMixes(); void sortMixes();
void updateResetParam(CustomFunctionData * cfd);
}; };
#endif // MODELDATA_H #endif // MODELDATA_H

View file

@ -84,7 +84,7 @@ enum MultiModuleRFProtocols {
MODULE_SUBTYPE_MULTI_MJXQ, MODULE_SUBTYPE_MULTI_MJXQ,
MODULE_SUBTYPE_MULTI_SHENQI, MODULE_SUBTYPE_MULTI_SHENQI,
MODULE_SUBTYPE_MULTI_FY326, MODULE_SUBTYPE_MULTI_FY326,
MODULE_SUBTYPE_MULTI_SFHSS, MODULE_SUBTYPE_MULTI_FUTABA,
MODULE_SUBTYPE_MULTI_J6PRO, MODULE_SUBTYPE_MULTI_J6PRO,
MODULE_SUBTYPE_MULTI_FQ777, MODULE_SUBTYPE_MULTI_FQ777,
MODULE_SUBTYPE_MULTI_ASSAN, MODULE_SUBTYPE_MULTI_ASSAN,
@ -115,7 +115,7 @@ enum MultiModuleRFProtocols {
MODULE_SUBTYPE_MULTI_REDPINE, MODULE_SUBTYPE_MULTI_REDPINE,
MODULE_SUBTYPE_MULTI_POTENSIC, MODULE_SUBTYPE_MULTI_POTENSIC,
MODULE_SUBTYPE_MULTI_ZSX, MODULE_SUBTYPE_MULTI_ZSX,
MODULE_SUBTYPE_MULTI_FLYZONE, MODULE_SUBTYPE_MULTI_HEIGHT,
MODULE_SUBTYPE_MULTI_SCANNER, MODULE_SUBTYPE_MULTI_SCANNER,
MODULE_SUBTYPE_MULTI_FRSKYX_RX, MODULE_SUBTYPE_MULTI_FRSKYX_RX,
MODULE_SUBTYPE_MULTI_AFHDS2A_RX, MODULE_SUBTYPE_MULTI_AFHDS2A_RX,
@ -135,7 +135,15 @@ enum MultiModuleRFProtocols {
MODULE_SUBTYPE_MULTI_DSM_RX, MODULE_SUBTYPE_MULTI_DSM_RX,
MODULE_SUBTYPE_MULTI_JJRC345, MODULE_SUBTYPE_MULTI_JJRC345,
MODULE_SUBTYPE_MULTI_Q90C, MODULE_SUBTYPE_MULTI_Q90C,
MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_Q90C MODULE_SUBTYPE_MULTI_KYOSHO,
MODULE_SUBTYPE_MULTI_RLINK,
MODULE_SUBTYPE_MULTI_ELRS,
MODULE_SUBTYPE_MULTI_REALACC,
MODULE_SUBTYPE_MULTI_OMP,
MODULE_SUBTYPE_MULTI_MLINK,
MODULE_SUBTYPE_MULTI_WFLY2,
MODULE_SUBTYPE_MULTI_E016HV2,
MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_E016HV2
}; };
enum TrainerProtocol { enum TrainerProtocol {

View file

@ -55,8 +55,9 @@ static const QStringList STR_SUBTYPE_ESky {"Standard", "ET4"};
static const QStringList STR_SUBTYPE_MT99 {"MT99", "H7", "YZ", "LS", "FY805"}; static const QStringList STR_SUBTYPE_MT99 {"MT99", "H7", "YZ", "LS", "FY805"};
static const QStringList STR_SUBTYPE_MJXQ {"WLH08", "X600", "X800", "H26D", "E010", "H26WH", "Phoenix"}; static const QStringList STR_SUBTYPE_MJXQ {"WLH08", "X600", "X800", "H26D", "E010", "H26WH", "Phoenix"};
static const QStringList STR_SUBTYPE_FY326 {"Standard", "FY319"}; static const QStringList STR_SUBTYPE_FY326 {"Standard", "FY319"};
static const QStringList STR_SUBTYPE_FUTABA {"SFHSS"};
static const QStringList STR_SUBTYPE_HONTAI {"Standard", "JJRC X1", "X5C1 Clone", "FQ777_951"}; static const QStringList STR_SUBTYPE_HONTAI {"Standard", "JJRC X1", "X5C1 Clone", "FQ777_951"};
static const QStringList STR_SUBTYPE_AFHDS2A {"PWM and IBUS", "PPM and IBUS", "PWM and SBUS", "PPM and SBUS"}; static const QStringList STR_SUBTYPE_AFHDS2A {"PWM and IBUS", "PPM and IBUS", "PWM and SBUS", "PPM and SBUS", "PWM and IBUS16", "PPM and IBUS16"};
static const QStringList STR_SUBTYPE_Q2X2 {"Q222", "Q242", "Q282"}; static const QStringList STR_SUBTYPE_Q2X2 {"Q222", "Q242", "Q282"};
static const QStringList STR_SUBTYPE_WK2x01 {"WK2801", "WK2401", "W6_5_1", "W6_6_1", "W6_HEL", "W6_HEL_I"}; static const QStringList STR_SUBTYPE_WK2x01 {"WK2801", "WK2401", "W6_5_1", "W6_6_1", "W6_HEL", "W6_HEL_I"};
static const QStringList STR_SUBTYPE_Q303 {"Standard", "CX35", "CX10D", "CX10WD"}; static const QStringList STR_SUBTYPE_Q303 {"Standard", "CX35", "CX10D", "CX10WD"};
@ -65,7 +66,7 @@ static const QStringList STR_SUBTYPE_ESKY150 {"4 Channel", "7 Channel"};
static const QStringList STR_SUBTYPE_H83D {"H8 Mini 3D", "H20H", "H20 Mini", "H30 Mini"}; static const QStringList STR_SUBTYPE_H83D {"H8 Mini 3D", "H20H", "H20 Mini", "H30 Mini"};
static const QStringList STR_SUBTYPE_CORONA {"Corona V1", "Corona V2", "Flydream V3"}; static const QStringList STR_SUBTYPE_CORONA {"Corona V1", "Corona V2", "Flydream V3"};
static const QStringList STR_SUBTYPE_HITEC {"Optima", "Optima Hub Telem", "Minima"}; static const QStringList STR_SUBTYPE_HITEC {"Optima", "Optima Hub Telem", "Minima"};
static const QStringList STR_SUBTYPE_WFLY {"WFR0xS"}; static const QStringList STR_SUBTYPE_WFLY {"WFR0x"};
static const QStringList STR_SUBTYPE_BUGS_MINI {"Standard", "Bugs 3H"}; static const QStringList STR_SUBTYPE_BUGS_MINI {"Standard", "Bugs 3H"};
static const QStringList STR_SUBTYPE_TRAXXAS {"6519 RX"}; static const QStringList STR_SUBTYPE_TRAXXAS {"6519 RX"};
static const QStringList STR_SUBTYPE_E01X {"E012", "E015", "E016H"}; static const QStringList STR_SUBTYPE_E01X {"E012", "E015", "E016H"};
@ -75,18 +76,24 @@ static const QStringList STR_SUBTYPE_V761 {"3 Channel", "4 Channel"};
static const QStringList STR_SUBTYPE_REDPINE {"Fast", "Slow"}; static const QStringList STR_SUBTYPE_REDPINE {"Fast", "Slow"};
static const QStringList STR_SUBTYPE_POTENSIC {"A20 Firefly"}; static const QStringList STR_SUBTYPE_POTENSIC {"A20 Firefly"};
static const QStringList STR_SUBTYPE_ZSX {"JJRC ZSX-280"}; static const QStringList STR_SUBTYPE_ZSX {"JJRC ZSX-280"};
static const QStringList STR_SUBTYPE_FLYZONE {"FZ-410 TX"}; static const QStringList STR_SUBTYPE_HEIGHT {"5 Channel", "8 Channel"};
static const QStringList STR_SUBTYPE_FRSKYX_RX {"RX", "Clone TX"}; static const QStringList STR_SUBTYPE_FRSKYX_RX {"RX", "Clone TX"};
static const QStringList STR_SUBTYPE_HOTT {"Sync", "No_Sync"}; static const QStringList STR_SUBTYPE_HOTT {"Sync", "No_Sync"};
static const QStringList STR_SUBTYPE_FX816 {"P38"}; static const QStringList STR_SUBTYPE_FX816 {"P38"};
static const QStringList STR_SUBTYPE_PELIKAN {"Pro", "Lite"}; static const QStringList STR_SUBTYPE_PELIKAN {"Pro", "Lite"};
static const QStringList STR_SUBTYPE_XK {"X450", "X420"}; static const QStringList STR_SUBTYPE_XK {"X450", "X420"};
static const QStringList STR_SUBTYPE_XN297DUMP {"250K", "1M", "2M", "AUTO", "NRF"}; static const QStringList STR_SUBTYPE_XN297DUMP {"250K", "1M", "2M", "AUTO", "NRF"};
static const QStringList STR_SUBTYPE_FRSKYX2 {"D16", "D16 8ch", "D16 EU-LBT", "D16 EU-LBT 8ch", "D16 Cloned"}; static const QStringList STR_SUBTYPE_FRSKYX2 {"D16", "D16 8ch", "D16 EU-LBT", "D16 EU-LBT 8ch", "Cloned", "Cloned 8ch"};
static const QStringList STR_SUBTYPE_FRSKYR9 {"915 MHz", "868 MHz", "915 MHz 8-Channel", "868 MHz 8-Channel"}; static const QStringList STR_SUBTYPE_FRSKYR9 {"915 MHz", "868 MHz", "915 MHz 8-Channel", "868 MHz 8-Channel", "FCC", "---", "FCC 8-Channel"};
static const QStringList STR_SUBTYPE_PROPEL {"74-Z"}; static const QStringList STR_SUBTYPE_PROPEL {"74-Z"};
static const QStringList STR_SUBTYPE_FRSKYL {"LR12", "LR12 6-Channel"}; static const QStringList STR_SUBTYPE_FRSKYL {"LR12", "LR12 6-Channel"};
static const QStringList STR_SUBTYPE_ESKY150V2 {"150 V2"}; static const QStringList STR_SUBTYPE_ESKY150V2 {"150 V2"};
static const QStringList STR_SUBTYPE_JJRC345 {"Standard", "SkyTumbler"};
static const QStringList STR_SUBTYPE_KYOSHO {"FHSS", "Hype"};
static const QStringList STR_SUBTYPE_RLINK {"Surface", "Air", "DumboRC"};
static const QStringList STR_SUBTYPE_ELRS {"Not Available WIP"};
static const QStringList STR_SUBTYPE_REALACC {"R11"};
static const QStringList STR_SUBTYPE_WFLY2 {"RF20x"};
static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT}; static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT};
@ -112,11 +119,11 @@ const Multiprotocols multiProtocols {
{MODULE_SUBTYPE_MULTI_MT99XX, 4, false, STR_SUBTYPE_MT99, nullptr}, {MODULE_SUBTYPE_MULTI_MT99XX, 4, false, STR_SUBTYPE_MT99, nullptr},
{MODULE_SUBTYPE_MULTI_MJXQ, 6, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_MJXQ, 6, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FY326, 1, false, STR_SUBTYPE_FY326, nullptr}, {MODULE_SUBTYPE_MULTI_FY326, 1, false, STR_SUBTYPE_FY326, nullptr},
{MODULE_SUBTYPE_MULTI_SFHSS, 0, true, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FUTABA, 0, true, STR_SUBTYPE_FUTABA, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_J6PRO, 0, false, NO_SUBTYPE, nullptr}, {MODULE_SUBTYPE_MULTI_J6PRO, 0, false, NO_SUBTYPE, nullptr},
{MODULE_SUBTYPE_MULTI_HONTAI, 3, false, STR_SUBTYPE_HONTAI, nullptr}, {MODULE_SUBTYPE_MULTI_HONTAI, 3, false, STR_SUBTYPE_HONTAI, nullptr},
{MODULE_SUBTYPE_MULTI_OLRS, 0, false, NO_SUBTYPE, STR_MULTI_RFPOWER}, {MODULE_SUBTYPE_MULTI_OLRS, 0, false, NO_SUBTYPE, STR_MULTI_RFPOWER},
{MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ}, {MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 5, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
{MODULE_SUBTYPE_MULTI_Q2X2, 2, false, STR_SUBTYPE_Q2X2, nullptr}, {MODULE_SUBTYPE_MULTI_Q2X2, 2, false, STR_SUBTYPE_Q2X2, nullptr},
{MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, STR_SUBTYPE_WK2x01, nullptr}, {MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, STR_SUBTYPE_WK2x01, nullptr},
{MODULE_SUBTYPE_MULTI_Q303, 3, false, STR_SUBTYPE_Q303, nullptr}, {MODULE_SUBTYPE_MULTI_Q303, 3, false, STR_SUBTYPE_Q303, nullptr},
@ -136,20 +143,28 @@ const Multiprotocols multiProtocols {
{MODULE_SUBTYPE_MULTI_REDPINE, 1, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_REDPINE, 1, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, STR_SUBTYPE_POTENSIC, nullptr}, {MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, STR_SUBTYPE_POTENSIC, nullptr},
{MODULE_SUBTYPE_MULTI_ZSX, 0, false, STR_SUBTYPE_ZSX, nullptr}, {MODULE_SUBTYPE_MULTI_ZSX, 0, false, STR_SUBTYPE_ZSX, nullptr},
{MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, STR_SUBTYPE_FLYZONE, nullptr}, {MODULE_SUBTYPE_MULTI_HEIGHT, 1, false, STR_SUBTYPE_HEIGHT, nullptr},
{MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_HOTT, 1, true, STR_SUBTYPE_HOTT, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_HOTT, 1, true, STR_SUBTYPE_HOTT, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FX816, 0, false, STR_SUBTYPE_FX816, nullptr}, {MODULE_SUBTYPE_MULTI_FX816, 0, false, STR_SUBTYPE_FX816, nullptr},
{MODULE_SUBTYPE_MULTI_PELIKAN, 1, false, STR_SUBTYPE_PELIKAN, nullptr}, {MODULE_SUBTYPE_MULTI_PELIKAN, 1, false, STR_SUBTYPE_PELIKAN, nullptr},
{MODULE_SUBTYPE_MULTI_XK, 1, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_XK, 1, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_XN297DUMP, 4, false, STR_SUBTYPE_XN297DUMP, nullptr}, {MODULE_SUBTYPE_MULTI_XN297DUMP, 4, false, STR_SUBTYPE_XN297DUMP, nullptr},
{MODULE_SUBTYPE_MULTI_FRSKYX2, 4, true, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FRSKYX2, 5, true, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FRSKY_R9, 3, true, STR_SUBTYPE_FRSKYR9, nullptr}, {MODULE_SUBTYPE_MULTI_FRSKY_R9, 6, true, STR_SUBTYPE_FRSKYR9, nullptr},
{MODULE_SUBTYPE_MULTI_PROPEL, 0, false, STR_SUBTYPE_PROPEL, nullptr}, {MODULE_SUBTYPE_MULTI_PROPEL, 0, false, STR_SUBTYPE_PROPEL, nullptr},
{MODULE_SUBTYPE_MULTI_FRSKYL, 1, false, STR_SUBTYPE_FRSKYL, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FRSKYL, 1, false, STR_SUBTYPE_FRSKYL, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_SKYARTEC, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_SKYARTEC, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_ESKY150V2, 0, false, STR_SUBTYPE_ESKY150V2, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_ESKY150V2, 0, false, STR_SUBTYPE_ESKY150V2, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_JJRC345, 1, false, STR_SUBTYPE_JJRC345, nullptr},
{MODULE_SUBTYPE_MULTI_Q90C, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_Q90C, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_KYOSHO, 1, false, STR_SUBTYPE_KYOSHO, nullptr},
{MODULE_SUBTYPE_MULTI_RLINK, 2, false, STR_SUBTYPE_RLINK, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_ELRS, 0, false, STR_SUBTYPE_ELRS, nullptr},
{MODULE_SUBTYPE_MULTI_REALACC, 0, false, STR_SUBTYPE_REALACC, nullptr},
{MODULE_SUBTYPE_MULTI_OMP, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_WFLY2, 0, false, STR_SUBTYPE_WFLY2, STR_MULTI_OPTION},
{MODULE_SUBTYPE_MULTI_E016HV2, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MM_RF_CUSTOM_SELECTED, 7, true, STR_SUBTYPE_CUSTOM, STR_MULTI_OPTION}, {MM_RF_CUSTOM_SELECTED, 7, true, STR_SUBTYPE_CUSTOM, STR_MULTI_OPTION},
// Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff) // Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff)
@ -189,12 +204,13 @@ QString Multiprotocols::protocolToString(int protocol, bool custom)
{ {
static const QStringList strings({ static const QStringList strings({
"FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023", "FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023",
"Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "J6 PRO","FQ777","Assan","Hontai","Open LRS", "Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "Futaba", "J6 PRO","FQ777","Assan","Hontai","Open LRS",
"FlySky AFHDS2A", "Q2x2", "WK2x01", "Q303", "GW008", "DM002", "Cabell", "ESky 150", "H8 3D", "Corona", "CFlie", "FlySky AFHDS2A", "Q2x2", "WK2x01", "Q303", "GW008", "DM002", "Cabell", "ESky 150", "H8 3D", "Corona", "CFlie",
"Hitec", "Wfly", "Bugs", "Bugs Mini", "Traxxas", "NCC-1701-A", "E01X", "WL Heli V911S", "GD00X", "Volantex V761", "Hitec", "Wfly", "Bugs", "Bugs Mini", "Traxxas", "NCC-1701-A", "E01X", "WL Heli V911S", "GD00X", "Volantex V761",
"KFPlan KF606", "Redpine", "Potensic", "ZSX", "FlyZone", "Scanner", "FrSky RX", "FlySky AFHDS2A RX", "HoTT", "Fx816", "KFPlan KF606", "Redpine", "Potensic", "ZSX", "Height", "Scanner", "FrSky RX", "FlySky AFHDS2A RX", "HoTT", "Fx816",
"Bayang RX", "Pelikan", "Tiger", "XK", "XN297 Dump", "FrSky X 2.1", "FrSky R9", "Propel", "FrSky L", "Skyartec", "Bayang RX", "Pelikan", "Tiger", "XK", "XN297 Dump", "FrSky X 2.1", "FrSky R9", "Propel", "FrSky L", "Skyartec",
"ESky 150v2", "DSM RX", "JJRC345", "Q90C" "ESky 150v2", "DSM RX", "JJRC345", "Q90C", "Kyosho", "RadioLink", "ExpressLRS", "Realacc", "OMP", "M-Link", "Wfly 2",
"E016H v2"
}); });
return strings.value(protocol, CPN_STR_UNKNOWN_ITEM); return strings.value(protocol, CPN_STR_UNKNOWN_ITEM);

View file

@ -48,6 +48,9 @@ inline int MAX_SWITCHES(Board::Type board, int version)
if (IS_FAMILY_T12(board)) if (IS_FAMILY_T12(board))
return 8; return 8;
if (IS_TARANIS_X7(board))
return 8;
return Boards::getCapability(board, Board::Switches); return Boards::getCapability(board, Board::Switches);
} }
@ -1406,8 +1409,7 @@ class CustomFunctionsConversionTable: public ConversionTable {
addConversion(FuncAdjustGV1+i, val); addConversion(FuncAdjustGV1+i, val);
val++; val++;
addConversion(FuncVolume, val++); addConversion(FuncVolume, val++);
addConversion(FuncSetFailsafeInternalModule, val); addConversion(FuncSetFailsafe, val++);
addConversion(FuncSetFailsafeExternalModule, val++);
addConversion(FuncRangeCheckInternalModule, val); addConversion(FuncRangeCheckInternalModule, val);
addConversion(FuncRangeCheckExternalModule, val++); addConversion(FuncRangeCheckExternalModule, val++);
addConversion(FuncBindInternalModule, val); addConversion(FuncBindInternalModule, val);
@ -1520,9 +1522,6 @@ class ArmCustomFunctionField: public TransformedField {
*((uint16_t *)_param) = fn.param; *((uint16_t *)_param) = fn.param;
*((uint8_t *)(_param+3)) = fn.func - FuncSetTimer1; *((uint8_t *)(_param+3)) = fn.func - FuncSetTimer1;
} }
else if (fn.func >= FuncSetFailsafeInternalModule && fn.func <= FuncSetFailsafeExternalModule) {
*((uint16_t *)_param) = fn.func - FuncSetFailsafeInternalModule;
}
else if (fn.func >= FuncRangeCheckInternalModule && fn.func <= FuncRangeCheckExternalModule) { else if (fn.func >= FuncRangeCheckInternalModule && fn.func <= FuncRangeCheckExternalModule) {
*((uint16_t *)_param) = fn.func - FuncRangeCheckInternalModule; *((uint16_t *)_param) = fn.func - FuncRangeCheckInternalModule;
} }

View file

@ -59,7 +59,7 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen
tr("THs"), tr("TH%"), tr("THt") tr("THs"), tr("TH%"), tr("THt")
}; };
const QStringList directionIndicators = QStringList() static const QStringList directionIndicators = QStringList()
<< CPN_STR_SW_INDICATOR_UP << CPN_STR_SW_INDICATOR_UP
<< CPN_STR_SW_INDICATOR_NEUT << CPN_STR_SW_INDICATOR_NEUT
<< CPN_STR_SW_INDICATOR_DN; << CPN_STR_SW_INDICATOR_DN;

View file

@ -28,4 +28,4 @@ qt5_wrap_ui(generaledit_SRCS ${generaledit_UIS})
qt5_wrap_cpp(generaledit_SRCS ${generaledit_HDRS}) qt5_wrap_cpp(generaledit_SRCS ${generaledit_HDRS})
add_library(generaledit ${generaledit_SRCS}) add_library(generaledit ${generaledit_SRCS})
target_link_libraries(generaledit PRIVATE ${CPN_COMMON_LIB} Qt5::Multimedia) target_link_libraries(generaledit PRIVATE datamodels ${CPN_COMMON_LIB} Qt5::Multimedia)

View file

@ -28,6 +28,7 @@
#include "hardware.h" #include "hardware.h"
#include "../modeledit/customfunctions.h" #include "../modeledit/customfunctions.h"
#include "verticalscrollarea.h" #include "verticalscrollarea.h"
#include "rawitemdatamodels.h"
GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * firmware) : GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * firmware) :
QDialog(parent), QDialog(parent),
@ -55,8 +56,10 @@ GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * fir
} }
} }
commonItemModels = new CommonItemModels(&generalSettings, nullptr, this);
addTab(new GeneralSetupPanel(this, generalSettings, firmware), tr("Setup")); addTab(new GeneralSetupPanel(this, generalSettings, firmware), tr("Setup"));
addTab(new CustomFunctionsPanel(this, NULL, generalSettings, firmware), tr("Global Functions")); addTab(new CustomFunctionsPanel(this, nullptr, generalSettings, firmware, commonItemModels), tr("Global Functions"));
addTab(new TrainerPanel(this, generalSettings, firmware), tr("Trainer")); addTab(new TrainerPanel(this, generalSettings, firmware), tr("Trainer"));
addTab(new HardwarePanel(this, generalSettings, firmware), tr("Hardware")); addTab(new HardwarePanel(this, generalSettings, firmware), tr("Hardware"));
addTab(new CalibrationPanel(this, generalSettings, firmware), tr("Calibration")); addTab(new CalibrationPanel(this, generalSettings, firmware), tr("Calibration"));

View file

@ -25,6 +25,8 @@
#include "eeprominterface.h" #include "eeprominterface.h"
#include "genericpanel.h" #include "genericpanel.h"
class CommonItemModels;
namespace Ui { namespace Ui {
class GeneralEdit; class GeneralEdit;
} }
@ -56,7 +58,7 @@ class GeneralEdit : public QDialog
void getGeneralSwitchDefPos(int i, bool val); void getGeneralSwitchDefPos(int i, bool val);
void setSwitchDefPos(); void setSwitchDefPos();
void updateVarioPitchRange(); void updateVarioPitchRange();
signals: signals:
void modified(); void modified();
@ -71,7 +73,7 @@ class GeneralEdit : public QDialog
QVector<GenericPanel *> panels; QVector<GenericPanel *> panels;
void addTab(GenericPanel *panel, QString text); void addTab(GenericPanel *panel, QString text);
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
CommonItemModels *commonItemModels;
}; };
#endif // _GENERALEDIT_H_ #endif // _GENERALEDIT_H_

View file

@ -210,170 +210,6 @@ void GVarGroup::setWeight(int val)
lock = false; lock = false;
} }
/*
* CurveGroup
*/
CurveGroup::CurveGroup(QComboBox * curveTypeCB, QCheckBox * curveGVarCB, QComboBox * curveValueCB, QSpinBox * curveValueSB, CurveReference & curve, const ModelData & model, unsigned int flags):
QObject(),
curveTypeCB(curveTypeCB),
curveGVarCB(curveGVarCB),
curveValueCB(curveValueCB),
curveValueSB(curveValueSB),
curve(curve),
model(model),
flags(flags),
lock(false),
lastType(-1)
{
if (!(flags & HIDE_DIFF)) curveTypeCB->addItem(tr("Diff"), 0);
if (!(flags & HIDE_EXPO)) curveTypeCB->addItem(tr("Expo"), 1);
curveTypeCB->addItem(tr("Func"), 2);
curveTypeCB->addItem(tr("Curve"), 3);
curveValueCB->setMaxVisibleItems(10);
connect(curveTypeCB, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int)));
connect(curveGVarCB, SIGNAL(stateChanged(int)), this, SLOT(gvarCBChanged(int)));
connect(curveValueCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
connect(curveValueSB, SIGNAL(editingFinished()), this, SLOT(valuesChanged()));
update();
}
void CurveGroup::update()
{
lock = true;
int found = curveTypeCB->findData(curve.type);
if (found < 0) found = 0;
curveTypeCB->setCurrentIndex(found);
if (curve.type == CurveReference::CURVE_REF_DIFF || curve.type == CurveReference::CURVE_REF_EXPO) {
curveGVarCB->setVisible(getCurrentFirmware()->getCapability(Gvars));
if (curve.value > 100 || curve.value < -100) {
curveGVarCB->setChecked(true);
if (lastType != CurveReference::CURVE_REF_DIFF && lastType != CurveReference::CURVE_REF_EXPO) {
lastType = curve.type;
Helpers::populateGVCB(*curveValueCB, curve.value, model);
}
curveValueCB->show();
curveValueSB->hide();
}
else {
curveGVarCB->setChecked(false);
curveValueSB->setMinimum(-100);
curveValueSB->setMaximum(100);
curveValueSB->setValue(curve.value);
curveValueSB->show();
curveValueCB->hide();
}
}
else {
curveGVarCB->hide();
curveValueSB->hide();
curveValueCB->show();
switch (curve.type) {
case CurveReference::CURVE_REF_FUNC:
if (lastType != curve.type) {
lastType = curve.type;
curveValueCB->clear();
for (int i=0; i<=6/*TODO constant*/; i++) {
curveValueCB->addItem(CurveReference(CurveReference::CURVE_REF_FUNC, i).toString(&model, false));
}
}
curveValueCB->setCurrentIndex(curve.value);
break;
case CurveReference::CURVE_REF_CUSTOM:
{
int numcurves = getCurrentFirmware()->getCapability(NumCurves);
if (lastType != curve.type) {
lastType = curve.type;
curveValueCB->clear();
for (int i= ((flags & HIDE_NEGATIVE_CURVES) ? 0 : -numcurves); i<=numcurves; i++) {
curveValueCB->addItem(CurveReference(CurveReference::CURVE_REF_CUSTOM, i).toString(&model, false), i);
if (i == curve.value) {
curveValueCB->setCurrentIndex(curveValueCB->count() - 1);
}
}
}
break;
}
default:
break;
}
}
lock = false;
}
void CurveGroup::gvarCBChanged(int state)
{
if (!lock) {
if (state) {
curve.value = 10000+1; // TODO constant in EEpromInterface ...
lastType = -1; // quickfix for issue #3518: force refresh of curveValueCB at next update() to set current index to GV1
}
else {
curve.value = 0; // TODO could be better
}
update();
}
}
void CurveGroup::typeChanged(int value)
{
if (!lock) {
int type = curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt();
switch (type) {
case 0:
curve = CurveReference(CurveReference::CURVE_REF_DIFF, 0);
break;
case 1:
curve = CurveReference(CurveReference::CURVE_REF_EXPO, 0);
break;
case 2:
curve = CurveReference(CurveReference::CURVE_REF_FUNC, 0);
break;
case 3:
curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, 0);
break;
}
update();
}
}
void CurveGroup::valuesChanged()
{
if (!lock) {
switch (curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt()) {
case 0:
case 1:
{
int value;
if (curveGVarCB->isChecked())
value = curveValueCB->itemData(curveValueCB->currentIndex()).toInt();
else
value = curveValueSB->value();
curve = CurveReference(curveTypeCB->itemData(curveTypeCB->currentIndex()).toInt() == 0 ? CurveReference::CURVE_REF_DIFF : CurveReference::CURVE_REF_EXPO, value);
break;
}
case 2:
curve = CurveReference(CurveReference::CURVE_REF_FUNC, curveValueCB->currentIndex());
break;
case 3:
curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, curveValueCB->itemData(curveValueCB->currentIndex()).toInt());
break;
}
update();
}
}
/* /*
* Helpers namespace functions * Helpers namespace functions
*/ */
@ -399,26 +235,6 @@ void Helpers::populateGVCB(QComboBox & b, int value, const ModelData & model)
b.setCurrentIndex(count); b.setCurrentIndex(count);
} }
// Returns Diff/Expo/Weight/Offset adjustment value as either a percentage or a global variable name.
QString Helpers::getAdjustmentString(int16_t val, const ModelData * model, bool sign)
{
QString ret;
if (val >= -10000 && val <= 10000) {
ret = "%1%";
if (sign && val > 0)
ret.prepend("+");
ret = ret.arg(val);
}
else {
ret = RawSource(SOURCE_TYPE_GVAR, abs(val) - 10001).toString(model);
if (val < 0)
ret.prepend("-");
else if (sign)
ret.prepend("+");
}
return ret;
}
// TODO: Move lookup to GVarData class (w/out combobox) // TODO: Move lookup to GVarData class (w/out combobox)
void Helpers::populateGvarUseCB(QComboBox * b, unsigned int phase) void Helpers::populateGvarUseCB(QComboBox * b, unsigned int phase)
{ {
@ -742,7 +558,8 @@ GpsCoord extractGpsCoordinates(const QString & position)
return result; return result;
} }
TableLayout::TableLayout(QWidget * parent, int rowCount, const QStringList & headerLabels) TableLayout::TableLayout(QWidget * parent, int rowCount, const QStringList & headerLabels) :
QObject(parent)
{ {
#if defined(TABLE_LAYOUT) #if defined(TABLE_LAYOUT)
tableWidget = new QTableWidget(parent); tableWidget = new QTableWidget(parent);

View file

@ -98,40 +98,10 @@ class GVarGroup: public QObject {
bool lock; bool lock;
}; };
#define HIDE_DIFF 0x01
#define HIDE_EXPO 0x02
#define HIDE_NEGATIVE_CURVES 0x04
class CurveGroup : public QObject {
Q_OBJECT
public:
CurveGroup(QComboBox *curveTypeCB, QCheckBox *curveGVarCB, QComboBox *curveValueCB, QSpinBox *curveValueSB, CurveReference & curve, const ModelData & model, unsigned int flags=0);
void update();
protected slots:
void gvarCBChanged(int);
void typeChanged(int);
void valuesChanged();
protected:
QComboBox *curveTypeCB;
QCheckBox *curveGVarCB;
QComboBox *curveValueCB;
QSpinBox *curveValueSB;
CurveReference & curve;
const ModelData & model;
unsigned int flags;
bool lock;
int lastType;
};
namespace Helpers namespace Helpers
{ {
void populateGvarUseCB(QComboBox *b, unsigned int phase); void populateGvarUseCB(QComboBox *b, unsigned int phase);
void populateGVCB(QComboBox & b, int value, const ModelData & model); void populateGVCB(QComboBox & b, int value, const ModelData & model);
QString getAdjustmentString(int16_t val, const ModelData * model = NULL, bool sign = false);
void populateFileComboBox(QComboBox * b, const QSet<QString> & set, const QString & current); void populateFileComboBox(QComboBox * b, const QSet<QString> & set, const QString & current);
void getFileComboBoxValue(QComboBox * b, char * dest, int length); void getFileComboBoxValue(QComboBox * b, char * dest, int length);
@ -208,8 +178,9 @@ private:
GpsCoord extractGpsCoordinates(const QString & position); GpsCoord extractGpsCoordinates(const QString & position);
class TableLayout class TableLayout: public QObject
{ {
Q_OBJECT
public: public:
TableLayout(QWidget * parent, int rowCount, const QStringList & headerLabels); TableLayout(QWidget * parent, int rowCount, const QStringList & headerLabels);
// ~TableLayout() ; // ~TableLayout() ;

View file

@ -20,6 +20,7 @@
#include "channels.h" #include "channels.h"
#include "helpers.h" #include "helpers.h"
#include "rawitemfilteredmodel.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, ModelPanel * panel):
firmware(firmware), firmware(firmware),
@ -95,15 +96,17 @@ void LimitsGroup::updateMinMax(int max)
} }
} }
} }
ChannelsPanel::ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels):
Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): ModelPanel(parent, model, generalSettings, firmware),
ModelPanel(parent, model, generalSettings, firmware) commonItemModels(commonItemModels)
{ {
Stopwatch s1("Channels");
chnCapability = firmware->getCapability(Outputs); chnCapability = firmware->getCapability(Outputs);
int channelNameMaxLen = firmware->getCapability(ChannelsName); int channelNameMaxLen = firmware->getCapability(ChannelsName);
curveFilteredModel = new RawItemFilteredModel(commonItemModels->curveItemModel(), RawItemFilteredModel::AllFilter, this);
connect(curveFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &ChannelsPanel::onModelDataAboutToBeUpdated);
connect(curveFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &ChannelsPanel::onModelDataUpdateComplete);
QStringList headerLabels; QStringList headerLabels;
headerLabels << "#"; headerLabels << "#";
if (channelNameMaxLen > 0) { if (channelNameMaxLen > 0) {
@ -118,8 +121,6 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
headerLabels << tr("Linear Subtrim"); headerLabels << tr("Linear Subtrim");
TableLayout *tableLayout = new TableLayout(this, chnCapability, headerLabels); TableLayout *tableLayout = new TableLayout(this, chnCapability, headerLabels);
s1.report("header");
for (int i = 0; i < chnCapability; i++) { for (int i = 0; i < chnCapability; i++) {
int col = 0; int col = 0;
@ -165,6 +166,7 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
curveCB[i] = new QComboBox(this); curveCB[i] = new QComboBox(this);
curveCB[i]->setProperty("index", i); curveCB[i]->setProperty("index", i);
curveCB[i]->setModel(curveFilteredModel);
connect(curveCB[i], SIGNAL(currentIndexChanged(int)), this, SLOT(curveEdited())); connect(curveCB[i], SIGNAL(currentIndexChanged(int)), this, SLOT(curveEdited()));
tableLayout->addWidget(i, col++, curveCB[i]); tableLayout->addWidget(i, col++, curveCB[i]);
} }
@ -193,15 +195,13 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
} }
} }
update(); update();
s1.report("add elements");
disableMouseScrolling(); disableMouseScrolling();
tableLayout->resizeColumnsToContents(); tableLayout->resizeColumnsToContents();
tableLayout->pushRowsUp(chnCapability+1); tableLayout->pushRowsUp(chnCapability+1);
s1.report("end");
} }
Channels::~Channels() ChannelsPanel::~ChannelsPanel()
{ {
// compiler warning if delete[] // compiler warning if delete[]
for (int i = 0; i < CPN_MAX_CHNOUT; i++) { for (int i = 0; i < CPN_MAX_CHNOUT; i++) {
@ -216,7 +216,7 @@ Channels::~Channels()
} }
} }
void Channels::symlimitsEdited() void ChannelsPanel::symlimitsEdited()
{ {
if (!lock) { if (!lock) {
QCheckBox *ckb = qobject_cast<QCheckBox*>(sender()); QCheckBox *ckb = qobject_cast<QCheckBox*>(sender());
@ -226,17 +226,20 @@ void Channels::symlimitsEdited()
} }
} }
void Channels::nameEdited() void ChannelsPanel::nameEdited()
{ {
if (!lock) { if (!lock) {
QLineEdit *le = qobject_cast<QLineEdit*>(sender()); QLineEdit *le = qobject_cast<QLineEdit*>(sender());
int index = le->property("index").toInt(); int index = le->property("index").toInt();
strcpy(model->limitData[index].name, le->text().toLatin1()); if (model->limitData[index].name != le->text()) {
emit modified(); strcpy(model->limitData[index].name, le->text().toLatin1());
updateItemModels();
emit modified();
}
} }
} }
void Channels::refreshExtendedLimits() void ChannelsPanel::refreshExtendedLimits()
{ {
int channelMax = model->getChannelsMax(); int channelMax = model->getChannelsMax();
@ -248,7 +251,7 @@ void Channels::refreshExtendedLimits()
emit modified(); emit modified();
} }
void Channels::invEdited() void ChannelsPanel::invEdited()
{ {
if (!lock) { if (!lock) {
QComboBox *cb = qobject_cast<QComboBox*>(sender()); QComboBox *cb = qobject_cast<QComboBox*>(sender());
@ -258,17 +261,20 @@ void Channels::invEdited()
} }
} }
void Channels::curveEdited() void ChannelsPanel::curveEdited()
{ {
if (!lock) { if (!lock) {
QComboBox *cb = qobject_cast<QComboBox*>(sender()); QComboBox *cb = qobject_cast<QComboBox*>(sender());
int index = cb->property("index").toInt(); int index = cb->property("index").toInt();
model->limitData[index].curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt()); // ignore unnecessary updates that could be triggered by updates to the data model
emit modified(); if (model->limitData[index].curve != CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt())) {
model->limitData[index].curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, cb->itemData(cb->currentIndex()).toInt());
emit modified();
}
} }
} }
void Channels::ppmcenterEdited() void ChannelsPanel::ppmcenterEdited()
{ {
if (!lock) { if (!lock) {
QSpinBox *sb = qobject_cast<QSpinBox*>(sender()); QSpinBox *sb = qobject_cast<QSpinBox*>(sender());
@ -278,51 +284,49 @@ void Channels::ppmcenterEdited()
} }
} }
void Channels::update() void ChannelsPanel::update()
{ {
for (int i = 0; i < chnCapability; i++) { for (int i = 0; i < chnCapability; i++) {
updateLine(i); updateLine(i);
} }
} }
void Channels::updateLine(int i) void ChannelsPanel::updateLine(int i)
{ {
lock = true; lock = true;
LimitData &chn = model->limitData[i];
if (firmware->getCapability(ChannelsName) > 0) { if (firmware->getCapability(ChannelsName) > 0) {
name[i]->setText(model->limitData[i].name); name[i]->setText(chn.name);
} }
chnOffset[i]->setValue(model->limitData[i].offset); chnOffset[i]->setValue(chn.offset);
chnMin[i]->setValue(model->limitData[i].min); chnMin[i]->setValue(chn.min);
chnMax[i]->setValue(model->limitData[i].max); chnMax[i]->setValue(chn.max);
invCB[i]->setCurrentIndex((model->limitData[i].revert) ? 1 : 0); invCB[i]->setCurrentIndex((chn.revert) ? 1 : 0);
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
int numcurves = firmware->getCapability(NumCurves); curveCB[i]->setCurrentIndex(curveCB[i]->findData(chn.curve.value));
curveCB[i]->clear();
for (int j = -numcurves; j <= numcurves; j++) {
curveCB[i]->addItem(CurveReference(CurveReference::CURVE_REF_CUSTOM, j).toString(model, false), j);
}
curveCB[i]->setCurrentIndex(model->limitData[i].curve.value + numcurves);
} }
if (firmware->getCapability(PPMCenter)) { if (firmware->getCapability(PPMCenter)) {
centerSB[i]->setValue(model->limitData[i].ppmCenter + 1500); centerSB[i]->setValue(chn.ppmCenter + 1500);
} }
if (firmware->getCapability(SYMLimits)) { if (firmware->getCapability(SYMLimits)) {
symlimitsChk[i]->setChecked(model->limitData[i].symetrical); symlimitsChk[i]->setChecked(chn.symetrical);
} }
lock = false; lock = false;
} }
void Channels::cmPaste() void ChannelsPanel::cmPaste()
{ {
QByteArray data; QByteArray data;
if (hasClipboardData(&data)) { if (hasClipboardData(&data)) {
memcpy(&model->limitData[selectedIndex], data.constData(), sizeof(LimitData)); memcpy(&model->limitData[selectedIndex], data.constData(), sizeof(LimitData));
updateLine(selectedIndex); updateLine(selectedIndex);
updateItemModels();
emit modified(); emit modified();
} }
} }
void Channels::cmDelete() void ChannelsPanel::cmDelete()
{ {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return; return;
@ -335,10 +339,11 @@ void Channels::cmDelete()
updateLine(i); updateLine(i);
} }
updateItemModels();
emit modified(); emit modified();
} }
void Channels::cmCopy() void ChannelsPanel::cmCopy()
{ {
QByteArray data; QByteArray data;
data.append((char*)&model->limitData[selectedIndex], sizeof(LimitData)); data.append((char*)&model->limitData[selectedIndex], sizeof(LimitData));
@ -347,7 +352,7 @@ void Channels::cmCopy()
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
} }
void Channels::cmCut() void ChannelsPanel::cmCut()
{ {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return; return;
@ -356,7 +361,7 @@ void Channels::cmCut()
cmClear(false); cmClear(false);
} }
void Channels::onCustomContextMenuRequested(QPoint pos) void ChannelsPanel::onCustomContextMenuRequested(QPoint pos)
{ {
QLabel *label = (QLabel *)sender(); QLabel *label = (QLabel *)sender();
selectedIndex = label->property("index").toInt(); selectedIndex = label->property("index").toInt();
@ -378,7 +383,7 @@ void Channels::onCustomContextMenuRequested(QPoint pos)
contextMenu.exec(globalPos); contextMenu.exec(globalPos);
} }
bool Channels::hasClipboardData(QByteArray * data) const bool ChannelsPanel::hasClipboardData(QByteArray * data) const
{ {
const QClipboard * clipboard = QApplication::clipboard(); const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData(); const QMimeData * mimeData = clipboard->mimeData();
@ -390,32 +395,32 @@ bool Channels::hasClipboardData(QByteArray * data) const
return false; return false;
} }
bool Channels::insertAllowed() const bool ChannelsPanel::insertAllowed() const
{ {
return ((selectedIndex < chnCapability - 1) && (model->limitData[chnCapability - 1].isEmpty())); return ((selectedIndex < chnCapability - 1) && (model->limitData[chnCapability - 1].isEmpty()));
} }
bool Channels::moveDownAllowed() const bool ChannelsPanel::moveDownAllowed() const
{ {
return selectedIndex < chnCapability - 1; return selectedIndex < chnCapability - 1;
} }
bool Channels::moveUpAllowed() const bool ChannelsPanel::moveUpAllowed() const
{ {
return selectedIndex > 0; return selectedIndex > 0;
} }
void Channels::cmMoveUp() void ChannelsPanel::cmMoveUp()
{ {
swapData(selectedIndex, selectedIndex - 1); swapData(selectedIndex, selectedIndex - 1);
} }
void Channels::cmMoveDown() void ChannelsPanel::cmMoveDown()
{ {
swapData(selectedIndex, selectedIndex + 1); swapData(selectedIndex, selectedIndex + 1);
} }
void Channels::cmClear(bool prompt) void ChannelsPanel::cmClear(bool prompt)
{ {
if (prompt) { if (prompt) {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
@ -425,10 +430,11 @@ void Channels::cmClear(bool prompt)
model->limitData[selectedIndex].clear(); model->limitData[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, selectedIndex); model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
updateLine(selectedIndex); updateLine(selectedIndex);
updateItemModels();
emit modified(); emit modified();
} }
void Channels::cmClearAll() void ChannelsPanel::cmClearAll()
{ {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Channels. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Channels. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return; return;
@ -438,19 +444,21 @@ void Channels::cmClearAll()
model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, i); model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, i);
updateLine(i); updateLine(i);
} }
updateItemModels();
emit modified(); emit modified();
} }
void Channels::cmInsert() void ChannelsPanel::cmInsert()
{ {
memmove(&model->limitData[selectedIndex + 1], &model->limitData[selectedIndex], (CPN_MAX_CHNOUT - (selectedIndex + 1)) * sizeof(LimitData)); memmove(&model->limitData[selectedIndex + 1], &model->limitData[selectedIndex], (CPN_MAX_CHNOUT - (selectedIndex + 1)) * sizeof(LimitData));
model->limitData[selectedIndex].clear(); model->limitData[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1); model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
void Channels::swapData(int idx1, int idx2) void ChannelsPanel::swapData(int idx1, int idx2)
{ {
if ((idx1 != idx2) && (!model->limitData[idx1].isEmpty() || !model->limitData[idx2].isEmpty())) { if ((idx1 != idx2) && (!model->limitData[idx1].isEmpty() || !model->limitData[idx2].isEmpty())) {
LimitData chntmp = model->limitData[idx2]; LimitData chntmp = model->limitData[idx2];
@ -461,6 +469,23 @@ void Channels::swapData(int idx1, int idx2)
model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
updateLine(idx1); updateLine(idx1);
updateLine(idx2); updateLine(idx2);
updateItemModels();
emit modified(); emit modified();
} }
} }
void ChannelsPanel::onModelDataAboutToBeUpdated()
{
lock = true;
}
void ChannelsPanel::onModelDataUpdateComplete()
{
update();
lock = false;
}
void ChannelsPanel::updateItemModels()
{
commonItemModels->update(CommonItemModels::RMO_CHANNELS);
}

View file

@ -26,6 +26,9 @@
#include <QtCore> #include <QtCore>
class CommonItemModels;
class RawItemFilteredModel;
constexpr char MIMETYPE_CHANNEL[] = "application/x-companion-channel"; constexpr char MIMETYPE_CHANNEL[] = "application/x-companion-channel";
class GVarGroup; class GVarGroup;
@ -49,13 +52,13 @@ class LimitsGroup
double displayStep; double displayStep;
}; };
class Channels : public ModelPanel class ChannelsPanel : public ModelPanel
{ {
Q_OBJECT Q_OBJECT
public: public:
Channels(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); ChannelsPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
~Channels(); ~ChannelsPanel();
public slots: public slots:
void refreshExtendedLimits(); void refreshExtendedLimits();
@ -78,6 +81,8 @@ class Channels : public ModelPanel
void cmClear(bool prompt = true); void cmClear(bool prompt = true);
void cmClearAll(); void cmClearAll();
void onCustomContextMenuRequested(QPoint pos); void onCustomContextMenuRequested(QPoint pos);
void onModelDataAboutToBeUpdated();
void onModelDataUpdateComplete();
private: private:
bool hasClipboardData(QByteArray * data = nullptr) const; bool hasClipboardData(QByteArray * data = nullptr) const;
@ -95,6 +100,9 @@ class Channels : public ModelPanel
QCheckBox *symlimitsChk[CPN_MAX_CHNOUT]; QCheckBox *symlimitsChk[CPN_MAX_CHNOUT];
int selectedIndex; int selectedIndex;
int chnCapability; int chnCapability;
CommonItemModels * commonItemModels;
RawItemFilteredModel *curveFilteredModel;
void updateItemModels();
}; };
#endif // _CHANNELS_H_ #endif // _CHANNELS_H_

View file

@ -23,6 +23,7 @@
#include "node.h" #include "node.h"
#include "edge.h" #include "edge.h"
#include "helpers.h" #include "helpers.h"
#include "rawitemfilteredmodel.h"
#define GFX_MARGIN 16 #define GFX_MARGIN 16
@ -108,10 +109,11 @@ float curveSymmetricalX(float x, float coeff, float yMin, float yMid, float yMax
return y; return y;
} }
Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): CurvesPanel::CurvesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::Curves), ui(new Ui::Curves),
currentCurve(0) currentCurve(0),
commonItemModels(commonItemModels)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -230,12 +232,12 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet
lock = false; lock = false;
} }
Curves::~Curves() CurvesPanel::~CurvesPanel()
{ {
delete ui; delete ui;
} }
void Curves::editCurve() void CurvesPanel::editCurve()
{ {
QPushButton *button = (QPushButton *)sender(); QPushButton *button = (QPushButton *)sender();
int index = button->property("index").toInt(); int index = button->property("index").toInt();
@ -243,7 +245,7 @@ void Curves::editCurve()
update(); update();
} }
void Curves::plotCurve(bool checked) void CurvesPanel::plotCurve(bool checked)
{ {
QCheckBox *chk = (QCheckBox *)sender(); QCheckBox *chk = (QCheckBox *)sender();
int index = chk->property("index").toInt(); int index = chk->property("index").toInt();
@ -251,7 +253,7 @@ void Curves::plotCurve(bool checked)
updateCurve(); updateCurve();
} }
void Curves::update() void CurvesPanel::update()
{ {
lock = true; lock = true;
@ -266,12 +268,12 @@ void Curves::update()
lock = false; lock = false;
} }
void Curves::setCurrentCurve(int index) void CurvesPanel::setCurrentCurve(int index)
{ {
currentCurve = index; currentCurve = index;
} }
void Curves::updateCurveType() void CurvesPanel::updateCurveType()
{ {
lock = true; lock = true;
@ -297,7 +299,7 @@ void Curves::updateCurveType()
lock = false; lock = false;
} }
void Curves::updateCurve() void CurvesPanel::updateCurve()
{ {
lock = true; lock = true;
@ -371,7 +373,7 @@ void Curves::updateCurve()
lock = false; lock = false;
} }
void Curves::updateCurvePoints() void CurvesPanel::updateCurvePoints()
{ {
lock = true; lock = true;
@ -405,7 +407,7 @@ void Curves::updateCurvePoints()
lock = false; lock = false;
} }
void Curves::onPointEdited() void CurvesPanel::onPointEdited()
{ {
if (!lock) { if (!lock) {
int index = sender()->property("index").toInt(); int index = sender()->property("index").toInt();
@ -417,7 +419,7 @@ void Curves::onPointEdited()
} }
} }
void Curves::onNodeMoved(int x, int y) void CurvesPanel::onNodeMoved(int x, int y)
{ {
if (!lock) { if (!lock) {
lock = true; lock = true;
@ -435,20 +437,20 @@ void Curves::onNodeMoved(int x, int y)
} }
} }
void Curves::onNodeFocus() void CurvesPanel::onNodeFocus()
{ {
int index = sender()->property("index").toInt(); int index = sender()->property("index").toInt();
spny[index]->setFocus(); spny[index]->setFocus();
} }
void Curves::onNodeUnfocus() void CurvesPanel::onNodeUnfocus()
{ {
int index = sender()->property("index").toInt(); int index = sender()->property("index").toInt();
spny[index]->clearFocus(); spny[index]->clearFocus();
updateCurve(); updateCurve();
} }
bool Curves::allowCurveType(int points, CurveData::CurveType type) bool CurvesPanel::allowCurveType(int points, CurveData::CurveType type)
{ {
int totalpoints = 0; int totalpoints = 0;
for (int i = 0; i < maxCurves; i++) { for (int i = 0; i < maxCurves; i++) {
@ -466,7 +468,7 @@ bool Curves::allowCurveType(int points, CurveData::CurveType type)
} }
} }
void Curves::on_curvePoints_currentIndexChanged(int index) void CurvesPanel::on_curvePoints_currentIndexChanged(int index)
{ {
if (!lock) { if (!lock) {
int numpoints = ((QComboBox *)sender())->itemData(index).toInt(); int numpoints = ((QComboBox *)sender())->itemData(index).toInt();
@ -489,7 +491,7 @@ void Curves::on_curvePoints_currentIndexChanged(int index)
} }
} }
void Curves::on_curveCustom_currentIndexChanged(int index) void CurvesPanel::on_curveCustom_currentIndexChanged(int index)
{ {
if (!lock) { if (!lock) {
CurveData::CurveType type = (CurveData::CurveType)index; CurveData::CurveType type = (CurveData::CurveType)index;
@ -513,20 +515,23 @@ void Curves::on_curveCustom_currentIndexChanged(int index)
} }
} }
void Curves::on_curveSmooth_currentIndexChanged(int index) void CurvesPanel::on_curveSmooth_currentIndexChanged(int index)
{ {
model->curves[currentCurve].smooth = index; model->curves[currentCurve].smooth = index;
update(); update();
} }
void Curves::on_curveName_editingFinished() void CurvesPanel::on_curveName_editingFinished()
{ {
memset(model->curves[currentCurve].name, 0, sizeof(model->curves[currentCurve].name)); if (ui->curveName->text() != model->curves[currentCurve].name) {
strcpy(model->curves[currentCurve].name, ui->curveName->text().toLatin1()); memset(model->curves[currentCurve].name, 0, sizeof(model->curves[currentCurve].name));
emit modified(); strcpy(model->curves[currentCurve].name, ui->curveName->text().toLatin1());
updateItemModels();
emit modified();
}
} }
void Curves::resizeEvent(QResizeEvent *event) void CurvesPanel::resizeEvent(QResizeEvent *event)
{ {
QRect qr = ui->curvePreview->contentsRect(); QRect qr = ui->curvePreview->contentsRect();
ui->curvePreview->scene()->setSceneRect(GFX_MARGIN, GFX_MARGIN, qr.width() - GFX_MARGIN * 2, qr.height() - GFX_MARGIN * 2); ui->curvePreview->scene()->setSceneRect(GFX_MARGIN, GFX_MARGIN, qr.width() - GFX_MARGIN * 2, qr.height() - GFX_MARGIN * 2);
@ -534,7 +539,7 @@ void Curves::resizeEvent(QResizeEvent *event)
ModelPanel::resizeEvent(event); ModelPanel::resizeEvent(event);
} }
void Curves::on_curveType_currentIndexChanged(int index) void CurvesPanel::on_curveType_currentIndexChanged(int index)
{ {
unsigned int flags = templates[index].flags; unsigned int flags = templates[index].flags;
ui->curveCoeffLabel->setVisible(flags & CURVE_COEFF_ENABLE); ui->curveCoeffLabel->setVisible(flags & CURVE_COEFF_ENABLE);
@ -548,7 +553,7 @@ void Curves::on_curveType_currentIndexChanged(int index)
ui->yMin->setValue(-100); ui->yMin->setValue(-100);
} }
void Curves::addTemplate(QString name, unsigned int flags, curveFunction function) void CurvesPanel::addTemplate(QString name, unsigned int flags, curveFunction function)
{ {
CurveCreatorTemplate tmpl; CurveCreatorTemplate tmpl;
tmpl.name = name; tmpl.name = name;
@ -558,7 +563,7 @@ void Curves::addTemplate(QString name, unsigned int flags, curveFunction functio
ui->curveType->addItem(name); ui->curveType->addItem(name);
} }
void Curves::on_curveApply_clicked() void CurvesPanel::on_curveApply_clicked()
{ {
int index = ui->curveType->currentIndex(); int index = ui->curveType->currentIndex();
int numpoints = model->curves[currentCurve].count; int numpoints = model->curves[currentCurve].count;
@ -595,14 +600,14 @@ void Curves::on_curveApply_clicked()
emit modified(); emit modified();
} }
void Curves::onPointSizeEdited() void CurvesPanel::onPointSizeEdited()
{ {
if (!lock) { if (!lock) {
update(); update();
} }
} }
void Curves::onNodeDelete() void CurvesPanel::onNodeDelete()
{ {
int index = sender()->property("index").toInt(); int index = sender()->property("index").toInt();
int numpoints = model->curves[currentCurve].count; int numpoints = model->curves[currentCurve].count;
@ -620,7 +625,7 @@ void Curves::onNodeDelete()
} }
} }
void Curves::onSceneNewPoint(int x, int y) void CurvesPanel::onSceneNewPoint(int x, int y)
{ {
if ((model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) && (model->curves[currentCurve].count < CPN_MAX_POINTS)) { if ((model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) && (model->curves[currentCurve].count < CPN_MAX_POINTS)) {
int newidx = 0; int newidx = 0;
@ -651,7 +656,7 @@ void Curves::onSceneNewPoint(int x, int y)
} }
} }
void Curves::onCustomContextMenuRequested(QPoint pos) void CurvesPanel::onCustomContextMenuRequested(QPoint pos)
{ {
QPushButton *button = (QPushButton *)sender(); QPushButton *button = (QPushButton *)sender();
selectedIndex = button->property("index").toInt(); selectedIndex = button->property("index").toInt();
@ -673,7 +678,7 @@ void Curves::onCustomContextMenuRequested(QPoint pos)
contextMenu.exec(globalPos); contextMenu.exec(globalPos);
} }
bool Curves::hasClipboardData(QByteArray * data) const bool CurvesPanel::hasClipboardData(QByteArray * data) const
{ {
const QClipboard * clipboard = QApplication::clipboard(); const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData(); const QMimeData * mimeData = clipboard->mimeData();
@ -685,22 +690,22 @@ bool Curves::hasClipboardData(QByteArray * data) const
return false; return false;
} }
bool Curves::insertAllowed() const bool CurvesPanel::insertAllowed() const
{ {
return ((selectedIndex < maxCurves - 1) && (model->curves[maxCurves - 1].isEmpty())); return ((selectedIndex < maxCurves - 1) && (model->curves[maxCurves - 1].isEmpty()));
} }
bool Curves::moveDownAllowed() const bool CurvesPanel::moveDownAllowed() const
{ {
return selectedIndex < maxCurves - 1; return selectedIndex < maxCurves - 1;
} }
bool Curves::moveUpAllowed() const bool CurvesPanel::moveUpAllowed() const
{ {
return selectedIndex > 0; return selectedIndex > 0;
} }
void Curves::cmClear(bool prompt) void CurvesPanel::cmClear(bool prompt)
{ {
if (prompt) { if (prompt) {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
@ -710,10 +715,11 @@ void Curves::cmClear(bool prompt)
model->curves[selectedIndex].clear(); model->curves[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, selectedIndex); model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
void Curves::cmClearAll() void CurvesPanel::cmClearAll()
{ {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Curves. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Curves. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return; return;
@ -723,10 +729,11 @@ void Curves::cmClearAll()
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, i); model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, i);
} }
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
void Curves::cmCopy() void CurvesPanel::cmCopy()
{ {
QByteArray data; QByteArray data;
data.append((char*)&model->curves[selectedIndex], sizeof(CurveData)); data.append((char*)&model->curves[selectedIndex], sizeof(CurveData));
@ -735,7 +742,7 @@ void Curves::cmCopy()
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
} }
void Curves::cmCut() void CurvesPanel::cmCut()
{ {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Cut Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return; return;
@ -743,7 +750,7 @@ void Curves::cmCut()
cmClear(false); cmClear(false);
} }
void Curves::cmDelete() void CurvesPanel::cmDelete()
{ {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return; return;
@ -752,40 +759,43 @@ void Curves::cmDelete()
model->curves[maxCurves - 1].clear(); model->curves[maxCurves - 1].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1); model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
void Curves::cmInsert() void CurvesPanel::cmInsert()
{ {
memmove(&model->curves[selectedIndex + 1], &model->curves[selectedIndex], (CPN_MAX_CURVES - (selectedIndex + 1)) * sizeof(CurveData)); memmove(&model->curves[selectedIndex + 1], &model->curves[selectedIndex], (CPN_MAX_CURVES - (selectedIndex + 1)) * sizeof(CurveData));
model->curves[selectedIndex].clear(); model->curves[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1); model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
void Curves::cmMoveDown() void CurvesPanel::cmMoveDown()
{ {
swapData(selectedIndex, selectedIndex + 1); swapData(selectedIndex, selectedIndex + 1);
} }
void Curves::cmMoveUp() void CurvesPanel::cmMoveUp()
{ {
swapData(selectedIndex, selectedIndex - 1); swapData(selectedIndex, selectedIndex - 1);
} }
void Curves::cmPaste() void CurvesPanel::cmPaste()
{ {
QByteArray data; QByteArray data;
if (hasClipboardData(&data)) { if (hasClipboardData(&data)) {
CurveData *cd = &model->curves[selectedIndex]; CurveData *cd = &model->curves[selectedIndex];
memcpy(cd, data.constData(), sizeof(CurveData)); memcpy(cd, data.constData(), sizeof(CurveData));
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
} }
void Curves::swapData(int idx1, int idx2) void CurvesPanel::swapData(int idx1, int idx2)
{ {
if ((idx1 != idx2) && (!model->curves[idx1].isEmpty() || !model->curves[idx2].isEmpty())) { if ((idx1 != idx2) && (!model->curves[idx1].isEmpty() || !model->curves[idx2].isEmpty())) {
CurveData cdtmp = model->curves[idx2]; CurveData cdtmp = model->curves[idx2];
@ -795,10 +805,16 @@ void Curves::swapData(int idx1, int idx2)
memcpy(cd1, &cdtmp, sizeof(CurveData)); memcpy(cd1, &cdtmp, sizeof(CurveData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
} }
void CurvesPanel::updateItemModels()
{
commonItemModels->update(CommonItemModels::RMO_CURVES);
}
CustomScene::CustomScene(QGraphicsView * view) : CustomScene::CustomScene(QGraphicsView * view) :
QGraphicsScene(view) QGraphicsScene(view)
{ {

View file

@ -26,6 +26,8 @@
#include <QGraphicsScene> #include <QGraphicsScene>
#include <QGraphicsView> #include <QGraphicsView>
class CommonItemModels;
constexpr char MIMETYPE_CURVE[] = "application/x-companion-curve"; constexpr char MIMETYPE_CURVE[] = "application/x-companion-curve";
namespace Ui { namespace Ui {
@ -54,13 +56,13 @@ class CustomScene : public QGraphicsScene
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event) override; virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event) override;
}; };
class Curves : public ModelPanel class CurvesPanel : public ModelPanel
{ {
Q_OBJECT Q_OBJECT
public: public:
Curves(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); CurvesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
virtual ~Curves(); virtual ~CurvesPanel();
virtual void update(); virtual void update();
@ -119,6 +121,8 @@ class Curves : public ModelPanel
bool moveDownAllowed() const; bool moveDownAllowed() const;
bool moveUpAllowed() const; bool moveUpAllowed() const;
void swapData(int idx1, int idx2); void swapData(int idx1, int idx2);
CommonItemModels * commonItemModels;
void updateItemModels();
}; };
#endif // _CURVES_H_ #endif // _CURVES_H_

View file

@ -41,7 +41,7 @@ RepeatComboBox::RepeatComboBox(QWidget *parent, int & repeatParam):
addItem(tr("No repeat"), 0); addItem(tr("No repeat"), 0);
for (unsigned int i=step; i<=60; i+=step) { for (unsigned int i = step; i <= 60; i += step) {
addItem(tr("%1s").arg(i), i); addItem(tr("%1s").arg(i), i);
} }
@ -66,24 +66,36 @@ void RepeatComboBox::update()
setCurrentIndex(value); setCurrentIndex(value);
} }
CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware): CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels):
GenericPanel(parent, model, generalSettings, firmware), GenericPanel(parent, model, generalSettings, firmware),
functions(model ? model->customFn : generalSettings.customFn), functions(model ? model->customFn : generalSettings.customFn),
commonItemModels(commonItemModels),
mediaPlayerCurrent(-1), mediaPlayerCurrent(-1),
mediaPlayer(nullptr) mediaPlayer(nullptr),
modelsUpdateCnt(0)
{ {
Stopwatch s1("CustomFunctionsPanel - populate");
lock = true; lock = true;
fswCapability = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions); fswCapability = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions);
rawSwitchItemModel = new RawSwitchFilterItemModel(&generalSettings, model, model ? RawSwitch::SpecialFunctionsContext : RawSwitch::GlobalFunctionsContext, this); rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), model ? RawSwitch::SpecialFunctionsContext : RawSwitch::GlobalFunctionsContext, this);
rawSrcAllItemModel = new RawSourceFilterItemModel(&generalSettings, model, this); connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &CustomFunctionsPanel::onModelDataAboutToBeUpdated);
rawSrcInputsItemModel = new RawSourceFilterItemModel(rawSrcAllItemModel->sourceModel(), RawSource::InputSourceGroups, this); connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &CustomFunctionsPanel::onModelDataUpdateComplete);
rawSrcGVarsItemModel = new RawSourceFilterItemModel(rawSrcAllItemModel->sourceModel(), RawSource::GVarsGroup, this);
rawSourceAllModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), this);
connect(rawSourceAllModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &CustomFunctionsPanel::onModelDataAboutToBeUpdated);
connect(rawSourceAllModel, &RawItemFilteredModel::dataUpdateComplete, this, &CustomFunctionsPanel::onModelDataUpdateComplete);
rawSourceInputsModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), RawSource::InputSourceGroups, this);
connect(rawSourceInputsModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &CustomFunctionsPanel::onModelDataAboutToBeUpdated);
connect(rawSourceInputsModel, &RawItemFilteredModel::dataUpdateComplete, this, &CustomFunctionsPanel::onModelDataUpdateComplete);
rawSourceGVarsModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), RawSource::GVarsGroup, this);
connect(rawSourceGVarsModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &CustomFunctionsPanel::onModelDataAboutToBeUpdated);
connect(rawSourceGVarsModel, &RawItemFilteredModel::dataUpdateComplete, this, &CustomFunctionsPanel::onModelDataUpdateComplete);
if (!firmware->getCapability(VoicesAsNumbers)) { if (!firmware->getCapability(VoicesAsNumbers)) {
tracksSet = getFilesSet(getSoundsPath(generalSettings), QStringList() << "*.wav" << "*.WAV", firmware->getCapability(VoicesMaxLength)); tracksSet = getFilesSet(getSoundsPath(generalSettings), QStringList() << "*.wav" << "*.WAV", firmware->getCapability(VoicesMaxLength));
for (int i=0; i<fswCapability; i++) { for (int i = 0; i < fswCapability; i++) {
if (functions[i].func == FuncPlayPrompt || functions[i].func == FuncBackgroundMusic) { if (functions[i].func == FuncPlayPrompt || functions[i].func == FuncBackgroundMusic) {
QString temp = functions[i].paramarm; QString temp = functions[i].paramarm;
if (!temp.isEmpty()) { if (!temp.isEmpty()) {
@ -93,11 +105,9 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
} }
} }
s1.report("get tracks");
if (IS_STM32(firmware->getBoard())) { if (IS_STM32(firmware->getBoard())) {
scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/FUNCTIONS", QStringList() << "*.lua", firmware->getCapability(VoicesMaxLength)); scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/FUNCTIONS", QStringList() << "*.lua", firmware->getCapability(VoicesMaxLength));
for (int i=0; i<fswCapability; i++) { for (int i = 0; i < fswCapability; i++) {
if (functions[i].func == FuncPlayScript) { if (functions[i].func == FuncPlayScript) {
QString temp = functions[i].paramarm; QString temp = functions[i].paramarm;
if (!temp.isEmpty()) { if (!temp.isEmpty()) {
@ -106,7 +116,6 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
} }
} }
} }
s1.report("get scripts");
CompanionIcon playIcon("play.png"); CompanionIcon playIcon("play.png");
playIcon.addImage("stop.png", QIcon::Normal, QIcon::On); playIcon.addImage("stop.png", QIcon::Normal, QIcon::On);
@ -115,7 +124,7 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
headerLabels << "#" << tr("Switch") << tr("Action") << tr("Parameters") << tr("Enable"); headerLabels << "#" << tr("Switch") << tr("Action") << tr("Parameters") << tr("Enable");
TableLayout * tableLayout = new TableLayout(this, fswCapability, headerLabels); TableLayout * tableLayout = new TableLayout(this, fswCapability, headerLabels);
for (int i=0; i<fswCapability; i++) { for (int i = 0; i < fswCapability; i++) {
// The label // The label
QLabel * label = new QLabel(this); QLabel * label = new QLabel(this);
label->setContextMenuPolicy(Qt::CustomContextMenu); label->setContextMenuPolicy(Qt::CustomContextMenu);
@ -123,9 +132,9 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
label->setMouseTracking(true); label->setMouseTracking(true);
label->setProperty("index", i); label->setProperty("index", i);
if (model) if (model)
label->setText(tr("SF%1").arg(i+1)); label->setText(tr("SF%1").arg(i + 1));
else else
label->setText(tr("GF%1").arg(i+1)); label->setText(tr("GF%1").arg(i + 1));
label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint))); connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint)));
tableLayout->addWidget(i, 0, label); tableLayout->addWidget(i, 0, label);
@ -133,7 +142,7 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
// The switch // The switch
fswtchSwtch[i] = new QComboBox(this); fswtchSwtch[i] = new QComboBox(this);
fswtchSwtch[i]->setModel(rawSwitchItemModel); fswtchSwtch[i]->setModel(rawSwitchFilteredModel);
fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(functions[i].swtch.toValue())); fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(functions[i].swtch.toValue()));
fswtchSwtch[i]->setProperty("index", i); fswtchSwtch[i]->setProperty("index", i);
fswtchSwtch[i]->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum); fswtchSwtch[i]->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
@ -198,7 +207,6 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
fswtchParamArmT[i]->setEditable(true); fswtchParamArmT[i]->setEditable(true);
fswtchParamArmT[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents); fswtchParamArmT[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
paramLayout->addWidget(fswtchParamArmT[i]); paramLayout->addWidget(fswtchParamArmT[i]);
connect(fswtchParamArmT[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited())); connect(fswtchParamArmT[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited()));
connect(fswtchParamArmT[i], SIGNAL(editTextChanged ( const QString)), this, SLOT(customFunctionEdited())); connect(fswtchParamArmT[i], SIGNAL(editTextChanged ( const QString)), this, SLOT(customFunctionEdited()));
@ -221,31 +229,24 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
QHBoxLayout * repeatLayout = new QHBoxLayout(); QHBoxLayout * repeatLayout = new QHBoxLayout();
tableLayout->addLayout(i, 4, repeatLayout); tableLayout->addLayout(i, 4, repeatLayout);
fswtchRepeat[i] = new RepeatComboBox(this, functions[i].repeatParam); fswtchRepeat[i] = new RepeatComboBox(this, functions[i].repeatParam);
repeatLayout->addWidget(fswtchRepeat[i], i+1); repeatLayout->addWidget(fswtchRepeat[i], i + 1);
connect(fswtchRepeat[i], SIGNAL(modified()), this, SLOT(onChildModified())); connect(fswtchRepeat[i], SIGNAL(modified()), this, SLOT(onRepeatModified()));
fswtchEnable[i] = new QCheckBox(this); fswtchEnable[i] = new QCheckBox(this);
fswtchEnable[i]->setProperty("index", i); fswtchEnable[i]->setProperty("index", i);
fswtchEnable[i]->setText(tr("ON")); fswtchEnable[i]->setText(tr("ON"));
fswtchEnable[i]->setFixedWidth(200); fswtchEnable[i]->setFixedWidth(200);
repeatLayout->addWidget(fswtchEnable[i], i+1); repeatLayout->addWidget(fswtchEnable[i], i + 1);
connect(fswtchEnable[i], SIGNAL(stateChanged(int)), this, SLOT(customFunctionEdited())); connect(fswtchEnable[i], SIGNAL(stateChanged(int)), this, SLOT(customFunctionEdited()));
} }
s1.report("add items");
disableMouseScrolling(); disableMouseScrolling();
s1.report("disableMouseScrolling"); tableLayout->resizeColumnsToContents();
tableLayout->setColumnWidth(3, 300);
lock = false; tableLayout->pushRowsUp(fswCapability + 1);
update(); update();
s1.report("update"); lock = false;
tableLayout->resizeColumnsToContents();
s1.report("resizeColumnsToContents");
tableLayout->setColumnWidth(3, 300);
tableLayout->pushRowsUp(fswCapability+1);
s1.report("end");
} }
CustomFunctionsPanel::~CustomFunctionsPanel() CustomFunctionsPanel::~CustomFunctionsPanel()
@ -254,15 +255,6 @@ CustomFunctionsPanel::~CustomFunctionsPanel()
stopSound(mediaPlayerCurrent); stopSound(mediaPlayerCurrent);
} }
void CustomFunctionsPanel::updateDataModels()
{
const bool oldLock = lock;
lock = true;
rawSwitchItemModel->update();
rawSrcAllItemModel->update();
lock = oldLock;
}
void CustomFunctionsPanel::onMediaPlayerStateChanged(QMediaPlayer::State state) void CustomFunctionsPanel::onMediaPlayerStateChanged(QMediaPlayer::State state)
{ {
if (state != QMediaPlayer::PlayingState) if (state != QMediaPlayer::PlayingState)
@ -343,6 +335,7 @@ void CustomFunctionsPanel::toggleSound(bool play)
#define CUSTOM_FUNCTION_BL_COLOR (1<<9) #define CUSTOM_FUNCTION_BL_COLOR (1<<9)
#define CUSTOM_FUNCTION_SHOW_FUNC (1<<10) #define CUSTOM_FUNCTION_SHOW_FUNC (1<<10)
void CustomFunctionsPanel::customFunctionEdited() void CustomFunctionsPanel::customFunctionEdited()
{ {
if (!lock) { if (!lock) {
@ -369,162 +362,155 @@ void CustomFunctionsPanel::functionEdited()
} }
} }
void CustomFunctionsPanel::onChildModified() void CustomFunctionsPanel::onRepeatModified()
{ {
emit modified(); emit modified();
} }
void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified) void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified)
{ {
CustomFunctionData & cfn = functions[i]; CustomFunctionData & cfn = functions[i];
AssignFunc func = (AssignFunc)fswtchFunc[i]->currentData().toInt(); AssignFunc func = (AssignFunc)fswtchFunc[i]->currentData().toInt();
unsigned int widgetsMask = 0; unsigned int widgetsMask = 0;
if (modified) { if (modified) {
cfn.swtch = RawSwitch(fswtchSwtch[i]->currentData().toInt()); cfn.swtch = RawSwitch(fswtchSwtch[i]->currentData().toInt());
cfn.func = func; cfn.func = func;
cfn.enabled = fswtchEnable[i]->isChecked(); cfn.enabled = fswtchEnable[i]->isChecked();
} }
else {
fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(cfn.swtch.toValue()));
fswtchFunc[i]->setCurrentIndex(fswtchFunc[i]->findData(cfn.func));
}
if (!cfn.isEmpty()) { if (!cfn.isEmpty()) {
widgetsMask |= CUSTOM_FUNCTION_SHOW_FUNC; widgetsMask |= CUSTOM_FUNCTION_SHOW_FUNC;
if (func >= FuncOverrideCH1 && func <= FuncOverrideCH32) { if (func >= FuncOverrideCH1 && func <= FuncOverrideCH32) {
if (model) { if (model) {
int channelsMax = model->getChannelsMax(true); int channelsMax = model->getChannelsMax(true);
fswtchParam[i]->setDecimals(0); fswtchParam[i]->setDecimals(0);
fswtchParam[i]->setSingleStep(1); fswtchParam[i]->setSingleStep(1);
fswtchParam[i]->setMinimum(-channelsMax); fswtchParam[i]->setMinimum(-channelsMax);
fswtchParam[i]->setMaximum(channelsMax); fswtchParam[i]->setMaximum(channelsMax);
if (modified) { if (modified) {
cfn.param = fswtchParam[i]->value(); cfn.param = fswtchParam[i]->value();
}
fswtchParam[i]->setValue(cfn.param);
widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_ENABLE;
} }
fswtchParam[i]->setValue(cfn.param);
widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_ENABLE;
} }
else if (func == FuncLogs) { }
fswtchParam[i]->setDecimals(1); else if (func == FuncLogs) {
fswtchParam[i]->setMinimum(0); fswtchParam[i]->setDecimals(1);
fswtchParam[i]->setMaximum(25.5); fswtchParam[i]->setMinimum(0);
fswtchParam[i]->setSingleStep(0.1); fswtchParam[i]->setMaximum(25.5);
fswtchParam[i]->setSingleStep(0.1);
if (modified)
cfn.param = fswtchParam[i]->value() * 10.0;
fswtchParam[i]->setValue(cfn.param / 10.0);
widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM;
}
else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast) {
int gvidx = func - FuncAdjustGV1;
if (modified)
cfn.adjustMode = fswtchGVmode[i]->currentIndex();
fswtchGVmode[i]->setCurrentIndex(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) if (modified)
cfn.param = fswtchParam[i]->value()*10.0; cfn.param = fswtchParam[i]->value() * model->gvarData[gvidx].multiplierSet();
fswtchParam[i]->setValue(cfn.param/10.0); fswtchParam[i]->setDecimals(model->gvarData[gvidx].prec);
widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM; fswtchParam[i]->setSingleStep(model->gvarData[gvidx].multiplierGet());
} fswtchParam[i]->setSuffix(model->gvarData[gvidx].unitToString());
else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast) { if (cfn.adjustMode == FUNC_ADJUST_GVAR_INCDEC) {
int gvidx = func - FuncAdjustGV1; double rng = abs(model->gvarData[gvidx].getMax() - model->gvarData[gvidx].getMin());
if (modified) rng *= model->gvarData[gvidx].multiplierGet();
cfn.adjustMode = fswtchGVmode[i]->currentIndex(); fswtchParam[i]->setMinimum(-rng);
fswtchGVmode[i]->setCurrentIndex(cfn.adjustMode); fswtchParam[i]->setMaximum(rng);
widgetsMask |= CUSTOM_FUNCTION_GV_MODE | CUSTOM_FUNCTION_ENABLE;
if (cfn.adjustMode == FUNC_ADJUST_GVAR_CONSTANT || cfn.adjustMode == FUNC_ADJUST_GVAR_INCDEC) {
if (modified)
cfn.param = fswtchParam[i]->value() * model->gvarData[gvidx].multiplierSet();
fswtchParam[i]->setDecimals(model->gvarData[gvidx].prec);
fswtchParam[i]->setSingleStep(model->gvarData[gvidx].multiplierGet());
fswtchParam[i]->setSuffix(model->gvarData[gvidx].unitToString());
if (cfn.adjustMode==FUNC_ADJUST_GVAR_INCDEC) {
double rng = abs(model->gvarData[gvidx].getMax() - model->gvarData[gvidx].getMin());
rng *= model->gvarData[gvidx].multiplierGet();
fswtchParam[i]->setMinimum(-rng);
fswtchParam[i]->setMaximum(rng);
}
else {
fswtchParam[i]->setMinimum(model->gvarData[gvidx].getMinPrec());
fswtchParam[i]->setMaximum(model->gvarData[gvidx].getMaxPrec());
}
fswtchParam[i]->setValue(cfn.param * model->gvarData[gvidx].multiplierGet());
widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM;
} }
else { else {
if (modified) fswtchParam[i]->setMinimum(model->gvarData[gvidx].getMinPrec());
cfn.param = fswtchParamT[i]->currentData().toInt(); fswtchParam[i]->setMaximum(model->gvarData[gvidx].getMaxPrec());
populateFuncParamCB(fswtchParamT[i], func, cfn.param, cfn.adjustMode);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
} }
fswtchParam[i]->setValue(cfn.param * model->gvarData[gvidx].multiplierGet());
widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM;
} }
else if (func == FuncReset) { else {
if (modified)
cfn.param = fswtchParamT[i]->currentData().toInt();
populateFuncParamCB(fswtchParamT[i], func, cfn.param, cfn.adjustMode);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
}
}
else if (func == FuncReset) {
if (modified)
cfn.param = fswtchParamT[i]->currentData().toInt();
populateFuncParamCB(fswtchParamT[i], func, cfn.param);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_ENABLE;
}
else if (func >= FuncSetTimer1 && func <= FuncSetTimer3) {
if (modified)
cfn.param = fswtchParamTime[i]->timeInSeconds();
RawSourceRange range = RawSource(SOURCE_TYPE_SPECIAL, func - FuncSetTimer1 + 2).getRange(model, generalSettings);
fswtchParamTime[i]->setTimeRange((int)range.min, (int)range.max);
fswtchParamTime[i]->setTime(cfn.param);
widgetsMask |= CUSTOM_FUNCTION_TIME_PARAM | CUSTOM_FUNCTION_ENABLE;
}
else if (func >= FuncSetFailsafe && func <= FuncBindExternalModule) {
widgetsMask |= CUSTOM_FUNCTION_ENABLE;
}
else if (func == FuncVolume || func == FuncBacklight) {
if (modified)
cfn.param = fswtchParamT[i]->currentData().toInt();
populateFuncParamCB(fswtchParamT[i], func, cfn.param);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_ENABLE;
}
else if (func == FuncPlaySound || func == FuncPlayHaptic || func == FuncPlayValue || func == FuncPlayPrompt || func == FuncPlayBoth || func == FuncBackgroundMusic) {
if (func != FuncBackgroundMusic) {
widgetsMask |= CUSTOM_FUNCTION_REPEAT;
fswtchRepeat[i]->update();
}
if (func == FuncPlayValue) {
if (modified) if (modified)
cfn.param = fswtchParamT[i]->currentData().toInt(); cfn.param = fswtchParamT[i]->currentData().toInt();
populateFuncParamCB(fswtchParamT[i], func, cfn.param); populateFuncParamCB(fswtchParamT[i], func, cfn.param);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_ENABLE; widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_REPEAT;
} }
else if (func >= FuncSetTimer1 && func <= FuncSetTimer3) { else if (func == FuncPlayPrompt || func == FuncPlayBoth) {
if (modified) if (firmware->getCapability(VoicesAsNumbers)) {
cfn.param = fswtchParamTime[i]->timeInSeconds(); fswtchParam[i]->setDecimals(0);
RawSourceRange range = RawSource(SOURCE_TYPE_SPECIAL, func - FuncSetTimer1 + 2).getRange(model, generalSettings); fswtchParam[i]->setSingleStep(1);
fswtchParamTime[i]->setTimeRange((int)range.min, (int)range.max); fswtchParam[i]->setMinimum(0);
fswtchParamTime[i]->setTime(cfn.param); if (func == FuncPlayPrompt) {
widgetsMask |= CUSTOM_FUNCTION_TIME_PARAM | CUSTOM_FUNCTION_ENABLE; widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_REPEAT | CUSTOM_FUNCTION_GV_TOOGLE;
}
else if (func >= FuncSetFailsafeInternalModule && func <= FuncBindExternalModule) {
widgetsMask |= CUSTOM_FUNCTION_ENABLE;
}
else if (func == FuncVolume || func == FuncBacklight) {
if (modified)
cfn.param = fswtchParamT[i]->currentData().toInt();
populateFuncParamCB(fswtchParamT[i], func, cfn.param);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_ENABLE;
}
else if (func == FuncPlaySound || func == FuncPlayHaptic || func == FuncPlayValue || func == FuncPlayPrompt || func == FuncPlayBoth || func == FuncBackgroundMusic) {
if (func != FuncBackgroundMusic) {
widgetsMask |= CUSTOM_FUNCTION_REPEAT;
fswtchRepeat[i]->update();
}
if (func == FuncPlayValue) {
if (modified)
cfn.param = fswtchParamT[i]->currentData().toInt();
populateFuncParamCB(fswtchParamT[i], func, cfn.param);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_REPEAT;
}
else if (func == FuncPlayPrompt || func == FuncPlayBoth) {
if (firmware->getCapability(VoicesAsNumbers)) {
fswtchParam[i]->setDecimals(0);
fswtchParam[i]->setSingleStep(1);
fswtchParam[i]->setMinimum(0);
if (func == FuncPlayPrompt) {
widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_REPEAT | CUSTOM_FUNCTION_GV_TOOGLE;
}
else {
widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_REPEAT;
fswtchParamGV[i]->setChecked(false);
}
fswtchParam[i]->setMaximum(func == FuncPlayBoth ? 254 : 255);
if (modified) {
if (fswtchParamGV[i]->isChecked()) {
fswtchParam[i]->setMinimum(1);
cfn.param = std::min(fswtchParam[i]->value(),5.0)+(fswtchParamGV[i]->isChecked() ? 250 : 0);
}
else {
cfn.param = fswtchParam[i]->value();
}
}
if (cfn.param>250 && (func!=FuncPlayBoth)) {
fswtchParamGV[i]->setChecked(true);
fswtchParam[i]->setValue(cfn.param-250);
fswtchParam[i]->setMaximum(5);
}
else {
fswtchParamGV[i]->setChecked(false);
fswtchParam[i]->setValue(cfn.param);
}
if (cfn.param < 251)
widgetsMask |= CUSTOM_FUNCTION_PLAY;
} }
else { else {
widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM; widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM | CUSTOM_FUNCTION_REPEAT;
if (modified) { fswtchParamGV[i]->setChecked(false);
Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, firmware->getCapability(VoicesMaxLength)); }
fswtchParam[i]->setMaximum(func == FuncPlayBoth ? 254 : 255);
if (modified) {
if (fswtchParamGV[i]->isChecked()) {
fswtchParam[i]->setMinimum(1);
cfn.param = std::min(fswtchParam[i]->value(),5.0)+(fswtchParamGV[i]->isChecked() ? 250 : 0);
} }
Helpers::populateFileComboBox(fswtchParamArmT[i], tracksSet, cfn.paramarm); else {
if (fswtchParamArmT[i]->currentText() != "----") { cfn.param = fswtchParam[i]->value();
widgetsMask |= CUSTOM_FUNCTION_PLAY;
} }
} }
if (cfn.param > 250 && (func != FuncPlayBoth)) {
fswtchParamGV[i]->setChecked(true);
fswtchParam[i]->setValue(cfn.param - 250);
fswtchParam[i]->setMaximum(5);
}
else {
fswtchParamGV[i]->setChecked(false);
fswtchParam[i]->setValue(cfn.param);
}
if (cfn.param < 251)
widgetsMask |= CUSTOM_FUNCTION_PLAY;
} }
else if (func == FuncBackgroundMusic) { else {
widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM; widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
if (modified) { if (modified) {
Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, firmware->getCapability(VoicesMaxLength)); Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, firmware->getCapability(VoicesMaxLength));
@ -534,58 +520,68 @@ void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified)
widgetsMask |= CUSTOM_FUNCTION_PLAY; widgetsMask |= CUSTOM_FUNCTION_PLAY;
} }
} }
else if (func == FuncPlaySound) {
if (modified)
cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
populateFuncParamCB(fswtchParamT[i], func, cfn.param);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
}
else if (func == FuncPlayHaptic) {
if (modified)
cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
populateFuncParamCB(fswtchParamT[i], func, cfn.param);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
}
} }
else if (func == FuncPlayScript) { else if (func == FuncBackgroundMusic) {
widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM; widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
if (modified) { if (modified) {
Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, 8); Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, firmware->getCapability(VoicesMaxLength));
}
Helpers::populateFileComboBox(fswtchParamArmT[i], tracksSet, cfn.paramarm);
if (fswtchParamArmT[i]->currentText() != "----") {
widgetsMask |= CUSTOM_FUNCTION_PLAY;
} }
Helpers::populateFileComboBox(fswtchParamArmT[i], scriptsSet, cfn.paramarm);
} }
else { else if (func == FuncPlaySound) {
if (modified) if (modified)
cfn.param = fswtchParam[i]->value(); cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
fswtchParam[i]->setDecimals(0); populateFuncParamCB(fswtchParamT[i], func, cfn.param);
fswtchParam[i]->setSingleStep(1); widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
fswtchParam[i]->setValue(cfn.param); }
if (func <= FuncInstantTrim) { else if (func == FuncPlayHaptic) {
widgetsMask |= CUSTOM_FUNCTION_ENABLE; if (modified)
} cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
populateFuncParamCB(fswtchParamT[i], func, cfn.param);
widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
} }
} }
else if (func == FuncPlayScript) {
widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
if (modified) {
Helpers::getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, 8);
}
Helpers::populateFileComboBox(fswtchParamArmT[i], scriptsSet, cfn.paramarm);
}
else {
if (modified)
cfn.param = fswtchParam[i]->value();
fswtchParam[i]->setDecimals(0);
fswtchParam[i]->setSingleStep(1);
fswtchParam[i]->setValue(cfn.param);
if (func <= FuncInstantTrim) {
widgetsMask |= CUSTOM_FUNCTION_ENABLE;
}
}
}
fswtchFunc[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SHOW_FUNC); fswtchFunc[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SHOW_FUNC);
fswtchParam[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_NUMERIC_PARAM); fswtchParam[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_NUMERIC_PARAM);
fswtchParamTime[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_TIME_PARAM); fswtchParamTime[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_TIME_PARAM);
fswtchParamGV[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_TOOGLE); fswtchParamGV[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_TOOGLE);
fswtchParamT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SOURCE_PARAM); fswtchParamT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SOURCE_PARAM);
fswtchParamArmT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_FILE_PARAM); fswtchParamArmT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_FILE_PARAM);
fswtchEnable[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_ENABLE); fswtchEnable[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_ENABLE);
if (widgetsMask & CUSTOM_FUNCTION_ENABLE) if (widgetsMask & CUSTOM_FUNCTION_ENABLE)
fswtchEnable[i]->setChecked(cfn.enabled); fswtchEnable[i]->setChecked(cfn.enabled);
else else
fswtchEnable[i]->setChecked(false); fswtchEnable[i]->setChecked(false);
fswtchRepeat[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_REPEAT); fswtchRepeat[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_REPEAT);
fswtchGVmode[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_MODE); fswtchGVmode[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_MODE);
fswtchBLcolor[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_BL_COLOR); fswtchBLcolor[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_BL_COLOR);
playBT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_PLAY); playBT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_PLAY);
} }
void CustomFunctionsPanel::update() void CustomFunctionsPanel::update()
{ {
updateDataModels();
lock = true; lock = true;
for (int i = 0; i < fswCapability; i++) { for (int i = 0; i < fswCapability; i++) {
refreshCustomFunction(i); refreshCustomFunction(i);
@ -660,16 +656,16 @@ void CustomFunctionsPanel::populateFuncCB(QComboBox *b, unsigned int value)
{ {
b->clear(); b->clear();
for (unsigned int i = 0; i < FuncCount; i++) { for (unsigned int i = 0; i < FuncCount; i++) {
if (((i>=FuncOverrideCH1 && i<=FuncOverrideCH32) && (!model || !firmware->getCapability(SafetyChannelCustomFunction))) || if (((i >= FuncOverrideCH1 && i <= FuncOverrideCH32) && (!model || !firmware->getCapability(SafetyChannelCustomFunction))) ||
((i==FuncVolume || i==FuncBackgroundMusic || i==FuncBackgroundMusicPause) && !firmware->getCapability(HasVolume)) || ((i == FuncVolume || i == FuncBackgroundMusic || i == FuncBackgroundMusicPause) && !firmware->getCapability(HasVolume)) ||
((i==FuncPlayScript && !IS_HORUS_OR_TARANIS(firmware->getBoard()))) || ((i == FuncPlayScript && !IS_HORUS_OR_TARANIS(firmware->getBoard()))) ||
((i==FuncPlayHaptic) && !firmware->getCapability(Haptic)) || ((i == FuncPlayHaptic) && !firmware->getCapability(Haptic)) ||
((i==FuncPlayBoth) && !firmware->getCapability(HasBeeper)) || ((i == FuncPlayBoth) && !firmware->getCapability(HasBeeper)) ||
((i==FuncLogs) && !firmware->getCapability(HasSDLogs)) || ((i == FuncLogs) && !firmware->getCapability(HasSDLogs)) ||
((i==FuncSetTimer3) && firmware->getCapability(Timers) < 3) || ((i == FuncSetTimer3) && firmware->getCapability(Timers) < 3) ||
((i==FuncScreenshot) && !IS_HORUS_OR_TARANIS(firmware->getBoard())) || ((i == FuncScreenshot) && !IS_HORUS_OR_TARANIS(firmware->getBoard())) ||
((i>=FuncRangeCheckInternalModule && i<=FuncBindExternalModule) && (!model || !firmware->getCapability(DangerousFunctions))) || ((i >= FuncRangeCheckInternalModule && i <= FuncBindExternalModule) && (!model || !firmware->getCapability(DangerousFunctions))) ||
((i>=FuncAdjustGV1 && i<=FuncAdjustGVLast) && (!model || !firmware->getCapability(Gvars))) ((i >= FuncAdjustGV1 && i <= FuncAdjustGVLast) && (!model || !firmware->getCapability(Gvars)))
) { ) {
// skipped // skipped
continue; continue;
@ -711,21 +707,21 @@ void CustomFunctionsPanel::populateFuncParamCB(QComboBox *b, uint function, unsi
CustomFunctionData::populateResetParams(model, b, value); CustomFunctionData::populateResetParams(model, b, value);
} }
else if (function == FuncVolume || function == FuncBacklight) { else if (function == FuncVolume || function == FuncBacklight) {
b->setModel(rawSrcInputsItemModel); b->setModel(rawSourceInputsModel);
b->setCurrentIndex(b->findData(value)); b->setCurrentIndex(b->findData(value));
} }
else if (function == FuncPlayValue) { else if (function == FuncPlayValue) {
b->setModel(rawSrcAllItemModel); b->setModel(rawSourceAllModel);
b->setCurrentIndex(b->findData(value)); b->setCurrentIndex(b->findData(value));
} }
else if (function >= FuncAdjustGV1 && function <= FuncAdjustGVLast) { else if (function >= FuncAdjustGV1 && function <= FuncAdjustGVLast) {
switch (adjustmode) { switch (adjustmode) {
case 1: case 1:
b->setModel(rawSrcInputsItemModel); b->setModel(rawSourceInputsModel);
b->setCurrentIndex(b->findData(value)); b->setCurrentIndex(b->findData(value));
break; break;
case 2: case 2:
b->setModel(rawSrcGVarsItemModel); b->setModel(rawSourceGVarsModel);
b->setCurrentIndex(b->findData(value)); b->setCurrentIndex(b->findData(value));
break; break;
} }
@ -830,3 +826,23 @@ bool CustomFunctionsPanel::moveUpAllowed() const
{ {
return selectedIndex > 0; return selectedIndex > 0;
} }
void CustomFunctionsPanel::onModelDataAboutToBeUpdated()
{
lock = true;
modelsUpdateCnt++;
}
void CustomFunctionsPanel::onModelDataUpdateComplete()
{
modelsUpdateCnt--;
if (modelsUpdateCnt < 1) {
lock = true;
for (int i = 0; i < fswCapability; i++) {
fswtchSwtch[i]->setCurrentIndex(fswtchSwtch[i]->findData(functions[i].swtch.toValue()));
fswtchFunc[i]->setCurrentIndex(fswtchFunc[i]->findData(functions[i].func));
}
update();
lock = false;
}
}

View file

@ -26,8 +26,8 @@
#include <QMediaPlayer> #include <QMediaPlayer>
class RawSourceFilterItemModel; class CommonItemModels;
class RawSwitchFilterItemModel; class RawItemFilteredModel;
class TimerEdit; class TimerEdit;
constexpr char MIMETYPE_CUSTOM_FUNCTION[] = "application/x-companion-custom-function"; constexpr char MIMETYPE_CUSTOM_FUNCTION[] = "application/x-companion-custom-function";
@ -55,7 +55,7 @@ class CustomFunctionsPanel : public GenericPanel
Q_OBJECT Q_OBJECT
public: public:
CustomFunctionsPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware); CustomFunctionsPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
~CustomFunctionsPanel(); ~CustomFunctionsPanel();
virtual void update(); virtual void update();
@ -64,12 +64,11 @@ class CustomFunctionsPanel : public GenericPanel
CustomFunctionData * functions; CustomFunctionData * functions;
private slots: private slots:
void updateDataModels();
void customFunctionEdited(); void customFunctionEdited();
void functionEdited(); void functionEdited();
void onCustomContextMenuRequested(QPoint pos); void onCustomContextMenuRequested(QPoint pos);
void refreshCustomFunction(int index, bool modified=false); void refreshCustomFunction(int index, bool modified=false);
void onChildModified(); void onRepeatModified();
bool playSound(int index); bool playSound(int index);
void stopSound(int index); void stopSound(int index);
void toggleSound(bool play); void toggleSound(bool play);
@ -84,6 +83,8 @@ class CustomFunctionsPanel : public GenericPanel
void cmInsert(); void cmInsert();
void cmClear(bool prompt = true); void cmClear(bool prompt = true);
void cmClearAll(); void cmClearAll();
void onModelDataAboutToBeUpdated();
void onModelDataUpdateComplete();
private: private:
void populateFuncCB(QComboBox *b, unsigned int value); void populateFuncCB(QComboBox *b, unsigned int value);
@ -95,10 +96,11 @@ class CustomFunctionsPanel : public GenericPanel
bool moveUpAllowed() const; bool moveUpAllowed() const;
void swapData(int idx1, int idx2); void swapData(int idx1, int idx2);
void resetCBsAndRefresh(int idx); void resetCBsAndRefresh(int idx);
RawSwitchFilterItemModel * rawSwitchItemModel; CommonItemModels * commonItemModels;
RawSourceFilterItemModel * rawSrcAllItemModel; RawItemFilteredModel * rawSwitchFilteredModel;
RawSourceFilterItemModel * rawSrcInputsItemModel; RawItemFilteredModel * rawSourceAllModel;
RawSourceFilterItemModel * rawSrcGVarsItemModel; RawItemFilteredModel * rawSourceInputsModel;
RawItemFilteredModel * rawSourceGVarsModel;
QSet<QString> tracksSet; QSet<QString> tracksSet;
QSet<QString> scriptsSet; QSet<QString> scriptsSet;
@ -119,7 +121,7 @@ class CustomFunctionsPanel : public GenericPanel
int selectedIndex; int selectedIndex;
int fswCapability; int fswCapability;
int modelsUpdateCnt;
}; };
#endif // _CUSTOMFUNCTIONS_H_ #endif // _CUSTOMFUNCTIONS_H_

View file

@ -24,7 +24,8 @@
#include "helpers.h" #include "helpers.h"
ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, GeneralSettings & generalSettings, ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, GeneralSettings & generalSettings,
Firmware * firmware, QString & inputName) : Firmware * firmware, QString & inputName, RawItemFilteredModel * rawSourceModel,
RawItemFilteredModel * rawSwitchModel, RawItemFilteredModel * curveItemModel) :
QDialog(parent), QDialog(parent),
ui(new Ui::ExpoDialog), ui(new Ui::ExpoDialog),
model(model), model(model),
@ -36,9 +37,10 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
lock(false) lock(false)
{ {
ui->setupUi(this); ui->setupUi(this);
QLabel * lb_fp[CPN_MAX_FLIGHT_MODES] = {ui->lb_FP0,ui->lb_FP1,ui->lb_FP2,ui->lb_FP3,ui->lb_FP4,ui->lb_FP5,ui->lb_FP6,ui->lb_FP7,ui->lb_FP8 };
QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0,ui->cb_FP1,ui->cb_FP2,ui->cb_FP3,ui->cb_FP4,ui->cb_FP5,ui->cb_FP6,ui->cb_FP7,ui->cb_FP8 }; QLabel * lb_fp[CPN_MAX_FLIGHT_MODES] = {ui->lb_FP0, ui->lb_FP1, ui->lb_FP2, ui->lb_FP3, ui->lb_FP4, ui->lb_FP5, ui->lb_FP6, ui->lb_FP7, ui->lb_FP8 };
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0, ui->cb_FP1, ui->cb_FP2, ui->cb_FP3, ui->cb_FP4, ui->cb_FP5, ui->cb_FP6, ui->cb_FP7, ui->cb_FP8 };
for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i] = tmp[i]; cb_fp[i] = tmp[i];
} }
@ -48,18 +50,16 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, ed->weight, model, 100, -100, 100); 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); gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, ed->offset, model, 0, -100, 100);
curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, ed->curve, model, curveItemModel, this);
curveGroup = new CurveGroup(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueCB, ui->curveValueSB, ed->curve, model, ui->switchesCB->setModel(rawSwitchModel);
firmware->getCapability(HasInputDiff) ? 0 : (HIDE_DIFF | HIDE_NEGATIVE_CURVES));
ui->switchesCB->setModel(new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::MixesContext, this));
ui->switchesCB->setCurrentIndex(ui->switchesCB->findData(ed->swtch.toValue())); ui->switchesCB->setCurrentIndex(ui->switchesCB->findData(ed->swtch.toValue()));
ui->sideCB->setCurrentIndex(ed->mode-1); ui->sideCB->setCurrentIndex(ed->mode - 1);
if (!firmware->getCapability(FlightModes)) { if (!firmware->getCapability(FlightModes)) {
ui->label_phases->hide(); ui->label_phases->hide();
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
lb_fp[i]->hide(); lb_fp[i]->hide();
cb_fp[i]->hide(); cb_fp[i]->hide();
} }
@ -69,13 +69,13 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
ui->label_phases->setContextMenuPolicy(Qt::CustomContextMenu); ui->label_phases->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->label_phases, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(label_phases_customContextMenuRequested(const QPoint &))); connect(ui->label_phases, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(label_phases_customContextMenuRequested(const QPoint &)));
int mask = 1; int mask = 1;
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
if ((ed->flightModes & mask) == 0) { if ((ed->flightModes & mask) == 0) {
cb_fp[i]->setChecked(true); cb_fp[i]->setChecked(true);
} }
mask <<= 1; mask <<= 1;
} }
for (int i=firmware->getCapability(FlightModes); i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = firmware->getCapability(FlightModes); i < CPN_MAX_FLIGHT_MODES; i++) {
lb_fp[i]->hide(); lb_fp[i]->hide();
cb_fp[i]->hide(); cb_fp[i]->hide();
} }
@ -83,9 +83,8 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
if (firmware->getCapability(VirtualInputs)) { if (firmware->getCapability(VirtualInputs)) {
ui->inputName->setMaxLength(firmware->getCapability(InputsLength)); ui->inputName->setMaxLength(firmware->getCapability(InputsLength));
ui->sourceCB->setModel(new RawSourceFilterItemModel(&generalSettings, &model, (RawSource::InputSourceGroups & ~RawSource::InputsGroup) | RawSource::TelemGroup, this)); ui->sourceCB->setModel(rawSourceModel);
ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(ed->srcRaw.toValue())); ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(ed->srcRaw.toValue()));
ui->sourceCB->removeItem(0);
ui->inputName->setValidator(new QRegExpValidator(rx, this)); ui->inputName->setValidator(new QRegExpValidator(rx, this));
ui->inputName->setText(inputName); ui->inputName->setText(inputName);
} }
@ -98,8 +97,8 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
ui->trimCB->hide(); ui->trimCB->hide();
} }
for(int i=0; i < getBoardCapability(getCurrentBoard(), Board::NumTrims); i++) { for(int i = 0; i < getBoardCapability(getCurrentBoard(), Board::NumTrims); i++) {
ui->trimCB->addItem(RawSource(SOURCE_TYPE_TRIM, i).toString(), i+1); ui->trimCB->addItem(RawSource(SOURCE_TYPE_TRIM, i).toString(), i + 1);
} }
ui->trimCB->setCurrentIndex(1 - ed->carryTrim); ui->trimCB->setCurrentIndex(1 - ed->carryTrim);
@ -124,7 +123,7 @@ ExpoDialog::ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expoData, G
connect(ui->trimCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged())); connect(ui->trimCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
connect(ui->switchesCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged())); connect(ui->switchesCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
connect(ui->sideCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged())); connect(ui->sideCB, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
connect(cb_fp[i], SIGNAL(toggled(bool)), this, SLOT(valuesChanged())); connect(cb_fp[i], SIGNAL(toggled(bool)), this, SLOT(valuesChanged()));
} }
if (firmware->getCapability(VirtualInputs)) { if (firmware->getCapability(VirtualInputs)) {
@ -138,7 +137,6 @@ ExpoDialog::~ExpoDialog()
{ {
delete gvWeightGroup; delete gvWeightGroup;
delete gvOffsetGroup; delete gvOffsetGroup;
delete curveGroup;
delete ui; delete ui;
} }
@ -181,7 +179,7 @@ void ExpoDialog::valuesChanged()
} }
ed->flightModes = 0; ed->flightModes = 0;
for (int i=CPN_MAX_FLIGHT_MODES-1; i>=0 ; i--) { for (int i = CPN_MAX_FLIGHT_MODES - 1; i >= 0 ; i--) {
if (!cb_fp[i]->checkState()) { if (!cb_fp[i]->checkState()) {
ed->flightModes++; ed->flightModes++;
} }
@ -212,7 +210,7 @@ void ExpoDialog::label_phases_customContextMenuRequested(const QPoint & pos)
void ExpoDialog::fmClearAll() void ExpoDialog::fmClearAll()
{ {
lock = true; lock = true;
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i]->setChecked(false); cb_fp[i]->setChecked(false);
} }
lock = false; lock = false;
@ -222,7 +220,7 @@ void ExpoDialog::fmClearAll()
void ExpoDialog::fmSetAll() void ExpoDialog::fmSetAll()
{ {
lock = true; lock = true;
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i]->setChecked(true); cb_fp[i]->setChecked(true);
} }
lock = false; lock = false;
@ -232,7 +230,7 @@ void ExpoDialog::fmSetAll()
void ExpoDialog::fmInvertAll() void ExpoDialog::fmInvertAll()
{ {
lock = true; lock = true;
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i]->setChecked(!cb_fp[i]->isChecked()); cb_fp[i]->setChecked(!cb_fp[i]->isChecked());
} }
lock = false; lock = false;

View file

@ -26,7 +26,8 @@
#include "modelprinter.h" #include "modelprinter.h"
class GVarGroup; class GVarGroup;
class CurveGroup; class RawItemFilteredModel;
class CurveReferenceUIManager;
namespace Ui { namespace Ui {
class ExpoDialog; class ExpoDialog;
@ -36,7 +37,8 @@ class ExpoDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expodata, GeneralSettings & generalSettings, ExpoDialog(QWidget *parent, ModelData & model, ExpoData *expodata, GeneralSettings & generalSettings,
Firmware * firmware, QString & inputName); Firmware * firmware, QString & inputName, RawItemFilteredModel * rawSourceItemModel,
RawItemFilteredModel * rawSwitchItemModel, RawItemFilteredModel * curveItemModel);
~ExpoDialog(); ~ExpoDialog();
protected: protected:
@ -59,7 +61,7 @@ class ExpoDialog : public QDialog {
QString & inputName; QString & inputName;
GVarGroup * gvWeightGroup; GVarGroup * gvWeightGroup;
GVarGroup * gvOffsetGroup; GVarGroup * gvOffsetGroup;
CurveGroup * curveGroup; CurveReferenceUIManager * curveGroup;
ModelPrinter modelPrinter; ModelPrinter modelPrinter;
bool lock; bool lock;
QCheckBox * cb_fp[CPN_MAX_FLIGHT_MODES]; QCheckBox * cb_fp[CPN_MAX_FLIGHT_MODES];

View file

@ -24,14 +24,15 @@
#include "helpers.h" #include "helpers.h"
#include "customdebug.h" #include "customdebug.h"
FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseIdx, GeneralSettings & generalSettings, Firmware * firmware, RawSwitchFilterItemModel * switchModel): FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseIdx, GeneralSettings & generalSettings, Firmware * firmware, RawItemFilteredModel * rawSwitchFilteredModel):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::FlightMode), ui(new Ui::FlightMode),
phaseIdx(phaseIdx), phaseIdx(phaseIdx),
phase(model.flightModeData[phaseIdx]), phase(model.flightModeData[phaseIdx])
rawSwitchItemModel(NULL)
{ {
ui->setupUi(this); ui->setupUi(this);
connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &FlightModePanel::onModelDataAboutToBeUpdated);
connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &FlightModePanel::onModelDataUpdateComplete);
ui->labelName->setContextMenuPolicy(Qt::CustomContextMenu); ui->labelName->setContextMenuPolicy(Qt::CustomContextMenu);
ui->labelName->setToolTip(tr("Popup menu available")); ui->labelName->setToolTip(tr("Popup menu available"));
@ -56,8 +57,8 @@ FlightModePanel::FlightModePanel(QWidget * parent, ModelData & model, int phaseI
// Flight mode switch // Flight mode switch
if (phaseIdx > 0) { if (phaseIdx > 0) {
ui->swtch->setModel(switchModel); ui->swtch->setModel(rawSwitchFilteredModel);
connect(ui->swtch, SIGNAL(activated(int)), this, SLOT(phaseSwitchChanged(int))); connect(ui->swtch, SIGNAL(currentIndexChanged(int)), this, SLOT(phaseSwitch_currentIndexChanged(int)));
} }
else { else {
ui->swtch->hide(); ui->swtch->hide();
@ -316,8 +317,6 @@ void FlightModePanel::update()
for (int i = 0; i < reCount; i++) { for (int i = 0; i < reCount; i++) {
updateRotaryEncoder(i); updateRotaryEncoder(i);
} }
emit nameModified();
} }
void FlightModePanel::updateGVar(int index) void FlightModePanel::updateGVar(int index)
@ -390,17 +389,18 @@ void FlightModePanel::phaseName_editingFinished()
{ {
QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender()); QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender());
strcpy(phase.name, lineEdit->text().toLatin1()); strcpy(phase.name, lineEdit->text().toLatin1());
emit phaseNameChanged();
emit modified(); emit modified();
emit nameModified();
} }
void FlightModePanel::phaseSwitchChanged(int index) void FlightModePanel::phaseSwitch_currentIndexChanged(int index)
{ {
if (!lock) { if (!lock) {
bool ok; bool ok;
const RawSwitch rs(ui->swtch->itemData(index).toInt(&ok)); const RawSwitch rs(ui->swtch->itemData(index).toInt(&ok));
if (ok && phase.swtch.toValue() != rs.toValue()) { if (ok && phase.swtch.toValue() != rs.toValue()) {
phase.swtch = rs; phase.swtch = rs;
emit phaseSwitchChanged();
emit modified(); emit modified();
} }
} }
@ -457,7 +457,7 @@ void FlightModePanel::phaseGVValue_editingFinished()
QDoubleSpinBox *spinBox = qobject_cast<QDoubleSpinBox*>(sender()); QDoubleSpinBox *spinBox = qobject_cast<QDoubleSpinBox*>(sender());
int gvar = spinBox->property("index").toInt(); int gvar = spinBox->property("index").toInt();
phase.gvars[gvar] = spinBox->value() * model->gvarData[gvar].multiplierSet(); phase.gvars[gvar] = spinBox->value() * model->gvarData[gvar].multiplierSet();
emit datachanged(); updateGVar(gvar);
emit modified(); emit modified();
} }
} }
@ -469,7 +469,7 @@ void FlightModePanel::GVName_editingFinished()
int gvar = lineedit->property("index").toInt(); int gvar = lineedit->property("index").toInt();
memset(&model->gvarData[gvar].name, 0, sizeof(model->gvarData[gvar].name)); memset(&model->gvarData[gvar].name, 0, sizeof(model->gvarData[gvar].name));
strcpy(model->gvarData[gvar].name, lineedit->text().toLatin1()); strcpy(model->gvarData[gvar].name, lineedit->text().toLatin1());
emit datachanged(); emit gvNameChanged();
emit modified(); emit modified();
} }
} }
@ -488,7 +488,7 @@ void FlightModePanel::phaseGVUse_currentIndexChanged(int index)
} }
if (model->isGVarLinkedCircular(phaseIdx, gvar)) if (model->isGVarLinkedCircular(phaseIdx, gvar))
QMessageBox::warning(this, "Companion", tr("Warning: Global variable links back to itself. Flight Mode 0 value used.")); QMessageBox::warning(this, "Companion", tr("Warning: Global variable links back to itself. Flight Mode 0 value used."));
emit datachanged(); updateGVar(gvar);
emit modified(); emit modified();
lock = false; lock = false;
} }
@ -500,7 +500,7 @@ void FlightModePanel::phaseGVUnit_currentIndexChanged(int index)
QComboBox *comboBox = qobject_cast<QComboBox*>(sender()); QComboBox *comboBox = qobject_cast<QComboBox*>(sender());
int gvar = comboBox->property("index").toInt(); int gvar = comboBox->property("index").toInt();
model->gvarData[gvar].unit = index; model->gvarData[gvar].unit = index;
emit datachanged(); updateGVar(gvar);
emit modified(); emit modified();
} }
} }
@ -511,7 +511,7 @@ void FlightModePanel::phaseGVPrec_currentIndexChanged(int index)
QComboBox *comboBox = qobject_cast<QComboBox*>(sender()); QComboBox *comboBox = qobject_cast<QComboBox*>(sender());
int gvar = comboBox->property("index").toInt(); int gvar = comboBox->property("index").toInt();
model->gvarData[gvar].prec = index; model->gvarData[gvar].prec = index;
emit datachanged(); updateGVar(gvar);
emit modified(); emit modified();
} }
} }
@ -534,7 +534,7 @@ void FlightModePanel::phaseGVMin_editingFinished()
} }
} }
} }
emit datachanged(); updateGVar(gvar);
emit modified(); emit modified();
} }
} }
@ -557,7 +557,7 @@ void FlightModePanel::phaseGVMax_editingFinished()
} }
} }
} }
emit datachanged(); updateGVar(gvar);
emit modified(); emit modified();
} }
} }
@ -741,7 +741,8 @@ void FlightModePanel::cmClear(bool prompt)
model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_CLEAR, phaseIdx); model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_CLEAR, phaseIdx);
emit datachanged(); update();
emit phaseDataChanged();
emit modified(); emit modified();
} }
@ -767,7 +768,7 @@ void FlightModePanel::cmClearAll()
model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_CLEAR, i); model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_CLEAR, i);
} }
emit datachanged(); emit phaseDataChanged();
emit modified(); emit modified();
} }
@ -846,7 +847,7 @@ void FlightModePanel::cmDelete()
model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SHIFT, phaseIdx, 0, -1); model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SHIFT, phaseIdx, 0, -1);
emit datachanged(); emit phaseDataChanged();
emit modified(); emit modified();
} }
@ -897,7 +898,7 @@ void FlightModePanel::cmInsert()
model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SHIFT, phaseIdx, 0, 1); model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SHIFT, phaseIdx, 0, 1);
emit datachanged(); emit phaseDataChanged();
emit modified(); emit modified();
} }
@ -946,7 +947,7 @@ void FlightModePanel::cmPaste()
} }
} }
emit datachanged(); emit phaseDataChanged();
emit modified(); emit modified();
} }
} }
@ -1035,7 +1036,7 @@ void FlightModePanel::swapData(int idx1, int idx2)
} }
model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); model->updateAllReferences(ModelData::REF_UPD_TYPE_FLIGHT_MODE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
emit datachanged(); emit phaseDataChanged();
emit modified(); emit modified();
} }
@ -1162,7 +1163,8 @@ void FlightModePanel::gvCmClear(bool prompt)
} }
phase.gvars[gvIdx] = phase.linkedGVarFlightModeZero(phaseIdx); phase.gvars[gvIdx] = phase.linkedGVarFlightModeZero(phaseIdx);
} }
emit datachanged(); updateGVar(gvIdx);
emit gvNameChanged();
emit modified(); emit modified();
} }
@ -1186,7 +1188,10 @@ void FlightModePanel::gvCmClearAll()
phase.gvars[i] = phase.linkedGVarFlightModeZero(phaseIdx); phase.gvars[i] = phase.linkedGVarFlightModeZero(phaseIdx);
} }
} }
emit datachanged(); for (int i = 0; i < gvCount; i++) {
updateGVar(i);
}
emit gvNameChanged();
emit modified(); emit modified();
} }
@ -1261,8 +1266,13 @@ void FlightModePanel::gvCmDelete()
for (int j = 0; j < fmCount; j++) { for (int j = 0; j < fmCount; j++) {
model->flightModeData[j].gvars[maxidx] = model->flightModeData[j].linkedGVarFlightModeZero(j); model->flightModeData[j].gvars[maxidx] = model->flightModeData[j].linkedGVarFlightModeZero(j);
} }
model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SHIFT, gvIdx, 0, -1); model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SHIFT, gvIdx, 0, -1);
emit datachanged();
for (int i = 0; i < gvCount; i++) {
updateGVar(i);
}
emit gvNameChanged();
emit modified(); emit modified();
} }
@ -1279,7 +1289,10 @@ void FlightModePanel::gvCmInsert()
model->flightModeData[j].gvars[gvIdx] = model->flightModeData[j].linkedGVarFlightModeZero(j); model->flightModeData[j].gvars[gvIdx] = model->flightModeData[j].linkedGVarFlightModeZero(j);
} }
model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SHIFT, gvIdx, 0, 1); model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SHIFT, gvIdx, 0, 1);
emit datachanged(); for (int i = 0; i < gvCount; i++) {
updateGVar(i);
}
emit gvNameChanged();
emit modified(); emit modified();
} }
@ -1322,7 +1335,8 @@ void FlightModePanel::gvCmPaste()
else else
phase.gvars[gvIdx] = val; phase.gvars[gvIdx] = val;
} }
emit datachanged(); updateGVar(gvIdx);
emit gvNameChanged();
emit modified(); emit modified();
} }
@ -1340,33 +1354,51 @@ void FlightModePanel::gvSwapData(int idx1, int idx2)
model->flightModeData[j].gvars[idx1] = valtmp; model->flightModeData[j].gvars[idx1] = valtmp;
} }
model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); model->updateAllReferences(ModelData::REF_UPD_TYPE_GLOBAL_VARIABLE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
emit datachanged(); updateGVar(idx1);
updateGVar(idx2);
emit gvNameChanged();
emit modified(); emit modified();
} }
} }
void FlightModePanel::onModelDataAboutToBeUpdated()
{
lock = true;
}
void FlightModePanel::onModelDataUpdateComplete()
{
update();
lock = false;
}
/**********************************************************/ /**********************************************************/
FlightModesPanel::FlightModesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): FlightModesPanel::FlightModesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
modesCount(firmware->getCapability(FlightModes)) commonItemModels(commonItemModels)
{ {
rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::MixesContext, this);
RawSwitchFilterItemModel * swModel = new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::MixesContext, this); modesCount = firmware->getCapability(FlightModes);
connect(this, &FlightModesPanel::updated, swModel, &RawSwitchFilterItemModel::update);
QGridLayout * gridLayout = new QGridLayout(this); QGridLayout * gridLayout = new QGridLayout(this);
tabWidget = new QTabWidget(this); tabWidget = new QTabWidget(this);
for (int i = 0; i < modesCount; i++) { for (int i = 0; i < modesCount; i++) {
FlightModePanel * tab = new FlightModePanel(tabWidget, model, i, generalSettings, firmware, swModel); FlightModePanel * tab = new FlightModePanel(tabWidget, model, i, generalSettings, firmware, rawSwitchFilteredModel);
tab->setProperty("index", i); tab->setProperty("index", i);
connect(tab, &FlightModePanel::datachanged, this, &FlightModesPanel::update); connect(tab, &FlightModePanel::modified, this, &FlightModesPanel::modified);
connect(tab, &FlightModePanel::modified, this, &FlightModesPanel::modified); connect(tab, &FlightModePanel::phaseDataChanged, this, &FlightModesPanel::onPhaseNameChanged);
connect(tab, &FlightModePanel::nameModified, this, &FlightModesPanel::onPhaseNameChanged); connect(tab, &FlightModePanel::phaseNameChanged, this, &FlightModesPanel::onPhaseNameChanged);
connect(this, &FlightModesPanel::updated, tab, &FlightModePanel::update); connect(tab, &FlightModePanel::phaseSwitchChanged, this, &FlightModesPanel::updateItemModels);
connect(tab, &FlightModePanel::gvNameChanged, this, &FlightModesPanel::updateItemModels);
connect(this, &FlightModesPanel::updated, tab, &FlightModePanel::update);
tabWidget->addTab(tab, getTabName(i)); tabWidget->addTab(tab, getTabName(i));
panels << tab;
} }
connect(tabWidget, &QTabWidget::currentChanged, this, &FlightModesPanel::onTabIndexChanged);
gridLayout->addWidget(tabWidget, 0, 0, 1, 1); gridLayout->addWidget(tabWidget, 0, 0, 1, 1);
onTabIndexChanged(0);
} }
FlightModesPanel::~FlightModesPanel() FlightModesPanel::~FlightModesPanel()
@ -1391,9 +1423,22 @@ void FlightModesPanel::onPhaseNameChanged()
{ {
int index = sender()->property("index").toInt(); int index = sender()->property("index").toInt();
tabWidget->setTabText(index, getTabName(index)); tabWidget->setTabText(index, getTabName(index));
updateItemModels();
} }
void FlightModesPanel::update() void FlightModesPanel::update()
{ {
emit updated(); emit updated();
} }
void FlightModesPanel::updateItemModels()
{
commonItemModels->update(CommonItemModels::RMO_FLIGHT_MODES);
commonItemModels->update(CommonItemModels::RMO_GLOBAL_VARIABLES);
}
void FlightModesPanel::onTabIndexChanged(int index)
{
if (index < panels.size())
panels.at(index)->update();
}

View file

@ -24,7 +24,8 @@
#include "modeledit.h" #include "modeledit.h"
#include "eeprominterface.h" #include "eeprominterface.h"
class RawSwitchFilterItemModel; class CommonItemModels;
class RawItemFilteredModel;
constexpr char MIMETYPE_FLIGHTMODE[] = "application/x-companion-flightmode"; constexpr char MIMETYPE_FLIGHTMODE[] = "application/x-companion-flightmode";
constexpr char MIMETYPE_GVAR_PARAMS[] = "application/x-companion-gvar-params"; constexpr char MIMETYPE_GVAR_PARAMS[] = "application/x-companion-gvar-params";
@ -40,18 +41,20 @@ class FlightModePanel : public ModelPanel
Q_OBJECT Q_OBJECT
public: public:
FlightModePanel(QWidget *parent, ModelData &model, int modeIdx, GeneralSettings & generalSettings, Firmware * firmware, RawSwitchFilterItemModel * switchModel); FlightModePanel(QWidget *parent, ModelData &model, int modeIdx, GeneralSettings & generalSettings, Firmware * firmware, RawItemFilteredModel * rawSwitchFilteredModel);
virtual ~FlightModePanel(); virtual ~FlightModePanel();
virtual void update(); virtual void update();
signals: signals:
void nameModified(); void gvNameChanged();
void datachanged(); void phaseDataChanged();
void phaseNameChanged();
void phaseSwitchChanged();
private slots: private slots:
void phaseName_editingFinished(); void phaseName_editingFinished();
void phaseSwitchChanged(int index); void phaseSwitch_currentIndexChanged(int index);
void phaseFadeIn_editingFinished(); void phaseFadeIn_editingFinished();
void phaseFadeOut_editingFinished(); void phaseFadeOut_editingFinished();
void phaseTrimUse_currentIndexChanged(int index); void phaseTrimUse_currentIndexChanged(int index);
@ -87,6 +90,8 @@ class FlightModePanel : public ModelPanel
void gvCmPaste(); void gvCmPaste();
void gvCmMoveDown(); void gvCmMoveDown();
void gvCmMoveUp(); void gvCmMoveUp();
void onModelDataAboutToBeUpdated();
void onModelDataUpdateComplete();
private: private:
Ui::FlightMode *ui; Ui::FlightMode *ui;
@ -111,7 +116,6 @@ class FlightModePanel : public ModelPanel
QVector<QComboBox *> trimsUse; QVector<QComboBox *> trimsUse;
QVector<QSpinBox *> trimsValue; QVector<QSpinBox *> trimsValue;
QVector<QSlider *> trimsSlider; QVector<QSlider *> trimsSlider;
RawSwitchFilterItemModel * rawSwitchItemModel;
Board::Type board; Board::Type board;
void trimUpdate(unsigned int trim); void trimUpdate(unsigned int trim);
@ -141,7 +145,7 @@ class FlightModesPanel : public ModelPanel
Q_OBJECT Q_OBJECT
public: public:
FlightModesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); FlightModesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
virtual ~FlightModesPanel(); virtual ~FlightModesPanel();
public slots: public slots:
@ -152,13 +156,17 @@ class FlightModesPanel : public ModelPanel
private slots: private slots:
void onPhaseNameChanged(); void onPhaseNameChanged();
void onTabIndexChanged(int index);
private: private:
QString getTabName(int index); QString getTabName(int index);
int modesCount; int modesCount;
QTabWidget *tabWidget; QTabWidget *tabWidget;
CommonItemModels *commonItemModels;
RawItemFilteredModel *rawSwitchFilteredModel;
QVector<GenericPanel *> panels;
void updateItemModels();
}; };
#endif // _FLIGHTMODES_H_ #endif // _FLIGHTMODES_H_

View file

@ -23,19 +23,26 @@
#include "helpers.h" #include "helpers.h"
#include "rawitemfilteredmodel.h" #include "rawitemfilteredmodel.h"
HeliPanel::HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): HeliPanel::HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::Heli) ui(new Ui::Heli),
commonItemModels(commonItemModels)
{ {
ui->setupUi(this); ui->setupUi(this);
rawSourceItemModel = new RawSourceFilterItemModel(&generalSettings, &model, RawSource::InputSourceGroups, this); rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), RawSource::InputSourceGroups, this);
connect(rawSourceFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &HeliPanel::onModelDataAboutToBeUpdated);
connect(rawSourceFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &HeliPanel::onModelDataUpdateComplete);
connect(ui->swashType, SIGNAL(currentIndexChanged(int)), this, SLOT(edited())); connect(ui->swashType, SIGNAL(currentIndexChanged(int)), this, SLOT(edited()));
connect(ui->swashRingVal, SIGNAL(editingFinished()), this, SLOT(edited())); connect(ui->swashRingVal, SIGNAL(editingFinished()), this, SLOT(edited()));
ui->swashCollectiveSource->setModel(rawSourceFilteredModel);
connect(ui->swashCollectiveSource, SIGNAL(currentIndexChanged(int)), this, SLOT(edited())); connect(ui->swashCollectiveSource, SIGNAL(currentIndexChanged(int)), this, SLOT(edited()));
if (firmware->getCapability(VirtualInputs)) { if (firmware->getCapability(VirtualInputs)) {
ui->swashAileronSource->setModel(rawSourceFilteredModel);
connect(ui->swashAileronSource, SIGNAL(currentIndexChanged(int)), this, SLOT(edited())); connect(ui->swashAileronSource, SIGNAL(currentIndexChanged(int)), this, SLOT(edited()));
ui->swashElevatorSource->setModel(rawSourceFilteredModel);
connect(ui->swashElevatorSource, SIGNAL(currentIndexChanged(int)), this, SLOT(edited())); connect(ui->swashElevatorSource, SIGNAL(currentIndexChanged(int)), this, SLOT(edited()));
connect(ui->swashAileronWeight, SIGNAL(editingFinished()), this, SLOT(edited())); connect(ui->swashAileronWeight, SIGNAL(editingFinished()), this, SLOT(edited()));
connect(ui->swashElevatorWeight, SIGNAL(editingFinished()), this, SLOT(edited())); connect(ui->swashElevatorWeight, SIGNAL(editingFinished()), this, SLOT(edited()));
@ -66,27 +73,15 @@ HeliPanel::~HeliPanel()
delete ui; delete ui;
} }
void HeliPanel::updateDataModels()
{
const bool oldLock = lock;
lock = true;
rawSourceItemModel->update();
lock = oldLock;
}
void HeliPanel::update() void HeliPanel::update()
{ {
lock = true; lock = true;
updateDataModels();
ui->swashType->setCurrentIndex(model->swashRingData.type); ui->swashType->setCurrentIndex(model->swashRingData.type);
ui->swashCollectiveSource->setModel(rawSourceItemModel);
ui->swashCollectiveSource->setCurrentIndex(ui->swashCollectiveSource->findData(model->swashRingData.collectiveSource.toValue())); ui->swashCollectiveSource->setCurrentIndex(ui->swashCollectiveSource->findData(model->swashRingData.collectiveSource.toValue()));
ui->swashRingVal->setValue(model->swashRingData.value); ui->swashRingVal->setValue(model->swashRingData.value);
if (firmware->getCapability(VirtualInputs)) { if (firmware->getCapability(VirtualInputs)) {
ui->swashElevatorSource->setModel(rawSourceItemModel);
ui->swashElevatorSource->setCurrentIndex(ui->swashElevatorSource->findData(model->swashRingData.elevatorSource.toValue())); ui->swashElevatorSource->setCurrentIndex(ui->swashElevatorSource->findData(model->swashRingData.elevatorSource.toValue()));
ui->swashAileronSource->setModel(rawSourceItemModel);
ui->swashAileronSource->setCurrentIndex(ui->swashAileronSource->findData(model->swashRingData.aileronSource.toValue())); ui->swashAileronSource->setCurrentIndex(ui->swashAileronSource->findData(model->swashRingData.aileronSource.toValue()));
ui->swashElevatorWeight->setValue(model->swashRingData.elevatorWeight); ui->swashElevatorWeight->setValue(model->swashRingData.elevatorWeight);
ui->swashAileronWeight->setValue(model->swashRingData.aileronWeight); ui->swashAileronWeight->setValue(model->swashRingData.aileronWeight);
@ -122,3 +117,14 @@ void HeliPanel::edited()
emit modified(); emit modified();
} }
} }
void HeliPanel::onModelDataAboutToBeUpdated()
{
lock = true;
}
void HeliPanel::onModelDataUpdateComplete()
{
update();
lock = false;
}

View file

@ -23,7 +23,8 @@
#include "modeledit.h" #include "modeledit.h"
class RawSourceFilterItemModel; class CommonItemModels;
class RawItemFilteredModel;
namespace Ui { namespace Ui {
class Heli; class Heli;
@ -34,17 +35,19 @@ class HeliPanel : public ModelPanel
Q_OBJECT Q_OBJECT
public: public:
HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); HeliPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
~HeliPanel(); ~HeliPanel();
void update(); void update();
private slots: private slots:
void updateDataModels();
void edited(); void edited();
void onModelDataAboutToBeUpdated();
void onModelDataUpdateComplete();
private: private:
Ui::Heli *ui; Ui::Heli *ui;
RawSourceFilterItemModel * rawSourceItemModel; CommonItemModels * commonItemModels;
RawItemFilteredModel * rawSourceFilteredModel;
}; };
#endif // _HELI_H_ #endif // _HELI_H_

View file

@ -21,12 +21,26 @@
#include "inputs.h" #include "inputs.h"
#include "expodialog.h" #include "expodialog.h"
#include "helpers.h" #include "helpers.h"
#include "rawitemfilteredmodel.h"
InputsPanel::InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): InputsPanel::InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
expoInserted(false), expoInserted(false),
modelPrinter(firmware, generalSettings, model) modelPrinter(firmware, generalSettings, model),
commonItemModels(commonItemModels)
{ {
rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), (RawSource::InputSourceGroups & ~ RawSource::NoneGroup & ~RawSource::InputsGroup), this);
connect(rawSourceFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &InputsPanel::onModelDataAboutToBeUpdated);
connect(rawSourceFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &InputsPanel::onModelDataUpdateComplete);
rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::MixesContext, this);
connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &InputsPanel::onModelDataAboutToBeUpdated);
connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &InputsPanel::onModelDataUpdateComplete);
curveFilteredModel = new RawItemFilteredModel(commonItemModels->curveItemModel(), RawItemFilteredModel::AllFilter, this);
connect(curveFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &InputsPanel::onModelDataAboutToBeUpdated);
connect(curveFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &InputsPanel::onModelDataUpdateComplete);
inputsCount = firmware->getCapability(VirtualInputs); inputsCount = firmware->getCapability(VirtualInputs);
if (inputsCount == 0) if (inputsCount == 0)
inputsCount = CPN_MAX_STICKS; inputsCount = CPN_MAX_STICKS;
@ -180,13 +194,14 @@ void InputsPanel::gm_openExpo(int index)
if (firmware->getCapability(VirtualInputs)) if (firmware->getCapability(VirtualInputs))
inputName = model->inputNames[ed.chn]; inputName = model->inputNames[ed.chn];
ExpoDialog *g = new ExpoDialog(this, *model, &ed, generalSettings, firmware, inputName); ExpoDialog *dlg = new ExpoDialog(this, *model, &ed, generalSettings, firmware, inputName, rawSourceFilteredModel, rawSwitchFilteredModel, curveFilteredModel);
if (g->exec()) { if (dlg->exec()) {
model->expoData[index] = ed; model->expoData[index] = ed;
if (firmware->getCapability(VirtualInputs)) if (firmware->getCapability(VirtualInputs))
strncpy(model->inputNames[ed.chn], inputName.toLatin1().data(), INPUT_NAME_LEN); strncpy(model->inputNames[ed.chn], inputName.toLatin1().data(), INPUT_NAME_LEN);
emit modified();
update(); update();
updateItemModels();
emit modified();
} }
else { else {
if (expoInserted) { if (expoInserted) {
@ -195,6 +210,7 @@ void InputsPanel::gm_openExpo(int index)
expoInserted=false; expoInserted=false;
update(); update();
} }
delete dlg;
} }
int InputsPanel::getExpoIndex(unsigned int dch) int InputsPanel::getExpoIndex(unsigned int dch)
@ -239,8 +255,9 @@ void InputsPanel::exposDelete(bool prompt)
} }
exposDeleteList(list, prompt); exposDeleteList(list, prompt);
emit modified();
update(); update();
updateItemModels();
emit modified();
} }
void InputsPanel::exposCut() void InputsPanel::exposCut()
@ -313,8 +330,9 @@ void InputsPanel::pasteExpoMimeData(const QMimeData * mimeData, int destIdx)
i += sizeof(ExpoData); i += sizeof(ExpoData);
} }
emit modified();
update(); update();
updateItemModels();
emit modified();
} }
} }
@ -481,8 +499,9 @@ void InputsPanel::moveExpoList(bool down)
} }
} }
if (mod) { if (mod) {
emit modified();
update(); update();
updateItemModels();
emit modified();
} }
setSelectedByExpoList(highlightList); setSelectedByExpoList(highlightList);
} }
@ -520,8 +539,9 @@ void InputsPanel::clearExpos()
for (int i = 0; i < inputsCount; i++) { for (int i = 0; i < inputsCount; i++) {
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, i); model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, i);
} }
emit modified();
update(); update();
updateItemModels();
emit modified();
} }
} }
@ -569,6 +589,7 @@ void InputsPanel::cmInputClear()
} }
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, inputIdx); model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, inputIdx);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
@ -592,6 +613,7 @@ void InputsPanel::cmInputDelete()
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, -1); model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, -1);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
@ -610,6 +632,7 @@ void InputsPanel::cmInputInsert()
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, 1); model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, 1);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
@ -671,6 +694,7 @@ void InputsPanel::cmInputSwapData(int idx1, int idx2)
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
@ -705,3 +729,19 @@ int InputsPanel::getInputIndexFromSelected()
} }
return idx; return idx;
} }
void InputsPanel::onModelDataAboutToBeUpdated()
{
lock = true;
}
void InputsPanel::onModelDataUpdateComplete()
{
update();
lock = false;
}
void InputsPanel::updateItemModels()
{
commonItemModels->update(CommonItemModels::RMO_INPUTS);
}

View file

@ -25,6 +25,9 @@
#include "mixerslistwidget.h" #include "mixerslistwidget.h"
#include "modelprinter.h" #include "modelprinter.h"
class CommonItemModels;
class RawItemFilteredModel;
constexpr char MIMETYPE_EXPO[] = "application/x-companion-expo"; constexpr char MIMETYPE_EXPO[] = "application/x-companion-expo";
class InputsPanel : public ModelPanel class InputsPanel : public ModelPanel
@ -32,7 +35,7 @@ class InputsPanel : public ModelPanel
Q_OBJECT Q_OBJECT
public: public:
InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
virtual ~InputsPanel(); virtual ~InputsPanel();
virtual void update(); virtual void update();
@ -59,6 +62,8 @@ class InputsPanel : public ModelPanel
void cmInputInsert(); void cmInputInsert();
void cmInputMoveDown(); void cmInputMoveDown();
void cmInputMoveUp(); void cmInputMoveUp();
void onModelDataAboutToBeUpdated();
void onModelDataUpdateComplete();
private: private:
bool expoInserted; bool expoInserted;
@ -67,6 +72,10 @@ class InputsPanel : public ModelPanel
ModelPrinter modelPrinter; ModelPrinter modelPrinter;
int selectedIdx; int selectedIdx;
int inputIdx; int inputIdx;
CommonItemModels * commonItemModels;
RawItemFilteredModel *rawSourceFilteredModel;
RawItemFilteredModel *rawSwitchFilteredModel;
RawItemFilteredModel *curveFilteredModel;
int getExpoIndex(unsigned int dch); int getExpoIndex(unsigned int dch);
bool gm_insertExpo(int idx); bool gm_insertExpo(int idx);
@ -87,6 +96,7 @@ class InputsPanel : public ModelPanel
bool isExpoIndex(const int index); bool isExpoIndex(const int index);
int getIndexFromSelected(); int getIndexFromSelected();
int getInputIndexFromSelected(); int getInputIndexFromSelected();
void updateItemModels();
}; };
#endif // _INPUTS_H_ #endif // _INPUTS_H_

View file

@ -24,16 +24,20 @@
#include <TimerEdit> #include <TimerEdit>
LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
selectedIndex(0) commonItemModels(commonItemModels),
selectedIndex(0),
modelsUpdateCnt(0)
{ {
Stopwatch s1("LogicalSwitchesPanel"); rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::LogicalSwitchesContext, this);
connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &LogicalSwitchesPanel::onModelDataAboutToBeUpdated);
rawSwitchItemModel = new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::LogicalSwitchesContext, this); connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &LogicalSwitchesPanel::onModelDataUpdateComplete);
const int srcGroups = firmware->getCapability(GvarsInCS) ? 0 : (RawSource::AllSourceGroups & ~RawSource::GVarsGroup); const int srcGroups = firmware->getCapability(GvarsInCS) ? 0 : (RawSource::AllSourceGroups & ~RawSource::GVarsGroup);
rawSourceItemModel = new RawSourceFilterItemModel(&generalSettings, &model, srcGroups, this); rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), srcGroups, this);
connect(rawSourceFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &LogicalSwitchesPanel::onModelDataAboutToBeUpdated);
connect(rawSourceFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &LogicalSwitchesPanel::onModelDataUpdateComplete);
lsCapability = firmware->getCapability(LogicalSwitches); lsCapability = firmware->getCapability(LogicalSwitches);
lsCapabilityExt = firmware->getCapability(LogicalSwitchesExt); lsCapabilityExt = firmware->getCapability(LogicalSwitchesExt);
@ -45,16 +49,13 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
} }
TableLayout * tableLayout = new TableLayout(this, lsCapability, headerLabels); TableLayout * tableLayout = new TableLayout(this, lsCapability, headerLabels);
s1.report("header");
const int channelsMax = model.getChannelsMax(true); const int channelsMax = model.getChannelsMax(true);
lock = true; for (int i = 0; i < lsCapability; i++) {
for (int i=0; i<lsCapability; i++) {
// The label // The label
QLabel * label = new QLabel(this); QLabel * label = new QLabel(this);
label->setProperty("index", i); label->setProperty("index", i);
label->setText(RawSwitch(SWITCH_TYPE_VIRTUAL, i+1).toString()); label->setText(RawSwitch(SWITCH_TYPE_VIRTUAL, i + 1).toString());
label->setContextMenuPolicy(Qt::CustomContextMenu); label->setContextMenuPolicy(Qt::CustomContextMenu);
label->setToolTip(tr("Popup menu available")); label->setToolTip(tr("Popup menu available"));
label->setMouseTracking(true); label->setMouseTracking(true);
@ -123,7 +124,8 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
// AND // AND
cbAndSwitch[i] = new QComboBox(this); cbAndSwitch[i] = new QComboBox(this);
cbAndSwitch[i]->setProperty("index", i); cbAndSwitch[i]->setProperty("index", i);
populateAndSwitchCB(cbAndSwitch[i]); cbAndSwitch[i]->setModel(rawSwitchFilteredModel);
cbAndSwitch[i]->setVisible(true);
connect(cbAndSwitch[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onAndSwitchChanged(int))); connect(cbAndSwitch[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onAndSwitchChanged(int)));
tableLayout->addWidget(i, 4, cbAndSwitch[i]); tableLayout->addWidget(i, 4, cbAndSwitch[i]);
@ -152,72 +154,63 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
} }
} }
s1.report("added elements");
disableMouseScrolling(); disableMouseScrolling();
lock = false;
update();
tableLayout->resizeColumnsToContents(); tableLayout->resizeColumnsToContents();
tableLayout->pushRowsUp(lsCapability+1); tableLayout->pushRowsUp(lsCapability+1);
s1.report("end");
} }
LogicalSwitchesPanel::~LogicalSwitchesPanel() LogicalSwitchesPanel::~LogicalSwitchesPanel()
{ {
} }
void LogicalSwitchesPanel::updateDataModels()
{
const bool oldLock = lock;
lock = true;
rawSwitchItemModel->update();
rawSourceItemModel->update();
lock = oldLock;
}
void LogicalSwitchesPanel::onFunctionChanged() void LogicalSwitchesPanel::onFunctionChanged()
{ {
int i = sender()->property("index").toInt(); if (!lock) {
unsigned newFunc = cbFunction[i]->currentData().toUInt(); int i = sender()->property("index").toInt();
unsigned newFunc = cbFunction[i]->currentData().toUInt();
if (model->logicalSw[i].func == newFunc) if (model->logicalSw[i].func == newFunc)
return; return;
const unsigned oldFunc = model->logicalSw[i].func; unsigned oldFunc = model->logicalSw[i].func;
CSFunctionFamily oldFuncFamily = model->logicalSw[i].getFunctionFamily(); CSFunctionFamily oldFuncFamily = model->logicalSw[i].getFunctionFamily();
model->logicalSw[i].func = newFunc;
CSFunctionFamily newFuncFamily = model->logicalSw[i].getFunctionFamily();
if (oldFuncFamily != newFuncFamily) {
model->logicalSw[i].clear();
model->logicalSw[i].func = newFunc; model->logicalSw[i].func = newFunc;
if (newFuncFamily == LS_FAMILY_TIMER) { CSFunctionFamily newFuncFamily = model->logicalSw[i].getFunctionFamily();
model->logicalSw[i].val1 = -119;
model->logicalSw[i].val2 = -119; if (oldFuncFamily != newFuncFamily || newFunc == LS_FN_OFF) {
model->logicalSw[i].clear();
model->logicalSw[i].func = newFunc;
if (newFuncFamily == LS_FAMILY_TIMER) {
model->logicalSw[i].val1 = -119;
model->logicalSw[i].val2 = -119;
}
else if (newFuncFamily == LS_FAMILY_EDGE) {
model->logicalSw[i].val2 = -129;
}
} }
else if (newFuncFamily == LS_FAMILY_EDGE) {
model->logicalSw[i].val2 = -129;
}
}
if (bool(oldFunc) != bool(newFunc))
update();
else
updateLine(i); updateLine(i);
emit modified(); if (oldFunc == LS_FN_OFF || newFunc == LS_FN_OFF)
updateItemModels();
emit modified();
}
} }
void LogicalSwitchesPanel::onV1Changed(int value) void LogicalSwitchesPanel::onV1Changed(int value)
{ {
if (!lock) { if (!lock) {
int i = sender()->property("index").toInt(); int i = sender()->property("index").toInt();
model->logicalSw[i].val1 = cbSource1[i]->itemData(value).toInt(); if (model->logicalSw[i].val1 != cbSource1[i]->itemData(value).toInt()) {
if (model->logicalSw[i].getFunctionFamily() == LS_FAMILY_VOFS) { model->logicalSw[i].val1 = cbSource1[i]->itemData(value).toInt();
if (!offsetChangedAt(i)) if (model->logicalSw[i].getFunctionFamily() == LS_FAMILY_VOFS) {
updateLine(i); if (!offsetChangedAt(i))
} updateLine(i);
else { }
emit modified(); else {
emit modified();
}
} }
} }
} }
@ -226,8 +219,10 @@ void LogicalSwitchesPanel::onV2Changed(int value)
{ {
if (!lock) { if (!lock) {
int i = sender()->property("index").toInt(); int i = sender()->property("index").toInt();
model->logicalSw[i].val2 = cbSource2[i]->itemData(value).toInt(); if (model->logicalSw[i].val2 != cbSource2[i]->itemData(value).toInt()) {
emit modified(); model->logicalSw[i].val2 = cbSource2[i]->itemData(value).toInt();
emit modified();
}
} }
} }
@ -235,8 +230,10 @@ void LogicalSwitchesPanel::onAndSwitchChanged(int value)
{ {
if (!lock) { if (!lock) {
int index = sender()->property("index").toInt(); int index = sender()->property("index").toInt();
model->logicalSw[index].andsw = cbAndSwitch[index]->itemData(value).toInt(); if (model->logicalSw[index].andsw != cbAndSwitch[index]->itemData(value).toInt()) {
emit modified(); model->logicalSw[index].andsw = cbAndSwitch[index]->itemData(value).toInt();
emit modified();
}
} }
} }
@ -244,7 +241,7 @@ void LogicalSwitchesPanel::onDurationChanged(double duration)
{ {
if (!lock) { if (!lock) {
int index = sender()->property("index").toInt(); int index = sender()->property("index").toInt();
model->logicalSw[index].duration = (uint8_t)round(duration*10); model->logicalSw[index].duration = (uint8_t)round(duration * 10);
emit modified(); emit modified();
} }
} }
@ -253,7 +250,7 @@ void LogicalSwitchesPanel::onDelayChanged(double delay)
{ {
if (!lock) { if (!lock) {
int index = sender()->property("index").toInt(); int index = sender()->property("index").toInt();
model->logicalSw[index].delay = (uint8_t)round(delay*10); model->logicalSw[index].delay = (uint8_t)round(delay * 10);
emit modified(); emit modified();
} }
} }
@ -326,9 +323,9 @@ void LogicalSwitchesPanel::updateTimerParam(QDoubleSpinBox *sb, int timer, doubl
sb->setMinimum(minimum); sb->setMinimum(minimum);
sb->setMaximum(175); sb->setMaximum(175);
float value = ValToTim(timer); float value = ValToTim(timer);
if (value>=60) if (value >= 60)
sb->setSingleStep(1); sb->setSingleStep(1);
else if (value>=2) else if (value >= 2)
sb->setSingleStep(0.5); sb->setSingleStep(0.5);
else else
sb->setSingleStep(0.1); sb->setSingleStep(0.1);
@ -347,16 +344,14 @@ void LogicalSwitchesPanel::updateTimerParam(QDoubleSpinBox *sb, int timer, doubl
void LogicalSwitchesPanel::updateLine(int i) void LogicalSwitchesPanel::updateLine(int i)
{ {
const bool savelock = lock;
lock = true; lock = true;
unsigned int mask; unsigned int mask = 0;
cbFunction[i]->setCurrentIndex(cbFunction[i]->findData(model->logicalSw[i].func)); cbFunction[i]->setCurrentIndex(cbFunction[i]->findData(model->logicalSw[i].func));
cbAndSwitch[i]->setCurrentIndex(cbAndSwitch[i]->findData(RawSwitch(model->logicalSw[i].andsw).toValue())); cbAndSwitch[i]->setCurrentIndex(cbAndSwitch[i]->findData(RawSwitch(model->logicalSw[i].andsw).toValue()));
if (!model->logicalSw[i].func) { if (!model->logicalSw[i].isEmpty()) {
mask = 0;
}
else {
mask = LINE_ENABLED | DELAY_ENABLED | DURATION_ENABLED; mask = LINE_ENABLED | DELAY_ENABLED | DURATION_ENABLED;
switch (model->logicalSw[i].getFunctionFamily()) switch (model->logicalSw[i].getFunctionFamily())
@ -367,7 +362,7 @@ void LogicalSwitchesPanel::updateLine(int i)
RawSource source = RawSource(model->logicalSw[i].val1); RawSource source = RawSource(model->logicalSw[i].val1);
RawSourceRange range = source.getRange(model, generalSettings, model->logicalSw[i].getRangeFlags()); RawSourceRange range = source.getRange(model, generalSettings, model->logicalSw[i].getRangeFlags());
double value = range.step * model->logicalSw[i].val2 + range.offset; /* TODO+source.getRawOffset(model)*/ double value = range.step * model->logicalSw[i].val2 + range.offset; /* TODO+source.getRawOffset(model)*/
cbSource1[i]->setModel(rawSourceItemModel); cbSource1[i]->setModel(rawSourceFilteredModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(source.toValue())); cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(source.toValue()));
if (source.isTimeBased()) { if (source.isTimeBased()) {
mask |= VALUE_TO_VISIBLE; mask |= VALUE_TO_VISIBLE;
@ -396,27 +391,27 @@ void LogicalSwitchesPanel::updateLine(int i)
case LS_FAMILY_STICKY: // no break case LS_FAMILY_STICKY: // no break
case LS_FAMILY_VBOOL: case LS_FAMILY_VBOOL:
mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE; mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE;
cbSource1[i]->setModel(rawSwitchItemModel); cbSource1[i]->setModel(rawSwitchFilteredModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1)); cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1));
cbSource2[i]->setModel(rawSwitchItemModel); cbSource2[i]->setModel(rawSwitchFilteredModel);
cbSource2[i]->setCurrentIndex(cbSource2[i]->findData(model->logicalSw[i].val2)); cbSource2[i]->setCurrentIndex(cbSource2[i]->findData(model->logicalSw[i].val2));
break; break;
case LS_FAMILY_EDGE: case LS_FAMILY_EDGE:
mask |= SOURCE1_VISIBLE | VALUE2_VISIBLE | VALUE3_VISIBLE; mask |= SOURCE1_VISIBLE | VALUE2_VISIBLE | VALUE3_VISIBLE;
mask &= ~DELAY_ENABLED; mask &= ~DELAY_ENABLED;
cbSource1[i]->setModel(rawSwitchItemModel); cbSource1[i]->setModel(rawSwitchFilteredModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1)); cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1));
updateTimerParam(dsbOffset[i], model->logicalSw[i].val2, 0.0); updateTimerParam(dsbOffset[i], model->logicalSw[i].val2, 0.0);
updateTimerParam(dsbOffset2[i], model->logicalSw[i].val2+model->logicalSw[i].val3, ValToTim(TimToVal(dsbOffset[i]->value())-1)); updateTimerParam(dsbOffset2[i], model->logicalSw[i].val2 + model->logicalSw[i].val3, ValToTim(TimToVal(dsbOffset[i]->value()) - 1));
dsbOffset2[i]->setSuffix((model->logicalSw[i].val3) ? "" : tr(" (infinite)")); dsbOffset2[i]->setSuffix((model->logicalSw[i].val3) ? "" : tr(" (infinite)"));
break; break;
case LS_FAMILY_VCOMP: case LS_FAMILY_VCOMP:
mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE; mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE;
cbSource1[i]->setModel(rawSourceItemModel); cbSource1[i]->setModel(rawSourceFilteredModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1)); cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1));
cbSource2[i]->setModel(rawSourceItemModel); cbSource2[i]->setModel(rawSourceFilteredModel);
cbSource2[i]->setCurrentIndex(cbSource2[i]->findData(model->logicalSw[i].val2)); cbSource2[i]->setCurrentIndex(cbSource2[i]->findData(model->logicalSw[i].val2));
break; break;
@ -439,12 +434,12 @@ void LogicalSwitchesPanel::updateLine(int i)
dsbDuration[i]->setVisible(mask & DURATION_ENABLED); dsbDuration[i]->setVisible(mask & DURATION_ENABLED);
dsbDelay[i]->setVisible(mask & DELAY_ENABLED); dsbDelay[i]->setVisible(mask & DELAY_ENABLED);
if (mask & DURATION_ENABLED) if (mask & DURATION_ENABLED)
dsbDuration[i]->setValue(model->logicalSw[i].duration/10.0); dsbDuration[i]->setValue(model->logicalSw[i].duration / 10.0);
if (mask & DELAY_ENABLED) if (mask & DELAY_ENABLED)
dsbDelay[i]->setValue(model->logicalSw[i].delay/10.0); dsbDelay[i]->setValue(model->logicalSw[i].delay / 10.0);
} }
lock = false; lock = savelock;
} }
void LogicalSwitchesPanel::populateFunctionCB(QComboBox *b) void LogicalSwitchesPanel::populateFunctionCB(QComboBox *b)
@ -475,7 +470,7 @@ void LogicalSwitchesPanel::populateFunctionCB(QComboBox *b)
}; };
b->clear(); b->clear();
for (int i=0; i<LS_FN_MAX; i++) { for (int i = 0; i < LS_FN_MAX; i++) {
int func = order[i]; int func = order[i];
if (func == LS_FN_NEQUAL || func == LS_FN_EGREATER || func == LS_FN_ELESS) if (func == LS_FN_NEQUAL || func == LS_FN_EGREATER || func == LS_FN_ELESS)
continue; continue;
@ -484,16 +479,9 @@ void LogicalSwitchesPanel::populateFunctionCB(QComboBox *b)
b->setMaxVisibleItems(10); b->setMaxVisibleItems(10);
} }
void LogicalSwitchesPanel::populateAndSwitchCB(QComboBox *b)
{
b->setModel(rawSwitchItemModel);
b->setVisible(true);
}
void LogicalSwitchesPanel::update() void LogicalSwitchesPanel::update()
{ {
updateDataModels(); for (int i = 0; i < lsCapability; i++) {
for (int i=0; i<lsCapability; i++) {
updateLine(i); updateLine(i);
} }
} }
@ -503,8 +491,8 @@ void LogicalSwitchesPanel::cmPaste()
QByteArray data; QByteArray data;
if (hasClipboardData(&data)) { if (hasClipboardData(&data)) {
memcpy(&model->logicalSw[selectedIndex], data.constData(), sizeof(LogicalSwitchData)); memcpy(&model->logicalSw[selectedIndex], data.constData(), sizeof(LogicalSwitchData));
updateDataModels();
updateLine(selectedIndex); updateLine(selectedIndex);
updateItemModels();
emit modified(); emit modified();
} }
} }
@ -519,6 +507,7 @@ void LogicalSwitchesPanel::cmDelete()
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1); model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
@ -528,7 +517,7 @@ void LogicalSwitchesPanel::cmCopy()
data.append((char*)&model->logicalSw[selectedIndex], sizeof(LogicalSwitchData)); data.append((char*)&model->logicalSw[selectedIndex], sizeof(LogicalSwitchData));
QMimeData *mimeData = new QMimeData; QMimeData *mimeData = new QMimeData;
mimeData->setData(MIMETYPE_LOGICAL_SWITCH, data); mimeData->setData(MIMETYPE_LOGICAL_SWITCH, data);
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard); QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
} }
void LogicalSwitchesPanel::cmCut() void LogicalSwitchesPanel::cmCut()
@ -539,7 +528,6 @@ void LogicalSwitchesPanel::cmCut()
cmClear(false); cmClear(false);
} }
// TODO make something generic here!
void LogicalSwitchesPanel::onCustomContextMenuRequested(QPoint pos) void LogicalSwitchesPanel::onCustomContextMenuRequested(QPoint pos)
{ {
QLabel *label = (QLabel *)sender(); QLabel *label = (QLabel *)sender();
@ -608,7 +596,8 @@ void LogicalSwitchesPanel::cmClear(bool prompt)
model->logicalSw[selectedIndex].clear(); model->logicalSw[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_CLEAR, selectedIndex); model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
update(); updateLine(selectedIndex);
updateItemModels();
emit modified(); emit modified();
} }
@ -617,11 +606,12 @@ void LogicalSwitchesPanel::cmClearAll()
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Logical Switches. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Logical Switches. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return; return;
for (int i=0; i<lsCapability; i++) { for (int i = 0; i < lsCapability; i++) {
model->logicalSw[i].clear(); model->logicalSw[i].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_CLEAR, i); model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_CLEAR, i);
} }
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
@ -631,6 +621,7 @@ void LogicalSwitchesPanel::cmInsert()
model->logicalSw[selectedIndex].clear(); model->logicalSw[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1); model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update(); update();
updateItemModels();
emit modified(); emit modified();
} }
@ -643,7 +634,30 @@ void LogicalSwitchesPanel::swapData(int idx1, int idx2)
memcpy(lsw2, lsw1, sizeof(LogicalSwitchData)); memcpy(lsw2, lsw1, sizeof(LogicalSwitchData));
memcpy(lsw1, &lstmp, sizeof(LogicalSwitchData)); memcpy(lsw1, &lstmp, sizeof(LogicalSwitchData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
update(); updateLine(idx1);
updateLine(idx2);
updateItemModels();
emit modified(); emit modified();
} }
} }
void LogicalSwitchesPanel::updateItemModels()
{
lock = true;
commonItemModels->update(CommonItemModels::RMO_LOGICAL_SWITCHES);
}
void LogicalSwitchesPanel::onModelDataAboutToBeUpdated()
{
lock = true;
modelsUpdateCnt++;
}
void LogicalSwitchesPanel::onModelDataUpdateComplete()
{
modelsUpdateCnt--;
if (modelsUpdateCnt < 1) {
update();
lock = false;
}
}

View file

@ -24,8 +24,8 @@
#include "modeledit.h" #include "modeledit.h"
#include "radiodata.h" #include "radiodata.h"
class RawSwitchFilterItemModel; class CommonItemModels;
class RawSourceFilterItemModel; class RawItemFilteredModel;
class TimerEdit; class TimerEdit;
constexpr char MIMETYPE_LOGICAL_SWITCH[] = "application/x-companion-logical-switch"; constexpr char MIMETYPE_LOGICAL_SWITCH[] = "application/x-companion-logical-switch";
@ -35,13 +35,12 @@ class LogicalSwitchesPanel : public ModelPanel
Q_OBJECT Q_OBJECT
public: public:
LogicalSwitchesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); LogicalSwitchesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
virtual ~LogicalSwitchesPanel(); virtual ~LogicalSwitchesPanel();
virtual void update(); virtual void update();
private slots: private slots:
void updateDataModels();
void onFunctionChanged(); void onFunctionChanged();
void onV1Changed(int value); void onV1Changed(int value);
void onV2Changed(int value); void onV2Changed(int value);
@ -61,6 +60,8 @@ class LogicalSwitchesPanel : public ModelPanel
void cmInsert(); void cmInsert();
void cmClear(bool prompt = true); void cmClear(bool prompt = true);
void cmClearAll(); void cmClearAll();
void onModelDataAboutToBeUpdated();
void onModelDataUpdateComplete();
private: private:
QComboBox * cbFunction[CPN_MAX_LOGICAL_SWITCHES]; QComboBox * cbFunction[CPN_MAX_LOGICAL_SWITCHES];
@ -73,11 +74,11 @@ class LogicalSwitchesPanel : public ModelPanel
QDoubleSpinBox * dsbDelay[CPN_MAX_LOGICAL_SWITCHES]; QDoubleSpinBox * dsbDelay[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbSource1[CPN_MAX_LOGICAL_SWITCHES]; QComboBox * cbSource1[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbSource2[CPN_MAX_LOGICAL_SWITCHES]; QComboBox * cbSource2[CPN_MAX_LOGICAL_SWITCHES];
RawSwitchFilterItemModel * rawSwitchItemModel; CommonItemModels * commonItemModels;
RawSourceFilterItemModel * rawSourceItemModel; RawItemFilteredModel * rawSwitchFilteredModel;
RawItemFilteredModel * rawSourceFilteredModel;
int selectedIndex; int selectedIndex;
void populateFunctionCB(QComboBox *b); void populateFunctionCB(QComboBox *b);
void populateAndSwitchCB(QComboBox *b);
void updateTimerParam(QDoubleSpinBox *sb, int timer, double minimum=0); void updateTimerParam(QDoubleSpinBox *sb, int timer, double minimum=0);
int lsCapability; int lsCapability;
int lsCapabilityExt; int lsCapabilityExt;
@ -86,6 +87,8 @@ class LogicalSwitchesPanel : public ModelPanel
bool insertAllowed() const; bool insertAllowed() const;
bool moveDownAllowed() const; bool moveDownAllowed() const;
bool moveUpAllowed() const; bool moveUpAllowed() const;
int modelsUpdateCnt;
void updateItemModels();
}; };
#endif // _LOGICALSWITCHES_H_ #endif // _LOGICALSWITCHES_H_

View file

@ -24,7 +24,8 @@
#include "rawitemfilteredmodel.h" #include "rawitemfilteredmodel.h"
#include "helpers.h" #include "helpers.h"
MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, GeneralSettings & generalSettings, Firmware * firmware) : MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata, GeneralSettings & generalSettings, Firmware * firmware,
RawItemFilteredModel * rawSourceModel, RawItemFilteredModel * rawSwitchModel, RawItemFilteredModel * curveItemModel) :
QDialog(parent), QDialog(parent),
ui(new Ui::MixerDialog), ui(new Ui::MixerDialog),
model(model), model(model),
@ -34,25 +35,24 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
lock(false) lock(false)
{ {
ui->setupUi(this); ui->setupUi(this);
QRegExp rx(CHAR_FOR_NAMES_REGEX); QRegExp rx(CHAR_FOR_NAMES_REGEX);
QLabel * lb_fp[CPN_MAX_FLIGHT_MODES] = {ui->lb_FP0,ui->lb_FP1,ui->lb_FP2,ui->lb_FP3,ui->lb_FP4,ui->lb_FP5,ui->lb_FP6,ui->lb_FP7,ui->lb_FP8 }; QLabel * lb_fp[CPN_MAX_FLIGHT_MODES] = {ui->lb_FP0, ui->lb_FP1, ui->lb_FP2, ui->lb_FP3, ui->lb_FP4, ui->lb_FP5, ui->lb_FP6, ui->lb_FP7, ui->lb_FP8 };
QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0,ui->cb_FP1,ui->cb_FP2,ui->cb_FP3,ui->cb_FP4,ui->cb_FP5,ui->cb_FP6,ui->cb_FP7,ui->cb_FP8 }; QCheckBox * tmp[CPN_MAX_FLIGHT_MODES] = {ui->cb_FP0, ui->cb_FP1, ui->cb_FP2, ui->cb_FP3, ui->cb_FP4, ui->cb_FP5, ui->cb_FP6, ui->cb_FP7, ui->cb_FP8 };
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i] = tmp[i]; cb_fp[i] = tmp[i];
} }
this->setWindowTitle(tr("DEST -> %1").arg(RawSource(SOURCE_TYPE_CH, md->destCh-1).toString(&model, &generalSettings))); this->setWindowTitle(tr("DEST -> %1").arg(RawSource(SOURCE_TYPE_CH, md->destCh - 1).toString(&model, &generalSettings)));
ui->sourceCB->setModel(new RawSourceFilterItemModel(&generalSettings, &model, RawSource::InputSourceGroups | RawSource::ScriptsGroup, this)); ui->sourceCB->setModel(rawSourceModel);
ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(md->srcRaw.toValue())); ui->sourceCB->setCurrentIndex(ui->sourceCB->findData(md->srcRaw.toValue()));
ui->sourceCB->removeItem(0);
int limit = firmware->getCapability(OffsetWeight); int limit = firmware->getCapability(OffsetWeight);
gvWeightGroup = new GVarGroup(ui->weightGV, ui->weightSB, ui->weightCB, md->weight, model, 100, -limit, limit); 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); gvOffsetGroup = new GVarGroup(ui->offsetGV, ui->offsetSB, ui->offsetCB, md->sOffset, model, 0, -limit, limit);
curveGroup = new CurveGroup(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueCB, ui->curveValueSB, curveGroup = new CurveReferenceUIManager(ui->curveTypeCB, ui->curveGVarCB, ui->curveValueSB, ui->curveValueCB, md->curve, model, curveItemModel, this);
md->curve, model, firmware->getCapability(HasMixerExpo) ? 0 : HIDE_EXPO);
ui->MixDR_CB->setChecked(md->noExpo == 0); ui->MixDR_CB->setChecked(md->noExpo == 0);
@ -62,7 +62,7 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
} }
if (!firmware->getCapability(VirtualInputs)) { if (!firmware->getCapability(VirtualInputs)) {
for(int i=0; i < CPN_MAX_STICKS; i++) { for(int i = 0; i < CPN_MAX_STICKS; i++) {
ui->trimCB->addItem(firmware->getAnalogInputName(i)); ui->trimCB->addItem(firmware->getAnalogInputName(i));
} }
} }
@ -82,7 +82,7 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
if (!firmware->getCapability(FlightModes)) { if (!firmware->getCapability(FlightModes)) {
ui->label_phases->hide(); ui->label_phases->hide();
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
lb_fp[i]->hide(); lb_fp[i]->hide();
cb_fp[i]->hide(); cb_fp[i]->hide();
} }
@ -92,40 +92,40 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
ui->label_phases->setContextMenuPolicy(Qt::CustomContextMenu); ui->label_phases->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->label_phases, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(label_phases_customContextMenuRequested(const QPoint &))); connect(ui->label_phases, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(label_phases_customContextMenuRequested(const QPoint &)));
int mask = 1; int mask = 1;
for (int i=0; i<CPN_MAX_FLIGHT_MODES ; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES ; i++) {
if ((md->flightModes & mask) == 0) { if ((md->flightModes & mask) == 0) {
cb_fp[i]->setChecked(true); cb_fp[i]->setChecked(true);
} }
mask <<= 1; mask <<= 1;
} }
for (int i=firmware->getCapability(FlightModes); i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = firmware->getCapability(FlightModes); i < CPN_MAX_FLIGHT_MODES; i++) {
lb_fp[i]->hide(); lb_fp[i]->hide();
cb_fp[i]->hide(); cb_fp[i]->hide();
} }
} }
ui->switchesCB->setModel(new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::MixesContext, this)); ui->switchesCB->setModel(rawSwitchModel);
ui->switchesCB->setCurrentIndex(ui->switchesCB->findData(md->swtch.toValue())); ui->switchesCB->setCurrentIndex(ui->switchesCB->findData(md->swtch.toValue()));
ui->warningCB->setCurrentIndex(md->mixWarn); ui->warningCB->setCurrentIndex(md->mixWarn);
ui->mltpxCB->setCurrentIndex(md->mltpx); ui->mltpxCB->setCurrentIndex(md->mltpx);
int scale=firmware->getCapability(SlowScale); int scale=firmware->getCapability(SlowScale);
float range=firmware->getCapability(SlowRange); float range=firmware->getCapability(SlowRange);
ui->slowDownSB->setMaximum(range/scale); ui->slowDownSB->setMaximum(range / scale);
ui->slowDownSB->setSingleStep(1.0/scale); ui->slowDownSB->setSingleStep(1.0 / scale);
ui->slowDownSB->setDecimals((scale==1 ? 0 :1)); ui->slowDownSB->setDecimals((scale == 1 ? 0 : 1));
ui->slowDownSB->setValue((float)md->speedDown/scale); ui->slowDownSB->setValue((float)md->speedDown/scale);
ui->slowUpSB->setMaximum(range/scale); ui->slowUpSB->setMaximum(range / scale);
ui->slowUpSB->setSingleStep(1.0/scale); ui->slowUpSB->setSingleStep(1.0 / scale);
ui->slowUpSB->setDecimals((scale==1 ? 0 :1)); ui->slowUpSB->setDecimals((scale == 1 ? 0 : 1));
ui->slowUpSB->setValue((float)md->speedUp/scale); ui->slowUpSB->setValue((float)md->speedUp/scale);
ui->delayDownSB->setMaximum(range/scale); ui->delayDownSB->setMaximum(range / scale);
ui->delayDownSB->setSingleStep(1.0/scale); ui->delayDownSB->setSingleStep(1.0 / scale);
ui->delayDownSB->setDecimals((scale==1 ? 0 :1)); ui->delayDownSB->setDecimals((scale == 1 ? 0 : 1));
ui->delayDownSB->setValue((float)md->delayDown/scale); ui->delayDownSB->setValue((float)md->delayDown / scale);
ui->delayUpSB->setMaximum(range/scale); ui->delayUpSB->setMaximum(range / scale);
ui->delayUpSB->setSingleStep(1.0/scale); ui->delayUpSB->setSingleStep(1.0 / scale);
ui->delayUpSB->setDecimals((scale==1 ? 0 :1)); ui->delayUpSB->setDecimals((scale == 1 ? 0 : 1));
ui->delayUpSB->setValue((float)md->delayUp/scale); ui->delayUpSB->setValue((float)md->delayUp / scale);
QTimer::singleShot(0, this, SLOT(shrink())); QTimer::singleShot(0, this, SLOT(shrink()));
valuesChanged(); valuesChanged();
@ -147,10 +147,9 @@ MixerDialog::MixerDialog(QWidget *parent, ModelData & model, MixData * mixdata,
MixerDialog::~MixerDialog() MixerDialog::~MixerDialog()
{ {
delete ui;
delete gvWeightGroup; delete gvWeightGroup;
delete gvOffsetGroup; delete gvOffsetGroup;
delete curveGroup;
delete ui;
} }
void MixerDialog::changeEvent(QEvent *e) void MixerDialog::changeEvent(QEvent *e)
@ -176,20 +175,20 @@ void MixerDialog::valuesChanged()
ui->MixDR_CB->setEnabled(drVisible); ui->MixDR_CB->setEnabled(drVisible);
ui->label_MixDR->setEnabled(drVisible); ui->label_MixDR->setEnabled(drVisible);
} }
md->carryTrim = -(ui->trimCB->currentIndex()-1); md->carryTrim = -(ui->trimCB->currentIndex() - 1);
md->noExpo = ui->MixDR_CB->checkState() ? 0 : 1; md->noExpo = ui->MixDR_CB->checkState() ? 0 : 1;
md->swtch = RawSwitch(ui->switchesCB->itemData(ui->switchesCB->currentIndex()).toInt()); md->swtch = RawSwitch(ui->switchesCB->itemData(ui->switchesCB->currentIndex()).toInt());
md->mixWarn = ui->warningCB->currentIndex(); md->mixWarn = ui->warningCB->currentIndex();
md->mltpx = (MltpxValue)ui->mltpxCB->currentIndex(); md->mltpx = (MltpxValue)ui->mltpxCB->currentIndex();
int scale = firmware->getCapability(SlowScale); int scale = firmware->getCapability(SlowScale);
md->delayDown = round(ui->delayDownSB->value()*scale); md->delayDown = round(ui->delayDownSB->value() * scale);
md->delayUp = round(ui->delayUpSB->value()*scale); md->delayUp = round(ui->delayUpSB->value() * scale);
md->speedDown = round(ui->slowDownSB->value()*scale); md->speedDown = round(ui->slowDownSB->value() * scale);
md->speedUp = round(ui->slowUpSB->value()*scale); md->speedUp = round(ui->slowUpSB->value() * scale);
strcpy(md->name, ui->mixerName->text().toLatin1()); strcpy(md->name, ui->mixerName->text().toLatin1());
md->flightModes = 0; md->flightModes = 0;
for (int i=CPN_MAX_FLIGHT_MODES-1; i>=0 ; i--) { for (int i = CPN_MAX_FLIGHT_MODES - 1; i >= 0 ; i--) {
if (!cb_fp[i]->checkState()) { if (!cb_fp[i]->checkState()) {
md->flightModes++; md->flightModes++;
} }
@ -220,7 +219,7 @@ void MixerDialog::label_phases_customContextMenuRequested(const QPoint & pos)
void MixerDialog::fmClearAll() void MixerDialog::fmClearAll()
{ {
lock = true; lock = true;
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i]->setChecked(false); cb_fp[i]->setChecked(false);
} }
lock = false; lock = false;
@ -230,7 +229,7 @@ void MixerDialog::fmClearAll()
void MixerDialog::fmSetAll() void MixerDialog::fmSetAll()
{ {
lock = true; lock = true;
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i]->setChecked(true); cb_fp[i]->setChecked(true);
} }
lock = false; lock = false;
@ -240,7 +239,7 @@ void MixerDialog::fmSetAll()
void MixerDialog::fmInvertAll() void MixerDialog::fmInvertAll()
{ {
lock = true; lock = true;
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) { for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
cb_fp[i]->setChecked(!cb_fp[i]->isChecked()); cb_fp[i]->setChecked(!cb_fp[i]->isChecked());
} }
lock = false; lock = false;

View file

@ -25,7 +25,8 @@
#include "eeprominterface.h" #include "eeprominterface.h"
class GVarGroup; class GVarGroup;
class CurveGroup; class RawItemFilteredModel;
class CurveReferenceUIManager;
namespace Ui { namespace Ui {
class MixerDialog; class MixerDialog;
@ -34,7 +35,8 @@ namespace Ui {
class MixerDialog : public QDialog { class MixerDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
MixerDialog(QWidget *parent, ModelData & model, MixData *mixdata, GeneralSettings & generalSettings, Firmware * firmware); MixerDialog(QWidget *parent, ModelData & model, MixData *mixdata, GeneralSettings & generalSettings, Firmware * firmware,
RawItemFilteredModel * rawSourceModel, RawItemFilteredModel * rawSwitchModel, RawItemFilteredModel * curveItemModel);
~MixerDialog(); ~MixerDialog();
protected: protected:
@ -57,7 +59,7 @@ class MixerDialog : public QDialog {
bool lock; bool lock;
GVarGroup * gvWeightGroup; GVarGroup * gvWeightGroup;
GVarGroup * gvOffsetGroup; GVarGroup * gvOffsetGroup;
CurveGroup * curveGroup; CurveReferenceUIManager * curveGroup;
QCheckBox * cb_fp[CPN_MAX_FLIGHT_MODES]; QCheckBox * cb_fp[CPN_MAX_FLIGHT_MODES];
}; };

View file

@ -20,13 +20,27 @@
#include "mixes.h" #include "mixes.h"
#include "helpers.h" #include "helpers.h"
#include "rawitemfilteredmodel.h"
MixesPanel::MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): MixesPanel::MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware,CommonItemModels * commonItemModels):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
mixInserted(false), mixInserted(false),
highlightedSource(0), highlightedSource(0),
modelPrinter(firmware, generalSettings, model) modelPrinter(firmware, generalSettings, model),
commonItemModels(commonItemModels)
{ {
rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), ((RawSource::InputSourceGroups | RawSource::ScriptsGroup) & ~ RawSource::NoneGroup), this);
connect(rawSourceFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &MixesPanel::onModelDataAboutToBeUpdated);
connect(rawSourceFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &MixesPanel::onModelDataUpdateComplete);
rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::MixesContext, this);
connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &MixesPanel::onModelDataAboutToBeUpdated);
connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &MixesPanel::onModelDataUpdateComplete);
curveFilteredModel = new RawItemFilteredModel(commonItemModels->curveItemModel(), RawItemFilteredModel::AllFilter, this);
connect(curveFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &MixesPanel::onModelDataAboutToBeUpdated);
connect(curveFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &MixesPanel::onModelDataUpdateComplete);
QGridLayout * mixesLayout = new QGridLayout(this); QGridLayout * mixesLayout = new QGridLayout(this);
mixersListWidget = new MixersListWidget(this, false); // TODO enum mixersListWidget = new MixersListWidget(this, false); // TODO enum
@ -175,8 +189,8 @@ void MixesPanel::gm_openMix(int index)
MixData mixd(model->mixData[index]); MixData mixd(model->mixData[index]);
MixerDialog *g = new MixerDialog(this, *model, &mixd, generalSettings, firmware); MixerDialog *dlg = new MixerDialog(this, *model, &mixd, generalSettings, firmware, rawSourceFilteredModel, rawSwitchFilteredModel, curveFilteredModel);
if(g->exec()) { if(dlg->exec()) {
model->mixData[index] = mixd; model->mixData[index] = mixd;
emit modified(); emit modified();
update(); update();
@ -188,6 +202,7 @@ void MixesPanel::gm_openMix(int index)
mixInserted = false; mixInserted = false;
update(); update();
} }
delete dlg;
} }
int MixesPanel::getMixerIndex(unsigned int dch) int MixesPanel::getMixerIndex(unsigned int dch)
@ -529,3 +544,14 @@ void MixesPanel::clearMixes()
update(); update();
} }
} }
void MixesPanel::onModelDataAboutToBeUpdated()
{
lock = true;
}
void MixesPanel::onModelDataUpdateComplete()
{
update();
lock = false;
}

View file

@ -26,12 +26,15 @@
#include "mixerdialog.h" #include "mixerdialog.h"
#include "modelprinter.h" #include "modelprinter.h"
class CommonItemModels;
class RawItemFilteredModel;
class MixesPanel : public ModelPanel class MixesPanel : public ModelPanel
{ {
Q_OBJECT Q_OBJECT
public: public:
MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); MixesPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
virtual ~MixesPanel(); virtual ~MixesPanel();
virtual void update(); virtual void update();
@ -50,7 +53,6 @@ class MixesPanel : public ModelPanel
void moveMixDown(); void moveMixDown();
void mixerHighlight(); void mixerHighlight();
void mixerlistWidget_customContextMenuRequested(QPoint pos); void mixerlistWidget_customContextMenuRequested(QPoint pos);
void mixerlistWidget_doubleClicked(QModelIndex index); void mixerlistWidget_doubleClicked(QModelIndex index);
void mixerlistWidget_KeyPress(QKeyEvent *event); void mixerlistWidget_KeyPress(QKeyEvent *event);
@ -58,11 +60,18 @@ class MixesPanel : public ModelPanel
void mimeMixerDropped(int index, const QMimeData *data, Qt::DropAction action); void mimeMixerDropped(int index, const QMimeData *data, Qt::DropAction action);
void pasteMixerMimeData(const QMimeData * mimeData, int destIdx); void pasteMixerMimeData(const QMimeData * mimeData, int destIdx);
void onModelDataAboutToBeUpdated();
void onModelDataUpdateComplete();
private: private:
MixersListWidget * mixersListWidget; MixersListWidget * mixersListWidget;
bool mixInserted; bool mixInserted;
unsigned int highlightedSource; unsigned int highlightedSource;
ModelPrinter modelPrinter; ModelPrinter modelPrinter;
CommonItemModels * commonItemModels;
RawItemFilteredModel *rawSourceFilteredModel;
RawItemFilteredModel *rawSwitchFilteredModel;
RawItemFilteredModel *curveFilteredModel;
int getMixerIndex(unsigned int dch); int getMixerIndex(unsigned int dch);
bool gm_insertMix(int idx); bool gm_insertMix(int idx);

View file

@ -33,6 +33,7 @@
#include "customfunctions.h" #include "customfunctions.h"
#include "telemetry.h" #include "telemetry.h"
#include "appdata.h" #include "appdata.h"
#include "rawitemdatamodels.h"
ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmware * firmware) : ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmware * firmware) :
QDialog(parent), QDialog(parent),
@ -48,33 +49,55 @@ ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmw
setWindowIcon(CompanionIcon("edit.png")); setWindowIcon(CompanionIcon("edit.png"));
restoreGeometry(g.modelEditGeo()); restoreGeometry(g.modelEditGeo());
ui->pushButton->setIcon(CompanionIcon("simulate.png")); ui->pushButton->setIcon(CompanionIcon("simulate.png"));
SetupPanel * setupPanel = new SetupPanel(this, radioData.models[modelId], radioData.generalSettings, firmware);
GeneralSettings &generalSettings = radioData.generalSettings;
ModelData &model = radioData.models[modelId];
commonItemModels = new CommonItemModels(&generalSettings, &model, this);
s1.report("Init");
SetupPanel * setupPanel = new SetupPanel(this, model, generalSettings, firmware, commonItemModels);
addTab(setupPanel, tr("Setup")); addTab(setupPanel, tr("Setup"));
if (firmware->getCapability(Heli)) s1.report("Setup");
addTab(new HeliPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Heli"));
addTab(new FlightModesPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Flight Modes")); if (firmware->getCapability(Heli)) {
addTab(new InputsPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Inputs")); addTab(new HeliPanel(this, model, generalSettings, firmware, commonItemModels), tr("Heli"));
s1.report("inputs"); s1.report("Heli");
addTab(new MixesPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Mixes")); }
addTab(new FlightModesPanel(this, model, generalSettings, firmware, commonItemModels), tr("Flight Modes"));
s1.report("Flight Modes");
addTab(new InputsPanel(this, model, generalSettings, firmware, commonItemModels), tr("Inputs"));
s1.report("Inputs");
addTab(new MixesPanel(this, model, generalSettings, firmware, commonItemModels), tr("Mixes"));
s1.report("Mixes"); s1.report("Mixes");
Channels * chnPanel = new Channels(this, radioData.models[modelId], radioData.generalSettings, firmware);
addTab(chnPanel, tr("Outputs")); ChannelsPanel * channelsPanel = new ChannelsPanel(this, model, generalSettings, firmware, commonItemModels);
addTab(channelsPanel, tr("Outputs"));
s1.report("Outputs"); s1.report("Outputs");
addTab(new Curves(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Curves"));
addTab(new LogicalSwitchesPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Logical Switches"));
s1.report("LS");
addTab(new CustomFunctionsPanel(this, &radioData.models[modelId], radioData.generalSettings, firmware), tr("Special Functions"));
s1.report("CF");
if (firmware->getCapability(Telemetry))
addTab(new TelemetryPanel(this, radioData.models[modelId], radioData.generalSettings, firmware), tr("Telemetry"));
onTabIndexChanged(ui->tabWidget->currentIndex()); // make sure to trigger update on default tab panel addTab(new CurvesPanel(this, model, generalSettings, firmware, commonItemModels), tr("Curves"));
s1.report("Curves");
connect(setupPanel, &SetupPanel::extendedLimitsToggled, chnPanel, &Channels::refreshExtendedLimits); addTab(new LogicalSwitchesPanel(this, model, generalSettings, firmware, commonItemModels), tr("Logical Switches"));
s1.report("Logical Switches");
addTab(new CustomFunctionsPanel(this, &model, generalSettings, firmware, commonItemModels), tr("Special Functions"));
s1.report("Special Functions");
if (firmware->getCapability(Telemetry)) {
addTab(new TelemetryPanel(this, model, generalSettings, firmware, commonItemModels), tr("Telemetry"));
s1.report("Telemetry");
}
connect(setupPanel, &SetupPanel::extendedLimitsToggled, channelsPanel, &ChannelsPanel::refreshExtendedLimits);
connect(ui->tabWidget, &QTabWidget::currentChanged, this, &ModelEdit::onTabIndexChanged); connect(ui->tabWidget, &QTabWidget::currentChanged, this, &ModelEdit::onTabIndexChanged);
connect(ui->pushButton, &QPushButton::clicked, this, &ModelEdit::launchSimulation); connect(ui->pushButton, &QPushButton::clicked, this, &ModelEdit::launchSimulation);
s1.report("end"); onTabIndexChanged(ui->tabWidget->currentIndex()); // make sure to trigger update on default tab panel
gStopwatch.report("ModelEdit end constructor"); gStopwatch.report("ModelEdit end constructor");
} }

View file

@ -25,6 +25,7 @@
#include "genericpanel.h" #include "genericpanel.h"
class RadioData; class RadioData;
class CommonItemModels;
namespace Ui { namespace Ui {
class ModelEdit; class ModelEdit;
@ -62,6 +63,7 @@ class ModelEdit : public QDialog
RadioData & radioData; RadioData & radioData;
Firmware * firmware; Firmware * firmware;
QVector<GenericPanel *> panels; QVector<GenericPanel *> panels;
CommonItemModels * commonItemModels;
void addTab(GenericPanel *panel, QString text); void addTab(GenericPanel *panel, QString text);
void launchSimulation(); void launchSimulation();

View file

@ -31,13 +31,14 @@
#include <QDir> #include <QDir>
TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, QWidget * prevFocus, RawSwitchFilterItemModel * switchModel): TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, QWidget * prevFocus, RawItemFilteredModel * rawSwitchFilteredModel):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
timer(timer), timer(timer),
ui(new Ui::Timer) ui(new Ui::Timer)
{ {
ui->setupUi(this); ui->setupUi(this);
connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &TimerPanel::onModelDataAboutToBeUpdated);
connect(rawSwitchFilteredModel, &RawItemFilteredModel::dataUpdateComplete, this, &TimerPanel::onModelDataUpdateComplete);
lock = true; lock = true;
@ -48,11 +49,10 @@ TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, Ge
} }
else { else {
ui->name->setMaxLength(length); ui->name->setMaxLength(length);
//ui->name->setText(timer.name);
} }
// Mode // Mode
ui->mode->setModel(switchModel); ui->mode->setModel(rawSwitchFilteredModel);
ui->mode->setCurrentIndex(ui->mode->findData(timer.mode.toValue())); ui->mode->setCurrentIndex(ui->mode->findData(timer.mode.toValue()));
connect(ui->mode, SIGNAL(activated(int)), this, SLOT(onModeChanged(int))); connect(ui->mode, SIGNAL(activated(int)), this, SLOT(onModeChanged(int)));
@ -94,6 +94,7 @@ TimerPanel::~TimerPanel()
void TimerPanel::update() void TimerPanel::update()
{ {
lock = true; lock = true;
ui->name->setText(timer.name); ui->name->setText(timer.name);
int hour = timer.val / 3600; int hour = timer.val / 3600;
@ -114,7 +115,7 @@ void TimerPanel::update()
pvalue -= hours * 3600; pvalue -= hours * 3600;
int minutes = pvalue / 60; int minutes = pvalue / 60;
int seconds = 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->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->countdownBeep->updateValue(); ui->countdownBeep->updateValue();
@ -131,7 +132,7 @@ QWidget * TimerPanel::getLastFocus()
void TimerPanel::on_value_editingFinished() void TimerPanel::on_value_editingFinished()
{ {
if (!lock) { if (!lock) {
unsigned val = ui->value->time().hour()*3600 + ui->value->time().minute()*60 + ui->value->time().second(); unsigned val = ui->value->time().hour() * 3600 + ui->value->time().minute() * 60 + ui->value->time().second();
if (timer.val != val) { if (timer.val != val) {
timer.val = val; timer.val = val;
emit modified(); emit modified();
@ -165,11 +166,23 @@ void TimerPanel::on_name_editingFinished()
if (QString(timer.name) != ui->name->text()) { if (QString(timer.name) != ui->name->text()) {
int length = ui->name->maxLength(); int length = ui->name->maxLength();
strncpy(timer.name, ui->name->text().toLatin1(), length); strncpy(timer.name, ui->name->text().toLatin1(), length);
emit nameChanged();
emit modified(); emit modified();
} }
} }
} }
void TimerPanel::onModelDataAboutToBeUpdated()
{
lock = true;
}
void TimerPanel::onModelDataUpdateComplete()
{
update();
lock = false;
}
/******************************************************************************/ /******************************************************************************/
#define FAILSAFE_CHANNEL_HOLD 2000 #define FAILSAFE_CHANNEL_HOLD 2000
@ -237,19 +250,19 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
} }
// The protocols available on this board // The protocols available on this board
for (unsigned int i=0; i<PULSES_PROTOCOL_LAST; i++) { for (unsigned int i = 0; i < PULSES_PROTOCOL_LAST; i++) {
if (firmware->isAvailable((PulsesProtocol) i, moduleIdx)) { if (firmware->isAvailable((PulsesProtocol) i, moduleIdx)) {
ui->protocol->addItem(ModuleData::protocolToString(i), i); ui->protocol->addItem(ModuleData::protocolToString(i), i);
if (i == module.protocol) if (i == module.protocol)
ui->protocol->setCurrentIndex(ui->protocol->count()-1); ui->protocol->setCurrentIndex(ui->protocol->count() - 1);
} }
} }
for (int i=0; i<=MODULE_SUBTYPE_MULTI_LAST; i++) { for (int i = 0; i <= MODULE_SUBTYPE_MULTI_LAST; i++) {
if (i == MODULE_SUBTYPE_MULTI_SCANNER) if (i == MODULE_SUBTYPE_MULTI_SCANNER)
continue; continue;
ui->multiProtocol->addItem(Multiprotocols::protocolToString(i), i); ui->multiProtocol->addItem(Multiprotocols::protocolToString(i), i);
} }
for (int i=MODULE_SUBTYPE_MULTI_LAST + 1; i <= 124; i++) { for (int i = MODULE_SUBTYPE_MULTI_LAST + 1; i <= 124; i++) {
ui->multiProtocol->addItem(QString::number(i + 3), i); ui->multiProtocol->addItem(QString::number(i + 3), i);
} }
@ -327,7 +340,7 @@ void ModulePanel::setupFailsafes()
else { else {
QLabel * label = new QLabel(this); QLabel * label = new QLabel(this);
label->setProperty("index", i); label->setProperty("index", i);
label->setText(QString::number(i+1)); label->setText(QString::number(i + 1));
QComboBox * combo = new QComboBox(this); QComboBox * combo = new QComboBox(this);
combo->setProperty("index", i); combo->setProperty("index", i);
@ -506,7 +519,7 @@ void ModulePanel::update()
ui->ppmFrameLength->setVisible(mask & MASK_SBUSPPM_FIELDS); ui->ppmFrameLength->setVisible(mask & MASK_SBUSPPM_FIELDS);
ui->ppmFrameLength->setMinimum(module.channelsCount * (model->extendedLimits ? 2.250 : 2)+3.5); ui->ppmFrameLength->setMinimum(module.channelsCount * (model->extendedLimits ? 2.250 : 2)+3.5);
ui->ppmFrameLength->setMaximum(firmware->getCapability(PPMFrameLength)); ui->ppmFrameLength->setMaximum(firmware->getCapability(PPMFrameLength));
ui->ppmFrameLength->setValue(22.5+((double)module.ppm.frameLength)*0.5); ui->ppmFrameLength->setValue(22.5 + ((double)module.ppm.frameLength) * 0.5);
// Antenna mode on Horus and XLite // Antenna mode on Horus and XLite
if (mask & MASK_ANTENNA) { if (mask & MASK_ANTENNA) {
@ -600,17 +613,17 @@ void ModulePanel::update()
ui->registrationIdLabel->setVisible(mask & MASK_ACCESS); ui->registrationIdLabel->setVisible(mask & MASK_ACCESS);
ui->registrationId->setVisible(mask & MASK_ACCESS); ui->registrationId->setVisible(mask & MASK_ACCESS);
ui->rx1Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<0))); ui->rx1Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 0)));
ui->clearRx1->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<0))); ui->clearRx1->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 0)));
ui->rx1->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<0))); ui->rx1->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 0)));
ui->rx2Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<1))); ui->rx2Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 1)));
ui->clearRx2->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<1))); ui->clearRx2->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 1)));
ui->rx2->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<1))); ui->rx2->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 1)));
ui->rx3Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<2))); ui->rx3Label->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 2)));
ui->clearRx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<2))); ui->clearRx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 2)));
ui->rx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1<<2))); ui->rx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 2)));
// Failsafes // Failsafes
ui->label_failsafeMode->setVisible(mask & MASK_FAILSAFES); ui->label_failsafeMode->setVisible(mask & MASK_FAILSAFES);
@ -703,8 +716,8 @@ void ModulePanel::on_channelsCount_editingFinished()
{ {
if (!lock && module.channelsCount != ui->channelsCount->value()) { if (!lock && module.channelsCount != ui->channelsCount->value()) {
module.channelsCount = ui->channelsCount->value(); module.channelsCount = ui->channelsCount->value();
update();
emit channelsRangeChanged(); emit channelsRangeChanged();
update();
emit modified(); emit modified();
} }
} }
@ -713,8 +726,8 @@ void ModulePanel::on_channelsStart_editingFinished()
{ {
if (!lock && module.channelsStart != (unsigned)ui->channelsStart->value() - 1) { if (!lock && module.channelsStart != (unsigned)ui->channelsStart->value() - 1) {
module.channelsStart = (unsigned)ui->channelsStart->value() - 1; module.channelsStart = (unsigned)ui->channelsStart->value() - 1;
update();
emit channelsRangeChanged(); emit channelsRangeChanged();
update();
emit modified(); emit modified();
} }
} }
@ -738,7 +751,7 @@ void ModulePanel::on_rxNumber_editingFinished()
void ModulePanel::on_ppmFrameLength_editingFinished() void ModulePanel::on_ppmFrameLength_editingFinished()
{ {
int val = (ui->ppmFrameLength->value()-22.5) / 0.5; int val = (ui->ppmFrameLength->value() - 22.5) / 0.5;
if (module.ppm.frameLength != val) { if (module.ppm.frameLength != val) {
module.ppm.frameLength = val; module.ppm.frameLength = val;
emit modified(); emit modified();
@ -762,8 +775,8 @@ void ModulePanel::onMultiProtocolChanged(int index)
module.multi.rfProtocol = (unsigned int)rfProtocol; module.multi.rfProtocol = (unsigned int)rfProtocol;
unsigned int maxSubTypes = multiProtocols.getProtocol(index).numSubTypes(); unsigned int maxSubTypes = multiProtocols.getProtocol(index).numSubTypes();
if (rfProtocol > MODULE_SUBTYPE_MULTI_LAST) if (rfProtocol > MODULE_SUBTYPE_MULTI_LAST)
maxSubTypes=8; maxSubTypes = 8;
module.subType = std::min(module.subType, maxSubTypes -1); module.subType = std::min(module.subType, maxSubTypes - 1);
module.channelsCount = module.getMaxChannelCount(); module.channelsCount = module.getMaxChannelCount();
update(); update();
emit modified(); emit modified();
@ -957,19 +970,19 @@ void ModulePanel::onClearAccessRxClicked()
QPushButton *button = qobject_cast<QPushButton *>(sender()); QPushButton *button = qobject_cast<QPushButton *>(sender());
if (button == ui->clearRx1) { if (button == ui->clearRx1) {
module.access.receivers &= ~(1<<0); module.access.receivers &= ~(1 << 0);
ui->rx1->clear(); ui->rx1->clear();
update(); update();
emit modified(); emit modified();
} }
else if (button == ui->clearRx2) { else if (button == ui->clearRx2) {
module.access.receivers &= ~(1<<1); module.access.receivers &= ~(1 << 1);
ui->rx2->clear(); ui->rx2->clear();
update(); update();
emit modified(); emit modified();
} }
else if (button == ui->clearRx3) { else if (button == ui->clearRx3) {
module.access.receivers &= ~(1<<2); module.access.receivers &= ~(1 << 2);
ui->rx3->clear(); ui->rx3->clear();
update(); update();
emit modified(); emit modified();
@ -978,18 +991,20 @@ void ModulePanel::onClearAccessRxClicked()
/******************************************************************************/ /******************************************************************************/
SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::Setup) ui(new Ui::Setup),
commonItemModels(commonItemModels)
{ {
ui->setupUi(this);
rawSwitchFilteredModel = new RawItemFilteredModel(commonItemModels->rawSwitchItemModel(), RawSwitch::TimersContext, this);
Board::Type board = firmware->getBoard(); Board::Type board = firmware->getBoard();
lock = true; lock = true;
memset(modules, 0, sizeof(modules)); memset(modules, 0, sizeof(modules));
ui->setupUi(this);
QRegExp rx(CHAR_FOR_NAMES_REGEX); QRegExp rx(CHAR_FOR_NAMES_REGEX);
ui->name->setValidator(new QRegExpValidator(rx, this)); ui->name->setValidator(new QRegExpValidator(rx, this));
ui->name->setMaxLength(firmware->getCapability(ModelName)); ui->name->setMaxLength(firmware->getCapability(ModelName));
@ -1007,7 +1022,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
foreach ( QString file, qd.entryList(filters, QDir::Files) ) { foreach ( QString file, qd.entryList(filters, QDir::Files) ) {
QFileInfo fi(file); QFileInfo fi(file);
QString temp = fi.fileName(); QString temp = fi.fileName();
if (!items.contains(temp) && temp.length() <= 6+4) { if (!items.contains(temp) && temp.length() <= 6 + 4) {
items.append(temp); items.append(temp);
} }
} }
@ -1017,7 +1032,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
foreach (QString file, qd.entryList(filters, QDir::Files)) { foreach (QString file, qd.entryList(filters, QDir::Files)) {
QFileInfo fi(file); QFileInfo fi(file);
QString temp = fi.completeBaseName(); QString temp = fi.completeBaseName();
if (!items.contains(temp) && temp.length() <= 10+4) { if (!items.contains(temp) && temp.length() <= 10 + 4) {
items.append(temp); items.append(temp);
} }
} }
@ -1030,7 +1045,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
foreach (QString file, items) { foreach (QString file, items) {
ui->image->addItem(file); ui->image->addItem(file);
if (file == model.bitmap) { if (file == model.bitmap) {
ui->image->setCurrentIndex(ui->image->count()-1); ui->image->setCurrentIndex(ui->image->count() - 1);
QString fileName = path; QString fileName = path;
fileName.append(model.bitmap); fileName.append(model.bitmap);
if (!IS_FAMILY_HORUS_OR_T16(board)) if (!IS_FAMILY_HORUS_OR_T16(board))
@ -1062,18 +1077,16 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
} }
QWidget * prevFocus = ui->image; QWidget * prevFocus = ui->image;
RawSwitchFilterItemModel * swModel = new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::TimersContext, this);
connect(this, &SetupPanel::updated, swModel, &RawSwitchFilterItemModel::update);
timersCount = firmware->getCapability(Timers); timersCount = firmware->getCapability(Timers);
for (int i = 0; i < CPN_MAX_TIMERS; i++) { for (int i = 0; i < CPN_MAX_TIMERS; i++) {
if (i < timersCount) { if (i < timersCount) {
timers[i] = new TimerPanel(this, model, model.timers[i], generalSettings, firmware, prevFocus, swModel); timers[i] = new TimerPanel(this, model, model.timers[i], generalSettings, firmware, prevFocus, rawSwitchFilteredModel);
ui->gridLayout->addWidget(timers[i], 1+i, 1); ui->gridLayout->addWidget(timers[i], 1+i, 1);
connect(timers[i], &TimerPanel::modified, this, &SetupPanel::modified); connect(timers[i], &TimerPanel::modified, this, &SetupPanel::modified);
connect(timers[i], &TimerPanel::nameChanged, this, &SetupPanel::onTimerNameChanged);
connect(this, &SetupPanel::updated, timers[i], &TimerPanel::update); connect(this, &SetupPanel::updated, timers[i], &TimerPanel::update);
connect(this, &SetupPanel::timerUpdated, timers[i], &TimerPanel::update);
prevFocus = timers[i]->getLastFocus(); prevFocus = timers[i]->getLastFocus();
// TODO more reliable method required // TODO more reliable method required
QLabel *label = findChild<QLabel *>(QString("label_timer%1").arg(i + 1)); QLabel *label = findChild<QLabel *>(QString("label_timer%1").arg(i + 1));
@ -1095,7 +1108,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
if (firmware->getCapability(HasTopLcd)) { if (firmware->getCapability(HasTopLcd)) {
ui->toplcdTimer->setField(model.toplcdTimer, this); ui->toplcdTimer->setField(model.toplcdTimer, this);
for (int i = 0; i < CPN_MAX_TIMERS; i++) { for (int i = 0; i < CPN_MAX_TIMERS; i++) {
if (i<timersCount) { if (i < timersCount) {
ui->toplcdTimer->addItem(tr("Timer %1").arg(i + 1), i); ui->toplcdTimer->addItem(tr("Timer %1").arg(i + 1), i);
} }
} }
@ -1118,12 +1131,12 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
prevFocus = ui->trimsDisplay; prevFocus = ui->trimsDisplay;
int analogs = CPN_MAX_STICKS + getBoardCapability(board, Board::Pots) + getBoardCapability(board, Board::Sliders); int analogs = CPN_MAX_STICKS + getBoardCapability(board, Board::Pots) + getBoardCapability(board, Board::Sliders);
int genAryIdx = 0; int genAryIdx = 0;
for (int i=0; i < analogs + firmware->getCapability(RotaryEncoders); i++) { for (int i = 0; i < analogs + firmware->getCapability(RotaryEncoders); i++) {
RawSource src((i < analogs) ? SOURCE_TYPE_STICK : SOURCE_TYPE_ROTARY_ENCODER, (i < analogs) ? i : analogs - i); RawSource src((i < analogs) ? SOURCE_TYPE_STICK : SOURCE_TYPE_ROTARY_ENCODER, (i < analogs) ? i : analogs - i);
QCheckBox * checkbox = new QCheckBox(this); QCheckBox * checkbox = new QCheckBox(this);
checkbox->setProperty("index", i); checkbox->setProperty("index", i);
checkbox->setText(src.toString(&model, &generalSettings)); checkbox->setText(src.toString(&model, &generalSettings));
ui->centerBeepLayout->addWidget(checkbox, 0, i+1); ui->centerBeepLayout->addWidget(checkbox, 0, i + 1);
connect(checkbox, SIGNAL(toggled(bool)), this, SLOT(onBeepCenterToggled(bool))); connect(checkbox, SIGNAL(toggled(bool)), this, SLOT(onBeepCenterToggled(bool)));
centerBeepCheckboxes << checkbox; centerBeepCheckboxes << checkbox;
if (IS_HORUS_OR_TARANIS(board)) { if (IS_HORUS_OR_TARANIS(board)) {
@ -1139,7 +1152,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
} }
// Startup switches warnings // Startup switches warnings
for (int i=0; i<getBoardCapability(board, Board::Switches); i++) { for (int i = 0; i < getBoardCapability(board, Board::Switches); i++) {
Board::SwitchInfo switchInfo = Boards::getSwitchInfo(board, i); Board::SwitchInfo switchInfo = Boards::getSwitchInfo(board, i);
switchInfo.config = Board::SwitchType(generalSettings.switchConfig[i]); switchInfo.config = Board::SwitchType(generalSettings.switchConfig[i]);
if (switchInfo.config == Board::SWITCH_NOT_AVAILABLE || switchInfo.config == Board::SWITCH_TOGGLE) { if (switchInfo.config == Board::SWITCH_NOT_AVAILABLE || switchInfo.config == Board::SWITCH_TOGGLE) {
@ -1163,11 +1176,11 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
label->setText(src.toString(&model, &generalSettings)); label->setText(src.toString(&model, &generalSettings));
slider->setMaximum(switchInfo.config == Board::SWITCH_3POS ? 2 : 1); slider->setMaximum(switchInfo.config == Board::SWITCH_3POS ? 2 : 1);
cb->setProperty("index", i); cb->setProperty("index", i);
ui->switchesStartupLayout->addWidget(label, 0, i+1); ui->switchesStartupLayout->addWidget(label, 0, i + 1);
ui->switchesStartupLayout->setAlignment(label, Qt::AlignCenter); ui->switchesStartupLayout->setAlignment(label, Qt::AlignCenter);
ui->switchesStartupLayout->addWidget(slider, 1, i+1); ui->switchesStartupLayout->addWidget(slider, 1, i + 1);
ui->switchesStartupLayout->setAlignment(slider, Qt::AlignCenter); ui->switchesStartupLayout->setAlignment(slider, Qt::AlignCenter);
ui->switchesStartupLayout->addWidget(cb, 2, i+1); ui->switchesStartupLayout->addWidget(cb, 2, i + 1);
ui->switchesStartupLayout->setAlignment(cb, Qt::AlignCenter); ui->switchesStartupLayout->setAlignment(cb, Qt::AlignCenter);
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(startupSwitchEdited(int))); connect(slider, SIGNAL(valueChanged(int)), this, SLOT(startupSwitchEdited(int)));
connect(cb, SIGNAL(toggled(bool)), this, SLOT(startupSwitchToggled(bool))); connect(cb, SIGNAL(toggled(bool)), this, SLOT(startupSwitchToggled(bool)));
@ -1181,12 +1194,12 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
// Pot warnings // Pot warnings
prevFocus = ui->potWarningMode; prevFocus = ui->potWarningMode;
if (IS_HORUS_OR_TARANIS(board)) { if (IS_HORUS_OR_TARANIS(board)) {
for (int i=0; i<getBoardCapability(board, Board::Pots)+getBoardCapability(board, Board::Sliders); i++) { for (int i = 0; i < getBoardCapability(board, Board::Pots) + getBoardCapability(board, Board::Sliders); i++) {
RawSource src(SOURCE_TYPE_STICK, CPN_MAX_STICKS + i); RawSource src(SOURCE_TYPE_STICK, CPN_MAX_STICKS + i);
QCheckBox * cb = new QCheckBox(this); QCheckBox * cb = new QCheckBox(this);
cb->setProperty("index", i); cb->setProperty("index", i);
cb->setText(src.toString(&model, &generalSettings)); cb->setText(src.toString(&model, &generalSettings));
ui->potWarningLayout->addWidget(cb, 0, i+1); ui->potWarningLayout->addWidget(cb, 0, i + 1);
connect(cb, SIGNAL(toggled(bool)), this, SLOT(potWarningToggled(bool))); connect(cb, SIGNAL(toggled(bool)), this, SLOT(potWarningToggled(bool)));
potWarningCheckboxes << cb; potWarningCheckboxes << cb;
if (src.isPot(&genAryIdx) && !generalSettings.isPotAvailable(genAryIdx)) { if (src.isPot(&genAryIdx) && !generalSettings.isPotAvailable(genAryIdx)) {
@ -1264,7 +1277,7 @@ void SetupPanel::on_extendedTrims_toggled(bool checked)
void SetupPanel::on_trimIncrement_currentIndexChanged(int index) void SetupPanel::on_trimIncrement_currentIndexChanged(int index)
{ {
model->trimInc = index-2; model->trimInc = index - 2;
emit modified(); emit modified();
} }
@ -1341,13 +1354,13 @@ void SetupPanel::populateThrottleSourceCB()
ui->throttleSource->clear(); ui->throttleSource->clear();
ui->throttleSource->addItem(tr("THR"), 0); ui->throttleSource->addItem(tr("THR"), 0);
int idx=1; int idx = 1;
for (int i=0; i<getBoardCapability(board, Board::Pots)+getBoardCapability(board, Board::Sliders); i++, idx++) { 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)) { if (RawSource(SOURCE_TYPE_STICK, 4 + i).isAvailable(model, &generalSettings, board)) {
ui->throttleSource->addItem(firmware->getAnalogInputName(4+i), idx); ui->throttleSource->addItem(firmware->getAnalogInputName(4 + i), idx);
} }
} }
for (int i=0; i<firmware->getCapability(Outputs); i++, idx++) { for (int i = 0; i < firmware->getCapability(Outputs); i++, idx++) {
ui->throttleSource->addItem(RawSource(SOURCE_TYPE_CH, i).toString(model, &generalSettings), idx); ui->throttleSource->addItem(RawSource(SOURCE_TYPE_CH, i).toString(model, &generalSettings), idx);
} }
@ -1362,9 +1375,15 @@ void SetupPanel::populateThrottleTrimSwitchCB()
lock = true; lock = true;
ui->throttleTrimSwitch->clear(); ui->throttleTrimSwitch->clear();
int idx=0; int idx=0;
QString trim;
for (int i=0; i<getBoardCapability(board, Board::NumTrims); i++, idx++) { for (int i=0; i<getBoardCapability(board, Board::NumTrims); i++, idx++) {
QString trim = RawSource(SOURCE_TYPE_TRIM, i).toString(model, &generalSettings); // here order is TERA instead of RETA
trim = (trim == "TrmR") ? "TrmT" : (trim == "TmrT") ? "TmrR" : trim; if (i == 0)
trim = RawSource(SOURCE_TYPE_TRIM, 2).toString(model, &generalSettings);
else if (i == 2)
trim = RawSource(SOURCE_TYPE_TRIM, 0).toString(model, &generalSettings);
else
trim = RawSource(SOURCE_TYPE_TRIM, i).toString(model, &generalSettings);
ui->throttleTrimSwitch->addItem(trim, idx); ui->throttleTrimSwitch->addItem(trim, idx);
} }
@ -1394,7 +1413,7 @@ void SetupPanel::update()
updatePotWarnings(); updatePotWarnings();
} }
for (int i=0; i<CPN_MAX_MODULES+1; i++) { for (int i = 0; i < CPN_MAX_MODULES + 1; i++) {
if (modules[i]) { if (modules[i]) {
modules[i]->update(); modules[i]->update();
} }
@ -1405,7 +1424,7 @@ void SetupPanel::update()
void SetupPanel::updateBeepCenter() void SetupPanel::updateBeepCenter()
{ {
for (int i=0; i<centerBeepCheckboxes.size(); i++) { for (int i = 0; i < centerBeepCheckboxes.size(); i++) {
centerBeepCheckboxes[i]->setChecked(model->beepANACenter & (0x01 << i)); centerBeepCheckboxes[i]->setChecked(model->beepANACenter & (0x01 << i));
} }
} }
@ -1417,20 +1436,20 @@ void SetupPanel::updateStartupSwitches()
uint64_t switchStates = model->switchWarningStates; uint64_t switchStates = model->switchWarningStates;
uint64_t value; uint64_t value;
for (int i=0; i<startupSwitchesSliders.size(); i++) { for (int i = 0; i < startupSwitchesSliders.size(); i++) {
QSlider * slider = startupSwitchesSliders[i]; QSlider * slider = startupSwitchesSliders[i];
QCheckBox * cb = startupSwitchesCheckboxes[i]; QCheckBox * cb = startupSwitchesCheckboxes[i];
int index = slider->property("index").toInt(); int index = slider->property("index").toInt();
bool enabled = !(model->switchWarningEnable & (1 << index)); bool enabled = !(model->switchWarningEnable & (1 << index));
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) { if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
value = (switchStates >> (2*index)) & 0x03; value = (switchStates >> (2 * index)) & 0x03;
if (generalSettings.switchConfig[index] != Board::SWITCH_3POS && value == 2) { if (generalSettings.switchConfig[index] != Board::SWITCH_3POS && value == 2) {
value = 1; value = 1;
} }
} }
else { else {
value = (i==0 ? switchStates & 0x3 : switchStates & 0x1); value = (i == 0 ? switchStates & 0x3 : switchStates & 0x1);
switchStates >>= (i==0 ? 2 : 1); switchStates >>= (i == 0 ? 2 : 1);
} }
slider->setValue(value); slider->setValue(value);
slider->setEnabled(enabled); slider->setEnabled(enabled);
@ -1456,7 +1475,7 @@ void SetupPanel::startupSwitchEdited(int value)
mask = 0x03; mask = 0x03;
} }
else { else {
shift = index+1; shift = index + 1;
mask = 0x01ull << shift; mask = 0x01ull << shift;
} }
} }
@ -1497,7 +1516,7 @@ void SetupPanel::updatePotWarnings()
{ {
lock = true; lock = true;
ui->potWarningMode->setCurrentIndex(model->potsWarningMode); ui->potWarningMode->setCurrentIndex(model->potsWarningMode);
for (int i=0; i<potWarningCheckboxes.size(); i++) { for (int i = 0; i < potWarningCheckboxes.size(); i++) {
QCheckBox *checkbox = potWarningCheckboxes[i]; QCheckBox *checkbox = potWarningCheckboxes[i];
int index = checkbox->property("index").toInt(); int index = checkbox->property("index").toInt();
checkbox->setChecked(!model->potsWarnEnabled[index]); checkbox->setChecked(!model->potsWarnEnabled[index]);
@ -1627,7 +1646,7 @@ void SetupPanel::cmTimerClear(bool prompt)
model->timers[selectedTimerIndex].clear(); model->timers[selectedTimerIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_CLEAR, selectedTimerIndex); model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_CLEAR, selectedTimerIndex);
emit timerUpdated(); updateItemModels();
emit modified(); emit modified();
} }
@ -1640,7 +1659,7 @@ void SetupPanel::cmTimerClearAll()
model->timers[i].clear(); model->timers[i].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_CLEAR, i); model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_CLEAR, i);
} }
emit timerUpdated(); updateItemModels();
emit modified(); emit modified();
} }
@ -1674,7 +1693,7 @@ void SetupPanel::cmTimerDelete()
} }
model->timers[maxidx].clear(); model->timers[maxidx].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, -1); model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, -1);
emit timerUpdated(); updateItemModels();
emit modified(); emit modified();
} }
@ -1687,7 +1706,7 @@ void SetupPanel::cmTimerInsert()
} }
model->timers[selectedTimerIndex].clear(); model->timers[selectedTimerIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, 1); model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, 1);
emit timerUpdated(); updateItemModels();
emit modified(); emit modified();
} }
@ -1707,7 +1726,7 @@ void SetupPanel::cmTimerPaste()
if (hasTimerClipboardData(&data)) { if (hasTimerClipboardData(&data)) {
TimerData *td = &model->timers[selectedTimerIndex]; TimerData *td = &model->timers[selectedTimerIndex];
memcpy(td, data.constData(), sizeof(TimerData)); memcpy(td, data.constData(), sizeof(TimerData));
emit timerUpdated(); updateItemModels();
emit modified(); emit modified();
} }
} }
@ -1721,7 +1740,17 @@ void SetupPanel::swapTimerData(int idx1, int idx2)
memcpy(td2, td1, sizeof(TimerData)); memcpy(td2, td1, sizeof(TimerData));
memcpy(td1, &tdtmp, sizeof(TimerData)); memcpy(td1, &tdtmp, sizeof(TimerData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
emit timerUpdated(); updateItemModels();
emit modified(); emit modified();
} }
} }
void SetupPanel::onTimerNameChanged()
{
updateItemModels();
}
void SetupPanel::updateItemModels()
{
commonItemModels->update(CommonItemModels::RMO_TIMERS);
}

View file

@ -26,7 +26,8 @@
constexpr char MIMETYPE_TIMER[] = "application/x-companion-timer"; constexpr char MIMETYPE_TIMER[] = "application/x-companion-timer";
class RawSwitchFilterItemModel; class CommonItemModels;
class RawItemFilteredModel;
namespace Ui { namespace Ui {
class Setup; class Setup;
@ -39,7 +40,7 @@ class TimerPanel : public ModelPanel
Q_OBJECT Q_OBJECT
public: public:
TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, QWidget *prevFocus, RawSwitchFilterItemModel * switchModel); TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, GeneralSettings & generalSettings, Firmware * firmware, QWidget *prevFocus, RawItemFilteredModel * switchModel);
virtual ~TimerPanel(); virtual ~TimerPanel();
virtual void update(); virtual void update();
@ -50,6 +51,11 @@ class TimerPanel : public ModelPanel
void on_value_editingFinished(); void on_value_editingFinished();
void on_minuteBeep_toggled(bool checked); void on_minuteBeep_toggled(bool checked);
void on_name_editingFinished(); void on_name_editingFinished();
void onModelDataAboutToBeUpdated();
void onModelDataUpdateComplete();
signals:
void nameChanged();
private: private:
TimerData & timer; TimerData & timer;
@ -125,7 +131,7 @@ class SetupPanel : public ModelPanel
Q_OBJECT Q_OBJECT
public: public:
SetupPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); SetupPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
virtual ~SetupPanel(); virtual ~SetupPanel();
virtual void update(); virtual void update();
@ -133,7 +139,6 @@ class SetupPanel : public ModelPanel
signals: signals:
void extendedLimitsToggled(); void extendedLimitsToggled();
void updated(); void updated();
void timerUpdated();
private slots: private slots:
void on_name_editingFinished(); void on_name_editingFinished();
@ -164,6 +169,7 @@ class SetupPanel : public ModelPanel
void cmTimerPaste(); void cmTimerPaste();
void cmTimerMoveDown(); void cmTimerMoveDown();
void cmTimerMoveUp(); void cmTimerMoveUp();
void onTimerNameChanged();
private: private:
Ui::Setup *ui; Ui::Setup *ui;
@ -185,6 +191,9 @@ class SetupPanel : public ModelPanel
bool moveTimerDownAllowed() const; bool moveTimerDownAllowed() const;
bool moveTimerUpAllowed() const; bool moveTimerUpAllowed() const;
void swapTimerData(int idx1, int idx2); void swapTimerData(int idx1, int idx2);
}; CommonItemModels * commonItemModels;
RawItemFilteredModel * rawSwitchFilteredModel;
void updateItemModels();
};
#endif // _SETUP_H_ #endif // _SETUP_H_

View file

@ -28,18 +28,20 @@
#include <TimerEdit> #include <TimerEdit>
TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware, RawSourceFilterItemModel * srcModel): TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware, RawItemFilteredModel * rawSourceModel):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::TelemetryCustomScreen), ui(new Ui::TelemetryCustomScreen),
screen(screen) screen(screen)
{ {
ui->setupUi(this); ui->setupUi(this);
connect(rawSourceModel, &RawItemFilteredModel::dataAboutToBeUpdated, this, &TelemetryCustomScreen::onModelDataAboutToBeUpdated);
connect(rawSourceModel, &RawItemFilteredModel::dataUpdateComplete, this, &TelemetryCustomScreen::onModelDataUpdateComplete);
for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensLines); l++) { for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensLines); l++) {
for (int c = 0; c < firmware->getCapability(TelemetryCustomScreensFieldsPerLine); c++) { for (int c = 0; c < firmware->getCapability(TelemetryCustomScreensFieldsPerLine); c++) {
fieldsCB[l][c] = new QComboBox(this); fieldsCB[l][c] = new QComboBox(this);
fieldsCB[l][c]->setProperty("index", c + (l << 8)); fieldsCB[l][c]->setProperty("index", c + (l << 8));
fieldsCB[l][c]->setModel(srcModel); fieldsCB[l][c]->setModel(rawSourceModel);
ui->screenNumsLayout->addWidget(fieldsCB[l][c], l, c, 1, 1); ui->screenNumsLayout->addWidget(fieldsCB[l][c], l, c, 1, 1);
connect(fieldsCB[l][c], SIGNAL(activated(int)), this, SLOT(customFieldChanged(int))); connect(fieldsCB[l][c], SIGNAL(activated(int)), this, SLOT(customFieldChanged(int)));
} }
@ -48,7 +50,7 @@ TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model,
for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensBars); l++) { for (int l = 0; l < firmware->getCapability(TelemetryCustomScreensBars); l++) {
barsCB[l] = new QComboBox(this); barsCB[l] = new QComboBox(this);
barsCB[l]->setProperty("index", l); barsCB[l]->setProperty("index", l);
barsCB[l]->setModel(srcModel); barsCB[l]->setModel(rawSourceModel);
connect(barsCB[l], SIGNAL(activated(int)), this, SLOT(barSourceChanged(int))); connect(barsCB[l], SIGNAL(activated(int)), this, SLOT(barSourceChanged(int)));
ui->screenBarsLayout->addWidget(barsCB[l], l, 0, 1, 1); ui->screenBarsLayout->addWidget(barsCB[l], l, 0, 1, 1);
@ -287,6 +289,17 @@ void TelemetryCustomScreen::barTimeChanged()
} }
} }
void TelemetryCustomScreen::onModelDataAboutToBeUpdated()
{
lock = true;
}
void TelemetryCustomScreen::onModelDataUpdateComplete()
{
update();
lock = false;
}
/******************************************************/ /******************************************************/
TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, int sensorCapability, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, int sensorCapability, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
@ -305,6 +318,7 @@ TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor,
QFontMetrics *f = new QFontMetrics(QFont()); QFontMetrics *f = new QFontMetrics(QFont());
QSize sz; QSize sz;
sz = f->size(Qt::TextSingleLine, "TELE00"); sz = f->size(Qt::TextSingleLine, "TELE00");
delete f;
ui->numLabel->setMinimumWidth(sz.width()); ui->numLabel->setMinimumWidth(sz.width());
ui->numLabel->setContextMenuPolicy(Qt::CustomContextMenu); ui->numLabel->setContextMenuPolicy(Qt::CustomContextMenu);
ui->numLabel->setToolTip(tr("Popup menu available")); ui->numLabel->setToolTip(tr("Popup menu available"));
@ -505,7 +519,6 @@ void TelemetrySensorPanel::on_name_editingFinished()
if (!lock) { if (!lock) {
strcpy(sensor.label, ui->name->text().toLatin1()); strcpy(sensor.label, ui->name->text().toLatin1());
emit dataModified(); emit dataModified();
emit modified();
} }
} }
@ -535,7 +548,6 @@ void TelemetrySensorPanel::on_formula_currentIndexChanged(int index)
sensor.unit = SensorData::UNIT_METERS; sensor.unit = SensorData::UNIT_METERS;
} }
emit dataModified(); emit dataModified();
emit modified();
} }
} }
@ -631,7 +643,6 @@ void TelemetrySensorPanel::cmPaste()
if (hasClipboardData(&data)) { if (hasClipboardData(&data)) {
memcpy(&sensor, data.constData(), sizeof(SensorData)); memcpy(&sensor, data.constData(), sizeof(SensorData));
emit dataModified(); emit dataModified();
emit modified();
} }
} }
@ -645,7 +656,6 @@ void TelemetrySensorPanel::cmClear(bool prompt)
sensor.clear(); sensor.clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_CLEAR, selectedIndex); model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
emit dataModified(); emit dataModified();
emit modified();
} }
void TelemetrySensorPanel::cmClearAll() void TelemetrySensorPanel::cmClearAll()
@ -678,11 +688,13 @@ void TelemetrySensorPanel::cmMoveDown()
/******************************************************/ /******************************************************/
TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware): TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels):
ModelPanel(parent, model, generalSettings, firmware), ModelPanel(parent, model, generalSettings, firmware),
ui(new Ui::Telemetry) ui(new Ui::Telemetry),
commonItemModels(commonItemModels)
{ {
ui->setupUi(this); ui->setupUi(this);
rawSourceFilteredModel = new RawItemFilteredModel(commonItemModels->rawSourceItemModel(), this);
sensorCapability = firmware->getCapability(Sensors); sensorCapability = firmware->getCapability(Sensors);
if (sensorCapability > CPN_MAX_SENSORS) // TODO should be role of getCapability if (sensorCapability > CPN_MAX_SENSORS) // TODO should be role of getCapability
@ -696,11 +708,12 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin
ui->varioCenterSilent->setField(model.frsky.varioCenterSilent, this); ui->varioCenterSilent->setField(model.frsky.varioCenterSilent, this);
ui->A1GB->hide(); ui->A1GB->hide();
ui->A2GB->hide(); ui->A2GB->hide();
for (int i = 0; i < sensorCapability; ++i) { for (int i = 0; i < sensorCapability; ++i) {
TelemetrySensorPanel * panel = new TelemetrySensorPanel(this, model.sensorData[i], i, sensorCapability, model, generalSettings, firmware); TelemetrySensorPanel * panel = new TelemetrySensorPanel(this, model.sensorData[i], i, sensorCapability, model, generalSettings, firmware);
ui->sensorsLayout->addWidget(panel); ui->sensorsLayout->addWidget(panel);
sensorPanels[i] = panel; sensorPanels[i] = panel;
connect(panel, SIGNAL(dataModified()), this, SLOT(update())); connect(panel, SIGNAL(dataModified()), this, SLOT(on_dataModifiedSensor()));
connect(panel, SIGNAL(modified()), this, SLOT(onModified())); connect(panel, SIGNAL(modified()), this, SLOT(onModified()));
connect(panel, SIGNAL(clearAllSensors()), this, SLOT(on_clearAllSensors())); connect(panel, SIGNAL(clearAllSensors()), this, SLOT(on_clearAllSensors()));
connect(panel, SIGNAL(insertSensor(int)), this, SLOT(on_insertSensor(int))); connect(panel, SIGNAL(insertSensor(int)), this, SLOT(on_insertSensor(int)));
@ -717,15 +730,11 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin
ui->topbarGB->hide(); ui->topbarGB->hide();
} }
RawSourceFilterItemModel * srcModel = (new RawSourceFilterItemModel(&generalSettings, &model, this));
connect(this, &TelemetryPanel::updated, srcModel, &RawSourceFilterItemModel::update);
for (int i = 0; i < firmware->getCapability(TelemetryCustomScreens); i++) { for (int i = 0; i < firmware->getCapability(TelemetryCustomScreens); i++) {
TelemetryCustomScreen * tab = new TelemetryCustomScreen(this, model, model.frsky.screens[i], generalSettings, firmware, srcModel); TelemetryCustomScreen * tab = new TelemetryCustomScreen(this, model, model.frsky.screens[i], generalSettings, firmware, rawSourceFilteredModel);
ui->customScreens->addTab(tab, tr("Telemetry screen %1").arg(i + 1)); ui->customScreens->addTab(tab, tr("Telemetry screen %1").arg(i + 1));
telemetryCustomScreens[i] = tab; telemetryCustomScreens[i] = tab;
connect(tab, &TelemetryCustomScreen::modified, this, &TelemetryPanel::onModified); connect(tab, &TelemetryCustomScreen::modified, this, &TelemetryPanel::onModified);
connect(this, &TelemetryPanel::updated, tab, &TelemetryCustomScreen::update);
} }
disableMouseScrolling(); disableMouseScrolling();
@ -759,79 +768,78 @@ void TelemetryPanel::update()
sensorPanels[i]->update(); sensorPanels[i]->update();
} }
emit updated(); for (int i = 0; i < firmware->getCapability(TelemetryCustomScreens); i++) {
telemetryCustomScreens[i]->update();
}
} }
void TelemetryPanel::setup() void TelemetryPanel::setup()
{ {
QString firmware_id = g.profile[g.id()].fwType(); lock = true;
lock = true; ui->telemetryProtocol->addItem(tr("FrSky S.PORT"), 0);
ui->telemetryProtocol->addItem(tr("FrSky D"), 1);
if (IS_9XRPRO(firmware->getBoard()) ||
(IS_TARANIS(firmware->getBoard()) && generalSettings.auxSerialMode == 2)) {
ui->telemetryProtocol->addItem(tr("FrSky D (cable)"), 2);
}
ui->telemetryProtocol->setCurrentIndex(model->telemetryProtocol);
ui->ignoreSensorIds->setField(model->frsky.ignoreSensorIds, this);
ui->disableTelemetryAlarms->setField(model->rssiAlarms.disabled);
ui->telemetryProtocol->addItem(tr("FrSky S.PORT"), 0); ui->rssiAlarmWarningSB->setValue(model->rssiAlarms.warning);
ui->telemetryProtocol->addItem(tr("FrSky D"), 1); ui->rssiAlarmCriticalSB->setValue(model->rssiAlarms.critical);
if (IS_9XRPRO(firmware->getBoard()) ||
(IS_TARANIS(firmware->getBoard()) && generalSettings.auxSerialMode == 2)) {
ui->telemetryProtocol->addItem(tr("FrSky D (cable)"), 2);
}
ui->telemetryProtocol->setCurrentIndex(model->telemetryProtocol);
ui->ignoreSensorIds->setField(model->frsky.ignoreSensorIds, this);
ui->disableTelemetryAlarms->setField(model->rssiAlarms.disabled);
ui->rssiAlarmWarningSB->setValue(model->rssiAlarms.warning); ui->rssiSourceLabel->show();
ui->rssiAlarmCriticalSB->setValue(model->rssiAlarms.critical); ui->rssiSourceLabel->setText(tr("Source"));
ui->rssiSourceCB->setField(model->rssiSource, this);
ui->rssiSourceCB->show();
populateTelemetrySourcesComboBox(ui->rssiSourceCB, model, false);
ui->rssiSourceLabel->show(); ui->rssiAlarmWarningCB->hide();
ui->rssiSourceLabel->setText(tr("Source")); ui->rssiAlarmCriticalCB->hide();
ui->rssiSourceCB->setField(model->rssiSource, this); ui->rssiAlarmWarningLabel->setText(tr("Low Alarm"));
ui->rssiSourceCB->show(); ui->rssiAlarmCriticalLabel->setText(tr("Critical Alarm"));
populateTelemetrySourcesComboBox(ui->rssiSourceCB, model, false);
ui->rssiAlarmWarningCB->hide(); if (!firmware->getCapability(HasVario)) {
ui->rssiAlarmCriticalCB->hide(); ui->varioLimitMax_DSB->hide();
ui->rssiAlarmWarningLabel->setText(tr("Low Alarm")); ui->varioLimitMin_DSB->hide();
ui->rssiAlarmCriticalLabel->setText(tr("Critical Alarm")); ui->varioLimitCenterMin_DSB->hide();
ui->varioLimitCenterMax_DSB->hide();
int varioCap = firmware->getCapability(HasVario); ui->varioLimit_label->hide();
if (!varioCap) { ui->VarioLabel_1->hide();
ui->varioLimitMax_DSB->hide(); ui->VarioLabel_2->hide();
ui->VarioLabel_3->hide();
ui->VarioLabel_4->hide();
ui->varioSource->hide();
ui->varioSource_label->hide();
}
else {
if (!firmware->getCapability(HasVarioSink)) {
ui->varioLimitMin_DSB->hide(); ui->varioLimitMin_DSB->hide();
ui->varioLimitCenterMin_DSB->hide(); ui->varioLimitCenterMin_DSB->hide();
ui->varioLimitCenterMax_DSB->hide();
ui->varioLimit_label->hide();
ui->VarioLabel_1->hide(); ui->VarioLabel_1->hide();
ui->VarioLabel_2->hide(); ui->VarioLabel_2->hide();
ui->VarioLabel_3->hide();
ui->VarioLabel_4->hide();
ui->varioSource->hide();
ui->varioSource_label->hide();
}
else {
if (!firmware->getCapability(HasVarioSink)) {
ui->varioLimitMin_DSB->hide();
ui->varioLimitCenterMin_DSB->hide();
ui->VarioLabel_1->hide();
ui->VarioLabel_2->hide();
}
ui->varioLimitMin_DSB->setValue(model->frsky.varioMin - 10);
ui->varioLimitMax_DSB->setValue(model->frsky.varioMax + 10);
ui->varioLimitCenterMax_DSB->setValue((model->frsky.varioCenterMax / 10.0) + 0.5);
ui->varioLimitCenterMin_DSB->setValue((model->frsky.varioCenterMin / 10.0) - 0.5);
} }
ui->varioLimitMin_DSB->setValue(model->frsky.varioMin - 10);
ui->varioLimitMax_DSB->setValue(model->frsky.varioMax + 10);
ui->varioLimitCenterMax_DSB->setValue((model->frsky.varioCenterMax / 10.0) + 0.5);
ui->varioLimitCenterMin_DSB->setValue((model->frsky.varioCenterMin / 10.0) - 0.5);
}
ui->altimetryGB->setVisible(firmware->getCapability(HasVario)), ui->altimetryGB->setVisible(firmware->getCapability(HasVario)),
ui->frskyProtoCB->setDisabled(firmware->getCapability(NoTelemetryProtocol)); ui->frskyProtoCB->setDisabled(firmware->getCapability(NoTelemetryProtocol));
if (firmware->getCapability(Telemetry)) { if (firmware->getCapability(Telemetry)) {
ui->frskyProtoCB->addItem(tr("Winged Shadow How High")); ui->frskyProtoCB->addItem(tr("Winged Shadow How High"));
} }
else { else {
ui->frskyProtoCB->addItem(tr("Winged Shadow How High (not supported)")); ui->frskyProtoCB->addItem(tr("Winged Shadow How High (not supported)"));
} }
ui->variousGB->hide(); ui->variousGB->hide();
lock = false; lock = false;
} }
void TelemetryPanel::populateVarioSource() void TelemetryPanel::populateVarioSource()
@ -972,6 +980,7 @@ void TelemetryPanel::on_clearAllSensors()
model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_CLEAR, i); model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_CLEAR, i);
} }
updateItemModels();
update(); update();
emit modified(); emit modified();
} }
@ -982,6 +991,7 @@ void TelemetryPanel::on_insertSensor(int selectedIndex)
model->sensorData[selectedIndex].clear(); model->sensorData[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1); model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
updateItemModels();
update(); update();
emit modified(); emit modified();
} }
@ -995,6 +1005,7 @@ void TelemetryPanel::on_deleteSensor(int selectedIndex)
model->sensorData[CPN_MAX_SENSORS - 1].clear(); model->sensorData[CPN_MAX_SENSORS - 1].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1); model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
updateItemModels();
update(); update();
emit modified(); emit modified();
} }
@ -1018,7 +1029,20 @@ void TelemetryPanel::swapData(int idx1, int idx2)
memcpy(sd2, sd1, sizeof(SensorData)); memcpy(sd2, sd1, sizeof(SensorData));
memcpy(sd1, &sdtmp, sizeof(SensorData)); memcpy(sd1, &sdtmp, sizeof(SensorData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SWAP, idx1, idx2); model->updateAllReferences(ModelData::REF_UPD_TYPE_SENSOR, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
updateItemModels();
update(); update();
emit modified(); emit modified();
} }
} }
void TelemetryPanel::on_dataModifiedSensor()
{
updateItemModels();
update();
emit modified();
}
void TelemetryPanel::updateItemModels()
{
commonItemModels->update(CommonItemModels::RMO_TELEMETRY_SENSORS);
}

View file

@ -27,7 +27,8 @@
constexpr char MIMETYPE_TELE_SENSOR[] = "application/x-companion-tele-sensor"; constexpr char MIMETYPE_TELE_SENSOR[] = "application/x-companion-tele-sensor";
class AutoComboBox; class AutoComboBox;
class RawSourceFilterItemModel; class CommonItemModels;
class RawItemFilteredModel;
class TimerEdit; class TimerEdit;
namespace Ui { namespace Ui {
@ -41,7 +42,7 @@ class TelemetryCustomScreen: public ModelPanel
Q_OBJECT Q_OBJECT
public: public:
TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware, RawSourceFilterItemModel * srcModel); TelemetryCustomScreen(QWidget *parent, ModelData & model, FrSkyScreenData & screen, GeneralSettings & generalSettings, Firmware * firmware, RawItemFilteredModel * rawSourceModel);
~TelemetryCustomScreen(); ~TelemetryCustomScreen();
void update(); void update();
@ -53,6 +54,8 @@ class TelemetryCustomScreen: public ModelPanel
void barMinChanged(double value); void barMinChanged(double value);
void barMaxChanged(double value); void barMaxChanged(double value);
void barTimeChanged(); void barTimeChanged();
void onModelDataAboutToBeUpdated();
void onModelDataUpdateComplete();
private: private:
void updateBar(int line); void updateBar(int line);
@ -122,7 +125,7 @@ class TelemetryPanel : public ModelPanel
Q_OBJECT Q_OBJECT
public: public:
TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware); TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware, CommonItemModels * commonItemModels);
virtual ~TelemetryPanel(); virtual ~TelemetryPanel();
virtual void update(); virtual void update();
@ -148,12 +151,15 @@ class TelemetryPanel : public ModelPanel
void on_deleteSensor(int index); void on_deleteSensor(int index);
void on_moveUpSensor(int index); void on_moveUpSensor(int index);
void on_moveDownSensor(int index); void on_moveDownSensor(int index);
void on_dataModifiedSensor();
private: private:
Ui::Telemetry *ui; Ui::Telemetry *ui;
TelemetryCustomScreen * telemetryCustomScreens[4]; TelemetryCustomScreen * telemetryCustomScreens[4];
TelemetrySensorPanel * sensorPanels[CPN_MAX_SENSORS]; TelemetrySensorPanel * sensorPanels[CPN_MAX_SENSORS];
int sensorCapability; int sensorCapability;
CommonItemModels * commonItemModels;
RawItemFilteredModel * rawSourceFilteredModel;
void setup(); void setup();
void telBarUpdate(); void telBarUpdate();
@ -161,6 +167,7 @@ class TelemetryPanel : public ModelPanel
void populateCurrentSource(); void populateCurrentSource();
void populateVarioSource(); void populateVarioSource();
void swapData(int idx1, int idx2); void swapData(int idx1, int idx2);
void updateItemModels();
}; };
#endif // _TELEMETRY_H_ #endif // _TELEMETRY_H_

View file

@ -24,6 +24,7 @@
#include "boards.h" #include "boards.h"
#include "helpers_html.h" #include "helpers_html.h"
#include "appdata.h" #include "appdata.h"
#include "adjustmentreference.h"
#include <QApplication> #include <QApplication>
#include <QPainter> #include <QPainter>
@ -396,7 +397,7 @@ QString ModelPrinter::printInputLine(const ExpoData & input)
str += input.srcRaw.toString(&model, &generalSettings).toHtmlEscaped(); str += input.srcRaw.toString(&model, &generalSettings).toHtmlEscaped();
} }
str += " " + tr("Weight").toHtmlEscaped() + QString("(%1)").arg(Helpers::getAdjustmentString(input.weight, &model, true).toHtmlEscaped()); str += " " + tr("Weight(%1)").arg(AdjustmentReference(input.weight).toString(&model, true)).toHtmlEscaped();
if (input.curve.value) if (input.curve.value)
str += " " + input.curve.toString(&model).toHtmlEscaped(); str += " " + input.curve.toString(&model).toHtmlEscaped();
@ -405,19 +406,18 @@ QString ModelPrinter::printInputLine(const ExpoData & input)
str += " " + flightModesStr.toHtmlEscaped(); str += " " + flightModesStr.toHtmlEscaped();
if (input.swtch.type != SWITCH_TYPE_NONE) if (input.swtch.type != SWITCH_TYPE_NONE)
str += " " + tr("Switch").toHtmlEscaped() + QString("(%1)").arg(input.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped(); str += " " + tr("Switch(%1)").arg(input.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
if (firmware->getCapability(VirtualInputs)) { if (firmware->getCapability(VirtualInputs)) {
if (input.carryTrim>0) if (input.carryTrim > 0)
str += " " + tr("NoTrim").toHtmlEscaped(); str += " " + tr("NoTrim");
else if (input.carryTrim<0) else if (input.carryTrim < 0)
str += " " + RawSource(SOURCE_TYPE_TRIM, (-(input.carryTrim)-1)).toString(&model, &generalSettings).toHtmlEscaped(); str += " " + RawSource(SOURCE_TYPE_TRIM, (-(input.carryTrim) - 1)).toString(&model, &generalSettings).toHtmlEscaped();
} }
if (input.offset) if (input.offset)
str += " " + tr("Offset(%1)").arg(Helpers::getAdjustmentString(input.offset, &model)).toHtmlEscaped(); str += " " + tr("Offset(%1)").arg(AdjustmentReference(input.offset).toString(&model)).toHtmlEscaped();
if (firmware->getCapability(HasExpoNames) && input.name[0]) if (firmware->getCapability(HasExpoNames) && input.name[0])
str += QString(" [%1]").arg(input.name).toHtmlEscaped(); str += QString(" [%1]").arg(input.name).toHtmlEscaped();
@ -440,7 +440,7 @@ QString ModelPrinter::printMixerLine(const MixData & mix, bool showMultiplex, in
} }
// highlight source if needed // highlight source if needed
QString source = mix.srcRaw.toString(&model, &generalSettings).toHtmlEscaped(); QString source = mix.srcRaw.toString(&model, &generalSettings).toHtmlEscaped();
if ( (mix.srcRaw.type == SOURCE_TYPE_CH) && (mix.srcRaw.index+1 == (int)highlightedSource) ) { if ( (mix.srcRaw.type == SOURCE_TYPE_CH) && (mix.srcRaw.index + 1 == (int)highlightedSource) ) {
source = "<b>" + source + "</b>"; source = "<b>" + source + "</b>";
} }
str += "&nbsp;" + source; str += "&nbsp;" + source;
@ -448,35 +448,35 @@ QString ModelPrinter::printMixerLine(const MixData & mix, bool showMultiplex, in
if (mix.mltpx == MLTPX_MUL && !showMultiplex) if (mix.mltpx == MLTPX_MUL && !showMultiplex)
str += " " + tr("MULT!").toHtmlEscaped(); str += " " + tr("MULT!").toHtmlEscaped();
else else
str += " " + tr("Weight") + QString("(%1)").arg(Helpers::getAdjustmentString(mix.weight, &model, true)).toHtmlEscaped(); str += " " + tr("Weight(%1)").arg(AdjustmentReference(mix.weight).toString(&model, true)).toHtmlEscaped();
QString flightModesStr = printFlightModes(mix.flightModes); QString flightModesStr = printFlightModes(mix.flightModes);
if (!flightModesStr.isEmpty()) if (!flightModesStr.isEmpty())
str += " " + flightModesStr.toHtmlEscaped(); str += " " + flightModesStr.toHtmlEscaped();
if (mix.swtch.type != SWITCH_TYPE_NONE) if (mix.swtch.type != SWITCH_TYPE_NONE)
str += " " + tr("Switch") + QString("(%1)").arg(mix.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped(); str += " " + tr("Switch(%1)").arg(mix.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
if (mix.carryTrim > 0) if (mix.carryTrim > 0)
str += " " + tr("NoTrim").toHtmlEscaped(); str += " " + tr("NoTrim");
else if (mix.carryTrim < 0) else if (mix.carryTrim < 0)
str += " " + RawSource(SOURCE_TYPE_TRIM, (-(mix.carryTrim)-1)).toString(&model, &generalSettings); str += " " + RawSource(SOURCE_TYPE_TRIM, (-(mix.carryTrim)-1)).toString(&model, &generalSettings);
if (firmware->getCapability(HasNoExpo) && mix.noExpo) if (firmware->getCapability(HasNoExpo) && mix.noExpo)
str += " " + tr("No DR/Expo").toHtmlEscaped(); str += " " + tr("No DR/Expo").toHtmlEscaped();
if (mix.sOffset) if (mix.sOffset)
str += " " + tr("Offset") + QString("(%1)").arg(Helpers::getAdjustmentString(mix.sOffset, &model)).toHtmlEscaped(); str += " " + tr("Offset(%1)").arg(AdjustmentReference(mix.sOffset).toString(&model)).toHtmlEscaped();
if (mix.curve.value) if (mix.curve.value)
str += " " + mix.curve.toString(&model).toHtmlEscaped(); str += " " + mix.curve.toString(&model).toHtmlEscaped();
int scale = firmware->getCapability(SlowScale); int scale = firmware->getCapability(SlowScale);
if (scale == 0) if (scale == 0)
scale = 1; scale = 1;
if (mix.delayDown || mix.delayUp) if (mix.delayDown || mix.delayUp)
str += " " + tr("Delay") + QString("(u%1:d%2)").arg((double)mix.delayUp/scale).arg((double)mix.delayDown/scale).toHtmlEscaped(); str += " " + tr("Delay(u%1:d%2)").arg((double)mix.delayUp / scale).arg((double)mix.delayDown / scale).toHtmlEscaped();
if (mix.speedDown || mix.speedUp) if (mix.speedDown || mix.speedUp)
str += " " + tr("Slow") + QString("(u%1:d%2)").arg((double)mix.speedUp/scale).arg((double)mix.speedDown/scale).toHtmlEscaped(); str += " " + tr("Slow(u%1:d%2)").arg((double)mix.speedUp / scale).arg((double)mix.speedDown / scale).toHtmlEscaped();
if (mix.mixWarn) if (mix.mixWarn)
str += " " + tr("Warn") + QString("(%1)").arg(mix.mixWarn).toHtmlEscaped(); str += " " + tr("Warn(%1)").arg(mix.mixWarn).toHtmlEscaped();
if (firmware->getCapability(HasMixerNames) && mix.name[0]) if (firmware->getCapability(HasMixerNames) && mix.name[0])
str += QString(" [%1]").arg(mix.name).toHtmlEscaped(); str += QString(" [%1]").arg(mix.name).toHtmlEscaped();
return str; return str;
@ -496,13 +496,13 @@ QString ModelPrinter::printFlightModes(unsigned int flightModes)
{ {
int numFlightModes = firmware->getCapability(FlightModes); int numFlightModes = firmware->getCapability(FlightModes);
if (numFlightModes && flightModes) { if (numFlightModes && flightModes) {
if (flightModes == (unsigned int)(1<<numFlightModes) - 1) { if (flightModes == (unsigned int)(1 << numFlightModes) - 1) {
return tr("Disabled in all flight modes"); return tr("Disabled in all flight modes");
} }
else { else {
QStringList list; QStringList list;
for (int i=0; i<numFlightModes; i++) { for (int i = 0; i < numFlightModes; i++) {
if (!(flightModes & (1<<i))) { if (!(flightModes & (1 << i))) {
list << printFlightModeName(i); list << printFlightModeName(i);
} }
} }
@ -517,13 +517,13 @@ QString ModelPrinter::printInputFlightModes(unsigned int flightModes)
{ {
int numFlightModes = firmware->getCapability(FlightModes); int numFlightModes = firmware->getCapability(FlightModes);
if (numFlightModes && flightModes) { if (numFlightModes && flightModes) {
if (flightModes == (unsigned int)(1<<numFlightModes) - 1) { if (flightModes == (unsigned int)(1 << numFlightModes) - 1) {
return tr("None"); return tr("None");
} }
else { else {
QStringList list; QStringList list;
for (int i=0; i<numFlightModes; i++) { for (int i = 0; i < numFlightModes; i++) {
if (!(flightModes & (1<<i))) { if (!(flightModes & (1 << i))) {
list << printFlightModeName(i); list << printFlightModeName(i);
} }
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -30,6 +30,11 @@ local function run(event)
return 2 return 2
end end
if crossfireTelemetryPush() == nil then
error("Crossfire not available!")
return 2
end
chdir("/SCRIPTS/TOOLS/CROSSFIRE") chdir("/SCRIPTS/TOOLS/CROSSFIRE")
return "crossfire.lua" return "crossfire.lua"
end end

View file

@ -30,6 +30,11 @@ local function run(event)
return 2 return 2
end end
if crossfireTelemetryPush() == nil then
error("Crossfire not available!")
return 2
end
chdir("/SCRIPTS/TOOLS/CROSSFIRE") chdir("/SCRIPTS/TOOLS/CROSSFIRE")
return "crossfire.lua" return "crossfire.lua"
end end

View file

@ -171,6 +171,8 @@ local function init()
local ver, radio, maj, minor, rev = getVersion() local ver, radio, maj, minor, rev = getVersion()
if string.match(radio, "x7") then if string.match(radio, "x7") then
switches = {"SA", "SB", "SC", "SD", "SF", "SH"} switches = {"SA", "SB", "SC", "SD", "SF", "SH"}
elseif string.match(radio, "tx12") then
switches = {"SA", "SB", "SC", "SD", "SE", "SF"}
else else
switches = {"SA", "SB", "SC", "SD"} switches = {"SA", "SB", "SC", "SD"}
end end

View file

@ -30,6 +30,11 @@ local function run(event)
return 2 return 2
end end
if crossfireTelemetryPush() == nil then
error("Crossfire not available!")
return 2
end
chdir("/SCRIPTS/TOOLS/CROSSFIRE") chdir("/SCRIPTS/TOOLS/CROSSFIRE")
return "crossfire.lua" return "crossfire.lua"
end end

View file

@ -36,7 +36,6 @@
#define HEADER_LINE_COLUMNS 0, #define HEADER_LINE_COLUMNS 0,
#endif #endif
#define COLUMN_X 0
#define drawFieldLabel(x, y, str) lcdDrawTextAlignedLeft(y, str) #define drawFieldLabel(x, y, str) lcdDrawTextAlignedLeft(y, str)
#define NUM_BODY_LINES (LCD_LINES-1) #define NUM_BODY_LINES (LCD_LINES-1)

View file

@ -83,7 +83,7 @@ void onModelSelectMenu(const char * result)
void menuModelSelect(event_t event) void menuModelSelect(event_t event)
{ {
event_t _event_ = event; event_t _event_ = event;
if ((s_copyMode && EVT_KEY_MASK(event) == KEY_EXIT) || event == EVT_KEY_BREAK(KEY_EXIT) || IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event)) { if ((s_copyMode && IS_KEY_EVT(event, KEY_EXIT)) || event == EVT_KEY_BREAK(KEY_EXIT) || IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event)) {
_event_ = 0; _event_ = 0;
} }

View file

@ -276,10 +276,12 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
lcdDrawNumber(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); lcdDrawNumber(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT);
} }
#endif // OVERRIDE_CHANNEL_FUNCTION #endif // OVERRIDE_CHANNEL_FUNCTION
else if (func >= FUNC_SET_FAILSAFE && func <= FUNC_BIND) { #if defined(DANGEROUS_MODULE_FUNCTIONS)
else if (func >= FUNC_RANGECHECK && func <= FUNC_BIND) {
val_max = NUM_MODULES-1; val_max = NUM_MODULES-1;
lcdDrawTextAtIndex(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, "\004Int.Ext.", CFN_PARAM(cfn), attr); lcdDrawTextAtIndex(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, "\004Int.Ext.", CFN_PARAM(cfn), attr);
} }
#endif
else if (func == FUNC_SET_TIMER) { else if (func == FUNC_SET_TIMER) {
getMixSrcRange(MIXSRC_FIRST_TIMER, val_min, val_max); getMixSrcRange(MIXSRC_FIRST_TIMER, val_min, val_max);
drawTimer(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT, attr); drawTimer(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT, attr);

View file

@ -44,7 +44,6 @@ struct {
#define PHASE_FLAGS 0 #define PHASE_FLAGS 0
#define VBATT_X (6*FW-1) #define VBATT_X (6*FW-1)
#define VBATT_Y (2*FH) #define VBATT_Y (2*FH)
#define VBATTUNIT_X (VBATT_X-1)
#define VBATTUNIT_Y (3*FH) #define VBATTUNIT_Y (3*FH)
#define REBOOT_X (20*FW-3) #define REBOOT_X (20*FW-3)
#define BAR_HEIGHT (BOX_WIDTH-1l) // don't remove the l here to force 16bits maths on 9X #define BAR_HEIGHT (BOX_WIDTH-1l) // don't remove the l here to force 16bits maths on 9X
@ -260,8 +259,13 @@ void displayBattVoltage()
count = (get_tmr10ms() & 127u) * count / 128; count = (get_tmr10ms() & 127u) * count / 128;
} }
#endif #endif
for (uint8_t i = 0; i < count; i += 2) for (uint8_t i = 0; i < count; i += 2) {
#if defined(USB_CHARGER)
if ((i >= count - 2) && usbChargerLed() && BLINK_ON_PHASE) // Blink last segment on charge
continue;
#endif
lcdDrawSolidVerticalLine(VBATT_X - 24 + i, VBATT_Y + 10, 3); lcdDrawSolidVerticalLine(VBATT_X - 24 + i, VBATT_Y + 10, 3);
}
if (!IS_TXBATT_WARNING() || BLINK_ON_PHASE) if (!IS_TXBATT_WARNING() || BLINK_ON_PHASE)
lcdDrawSolidFilledRect(VBATT_X - 26, VBATT_Y, 24, 15); lcdDrawSolidFilledRect(VBATT_X - 26, VBATT_Y, 24, 15);
#else #else

View file

@ -268,10 +268,12 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
lcdDrawNumber(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); lcdDrawNumber(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT);
} }
#endif #endif
else if (func >= FUNC_SET_FAILSAFE && func <= FUNC_BIND) { #if defined(DANGEROUS_MODULE_FUNCTIONS)
else if (func >= FUNC_RANGECHECK && func <= FUNC_BIND) {
val_max = NUM_MODULES-1; val_max = NUM_MODULES-1;
lcdDrawTextAtIndex(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, "\004Int.Ext.", CFN_PARAM(cfn), attr); lcdDrawTextAtIndex(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, "\004Int.Ext.", CFN_PARAM(cfn), attr);
} }
#endif
else if (func == FUNC_SET_TIMER) { else if (func == FUNC_SET_TIMER) {
getMixSrcRange(MIXSRC_FIRST_TIMER, val_min, val_max); getMixSrcRange(MIXSRC_FIRST_TIMER, val_min, val_max);
drawTimer(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT|TIMEHOUR, attr); drawTimer(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT|TIMEHOUR, attr);

View file

@ -27,7 +27,6 @@
#define MODELNAME_Y (11) #define MODELNAME_Y (11)
#define VBATT_X (MODELNAME_X+26) #define VBATT_X (MODELNAME_X+26)
#define VBATT_Y (FH+3) #define VBATT_Y (FH+3)
#define VBATTUNIT_X (VBATT_X-2)
#define VBATTUNIT_Y VBATT_Y #define VBATTUNIT_Y VBATT_Y
#define BITMAP_X ((LCD_W-64)/2) #define BITMAP_X ((LCD_W-64)/2)
#define BITMAP_Y (LCD_H/2) #define BITMAP_Y (LCD_H/2)

View file

@ -1,105 +0,0 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "opentx.h"
#include "sliders.h"
#include "trims.h"
#define HAS_TOPBAR() (persistentData->options[0].value.boolValue == true)
#define HAS_FM() (persistentData->options[1].value.boolValue == true)
#define HAS_SLIDERS() (persistentData->options[2].value.boolValue == true)
#define HAS_TRIMS() (persistentData->options[3].value.boolValue == true)
#define IS_MIRRORED() (persistentData->options[4].value.boolValue == true)
const uint8_t LBM_LAYOUT_4P2[] = {
#include "mask_layout4+2.lbm"
};
const ZoneOption OPTIONS_LAYOUT_4P2[] = {
{ STR_TOP_BAR, ZoneOption::Bool },
{ STR_FLIGHT_MODE, ZoneOption::Bool },
{ STR_SLIDERS, ZoneOption::Bool },
{ STR_TRIMS, ZoneOption::Bool },
{ STR_MIRROR, ZoneOption::Bool },
{ nullptr, ZoneOption::Bool }
};
class Layout4P2: public Layout
{
public:
Layout4P2(const LayoutFactory * factory, Layout::PersistentData * persistentData):
Layout(factory, persistentData)
{
decorate();
}
void create() override
{
Layout::create();
persistentData->options[0].value.boolValue = true;
persistentData->options[1].value.boolValue = true;
persistentData->options[2].value.boolValue = true;
persistentData->options[3].value.boolValue = true;
persistentData->options[4].value.boolValue = false;
persistentData->options[5].value.boolValue = false;
decorate();
}
void decorate()
{
Layout::decorate(HAS_TOPBAR(), HAS_SLIDERS(), HAS_TRIMS(), HAS_FM());
}
unsigned int getZonesCount() const override
{
return 6;
}
rect_t getZone(unsigned int index) const override
{
coord_t areaw = LCD_W - (HAS_SLIDERS() ? 2 * TRIM_SQUARE_SIZE : 0) - (HAS_TRIMS() ? 2 * TRIM_SQUARE_SIZE : 0) - 10;
coord_t areah = LCD_H - (HAS_TOPBAR() ? TOPBAR_HEIGHT : 0) - (HAS_SLIDERS() ? TRIM_SQUARE_SIZE : 0) - (HAS_TRIMS() ? TRIM_SQUARE_SIZE : 0) - 10;
areah = 4 * (areah % 4);
return {
IS_MIRRORED() ? ((index >= 4) ? (LCD_W - areaw) / 2 : 240) : ((index >= 4) ? 240 : (LCD_W - areaw) / 2),
static_cast<coord_t>((index >= 4) ? (HAS_TOPBAR() ? TOPBAR_HEIGHT + 1 : 1) + (index == 5 ? areah / 4 : 0) : (HAS_TOPBAR() ? TOPBAR_HEIGHT + 1 : 1) + (index % 4) * (areah / 4)),
areaw / 2,
(index >= 4) ? (areah / 2) : (areah / 4)
};
}
void checkEvents() override
{
Layout::checkEvents();
uint8_t newValue = persistentData->options[4].value.boolValue << 4 | persistentData->options[3].value.boolValue << 3 | persistentData->options[2].value.boolValue << 2
| persistentData->options[1].value.boolValue << 1 | persistentData->options[0].value.boolValue;
if (value != newValue) {
value = newValue;
// TODO call this from the Layout config window
this->clear();
decorate();
}
}
protected:
uint8_t value = 0;
};
BaseLayoutFactory<Layout4P2> layout4P2("Layout4P2", "4 + 2", LBM_LAYOUT_4P2, OPTIONS_LAYOUT_4P2);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -614,6 +614,7 @@ bool menuScreenSetup(int index, event_t event)
ZoneOptionValue * value = currentScreen->getOptionValue(o); ZoneOptionValue * value = currentScreen->getOptionValue(o);
if (editZoneOption(y, option, value, attr, EE_MODEL, event)) { if (editZoneOption(y, option, value, attr, EE_MODEL, event)) {
currentScreen->update(); currentScreen->update();
loadCustomScreens();
} }
} }
else if (menuPageCount > 3 && o == optionsCount) { else if (menuPageCount > 3 && o == optionsCount) {

View file

@ -64,6 +64,11 @@ void TopBar::paint(BitmapBuffer * dc)
dc->drawBitmapPattern(LCD_W - 98, 8, LBM_TOPMENU_USB, MENU_COLOR); dc->drawBitmapPattern(LCD_W - 98, 8, LBM_TOPMENU_USB, MENU_COLOR);
} }
// Logs
if (isFunctionActive(FUNCTION_LOGS) && !usbPlugged() && BLINK_ON_PHASE) {
dc->drawBitmapPattern(LCD_W - 98, 6, LBM_DOT, MENU_COLOR);
}
// RSSI // RSSI
const uint8_t rssiBarsValue[] = {30, 40, 50, 60, 80}; const uint8_t rssiBarsValue[] = {30, 40, 50, 60, 80};
const uint8_t rssiBarsHeight[] = {5, 10, 15, 21, 31}; const uint8_t rssiBarsHeight[] = {5, 10, 15, 21, 31};

View file

@ -128,7 +128,7 @@ bool menuAboutView(event_t event)
break; break;
case ABOUT_HARDWARE: case ABOUT_HARDWARE:
lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, "FrSky", INVERS); lcdDrawText(ABOUT_X, MENU_CONTENT_TOP, STR_ABOUT_HARDWARE_1, INVERS);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_HARDWARE_2); lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_HARDWARE_2);
lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_HARDWARE_3); lcdDrawText(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_HARDWARE_3);
break; break;

View file

@ -25,6 +25,8 @@ void menuGhostModuleConfig(event_t event)
switch (event) { switch (event) {
case EVT_ENTRY: case EVT_ENTRY:
memclear(&reusableBuffer.ghostMenu, sizeof(reusableBuffer.ghostMenu)); memclear(&reusableBuffer.ghostMenu, sizeof(reusableBuffer.ghostMenu));
strAppend((char *) &reusableBuffer.ghostMenu.line[1].menuText, STR_WAITING_FOR_MODULE, 0);
reusableBuffer.ghostMenu.line[1].lineFlags = GHST_LINE_FLAGS_VALUE_EDIT;
reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE; reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE;
reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_OPEN; reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_OPEN;
moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL; moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
@ -40,6 +42,7 @@ void menuGhostModuleConfig(event_t event)
reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYUP; reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYUP;
reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE; reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL; moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
audioKeyPress();
break; break;
#if defined(ROTARY_ENCODER_NAVIGATION) #if defined(ROTARY_ENCODER_NAVIGATION)
@ -52,6 +55,7 @@ void menuGhostModuleConfig(event_t event)
reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYDOWN; reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYDOWN;
reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE; reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL; moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
audioKeyPress();
break; break;
@ -59,12 +63,14 @@ void menuGhostModuleConfig(event_t event)
reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYPRESS; reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYPRESS;
reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE; reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL; moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
audioKeyPress();
break; break;
case EVT_KEY_BREAK(KEY_EXIT): case EVT_KEY_BREAK(KEY_EXIT):
reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYLEFT; reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYLEFT;
reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE; reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL; moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
audioKeyPress();
break; break;
case EVT_KEY_LONG(KEY_EXIT): case EVT_KEY_LONG(KEY_EXIT):
@ -78,7 +84,12 @@ void menuGhostModuleConfig(event_t event)
break; break;
} }
if (reusableBuffer.ghostMenu.menuAction == GHST_MENU_CTRL_CLOSE) { if (reusableBuffer.ghostMenu.menuStatus == GHST_MENU_STATUS_UNOPENED) { // Handles situation where module is plugged after tools start
reusableBuffer.ghostMenu.buttonAction = GHST_BTN_NONE;
reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_OPEN;
moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
}
else if (reusableBuffer.ghostMenu.menuStatus == GHST_MENU_STATUS_CLOSING) {
popMenu(); popMenu();
} }
@ -104,6 +115,8 @@ void menuGhostModuleConfig(event_t event)
else { else {
if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_LABEL_SELECT) if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_LABEL_SELECT)
flags = INVERS; flags = INVERS;
if (reusableBuffer.ghostMenu.line[line].lineFlags & GHST_LINE_FLAGS_VALUE_EDIT)
flags |= BLINK;
lcdDrawText(xOffset, yOffset + line * FH, reusableBuffer.ghostMenu.line[line].menuText, flags); lcdDrawText(xOffset, yOffset + line * FH, reusableBuffer.ghostMenu.line[line].menuText, flags);
} }
} }

View file

@ -227,14 +227,19 @@ void onSdManagerMenu(const char * result)
#if defined(INTERNAL_MODULE_MULTI) #if defined(INTERNAL_MODULE_MULTI)
else if (result == STR_FLASH_INTERNAL_MULTI) { else if (result == STR_FLASH_INTERNAL_MULTI) {
getSelectionFullPath(lfn); getSelectionFullPath(lfn);
MultiDeviceFirmwareUpdate device(INTERNAL_MODULE); MultiDeviceFirmwareUpdate device(INTERNAL_MODULE, MULTI_TYPE_MULTIMODULE);
device.flashFirmware(lfn, drawProgressScreen); device.flashFirmware(lfn, drawProgressScreen);
} }
#endif #endif
else if (result == STR_FLASH_EXTERNAL_MULTI) { else if (result == STR_FLASH_EXTERNAL_MULTI) {
getSelectionFullPath(lfn); getSelectionFullPath(lfn);
MultiDeviceFirmwareUpdate device(EXTERNAL_MODULE); MultiDeviceFirmwareUpdate device(EXTERNAL_MODULE);
device.flashFirmware(lfn, drawProgressScreen); device.flashFirmware(lfn, MULTI_TYPE_MULTIMODULE, drawProgressScreen);
}
else if (result == STR_FLASH_EXTERNAL_ELRS) {
getSelectionFullPath(lfn);
MultiDeviceFirmwareUpdate device(EXTERNAL_MODULE);
device.flashFirmware(lfn, MULTI_TYPE_ELRS, drawProgressScreen);
} }
#endif #endif
#if defined(BLUETOOTH) #if defined(BLUETOOTH)
@ -404,6 +409,12 @@ void menuRadioSdManager(event_t _event)
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MULTI); POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MULTI);
} }
} }
if (!READ_ONLY() && !strcasecmp(ext, ELRS_FIRMWARE_EXT)) {
TCHAR lfn[FF_MAX_LFN + 1];
getSelectionFullPath(lfn);
POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_ELRS);
}
#endif #endif
#if defined(PCBTARANIS) #if defined(PCBTARANIS)
if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) { if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) {

View file

@ -133,6 +133,7 @@ void menuRadioTools(event_t event)
if (isModuleGhost(EXTERNAL_MODULE)) if (isModuleGhost(EXTERNAL_MODULE))
addRadioModuleTool(index++, "Ghost Menu", menuGhostModuleConfig, EXTERNAL_MODULE); addRadioModuleTool(index++, "Ghost Menu", menuGhostModuleConfig, EXTERNAL_MODULE);
#endif #endif
if (index == 0) { if (index == 0) {
lcdDrawCenteredText(LCD_H/2, STR_NO_TOOLS); lcdDrawCenteredText(LCD_H/2, STR_NO_TOOLS);
} }

View file

@ -555,7 +555,7 @@ bool isPxx2IsrmChannelsCountAllowed(int channels)
bool isTrainerUsingModuleBay() bool isTrainerUsingModuleBay()
{ {
#if defined(PCBTARANIS) #if defined(PCBTARANIS)
if (TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE <= g_model.trainerData.mode && g_model.trainerData.mode <= TRAINER_MODE_MASTER_BATTERY_COMPARTMENT) if (TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE <= g_model.trainerData.mode && g_model.trainerData.mode <= TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)
return true; return true;
#endif #endif
return false; return false;
@ -951,8 +951,9 @@ const char STR_SUBTYPE_ESky[] = "\003""Std""ET4";
const char STR_SUBTYPE_MT99[] = "\006""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805"; const char STR_SUBTYPE_MT99[] = "\006""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805";
const char STR_SUBTYPE_MJXQ[] = "\007""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix"; const char STR_SUBTYPE_MJXQ[] = "\007""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix";
const char STR_SUBTYPE_FY326[] = "\005""Std\0 ""FY319"; const char STR_SUBTYPE_FY326[] = "\005""Std\0 ""FY319";
const char STR_SUBTYPE_FUTABA[] = "\005""SFHSS";
const char STR_SUBTYPE_HONTAI[] = "\007""Std\0 ""JJRC X1""X5C1\0 ""FQ_951"; const char STR_SUBTYPE_HONTAI[] = "\007""Std\0 ""JJRC X1""X5C1\0 ""FQ_951";
const char STR_SUBTYPE_AFHDS2A[] = "\010""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS"; const char STR_SUBTYPE_AFHDS2A[] = "\010""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS""PWM,IB16""PPM,IB16";
const char STR_SUBTYPE_Q2X2[] = "\004""Q222""Q242""Q282"; const char STR_SUBTYPE_Q2X2[] = "\004""Q222""Q242""Q282";
const char STR_SUBTYPE_WK2x01[] = "\006""WK2801""WK2401""W6_5_1""W6_6_1""W6_HeL""W6_HeI"; const char STR_SUBTYPE_WK2x01[] = "\006""WK2801""WK2401""W6_5_1""W6_6_1""W6_HeL""W6_HeI";
const char STR_SUBTYPE_Q303[] = "\006""Std\0 ""CX35\0 ""CX10D\0""CX10WD"; const char STR_SUBTYPE_Q303[] = "\006""Std\0 ""CX35\0 ""CX10D\0""CX10WD";
@ -961,7 +962,7 @@ const char STR_SUBTYPE_ESKY150[] = "\003""4ch""7ch";
const char STR_SUBTYPE_H83D[] = "\007""Std\0 ""H20H\0 ""H20Mini""H30Mini"; const char STR_SUBTYPE_H83D[] = "\007""Std\0 ""H20H\0 ""H20Mini""H30Mini";
const char STR_SUBTYPE_CORONA[] = "\005""V1\0 ""V2\0 ""FD V3"; const char STR_SUBTYPE_CORONA[] = "\005""V1\0 ""V2\0 ""FD V3";
const char STR_SUBTYPE_HITEC[] = "\007""Optima\0""Opt Hub""Minima\0"; const char STR_SUBTYPE_HITEC[] = "\007""Optima\0""Opt Hub""Minima\0";
const char STR_SUBTYPE_WFLY[] = "\006""WFR0xS"; const char STR_SUBTYPE_WFLY[] = "\005""WFR0x";
const char STR_SUBTYPE_BUGS_MINI[] = "\006""Std\0 ""Bugs3H"; const char STR_SUBTYPE_BUGS_MINI[] = "\006""Std\0 ""Bugs3H";
const char STR_SUBTYPE_TRAXXAS[] = "\004""6519"; const char STR_SUBTYPE_TRAXXAS[] = "\004""6519";
const char STR_SUBTYPE_E01X[] = "\005""E012\0""E015\0""E016H"; const char STR_SUBTYPE_E01X[] = "\005""E012\0""E015\0""E016H";
@ -971,18 +972,24 @@ const char STR_SUBTYPE_V761[] = "\003""3ch""4ch";
const char STR_SUBTYPE_REDPINE[] = "\004""Fast""Slow"; const char STR_SUBTYPE_REDPINE[] = "\004""Fast""Slow";
const char STR_SUBTYPE_POTENSIC[] = "\003""A20"; const char STR_SUBTYPE_POTENSIC[] = "\003""A20";
const char STR_SUBTYPE_ZSX[] = "\007""280JJRC"; const char STR_SUBTYPE_ZSX[] = "\007""280JJRC";
const char STR_SUBTYPE_FLYZONE[] = "\005""FZ410"; const char STR_SUBTYPE_HEIGHT[] = "\003""5ch""8ch";
const char STR_SUBTYPE_FRSKYX_RX[] = "\007""RX\0 ""CloneTX"; const char STR_SUBTYPE_FRSKYX_RX[] = "\007""RX\0 ""CloneTX";
const char STR_SUBTYPE_HOTT[] = "\007""Sync\0 ""No_Sync"; const char STR_SUBTYPE_HOTT[] = "\007""Sync\0 ""No_Sync";
const char STR_SUBTYPE_FX816[] = "\003""P38"; const char STR_SUBTYPE_FX816[] = "\003""P38";
const char STR_SUBTYPE_PELIKAN[] = "\004""Pro\0""Lite"; const char STR_SUBTYPE_PELIKAN[] = "\004""Pro\0""Lite";
const char STR_SUBTYPE_XK[] = "\004""X450""X420"; const char STR_SUBTYPE_XK[] = "\004""X450""X420";
const char STR_SUBTYPE_XN297DUMP[] = "\004""250K""1M\0 ""2M\0 ""AUTO""NRF\0"; const char STR_SUBTYPE_XN297DUMP[] = "\004""250K""1M\0 ""2M\0 ""AUTO""NRF\0";
const char STR_SUBTYPE_FRSKYX2[] = "\011""D16\0 ""D16 8ch\0 ""LBT(EU)\0 ""LBT 8ch\0 ""D16Cloned"; const char STR_SUBTYPE_FRSKYX2[] = "\010""D16\0 ""D16 8ch\0""LBT(EU)\0""LBT 8ch\0""Cloned\0 ""Clone8ch";
const char STR_SUBTYPE_FRSKYR9[] = "\007""915MHz\0""868MHz\0""915 8ch""868 8ch"; const char STR_SUBTYPE_FRSKYR9[] = "\007""915MHz\0""868MHz\0""915 8ch""868 8ch""FCC\0 ""---\0 ""FCC 8ch";
const char STR_SUBTYPE_PROPEL[] = "\004""74-Z"; const char STR_SUBTYPE_PROPEL[] = "\004""74-Z";
const char STR_SUBTYPE_FRSKYL[] = "\010""LR12\0 ""LR12 6ch"; const char STR_SUBTYPE_FRSKYL[] = "\010""LR12\0 ""LR12 6ch";
const char STR_SUBTYPE_ESKY150V2[] = "\006""150 V2"; const char STR_SUBTYPE_ESKY150V2[] = "\006""150 V2";
const char STR_SUBTYPE_JJRC345[] = "\007""Std\0 ""SkyTmbr";
const char STR_SUBTYPE_KYOSHO[] = "\004""FHSS""Hype";
const char STR_SUBTYPE_RLINK[] = "\007""Surface""Air\0 ""DumboRC";
const char STR_SUBTYPE_ELRS[] = "\007""N/A WIP";
const char STR_SUBTYPE_REALACC[] = "\003""R11";
const char STR_SUBTYPE_WFLY2[] = "\005""RF20x";
const char* mm_options_strings::options[] = { const char* mm_options_strings::options[] = {
nullptr, nullptr,
@ -1017,11 +1024,11 @@ const mm_protocol_definition multi_protocols[] = {
{MODULE_SUBTYPE_MULTI_MT99XX, 4, false, false, STR_SUBTYPE_MT99, nullptr}, {MODULE_SUBTYPE_MULTI_MT99XX, 4, false, false, STR_SUBTYPE_MT99, nullptr},
{MODULE_SUBTYPE_MULTI_MJXQ, 6, false, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_MJXQ, 6, false, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FY326, 1, false, false, STR_SUBTYPE_FY326, nullptr}, {MODULE_SUBTYPE_MULTI_FY326, 1, false, false, STR_SUBTYPE_FY326, nullptr},
{MODULE_SUBTYPE_MULTI_SFHSS, 0, true, true, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FUTABA, 0, true, true, STR_SUBTYPE_FUTABA, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_J6PRO, 0, false, true, NO_SUBTYPE, nullptr}, {MODULE_SUBTYPE_MULTI_J6PRO, 0, false, true, NO_SUBTYPE, nullptr},
{MODULE_SUBTYPE_MULTI_HONTAI, 3, false, false, STR_SUBTYPE_HONTAI, nullptr}, {MODULE_SUBTYPE_MULTI_HONTAI, 3, false, false, STR_SUBTYPE_HONTAI, nullptr},
{MODULE_SUBTYPE_MULTI_OLRS, 0, false, false, NO_SUBTYPE, STR_RF_POWER}, {MODULE_SUBTYPE_MULTI_OLRS, 0, false, false, NO_SUBTYPE, STR_RF_POWER},
{MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ}, {MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 5, true, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
{MODULE_SUBTYPE_MULTI_Q2X2, 2, false, false, STR_SUBTYPE_Q2X2, nullptr}, {MODULE_SUBTYPE_MULTI_Q2X2, 2, false, false, STR_SUBTYPE_Q2X2, nullptr},
{MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, true, STR_SUBTYPE_WK2x01, nullptr}, {MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, true, STR_SUBTYPE_WK2x01, nullptr},
{MODULE_SUBTYPE_MULTI_Q303, 3, false, false, STR_SUBTYPE_Q303, nullptr}, {MODULE_SUBTYPE_MULTI_Q303, 3, false, false, STR_SUBTYPE_Q303, nullptr},
@ -1041,20 +1048,28 @@ const mm_protocol_definition multi_protocols[] = {
{MODULE_SUBTYPE_MULTI_REDPINE, 1, false, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_REDPINE, 1, false, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, false, STR_SUBTYPE_POTENSIC, nullptr}, {MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, false, STR_SUBTYPE_POTENSIC, nullptr},
{MODULE_SUBTYPE_MULTI_ZSX, 0, false, false, STR_SUBTYPE_ZSX, nullptr}, {MODULE_SUBTYPE_MULTI_ZSX, 0, false, false, STR_SUBTYPE_ZSX, nullptr},
{MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, false, STR_SUBTYPE_FLYZONE, nullptr}, {MODULE_SUBTYPE_MULTI_HEIGHT, 1, false, false, STR_SUBTYPE_HEIGHT, nullptr},
{MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_HOTT, 1, true, false, STR_SUBTYPE_HOTT, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_HOTT, 1, true, false, STR_SUBTYPE_HOTT, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FX816, 0, false, false, STR_SUBTYPE_FX816, nullptr}, {MODULE_SUBTYPE_MULTI_FX816, 0, false, false, STR_SUBTYPE_FX816, nullptr},
{MODULE_SUBTYPE_MULTI_PELIKAN, 1, false, false, STR_SUBTYPE_PELIKAN, nullptr}, {MODULE_SUBTYPE_MULTI_PELIKAN, 1, false, true, STR_SUBTYPE_PELIKAN, nullptr},
{MODULE_SUBTYPE_MULTI_XK, 1, false, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_XK, 1, false, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_XN297DUMP, 4, false, false, STR_SUBTYPE_XN297DUMP, STR_MULTI_RFCHAN}, {MODULE_SUBTYPE_MULTI_XN297DUMP, 4, false, false, STR_SUBTYPE_XN297DUMP, STR_MULTI_RFCHAN},
{MODULE_SUBTYPE_MULTI_FRSKYX2, 4, true, false, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FRSKYX2, 5, true, false, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_FRSKY_R9, 3, true, false, STR_SUBTYPE_FRSKYR9, nullptr}, {MODULE_SUBTYPE_MULTI_FRSKY_R9, 6, true, false, STR_SUBTYPE_FRSKYR9, nullptr},
{MODULE_SUBTYPE_MULTI_PROPEL, 0, false, false, STR_SUBTYPE_PROPEL, nullptr}, {MODULE_SUBTYPE_MULTI_PROPEL, 0, false, false, STR_SUBTYPE_PROPEL, nullptr},
{MODULE_SUBTYPE_MULTI_FRSKYL, 1, false, false, STR_SUBTYPE_FRSKYL, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_FRSKYL, 1, false, false, STR_SUBTYPE_FRSKYL, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_SKYARTEC, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_SKYARTEC, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_ESKY150V2, 0, false, true, STR_SUBTYPE_ESKY150V2, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_ESKY150V2, 0, false, true, STR_SUBTYPE_ESKY150V2, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_JJRC345, 1, false, false, STR_SUBTYPE_JJRC345, nullptr},
{MODULE_SUBTYPE_MULTI_Q90C, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE}, {MODULE_SUBTYPE_MULTI_Q90C, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_KYOSHO, 1, false, true, STR_SUBTYPE_KYOSHO, nullptr},
{MODULE_SUBTYPE_MULTI_RLINK, 2, false, false, STR_SUBTYPE_RLINK, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_ELRS, 0, false, false, STR_SUBTYPE_ELRS, nullptr},
{MODULE_SUBTYPE_MULTI_REALACC, 0, false, false, STR_SUBTYPE_REALACC, nullptr},
{MODULE_SUBTYPE_MULTI_OMP, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MODULE_SUBTYPE_MULTI_WFLY2, 0, false, false, STR_SUBTYPE_WFLY2, STR_MULTI_OPTION},
{MODULE_SUBTYPE_MULTI_E016HV2, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
{MM_RF_CUSTOM_SELECTED, 7, true, true, NO_SUBTYPE, STR_MULTI_OPTION}, {MM_RF_CUSTOM_SELECTED, 7, true, true, NO_SUBTYPE, STR_MULTI_OPTION},
// Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff) // Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff)

View file

@ -248,10 +248,12 @@ inline bool MULTIMODULE_HAS_SUBTYPE(uint8_t moduleIdx)
} }
else else
{ {
if (g_model.moduleData[moduleIdx].getMultiProtocol() > MODULE_SUBTYPE_MULTI_LAST) if (g_model.moduleData[moduleIdx].getMultiProtocol() > MODULE_SUBTYPE_MULTI_LAST) {
return true; return true;
else }
return getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol())->maxSubtype > 0; else {
return getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol())->subTypeString != nullptr;
}
} }
} }
@ -303,9 +305,9 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx)
#endif #endif
#if defined(AFHDS3) #if defined(AFHDS3)
#define AFHDS3_PROTOCOL_ROW(moduleIdx) isModuleAFHDS3(moduleIdx) ? 0 : HIDDEN_ROW, #define AFHDS3_PROTOCOL_ROW(moduleIdx) isModuleAFHDS3(moduleIdx) ? uint8_t(0) : HIDDEN_ROW,
#define AFHDS3_MODE_ROWS(moduleIdx) isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, #define AFHDS3_MODE_ROWS(moduleIdx) isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW,
#define AFHDS3_MODULE_ROWS(moduleIdx) isModuleAFHDS3(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? (uint8_t) TITLE_ROW : HIDDEN_ROW, #define AFHDS3_MODULE_ROWS(moduleIdx) isModuleAFHDS3(moduleIdx) ? uint8_t(0) : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW,
#else #else
#define AFHDS3_PROTOCOL_ROW(moduleIdx) #define AFHDS3_PROTOCOL_ROW(moduleIdx)
#define AFHDS3_MODE_ROWS(moduleIdx) #define AFHDS3_MODE_ROWS(moduleIdx)

View file

@ -19,6 +19,7 @@
*/ */
#if !defined(DISABLE_MULTI_UPDATE) #if !defined(DISABLE_MULTI_UPDATE)
#include "opentx.h" #include "opentx.h"
#include "multi_firmware_update.h" #include "multi_firmware_update.h"
#include "stk500.h" #include "stk500.h"
@ -35,23 +36,22 @@ class MultiFirmwareUpdateDriver
protected: protected:
virtual void moduleOn() const = 0; virtual void moduleOn() const = 0;
virtual void init(bool inverted) const = 0; virtual void init(bool inverted) const = 0;
virtual bool getByte(uint8_t& byte) const = 0; virtual bool getByte(uint8_t & byte) const = 0;
virtual void sendByte(uint8_t byte) const = 0; virtual void sendByte(uint8_t byte) const = 0;
virtual void clear() const = 0; virtual void clear() const = 0;
virtual void deinit(bool inverted) const {} virtual void deinit(bool inverted) const {}
private: private:
bool getRxByte(uint8_t& byte) const; bool getRxByte(uint8_t & byte) const;
bool checkRxByte(uint8_t byte) const; bool checkRxByte(uint8_t byte) const;
const char * waitForInitialSync(bool& inverted) const; const char * waitForInitialSync(bool& inverted) const;
const char * getDeviceSignature(uint8_t* signature) const; const char * getDeviceSignature(uint8_t * signature) const;
const char * loadAddress(uint32_t offset) const; const char * loadAddress(uint32_t offset) const;
const char * progPage(uint8_t* buffer, uint16_t size) const; const char * progPage(uint8_t * buffer, uint16_t size) const;
void leaveProgMode(bool inverted) const; void leaveProgMode(bool inverted) const;
}; };
#if defined(INTERNAL_MODULE_MULTI) #if defined(INTERNAL_MODULE_MULTI)
class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver
{ {
public: public:
@ -68,7 +68,7 @@ class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver
intmoduleSerialStart(57600, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b); intmoduleSerialStart(57600, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b);
} }
bool getByte(uint8_t& byte) const override bool getByte(uint8_t & byte) const override
{ {
return intmoduleFifo.pop(byte); return intmoduleFifo.pop(byte);
} }
@ -90,7 +90,6 @@ class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver
}; };
static const MultiInternalUpdateDriver multiInternalUpdateDriver; static const MultiInternalUpdateDriver multiInternalUpdateDriver;
#endif #endif
class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver
@ -122,7 +121,7 @@ class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver
telemetryPortInit(57600, TELEMETRY_SERIAL_DEFAULT); telemetryPortInit(57600, TELEMETRY_SERIAL_DEFAULT);
} }
bool getByte(uint8_t& byte) const override bool getByte(uint8_t & byte) const override
{ {
return telemetryGetByte(&byte); return telemetryGetByte(&byte);
} }
@ -150,12 +149,53 @@ class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver
static const MultiExternalUpdateDriver multiExternalUpdateDriver; static const MultiExternalUpdateDriver multiExternalUpdateDriver;
bool MultiFirmwareUpdateDriver::getRxByte(uint8_t& byte) const class MultiExtSportUpdateDriver: public MultiFirmwareUpdateDriver
{
public:
MultiExtSportUpdateDriver(): MultiFirmwareUpdateDriver() {}
protected:
void moduleOn() const override
{
EXTERNAL_MODULE_ON();
}
void init(bool inverted) const override
{
telemetryPortInit(57600, TELEMETRY_SERIAL_DEFAULT);
}
bool getByte(uint8_t & byte) const override
{
return telemetryGetByte(&byte);
}
void sendByte(uint8_t byte) const override
{
sportSendByte(byte);
telemetryPortSetDirectionInput();
}
void clear() const override
{
telemetryClearFifo();
}
void deinit(bool inverted) const override
{
telemetryPortInit(0, 0);
clear();
}
};
static const MultiExtSportUpdateDriver multiExtSportUpdateDriver;
bool MultiFirmwareUpdateDriver::getRxByte(uint8_t & byte) const
{ {
uint16_t time; uint16_t time;
time = getTmr2MHz() ; time = getTmr2MHz();
while ( (uint16_t) (getTmr2MHz() - time) < 25000 ) { // 12.5mS while ((uint16_t) (getTmr2MHz() - time) < 25000) { // 12.5mS
if (getByte(byte)) { if (getByte(byte)) {
#if defined(DEBUG_EXT_MODULE_FLASH) #if defined(DEBUG_EXT_MODULE_FLASH)
@ -175,11 +215,15 @@ bool MultiFirmwareUpdateDriver::checkRxByte(uint8_t byte) const
return getRxByte(rxchar) ? rxchar == byte : false; return getRxByte(rxchar) ? rxchar == byte : false;
} }
const char * MultiFirmwareUpdateDriver::waitForInitialSync(bool& inverted) const const char * MultiFirmwareUpdateDriver::waitForInitialSync(bool & inverted) const
{ {
uint8_t byte; uint8_t byte;
int retries = 200; int retries = 200;
#if defined(DEBUG_EXT_MODULE_FLASH)
TRACE("[Wait for Sync]");
#endif
clear(); clear();
do { do {
@ -189,7 +233,7 @@ const char * MultiFirmwareUpdateDriver::waitForInitialSync(bool& inverted) const
inverted = !inverted; inverted = !inverted;
init(inverted); init(inverted);
} }
// Send sync request // Send sync request
sendByte(STK_GET_SYNC); sendByte(STK_GET_SYNC);
sendByte(CRC_EOP); sendByte(CRC_EOP);
@ -197,24 +241,35 @@ const char * MultiFirmwareUpdateDriver::waitForInitialSync(bool& inverted) const
getRxByte(byte); getRxByte(byte);
WDG_RESET(); WDG_RESET();
} while((byte != STK_INSYNC) && --retries); } while ((byte != STK_INSYNC) && --retries);
if (!retries) { if (!retries) {
return "NoSync"; return "NoSync";
} }
if (byte != STK_INSYNC) { if (byte != STK_INSYNC) {
#if defined(DEBUG_EXT_MODULE_FLASH)
TRACE("[byte != STK_INSYNC]");
#endif
return "NoSync"; return "NoSync";
} }
if (!checkRxByte(STK_OK)) { if (!checkRxByte(STK_OK)) {
#if defined(DEBUG_EXT_MODULE_FLASH)
TRACE("[!checkRxByte(STK_OK)]");
#endif
return "NoSync"; return "NoSync";
} }
// avoids sending STK_READ_SIGN with STK_OK
// in case the receiver is too slow changing
// to RX mode (half-duplex).
RTOS_WAIT_TICKS(1);
return nullptr; return nullptr;
} }
const char * MultiFirmwareUpdateDriver::getDeviceSignature(uint8_t* signature) const const char * MultiFirmwareUpdateDriver::getDeviceSignature(uint8_t * signature) const
{ {
// Read signature // Read signature
sendByte(STK_READ_SIGN); sendByte(STK_READ_SIGN);
@ -224,7 +279,7 @@ const char * MultiFirmwareUpdateDriver::getDeviceSignature(uint8_t* signature) c
if (!checkRxByte(STK_INSYNC)) if (!checkRxByte(STK_INSYNC))
return "NoSync"; return "NoSync";
for (uint8_t i=0; i<4; i++) { for (uint8_t i = 0; i < 4; i++) {
if (!getRxByte(signature[i])) { if (!getRxByte(signature[i])) {
return "NoSignature"; return "NoSignature";
} }
@ -244,10 +299,14 @@ const char * MultiFirmwareUpdateDriver::loadAddress(uint32_t offset) const
return "NoSync"; return "NoSync";
} }
// avoids sending next page back-to-back with STK_OK
// in case the receiver is to slow changing to RX mode (half-duplex).
RTOS_WAIT_TICKS(1);
return nullptr; return nullptr;
} }
const char * MultiFirmwareUpdateDriver::progPage(uint8_t* buffer, uint16_t size) const const char * MultiFirmwareUpdateDriver::progPage(uint8_t * buffer, uint16_t size) const
{ {
sendByte(STK_PROG_PAGE); sendByte(STK_PROG_PAGE);
@ -258,9 +317,10 @@ const char * MultiFirmwareUpdateDriver::progPage(uint8_t* buffer, uint16_t size)
// flash/eeprom flag // flash/eeprom flag
sendByte(0); sendByte(0);
for (uint16_t i=0; i < size; i++) { for (uint16_t i = 0; i < size; i++) {
sendByte(buffer[i]); sendByte(buffer[i]);
} }
sendByte(CRC_EOP); sendByte(CRC_EOP);
if (!checkRxByte(STK_INSYNC)) if (!checkRxByte(STK_INSYNC))
@ -271,7 +331,7 @@ const char * MultiFirmwareUpdateDriver::progPage(uint8_t* buffer, uint16_t size)
do { do {
getRxByte(byte); getRxByte(byte);
WDG_RESET(); WDG_RESET();
} while(!byte && --retries); } while (!byte && --retries);
if (!retries || (byte != STK_OK)) if (!retries || (byte != STK_OK))
return "NoPageSync"; return "NoPageSync";
@ -323,7 +383,7 @@ const char * MultiFirmwareUpdateDriver::flashFirmware(FIL * file, const char * l
return result; return result;
} }
uint8_t buffer[256]; uint8_t buffer[256];
uint16_t pageSize = 128; uint16_t pageSize = 128;
uint32_t writeOffset = 0; uint32_t writeOffset = 0;
@ -340,7 +400,7 @@ const char * MultiFirmwareUpdateDriver::flashFirmware(FIL * file, const char * l
while (!f_eof(file)) { while (!f_eof(file)) {
progressHandler(label, STR_WRITING, file->fptr, file->obj.objsize); progressHandler(label, STR_WRITING, file->fptr, file->obj.objsize);
UINT count=0; UINT count = 0;
memclear(buffer, pageSize); memclear(buffer, pageSize);
if (f_read(file, buffer, pageSize, &count) != FR_OK) { if (f_read(file, buffer, pageSize, &count) != FR_OK) {
result = "Error reading file"; result = "Error reading file";
@ -460,7 +520,7 @@ const char * MultiFirmwareInformation::readMultiFirmwareInformation(const char *
if (f_open(&file, filename, FA_READ) != FR_OK) if (f_open(&file, filename, FA_READ) != FR_OK)
return "Error opening file"; return "Error opening file";
const char * err = readMultiFirmwareInformation(&file); const char * err = readMultiFirmwareInformation(&file);
f_close(&file); f_close(&file);
return err; return err;
@ -473,7 +533,7 @@ const char * MultiFirmwareInformation::readMultiFirmwareInformation(FIL * file)
if (f_size(file) < MULTI_SIGN_SIZE) if (f_size(file) < MULTI_SIGN_SIZE)
return "File too small"; return "File too small";
f_lseek(file, f_size(file) - MULTI_SIGN_SIZE); f_lseek(file, f_size(file) - MULTI_SIGN_SIZE);
if (f_read(file, buffer, MULTI_SIGN_SIZE, &count) != FR_OK || count != MULTI_SIGN_SIZE) { if (f_read(file, buffer, MULTI_SIGN_SIZE, &count) != FR_OK || count != MULTI_SIGN_SIZE) {
return "Error reading file"; return "Error reading file";
@ -482,11 +542,11 @@ const char * MultiFirmwareInformation::readMultiFirmwareInformation(FIL * file)
if (!memcmp(buffer, "multi-x", 7)) { if (!memcmp(buffer, "multi-x", 7)) {
return readV2Signature(buffer); return readV2Signature(buffer);
} }
return readV1Signature(buffer); return readV1Signature(buffer);
} }
bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHandler progressHandler) bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, MultiModuleType type, ProgressHandler progressHandler)
{ {
FIL file; FIL file;
@ -495,34 +555,38 @@ bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHan
return false; return false;
} }
MultiFirmwareInformation firmwareFile; if (type == MULTI_TYPE_MULTIMODULE) {
if (firmwareFile.readMultiFirmwareInformation(&file)) { MultiFirmwareInformation firmwareFile;
f_close(&file); if (firmwareFile.readMultiFirmwareInformation(&file)) {
POPUP_WARNING("Not a valid file");
return false;
}
f_lseek(&file, 0);
if (module == EXTERNAL_MODULE) {
if (!firmwareFile.isMultiExternalFirmware()) {
f_close(&file); f_close(&file);
POPUP_WARNING(STR_NEEDS_FILE, STR_EXT_MULTI_SPEC); POPUP_WARNING("Not a valid file");
return false; return false;
} }
} f_lseek(&file, 0);
else {
if (!firmwareFile.isMultiInternalFirmware()) { if (module == EXTERNAL_MODULE) {
f_close(&file); if (!firmwareFile.isMultiExternalFirmware()) {
POPUP_WARNING(STR_NEEDS_FILE, STR_INT_MULTI_SPEC); f_close(&file);
return false; POPUP_WARNING(STR_NEEDS_FILE, STR_EXT_MULTI_SPEC);
return false;
}
}
else {
if (!firmwareFile.isMultiInternalFirmware()) {
f_close(&file);
POPUP_WARNING(STR_NEEDS_FILE, STR_INT_MULTI_SPEC);
return false;
}
} }
} }
const MultiFirmwareUpdateDriver* driver = &multiExternalUpdateDriver; const MultiFirmwareUpdateDriver * driver = &multiExternalUpdateDriver;
#if defined(INTERNAL_MODULE_MULTI) #if defined(INTERNAL_MODULE_MULTI)
if (module == INTERNAL_MODULE) if (module == INTERNAL_MODULE)
driver = &multiInternalUpdateDriver; driver = &multiInternalUpdateDriver;
#endif #endif
if (type == MULTI_TYPE_ELRS)
driver = &multiExtSportUpdateDriver;
pausePulses(); pausePulses();
@ -548,7 +612,7 @@ bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHan
const char * result = driver->flashFirmware(&file, getBasename(filename), progressHandler); const char * result = driver->flashFirmware(&file, getBasename(filename), progressHandler);
f_close(&file); f_close(&file);
AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 ); AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1);
BACKLIGHT_ENABLE(); BACKLIGHT_ENABLE();
#if defined(HARDWARE_INTERNAL_MODULE) #if defined(HARDWARE_INTERNAL_MODULE)
@ -570,7 +634,7 @@ bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHan
// reset telemetry protocol // reset telemetry protocol
telemetryInit(255); telemetryInit(255);
#if defined(HARDWARE_INTERNAL_MODULE) #if defined(HARDWARE_INTERNAL_MODULE)
if (intPwr) { if (intPwr) {
INTERNAL_MODULE_ON(); INTERNAL_MODULE_ON();

View file

@ -18,8 +18,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef OPENTX_MULTI_FIRMWARE_H #pragma once
#define OPENTX_MULTI_FIRMWARE_H
#include "ff.h" #include "ff.h"
@ -101,6 +100,11 @@ class MultiFirmwareInformation {
const char * readV2Signature(const char * buffer); const char * readV2Signature(const char * buffer);
}; };
enum MultiModuleType {
MULTI_TYPE_MULTIMODULE = 0,
MULTI_TYPE_ELRS,
};
class MultiDeviceFirmwareUpdate { class MultiDeviceFirmwareUpdate {
public: public:
explicit MultiDeviceFirmwareUpdate(ModuleIndex module): explicit MultiDeviceFirmwareUpdate(ModuleIndex module):
@ -108,10 +112,8 @@ class MultiDeviceFirmwareUpdate {
{ {
} }
bool flashFirmware(const char * filename, ProgressHandler progressHandler); bool flashFirmware(const char * filename, MultiModuleType type, ProgressHandler progressHandler);
protected: protected:
ModuleIndex module; ModuleIndex module;
}; };
#endif //OPENTX_MULTI_FIRMWARE_H

View file

@ -76,9 +76,22 @@ constexpr bool IS_VIRTUAL_KEY_EVENT(event_t event)
// normal order of events is: FIRST, LONG, REPEAT, REPEAT, ..., BREAK // normal order of events is: FIRST, LONG, REPEAT, REPEAT, ..., BREAK
#define EVT_KEY_MASK(e) ((e) & 0x1F) #define EVT_KEY_MASK(e) ((e) & 0x1F)
#define EVT_KEY_FIRST(key) ((key)|_MSK_KEY_FIRST) // fired when key is pressed
#define EVT_KEY_LONG(key) ((key)|_MSK_KEY_LONG) // fired when key is held pressed for a while constexpr event_t EVT_KEY_FIRST(uint8_t key)
#define EVT_KEY_REPT(key) ((key)|_MSK_KEY_REPT) // fired when key is held pressed long enough, fires multiple times with increasing speed {
return (key | _MSK_KEY_FIRST); // fired when key is pressed
}
constexpr event_t EVT_KEY_REPT(uint8_t key)
{
return (key | _MSK_KEY_REPT); // fired when key is held pressed long enough, fires multiple times with increasing speed
}
constexpr event_t EVT_KEY_LONG(uint8_t key)
{
return (key | _MSK_KEY_LONG); // fired when key is held pressed for a while
}
constexpr event_t EVT_KEY_BREAK(uint8_t key) constexpr event_t EVT_KEY_BREAK(uint8_t key)
{ {
return (key | _MSK_KEY_BREAK); // fired when key is released (short or long), but only if the event was not killed return (key | _MSK_KEY_BREAK); // fired when key is released (short or long), but only if the event was not killed
@ -94,10 +107,30 @@ constexpr bool IS_TRIM_EVENT(event_t event)
return (IS_KEY_EVENT(event) && EVT_KEY_MASK(event) >= TRM_BASE); return (IS_KEY_EVENT(event) && EVT_KEY_MASK(event) >= TRM_BASE);
} }
#define IS_KEY_FIRST(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_FIRST) inline bool IS_KEY_FIRST(event_t evt)
#define IS_KEY_LONG(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_LONG) {
#define IS_KEY_REPT(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_REPT) return (evt & _MSK_KEY_FLAGS) == _MSK_KEY_FIRST;
#define IS_KEY_BREAK(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_BREAK) }
inline bool IS_KEY_REPT(event_t evt)
{
return (evt & _MSK_KEY_FLAGS) == _MSK_KEY_REPT;
}
inline bool IS_KEY_LONG(event_t evt)
{
return (evt & _MSK_KEY_FLAGS) == _MSK_KEY_LONG;
}
inline bool IS_KEY_BREAK(event_t evt)
{
return (evt & _MSK_KEY_FLAGS) == _MSK_KEY_BREAK;
}
inline bool IS_KEY_EVT(event_t evt, uint8_t key)
{
return (evt & _MSK_KEY_FLAGS) && (EVT_KEY_MASK(evt) == key);
}
#if defined(PCBXLITE) #if defined(PCBXLITE)
#define EVT_ROTARY_BREAK EVT_KEY_BREAK(KEY_ENTER) #define EVT_ROTARY_BREAK EVT_KEY_BREAK(KEY_ENTER)

View file

@ -71,7 +71,8 @@ Reset the backlight timeout
*/ */
static int luaLcdResetBacklightTimeout(lua_State * L) static int luaLcdResetBacklightTimeout(lua_State * L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
resetBacklightTimeout(); resetBacklightTimeout();
return 0; return 0;
} }
@ -95,7 +96,8 @@ bottom line is 63. Drawing on an existing black pixel produces white pixel (TODO
*/ */
static int luaLcdDrawPoint(lua_State *L) static int luaLcdDrawPoint(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
LcdFlags att = luaL_optunsigned(L, 3, 0); LcdFlags att = luaL_optunsigned(L, 3, 0);
@ -123,7 +125,8 @@ whole line will not be drawn (starting from OpenTX 2.1.5)
*/ */
static int luaLcdDrawLine(lua_State *L) static int luaLcdDrawLine(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
coord_t x1 = luaL_checkunsigned(L, 1); coord_t x1 = luaL_checkunsigned(L, 1);
coord_t y1 = luaL_checkunsigned(L, 2); coord_t y1 = luaL_checkunsigned(L, 2);
coord_t x2 = luaL_checkunsigned(L, 3); coord_t x2 = luaL_checkunsigned(L, 3);
@ -228,7 +231,8 @@ See the [Appendix](../appendix/fonts.md) for available characters in each font s
*/ */
static int luaLcdDrawText(lua_State *L) static int luaLcdDrawText(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
const char * s = luaL_checkstring(L, 3); const char * s = luaL_checkstring(L, 3);
@ -259,7 +263,8 @@ Display a value formatted as time at (x,y)
*/ */
static int luaLcdDrawTimer(lua_State *L) static int luaLcdDrawTimer(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
int seconds = luaL_checkinteger(L, 3); int seconds = luaL_checkinteger(L, 3);
@ -293,7 +298,8 @@ Display a number at (x,y)
*/ */
static int luaLcdDrawNumber(lua_State *L) static int luaLcdDrawNumber(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
int val = luaL_checkinteger(L, 3); int val = luaL_checkinteger(L, 3);
@ -321,7 +327,8 @@ See getValue()
*/ */
static int luaLcdDrawChannel(lua_State *L) static int luaLcdDrawChannel(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
int channel = -1; int channel = -1;
@ -358,7 +365,8 @@ displays negated switch
*/ */
static int luaLcdDrawSwitch(lua_State *L) static int luaLcdDrawSwitch(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
int s = luaL_checkinteger(L, 3); int s = luaL_checkinteger(L, 3);
@ -382,7 +390,8 @@ Displays the name of the corresponding input as defined by the source at (x,y)
*/ */
static int luaLcdDrawSource(lua_State *L) static int luaLcdDrawSource(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
int s = luaL_checkinteger(L, 3); int s = luaL_checkinteger(L, 3);
@ -532,7 +541,8 @@ Omitting scale draws image in 1:1 scale and is faster than specifying 100 for sc
*/ */
static int luaLcdDrawBitmap(lua_State *L) static int luaLcdDrawBitmap(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
const BitmapBuffer * b = checkBitmap(L, 1); const BitmapBuffer * b = checkBitmap(L, 1);
if (b) { if (b) {
@ -564,7 +574,8 @@ Draw a bitmap at (x,y)
*/ */
static int luaLcdDrawPixmap(lua_State *L) static int luaLcdDrawPixmap(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
const char * filename = luaL_checkstring(L, 3); const char * filename = luaL_checkstring(L, 3);
@ -597,7 +608,8 @@ Draw a rectangle from top left corner (x,y) of specified width and height
*/ */
static int luaLcdDrawRectangle(lua_State *L) static int luaLcdDrawRectangle(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3); int w = luaL_checkinteger(L, 3);
@ -629,7 +641,8 @@ Draw a solid rectangle from top left corner (x,y) of specified width and height
*/ */
static int luaLcdDrawFilledRectangle(lua_State *L) static int luaLcdDrawFilledRectangle(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3); int w = luaL_checkinteger(L, 3);
@ -661,7 +674,8 @@ Draw a simple gauge that is filled based upon fill value
*/ */
static int luaLcdDrawGauge(lua_State *L) static int luaLcdDrawGauge(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3); int w = luaL_checkinteger(L, 3);
@ -699,7 +713,8 @@ the right side of title bar. (i.e. idx=2, cnt=5, display `2/5`)
*/ */
static int luaLcdDrawScreenTitle(lua_State *L) static int luaLcdDrawScreenTitle(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
const char * str = luaL_checkstring(L, 1); const char * str = luaL_checkstring(L, 1);
int idx = luaL_checkinteger(L, 2); int idx = luaL_checkinteger(L, 2);
int cnt = luaL_checkinteger(L, 3); int cnt = luaL_checkinteger(L, 3);
@ -739,7 +754,8 @@ Draw a combo box
*/ */
static int luaLcdDrawCombobox(lua_State *L) static int luaLcdDrawCombobox(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int x = luaL_checkinteger(L, 1); int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3); int w = luaL_checkinteger(L, 3);
@ -818,7 +834,13 @@ Set a color for specific area
* `MENU_BGCOLOR` * `MENU_BGCOLOR`
* `HEADER_ICON_BGCOLOR` * `HEADER_ICON_BGCOLOR`
* `HEADER_CURRENT_BGCOLOR` * `HEADER_CURRENT_BGCOLOR`
* `MAINVIEW_PANES_COLOR`
* `MAINVIEW_GRAPHICS_COLOR`
* `OVERLAY_COLOR` * `OVERLAY_COLOR`
* `BARGRAPH1_COLOR`
* `BARGRAPH2_COLOR`
* `BARGRAPH_BGCOLOR`
* `CUSTOM_COLOR`
@param color (number) color in 5/6/5 rgb format. The following prefined colors are available @param color (number) color in 5/6/5 rgb format. The following prefined colors are available
* `WHITE` * `WHITE`
@ -831,19 +853,40 @@ Set a color for specific area
* `RED` * `RED`
* `DARKRED` * `DARKRED`
@notice Only available on Horus @notice Only available on Colorlcd radios
@status current Introduced in 2.2.0 @status current Introduced in 2.2.0
*/ */
static int luaLcdSetColor(lua_State *L) static int luaLcdSetColor(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
unsigned int index = luaL_checkunsigned(L, 1) >> 16; unsigned int index = luaL_checkunsigned(L, 1) >> 16;
unsigned int color = luaL_checkunsigned(L, 2); unsigned int color = luaL_checkunsigned(L, 2);
lcdColorTable[index] = color; lcdColorTable[index] = color;
return 0; return 0;
} }
/*luadoc
@function lcd.getColor(area)
Get the color for specific area : see lcd.setColor for area list
@notice Only available on Colorlcd radios
@status current Introduced in 2.3.11
*/
static int luaLcdGetColor(lua_State *L)
{
if (!luaLcdAllowed)
return 0;
unsigned int index = luaL_checkunsigned(L, 1) >> 16;
lua_pushunsigned(L, lcdColorTable[index]);
return 1;
}
/*luadoc /*luadoc
@function lcd.RGB(r, g, b) @function lcd.RGB(r, g, b)
@ -857,13 +900,14 @@ Returns a 5/6/5 rgb color code, that can be used with lcd.setColor
@retval number (integer) rgb color expressed in 5/6/5 format @retval number (integer) rgb color expressed in 5/6/5 format
@notice Only available on Horus @notice Only available on Colorlcd radios
@status current Introduced in 2.2.0 @status current Introduced in 2.2.0
*/ */
static int luaRGB(lua_State *L) static int luaRGB(lua_State *L)
{ {
if (!luaLcdAllowed) return 0; if (!luaLcdAllowed)
return 0;
int r = luaL_checkinteger(L, 1); int r = luaL_checkinteger(L, 1);
int g = luaL_checkinteger(L, 2); int g = luaL_checkinteger(L, 2);
int b = luaL_checkinteger(L, 3); int b = luaL_checkinteger(L, 3);
@ -890,6 +934,7 @@ const luaL_Reg lcdLib[] = {
#if defined(COLORLCD) #if defined(COLORLCD)
{ "drawBitmap", luaLcdDrawBitmap }, { "drawBitmap", luaLcdDrawBitmap },
{ "setColor", luaLcdSetColor }, { "setColor", luaLcdSetColor },
{ "getColor", luaLcdGetColor },
{ "RGB", luaRGB }, { "RGB", luaRGB },
#else #else
{ "getLastPos", luaLcdGetLastPos }, { "getLastPos", luaLcdGetLastPos },

View file

@ -1518,16 +1518,16 @@ Get Telemetry Sensor parameters
@param sensor (unsigned number) sensor number (use 0 for sensor 1) @param sensor (unsigned number) sensor number (use 0 for sensor 1)
@retval nil requested logical switch does not exist @retval nil requested sensor does not exist
@retval table logical switch data: @retval table with sensor data:
* `func` (number) function index * `type` (number) 0 = custom, 1 = calculated
* `v1` (number) V1 value (index) * `name` (string) Name
* `v2` (number) V2 value (index or value) * `unit` (number) See list of units in the appendix of the OpenTX Lua Reference Guide
* `v3` (number) V3 value (index or value) * `prec` (number) Number of decimals
* `and` (number) AND switch index * `id` (number) Only custom sensors
* `delay` (number) delay (time in 1/10 s) * `instance` (number) Only custom sensors
* `duration` (number) duration (time in 1/10 s) * `formula` (number) Only calculated sensors. 0 = Add etc. see list of formula choices in Companion popup
@status current Introduced in 2.3.0 @status current Introduced in 2.3.0
*/ */
@ -1564,7 +1564,7 @@ Reset Telemetry Sensor parameters
@retval nil @retval nil
@status current Introduced in 2.3.0 @status current Introduced in 2.3.11
*/ */
static int luaModelResetSensor(lua_State *L) static int luaModelResetSensor(lua_State *L)
{ {
@ -1572,7 +1572,7 @@ static int luaModelResetSensor(lua_State *L)
if (idx < MAX_TELEMETRY_SENSORS) { if (idx < MAX_TELEMETRY_SENSORS) {
telemetryItems[idx].clear(); telemetryItems[idx].clear();
} }
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
} }

View file

@ -18,8 +18,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef _OPENTX_H_ #pragma once
#define _OPENTX_H_
#include <stdlib.h> #include <stdlib.h>
#include "definitions.h" #include "definitions.h"
@ -1115,6 +1114,7 @@ union ReusableBuffer
#if defined(GHOST) #if defined(GHOST)
struct { struct {
GhostMenuData line[GHST_MENU_LINES + 1]; GhostMenuData line[GHST_MENU_LINES + 1];
uint8_t menuStatus;
uint8_t menuAction; uint8_t menuAction;
uint8_t buttonAction; uint8_t buttonAction;
} ghostMenu; } ghostMenu;
@ -1313,4 +1313,3 @@ inline bool isAsteriskDisplayed()
#include "thirdparty/libACCESS/libAccess.h" #include "thirdparty/libACCESS/libAccess.h"
#endif #endif
#endif // _OPENTX_H_

View file

@ -22,8 +22,6 @@
uint8_t createGhostMenuControlFrame(uint8_t * frame, int16_t * pulses) uint8_t createGhostMenuControlFrame(uint8_t * frame, int16_t * pulses)
{ {
moduleState[EXTERNAL_MODULE].counter = GHST_FRAME_CHANNEL;
uint8_t * buf = frame; uint8_t * buf = frame;
#if SPORT_MAX_BAUDRATE < 400000 #if SPORT_MAX_BAUDRATE < 400000
*buf++ = g_eeGeneral.telemetryBaudrate == GHST_TELEMETRY_RATE_400K ? GHST_ADDR_MODULE_SYM : GHST_ADDR_MODULE_ASYM; *buf++ = g_eeGeneral.telemetryBaudrate == GHST_TELEMETRY_RATE_400K ? GHST_ADDR_MODULE_SYM : GHST_ADDR_MODULE_ASYM;
@ -118,5 +116,7 @@ void setupPulsesGhost()
extmodulePulsesData.ghost.length = createGhostMenuControlFrame(pulses, &channelOutputs[g_model.moduleData[EXTERNAL_MODULE].channelsStart]); extmodulePulsesData.ghost.length = createGhostMenuControlFrame(pulses, &channelOutputs[g_model.moduleData[EXTERNAL_MODULE].channelsStart]);
else else
extmodulePulsesData.ghost.length = createGhostChannelsFrame(pulses, &channelOutputs[g_model.moduleData[EXTERNAL_MODULE].channelsStart]); extmodulePulsesData.ghost.length = createGhostChannelsFrame(pulses, &channelOutputs[g_model.moduleData[EXTERNAL_MODULE].channelsStart]);
moduleState[EXTERNAL_MODULE].counter = GHST_FRAME_CHANNEL;
} }
} }

View file

@ -121,7 +121,7 @@ enum ModuleSubtypeMulti {
MODULE_SUBTYPE_MULTI_MJXQ, MODULE_SUBTYPE_MULTI_MJXQ,
MODULE_SUBTYPE_MULTI_SHENQI, MODULE_SUBTYPE_MULTI_SHENQI,
MODULE_SUBTYPE_MULTI_FY326, MODULE_SUBTYPE_MULTI_FY326,
MODULE_SUBTYPE_MULTI_SFHSS, MODULE_SUBTYPE_MULTI_FUTABA,
MODULE_SUBTYPE_MULTI_J6PRO, //20 MODULE_SUBTYPE_MULTI_J6PRO, //20
MODULE_SUBTYPE_MULTI_FQ777, MODULE_SUBTYPE_MULTI_FQ777,
MODULE_SUBTYPE_MULTI_ASSAN, MODULE_SUBTYPE_MULTI_ASSAN,
@ -152,7 +152,7 @@ enum ModuleSubtypeMulti {
MODULE_SUBTYPE_MULTI_REDPINE, MODULE_SUBTYPE_MULTI_REDPINE,
MODULE_SUBTYPE_MULTI_POTENSIC, MODULE_SUBTYPE_MULTI_POTENSIC,
MODULE_SUBTYPE_MULTI_ZSX, MODULE_SUBTYPE_MULTI_ZSX,
MODULE_SUBTYPE_MULTI_FLYZONE, //50 MODULE_SUBTYPE_MULTI_HEIGHT, //50
MODULE_SUBTYPE_MULTI_SCANNER, MODULE_SUBTYPE_MULTI_SCANNER,
MODULE_SUBTYPE_MULTI_FRSKYX_RX, MODULE_SUBTYPE_MULTI_FRSKYX_RX,
MODULE_SUBTYPE_MULTI_AFHDS2A_RX, MODULE_SUBTYPE_MULTI_AFHDS2A_RX,
@ -172,7 +172,15 @@ enum ModuleSubtypeMulti {
MODULE_SUBTYPE_MULTI_DSM_RX, MODULE_SUBTYPE_MULTI_DSM_RX,
MODULE_SUBTYPE_MULTI_JJRC345, MODULE_SUBTYPE_MULTI_JJRC345,
MODULE_SUBTYPE_MULTI_Q90C, MODULE_SUBTYPE_MULTI_Q90C,
MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_Q90C MODULE_SUBTYPE_MULTI_KYOSHO, //70
MODULE_SUBTYPE_MULTI_RLINK,
MODULE_SUBTYPE_MULTI_ELRS,
MODULE_SUBTYPE_MULTI_REALACC,
MODULE_SUBTYPE_MULTI_OMP,
MODULE_SUBTYPE_MULTI_MLINK, //75
MODULE_SUBTYPE_MULTI_WFLY2,
MODULE_SUBTYPE_MULTI_E016HV2,
MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_E016HV2
}; };
#define MODULE_SUBTYPE_MULTI_XN297DP 63-3 #define MODULE_SUBTYPE_MULTI_XN297DP 63-3

View file

@ -284,9 +284,14 @@ inline bool isModulePXX1(uint8_t idx)
return isModuleTypePXX1(g_model.moduleData[idx].type); return isModuleTypePXX1(g_model.moduleData[idx].type);
} }
inline bool isModuleXJTLite(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_XJT_LITE_PXX2;
}
inline bool isModulePXX2(uint8_t idx) inline bool isModulePXX2(uint8_t idx)
{ {
return isModuleISRM(idx) || isModuleR9MAccess(idx); return isModuleISRM(idx) || isModuleR9MAccess(idx) || isModuleXJTLite(idx);
} }
inline bool isModuleRFAccess(uint8_t idx) inline bool isModuleRFAccess(uint8_t idx)

View file

@ -76,6 +76,7 @@ const char RADIO_SETTINGS_YAML_PATH[] = RADIO_PATH "/radio.yml";
#define SPORT_FIRMWARE_EXT ".frk" #define SPORT_FIRMWARE_EXT ".frk"
#define FRSKY_FIRMWARE_EXT ".frsk" #define FRSKY_FIRMWARE_EXT ".frsk"
#define MULTI_FIRMWARE_EXT ".bin" #define MULTI_FIRMWARE_EXT ".bin"
#define ELRS_FIRMWARE_EXT ".elrs"
#define YAML_EXT ".yml" #define YAML_EXT ".yml"
#if defined(COLORLCD) #if defined(COLORLCD)

View file

@ -236,12 +236,8 @@ set(FIRMWARE_TARGET_SRC
${FIRMWARE_TARGET_SRC} ${FIRMWARE_TARGET_SRC}
keys_driver.cpp keys_driver.cpp
diskio.cpp diskio.cpp
)
set(TARGET_SRC
${TARGET_SRC}
telemetry_driver.cpp telemetry_driver.cpp
) )
set(FIRMWARE_SRC set(FIRMWARE_SRC
${FIRMWARE_SRC} ${FIRMWARE_SRC}

View file

@ -150,7 +150,7 @@ void auxSerialInit(unsigned int mode, unsigned int protocol)
break; break;
case UART_MODE_SBUS_TRAINER: case UART_MODE_SBUS_TRAINER:
auxSerialSetup(SBUS_BAUDRATE, false, 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); // 2 stop bits requires USART_WordLength_9b
AUX_SERIAL_POWER_ON(); AUX_SERIAL_POWER_ON();
break; break;
@ -238,10 +238,6 @@ extern "C" void AUX_SERIAL_USART_IRQHandler(void)
#if defined(LUA) & !defined(CLI) #if defined(LUA) & !defined(CLI)
if (luaRxFifo && auxSerialMode == UART_MODE_LUA) if (luaRxFifo && auxSerialMode == UART_MODE_LUA)
luaRxFifo->push(data); luaRxFifo->push(data);
#endif
#if !defined(BOOT)
if (auxSerialMode == UART_MODE_SBUS_TRAINER)
trainerSbusFifo.push(data);
#endif #endif
} }
status = AUX_SERIAL_USART->SR; status = AUX_SERIAL_USART->SR;
@ -352,7 +348,7 @@ void aux2SerialInit(unsigned int mode, unsigned int protocol)
break; break;
case UART_MODE_SBUS_TRAINER: case UART_MODE_SBUS_TRAINER:
aux2SerialSetup(SBUS_BAUDRATE, false, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // 2 stop bits requires USART_WordLength_9b aux2SerialSetup(SBUS_BAUDRATE, true, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // 2 stop bits requires USART_WordLength_9b
AUX2_SERIAL_POWER_ON(); AUX2_SERIAL_POWER_ON();
break; break;
@ -438,11 +434,6 @@ extern "C" void AUX2_SERIAL_USART_IRQHandler(void)
if (luaRxFifo && aux2SerialMode == UART_MODE_LUA) { if (luaRxFifo && aux2SerialMode == UART_MODE_LUA) {
luaRxFifo->push(data); luaRxFifo->push(data);
} }
#endif
#if !defined(BOOT)
if (aux2SerialMode == UART_MODE_SBUS_TRAINER) {
trainerSbusFifo.push(data);
}
#endif #endif
} }
status = AUX2_SERIAL_USART->SR; status = AUX2_SERIAL_USART->SR;

View file

@ -54,28 +54,32 @@
* @{ * @{
*/ */
#define USBD_VID 0x0483 #define USBD_VID_STM 0x0483 // STM Vendor ID
#define USBD_VID_PID_CODES 0x1209 // https://pid.codes
#define USBD_LANGID_STRING 0x409 #define USBD_LANGID_STRING 0x409
#define USBD_MANUFACTURER_STRING "OpenTX"
#define USBD_SERIALNUMBER_FS_STRING "00000000001B" #define USBD_SERIALNUMBER_FS_STRING "00000000001B"
#if defined(BOOT) #if defined(BOOT)
#define USBD_MSC_PRODUCT_FS_STRING USB_NAME " Bootloader" #define USBD_MSC_PRODUCT_FS_STRING USB_NAME " Bootloader"
#else #else
#define USBD_MSC_PRODUCT_FS_STRING USB_NAME " Mass Storage" #define USBD_MSC_PRODUCT_FS_STRING USB_NAME " Mass Storage"
#endif #endif
#define USBD_MSC_VID USBD_VID_STM
#define USBD_MSC_PID 0x5720 #define USBD_MSC_PID 0x5720
#define USBD_MSC_CONFIGURATION_FS_STRING "MSC Config" #define USBD_MSC_CONFIGURATION_FS_STRING "MSC Config"
#define USBD_MSC_INTERFACE_FS_STRING "MSC Interface" #define USBD_MSC_INTERFACE_FS_STRING "MSC Interface"
#define USBD_HID_PID 0x5710 #define USBD_HID_VID USBD_VID_PID_CODES
#define USBD_HID_PID 0x4F54 // OpenTX assigned PID
#define USBD_HID_PRODUCT_FS_STRING USB_NAME " Joystick" #define USBD_HID_PRODUCT_FS_STRING USB_NAME " Joystick"
#define USBD_HID_CONFIGURATION_FS_STRING "HID Config" #define USBD_HID_CONFIGURATION_FS_STRING "HID Config"
#define USBD_HID_INTERFACE_FS_STRING "HID Interface" #define USBD_HID_INTERFACE_FS_STRING "HID Interface"
#define USBD_CDC_PID 0x5740 // do not change, this ID is used by the ST USB driver for Windows #define USBD_CDC_VID USBD_VID_STM
#define USBD_CDC_PID 0x5740 // do not change, this ID is used by the ST USB driver for Windows
#define USBD_CDC_PRODUCT_FS_STRING USB_NAME " Serial Port" #define USBD_CDC_PRODUCT_FS_STRING USB_NAME " Serial Port"
#define USBD_CDC_CONFIGURATION_FS_STRING "VSP Config" #define USBD_CDC_CONFIGURATION_FS_STRING "VSP Config"
#define USBD_CDC_INTERFACE_FS_STRING "VSP Interface" #define USBD_CDC_INTERFACE_FS_STRING "VSP Interface"
@ -125,20 +129,29 @@ __ALIGN_BEGIN uint8_t USBD_StrDesc[USB_MAX_STR_DESC_SIZ] __ALIGN_END ; // modifi
* @param length : pointer to data length variable * @param length : pointer to data length variable
* @retval pointer to descriptor buffer * @retval pointer to descriptor buffer
*/ */
uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length) uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length)
{ {
int pid=0; int vid, pid;
switch (getSelectedUsbMode()) { switch (getSelectedUsbMode()) {
case USB_JOYSTICK_MODE: case USB_JOYSTICK_MODE:
vid = USBD_HID_VID;
pid = USBD_HID_PID; pid = USBD_HID_PID;
break; break;
case USB_SERIAL_MODE: case USB_SERIAL_MODE:
vid = USBD_CDC_VID;
pid = USBD_CDC_PID; pid = USBD_CDC_PID;
break; break;
case USB_MASS_STORAGE_MODE: case USB_MASS_STORAGE_MODE:
vid = USBD_MSC_VID;
pid = USBD_MSC_PID; pid = USBD_MSC_PID;
break; break;
default:
vid = 0;
pid = 0;
} }
/* USB Standard Device Descriptor */ /* USB Standard Device Descriptor */
@ -152,10 +165,10 @@ uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length)
0x00, /*bDeviceSubClass*/ 0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/ 0x00, /*bDeviceProtocol*/
USB_OTG_MAX_EP0_SIZE, /*bMaxPacketSize*/ USB_OTG_MAX_EP0_SIZE, /*bMaxPacketSize*/
LOBYTE(USBD_VID), /*idVendor*/ LOBYTE(vid), /*idVendor*/
HIBYTE(USBD_VID), /*idVendor*/ HIBYTE(vid), /*idVendor*/
LOBYTE(pid), /*idVendor*/ LOBYTE(pid), /*idVendor*/
HIBYTE(pid), /*idVendor*/ HIBYTE(pid), /*idVendor*/
0x00, /*bcdDevice rel. 2.00*/ 0x00, /*bcdDevice rel. 2.00*/
0x02, 0x02,
USBD_IDX_MFC_STR, /*Index of manufacturer string*/ USBD_IDX_MFC_STR, /*Index of manufacturer string*/

View file

@ -637,7 +637,11 @@ void sportUpdatePowerInit();
#endif #endif
// Aux serial port driver // Aux serial port driver
#define DEBUG_BAUDRATE 115200 #if defined(RADIO_TX16S)
#define DEBUG_BAUDRATE 400000
#else
#define DEBUG_BAUDRATE 115200
#endif
#if defined(AUX_SERIAL_GPIO) #if defined(AUX_SERIAL_GPIO)
extern uint8_t auxSerialMode; extern uint8_t auxSerialMode;
void auxSerialInit(unsigned int mode, unsigned int protocol); void auxSerialInit(unsigned int mode, unsigned int protocol);
@ -711,6 +715,7 @@ void bluetoothDisable();
extern DMAFifo<512> telemetryFifo; extern DMAFifo<512> telemetryFifo;
typedef DMAFifo<32> AuxSerialRxFifo; typedef DMAFifo<32> AuxSerialRxFifo;
extern AuxSerialRxFifo auxSerialRxFifo; extern AuxSerialRxFifo auxSerialRxFifo;
extern AuxSerialRxFifo aux2SerialRxFifo;
extern volatile uint32_t externalModulePort; extern volatile uint32_t externalModulePort;
#endif #endif

View file

@ -160,9 +160,16 @@ extern "C" void TRAINER_TIMER_IRQHandler()
int sbusGetByte(uint8_t * byte) int sbusGetByte(uint8_t * byte)
{ {
switch (currentTrainerMode) { switch (currentTrainerMode) {
#if defined(AUX_SERIAL) #if defined(AUX_SERIAL) || defined(AUX2_SERIAL)
case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT:
return trainerSbusFifo.pop(*byte); #if defined(AUX_SERIAL)
if (auxSerialMode == UART_MODE_SBUS_TRAINER)
return auxSerialRxFifo.pop(*byte);
#endif
#if defined(AUX2_SERIAL)
if (aux2SerialMode == UART_MODE_SBUS_TRAINER)
return aux2SerialRxFifo.pop(*byte);
#endif
#endif #endif
default: default:
return false; return false;

View file

@ -42,6 +42,8 @@ char * main_thread_error = nullptr;
bool simu_shutdown = false; bool simu_shutdown = false;
bool simu_running = false; bool simu_running = false;
uint32_t telemetryErrors = 0;
#if defined(STM32) #if defined(STM32)
GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, gpioh, gpioi, gpioj; GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, gpioh, gpioi, gpioj;
TIM_TypeDef tim1, tim2, tim3, tim4, tim5, tim6, tim7, tim8, tim9, tim10; TIM_TypeDef tim1, tim2, tim3, tim4, tim5, tim6, tim7, tim8, tim9, tim10;
@ -470,6 +472,47 @@ void sportUpdatePowerInit()
{ {
} }
void telemetryPortSetDirectionInput()
{
}
void telemetryPortSetDirectionOutput()
{
}
void rxPdcUsart( void (*pChProcess)(uint8_t x) )
{
}
void telemetryPortInit(uint32_t baudrate, uint8_t mode)
{
}
bool telemetryGetByte(uint8_t * byte)
{
return false;
}
void telemetryClearFifo()
{
}
void telemetryPortInvertedInit(uint32_t baudrate)
{
}
void sportSendByte(uint8_t byte)
{
}
void sportSendBuffer(const uint8_t * buffer, uint32_t count)
{
}
void check_telemetry_exti()
{
}
void boardInit() void boardInit()
{ {
} }

View file

@ -125,9 +125,13 @@ set(FIRMWARE_TARGET_SRC
MEDSdcard.c MEDSdcard.c
) )
set(FIRMWARE_TARGET_SRC
${FIRMWARE_TARGET_SRC}
telemetry_driver.cpp
)
set(TARGET_SRC set(TARGET_SRC
${TARGET_SRC} ${TARGET_SRC}
telemetry_driver.cpp
adc_driver.cpp adc_driver.cpp
pulses_driver.cpp pulses_driver.cpp
audio_driver.cpp audio_driver.cpp

View file

@ -399,10 +399,8 @@ void debugPutc(const char c);
// Telemetry driver // Telemetry driver
void telemetryPortInit(uint32_t baudrate, uint8_t mode); void telemetryPortInit(uint32_t baudrate, uint8_t mode);
inline void telemetryPortSetDirectionOutput() void telemetryPortSetDirectionOutput();
{ void telemetryPortSetDirectionInput();
}
uint32_t telemetryTransmitPending();
void telemetryTransmitBuffer(const uint8_t * buffer, uint32_t size); void telemetryTransmitBuffer(const uint8_t * buffer, uint32_t size);
void rxPdcUsart( void (*pChProcess)(uint8_t x) ); void rxPdcUsart( void (*pChProcess)(uint8_t x) );
void sportSendBuffer(const uint8_t * buffer, uint32_t size); void sportSendBuffer(const uint8_t * buffer, uint32_t size);

View file

@ -93,10 +93,8 @@ void startPdcUsartReceive()
{ {
Usart *pUsart = SECOND_USART; Usart *pUsart = SECOND_USART;
TelemetryInBuffer.outPtr = TelemetryInBuffer.fifo ; TelemetryInBuffer.outPtr = TelemetryInBuffer.fifo ;
#ifndef SIMU
pUsart->US_RPR = (uint32_t)TelemetryInBuffer.fifo ; pUsart->US_RPR = (uint32_t)TelemetryInBuffer.fifo ;
pUsart->US_RNPR = (uint32_t)TelemetryInBuffer.fifo ; pUsart->US_RNPR = (uint32_t)TelemetryInBuffer.fifo ;
#endif
pUsart->US_RCR = RX_UART_BUFFER_SIZE ; pUsart->US_RCR = RX_UART_BUFFER_SIZE ;
pUsart->US_RNCR = RX_UART_BUFFER_SIZE ; pUsart->US_RNCR = RX_UART_BUFFER_SIZE ;
pUsart->US_PTCR = US_PTCR_RXTEN ; pUsart->US_PTCR = US_PTCR_RXTEN ;
@ -104,7 +102,6 @@ void startPdcUsartReceive()
void rxPdcUsart( void (*pChProcess)(uint8_t x) ) void rxPdcUsart( void (*pChProcess)(uint8_t x) )
{ {
#if !defined(SIMU)
Usart *pUsart = SECOND_USART; Usart *pUsart = SECOND_USART;
uint8_t *ptr ; uint8_t *ptr ;
uint8_t *endPtr ; uint8_t *endPtr ;
@ -132,7 +129,6 @@ void rxPdcUsart( void (*pChProcess)(uint8_t x) )
pUsart->US_RNPR = (uint32_t)TelemetryInBuffer.fifo ; pUsart->US_RNPR = (uint32_t)TelemetryInBuffer.fifo ;
pUsart->US_RNCR = RX_UART_BUFFER_SIZE ; pUsart->US_RNCR = RX_UART_BUFFER_SIZE ;
} }
#endif
} }
uint32_t txPdcUsart(const uint8_t * buffer, uint32_t size) uint32_t txPdcUsart(const uint8_t * buffer, uint32_t size)
@ -140,9 +136,7 @@ uint32_t txPdcUsart(const uint8_t * buffer, uint32_t size)
Usart * pUsart = SECOND_USART; Usart * pUsart = SECOND_USART;
if (pUsart->US_TNCR == 0) { if (pUsart->US_TNCR == 0) {
#ifndef SIMU
pUsart->US_TNPR = (uint32_t)buffer ; pUsart->US_TNPR = (uint32_t)buffer ;
#endif
pUsart->US_TNCR = size ; pUsart->US_TNCR = size ;
pUsart->US_PTCR = US_PTCR_TXTEN ; pUsart->US_PTCR = US_PTCR_TXTEN ;
return 1 ; return 1 ;
@ -150,6 +144,7 @@ uint32_t txPdcUsart(const uint8_t * buffer, uint32_t size)
return 0 ; return 0 ;
} }
/*
uint32_t telemetryTransmitPending() uint32_t telemetryTransmitPending()
{ {
Usart *pUsart = SECOND_USART; Usart *pUsart = SECOND_USART;
@ -164,13 +159,20 @@ uint32_t telemetryTransmitPending()
return x ; return x ;
} }
*/
void telemetryPortSetDirectionOutput()
{
}
void telemetryPortSetDirectionInput()
{
}
void telemetryPortInit(uint32_t baudrate, uint8_t mode) void telemetryPortInit(uint32_t baudrate, uint8_t mode)
{ {
#if !defined(SIMU)
UART2_Configure(baudrate, Master_frequency, mode); UART2_Configure(baudrate, Master_frequency, mode);
startPdcUsartReceive(); startPdcUsartReceive();
#endif
} }
void sportSendBuffer(const uint8_t * buffer, uint32_t size) void sportSendBuffer(const uint8_t * buffer, uint32_t size)

View file

@ -135,7 +135,6 @@ elseif(PCB STREQUAL X7)
set(LUA_EXPORT lua_export_t12) set(LUA_EXPORT lua_export_t12)
add_definitions(-DRADIO_T12) add_definitions(-DRADIO_T12)
add_definitions(-DEEPROM_VARIANT=0x4001) add_definitions(-DEEPROM_VARIANT=0x4001)
add_definitions(-DMANUFACTURER_JUMPER)
elseif(PCBREV STREQUAL TX12) elseif(PCBREV STREQUAL TX12)
option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" ON) option(INTERNAL_MODULE_MULTI "Support for MULTI internal module" ON)
set(FLAVOUR tx12) set(FLAVOUR tx12)
@ -146,6 +145,7 @@ elseif(PCB STREQUAL X7)
set(ROTARY_ENCODER YES) set(ROTARY_ENCODER YES)
set(LUA_EXPORT lua_export_tx12) set(LUA_EXPORT lua_export_tx12)
set(BLUETOOTH NO) set(BLUETOOTH NO)
set(USB_CHARGER YES)
add_definitions(-DRADIO_TX12) add_definitions(-DRADIO_TX12)
add_definitions(-DEEPROM_VARIANT=0x4002) add_definitions(-DEEPROM_VARIANT=0x4002)
add_definitions(-DMANUFACTURER_RADIOMASTER) add_definitions(-DMANUFACTURER_RADIOMASTER)
@ -347,6 +347,11 @@ if(ROTARY_ENCODER)
) )
endif() endif()
if(USB_CHARGER)
set(TARGET_SRC ${TARGET_SRC} usb_charger_driver.cpp)
add_definitions(-DUSB_CHARGER)
endif()
if(BLUETOOTH) if(BLUETOOTH)
add_definitions(-DBLUETOOTH) add_definitions(-DBLUETOOTH)
set(TARGET_SRC set(TARGET_SRC

View file

@ -92,7 +92,8 @@ void boardInit()
TRAINER_RCC_AHB1Periph | TRAINER_RCC_AHB1Periph |
TRAINER_MODULE_RCC_AHB1Periph | TRAINER_MODULE_RCC_AHB1Periph |
BT_RCC_AHB1Periph | BT_RCC_AHB1Periph |
GYRO_RCC_AHB1Periph, GYRO_RCC_AHB1Periph |
USB_CHARGER_RCC_AHB1Periph,
ENABLE); ENABLE);
RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph | RCC_APB1PeriphClockCmd(ROTARY_ENCODER_RCC_APB1Periph |
@ -193,6 +194,10 @@ void boardInit()
toplcdInit(); toplcdInit();
#endif #endif
#if defined(USB_CHARGER)
usbChargerInit();
#endif
if (HAS_SPORT_UPDATE_CONNECTOR()) { if (HAS_SPORT_UPDATE_CONNECTOR()) {
sportUpdateInit(); sportUpdateInit();
} }

View file

@ -863,6 +863,10 @@ void bluetoothDisable();
#define IS_BLUETOOTH_CHIP_PRESENT() (true) #define IS_BLUETOOTH_CHIP_PRESENT() (true)
#endif #endif
// USB Charger
void usbChargerInit();
bool usbChargerLed();
// LED driver // LED driver
void ledInit(); void ledInit();
void ledOff(); void ledOff();

View file

@ -1431,6 +1431,16 @@
#define PCBREV_RCC_AHB1Periph 0 #define PCBREV_RCC_AHB1Periph 0
#endif #endif
// USB Charger
#if defined(USB_CHARGER)
#define USB_CHARGER_RCC_AHB1Periph RCC_AHB1Periph_GPIOB
#define USB_CHARGER_GPIO GPIOB
#define USB_CHARGER_GPIO_PIN GPIO_Pin_5 // PB.05
#else
#define USB_CHARGER_RCC_AHB1Periph 0
#endif
// S.Port update connector // S.Port update connector
#if defined(PCBXLITE) #if defined(PCBXLITE)
#define SPORT_MAX_BAUDRATE 250000 // not tested #define SPORT_MAX_BAUDRATE 250000 // not tested
@ -1446,7 +1456,7 @@
#define SPORT_UPDATE_PWR_GPIO_PIN GPIO_Pin_3 // PB.03 #define SPORT_UPDATE_PWR_GPIO_PIN GPIO_Pin_3 // PB.03
#define GPIO_SPORT_UPDATE_PWR_GPIO_ON GPIO_SetBits #define GPIO_SPORT_UPDATE_PWR_GPIO_ON GPIO_SetBits
#define GPIO_SPORT_UPDATE_PWR_GPIO_OFF GPIO_ResetBits #define GPIO_SPORT_UPDATE_PWR_GPIO_OFF GPIO_ResetBits
#elif defined(PCBX7) #elif defined(RADIO_X7)
#define SPORT_MAX_BAUDRATE 250000 // < 400000 #define SPORT_MAX_BAUDRATE 250000 // < 400000
#define SPORT_UPDATE_RCC_AHB1Periph RCC_AHB1Periph_GPIOB #define SPORT_UPDATE_RCC_AHB1Periph RCC_AHB1Periph_GPIOB
#define SPORT_UPDATE_PWR_GPIO GPIOB #define SPORT_UPDATE_PWR_GPIO GPIOB

View file

@ -0,0 +1,37 @@
/*
* 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"
void usbChargerInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = USB_CHARGER_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(USB_CHARGER_GPIO, &GPIO_InitStructure);
}
bool usbChargerLed()
{
return (GPIO_ReadInputDataBit(USB_CHARGER_GPIO, USB_CHARGER_GPIO_PIN) == Bit_RESET && usbPlugged());
}

View file

@ -192,11 +192,10 @@ void processGhostTelemetryFrame()
{ {
GhostMenuFrame * packet; GhostMenuFrame * packet;
GhostMenuData * lineData; GhostMenuData * lineData;
packet = (GhostMenuFrame * ) telemetryRxBuffer; packet = (GhostMenuFrame * ) telemetryRxBuffer;
lineData = (GhostMenuData *) &reusableBuffer.ghostMenu.line[packet->lineIndex]; lineData = (GhostMenuData *) &reusableBuffer.ghostMenu.line[packet->lineIndex];
lineData->splitLine = 0; lineData->splitLine = 0;
reusableBuffer.ghostMenu.menuAction = packet->menuFlags; reusableBuffer.ghostMenu.menuStatus = packet->menuStatus;
lineData->lineFlags = packet->lineFlags; lineData->lineFlags = packet->lineFlags;
for (uint8_t i = 0; i < GHST_MENU_CHARS; i++) { for (uint8_t i = 0; i < GHST_MENU_CHARS; i++) {
if (packet->menuText[i] == 0x7C) { if (packet->menuText[i] == 0x7C) {
@ -208,8 +207,6 @@ void processGhostTelemetryFrame()
} }
} }
lineData->menuText[GHST_MENU_CHARS] = '\0'; lineData->menuText[GHST_MENU_CHARS] = '\0';
if (packet->lineIndex == GHST_MENU_LINES - 1)
lineData->menuUpdateNeeded = true;
break; break;
} }

View file

@ -142,6 +142,13 @@ enum GhostMenuControl
GHST_MENU_CTRL_REDRAW = 0X04, GHST_MENU_CTRL_REDRAW = 0X04,
}; };
enum GhostMenuStatus
{
GHST_MENU_STATUS_UNOPENED = 0x00,
GHST_MENU_STATUS_OPENED = 0x01,
GHST_MENU_STATUS_CLOSING = 0x02,
};
enum GhostFrames enum GhostFrames
{ {
GHST_FRAME_CHANNEL, GHST_FRAME_CHANNEL,
@ -157,8 +164,8 @@ struct GhostMenuFrame
uint8_t address; uint8_t address;
uint8_t length ; uint8_t length ;
uint8_t packetId; uint8_t packetId;
uint8_t menuFlags; // GHST_MENU_CTRL uint8_t menuStatus; // GhostMenuStatus
uint8_t lineFlags; // Carat states, Inverse, Bold for each of Menu Label, and Value uint8_t lineFlags; // GhostLineFlags
uint8_t lineIndex; // 0 = first line uint8_t lineIndex; // 0 = first line
unsigned char menuText[GHST_MENU_CHARS]; unsigned char menuText[GHST_MENU_CHARS];
uint8_t crc; uint8_t crc;
@ -166,9 +173,9 @@ struct GhostMenuFrame
struct GhostMenuData struct GhostMenuData
{ {
uint8_t menuFlags; // Update Line, Clear Menu, etc. uint8_t menuStatus; // Update Line, Clear Menu, etc.
uint8_t lineFlags; // Carat states, Inverse, Bold for each of Menu Label, and Value uint8_t lineFlags; // Carat states, Inverse, Bold for each of Menu Label, and Value
uint8_t splitLine; // Store beginning of Value substring uint8_t splitLine; // Store beginning of Value substring
char menuText[GHST_MENU_CHARS + 1]; char menuText[GHST_MENU_CHARS + 1];
uint8_t menuUpdateNeeded;
}; };

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