Merge branch '2.3' into 2.4
@@ -6,7 +6,7 @@ set(VERSION_REVISION "0")
|
||||
set(VERSION_SUFFIX $ENV{OPENTX_VERSION_SUFFIX})
|
||||
set(VERSION_FAMILY ${VERSION_MAJOR}.${VERSION_MINOR})
|
||||
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}${VERSION_SUFFIX})
|
||||
set(SDCARD_REVISION "0036")
|
||||
set(SDCARD_REVISION "0037")
|
||||
set(SDCARD_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}V${SDCARD_REVISION})
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
@@ -2237,3 +2237,33 @@ Glenn Noonan
|
||||
Michael Jakob
|
||||
Dean Berg
|
||||
David Hankins
|
||||
Gary Cripps
|
||||
Devin Crumb
|
||||
Daniel Naude
|
||||
James Miller
|
||||
Pascal Cayol
|
||||
eDefine
|
||||
Mario Sette
|
||||
Hans-Georg Böhm
|
||||
Robert Oats
|
||||
Helmut Suhrbier
|
||||
Johannes Vorster
|
||||
Deon du Rand
|
||||
Stephen Hill-Harriss
|
||||
Regi Pradeeswaran
|
||||
Gary Busler
|
||||
Stefano Boggia
|
||||
Vernon Martin
|
||||
Alexander W Wilson Jr
|
||||
Adam Bowersock
|
||||
Gary Burrows
|
||||
Mark Gaskievicz
|
||||
James Miller
|
||||
Donald Taylor
|
||||
Paul Makepeace
|
||||
Thomas Fowler
|
||||
Walter Szempruch
|
||||
Charles Starck
|
||||
Fabian Mächler
|
||||
David Van Dyne
|
||||
Karim el Mawardi
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "boards.h"
|
||||
#include "macros.h"
|
||||
#include "compounditemmodels.h"
|
||||
|
||||
// TODO remove all those constants
|
||||
// Update: These are now all only used within this class.
|
||||
@@ -374,7 +375,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
|
||||
case MultiposPotsPositions:
|
||||
return IS_HORUS_OR_TARANIS(board) ? 6 : 0;
|
||||
|
||||
case Switches:
|
||||
case Board::Switches:
|
||||
if (IS_TARANIS_X9E(board))
|
||||
return 18;
|
||||
else if (board == Board::BOARD_TARANIS_X9LITE)
|
||||
@@ -410,11 +411,11 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
|
||||
else if (IS_HORUS_X12S(board))
|
||||
return 8;
|
||||
else
|
||||
return getCapability(board, Switches);
|
||||
return getCapability(board, Board::Switches);
|
||||
|
||||
case SwitchPositions:
|
||||
if (IS_HORUS_OR_TARANIS(board))
|
||||
return getCapability(board, Switches) * 3;
|
||||
return getCapability(board, Board::Switches) * 3;
|
||||
else
|
||||
return 9;
|
||||
|
||||
@@ -425,10 +426,14 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
|
||||
return 4;
|
||||
|
||||
case NumTrimSwitches:
|
||||
return getCapability(board, NumTrims) * 2;
|
||||
}
|
||||
return getCapability(board, Board::NumTrims) * 2;
|
||||
|
||||
return 0;
|
||||
case HasRTC:
|
||||
return IS_STM32(board) ? true : false;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QString Boards::getAxisName(int index)
|
||||
@@ -444,7 +449,7 @@ QString Boards::getAxisName(int index)
|
||||
if (index < (int)DIM(axes))
|
||||
return axes[index];
|
||||
else
|
||||
return tr("Unknown");
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
|
||||
QString Boards::getAnalogInputName(Board::Type board, int index)
|
||||
@@ -595,6 +600,96 @@ QString Boards::getBoardName(Board::Type board)
|
||||
case BOARD_RADIOMASTER_T8:
|
||||
return "Radiomaster T8";
|
||||
default:
|
||||
return tr("Unknown");
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
QString Boards::potTypeToString(int value)
|
||||
{
|
||||
switch(value) {
|
||||
case POT_NONE:
|
||||
return tr("None");
|
||||
case POT_WITH_DETENT:
|
||||
return tr("Pot with detent");
|
||||
case POT_MULTIPOS_SWITCH:
|
||||
return tr("Multi pos switch");
|
||||
case POT_WITHOUT_DETENT:
|
||||
return tr("Pot without detent");
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
QString Boards::sliderTypeToString(int value)
|
||||
{
|
||||
switch(value) {
|
||||
case SLIDER_NONE:
|
||||
return tr("None");
|
||||
case SLIDER_WITH_DETENT:
|
||||
return tr("Slider with detent");
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
QString Boards::switchTypeToString(int value)
|
||||
{
|
||||
switch(value) {
|
||||
case SWITCH_NOT_AVAILABLE:
|
||||
return tr("None");
|
||||
case SWITCH_TOGGLE:
|
||||
return tr("2 Positions Toggle");
|
||||
case SWITCH_2POS:
|
||||
return tr("2 Positions");
|
||||
case SWITCH_3POS:
|
||||
return tr("3 Positions");
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * Boards::potTypeItemModel()
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName(AIM_BOARDS_POT_TYPE);
|
||||
|
||||
for (int i = 0; i < POT_TYPE_COUNT; i++) {
|
||||
mdl->appendToItemList(potTypeToString(i), i);
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * Boards::sliderTypeItemModel()
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName(AIM_BOARDS_SLIDER_TYPE);
|
||||
|
||||
for (int i = 0; i < SLIDER_TYPE_COUNT; i++) {
|
||||
mdl->appendToItemList(sliderTypeToString(i), i);
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * Boards::switchTypeItemModel()
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName(AIM_BOARDS_SWITCH_TYPE);
|
||||
|
||||
for (int i = 0; i < SWITCH_TYPE_COUNT; i++) {
|
||||
mdl->appendToItemList(switchTypeToString(i), i, true, 0, (i < SWITCH_3POS ? SwitchTypeFlag2Pos : SwitchTypeFlag3Pos));
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
@@ -18,13 +18,19 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _BOARDS_H_
|
||||
#define _BOARDS_H_
|
||||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class AbstractStaticItemModel;
|
||||
|
||||
// identiying names of static abstract item models
|
||||
constexpr char AIM_BOARDS_POT_TYPE[] {"boards.pottype"};
|
||||
constexpr char AIM_BOARDS_SLIDER_TYPE[] {"boards.slidertype"};
|
||||
constexpr char AIM_BOARDS_SWITCH_TYPE[] {"boards.switchtype"};
|
||||
|
||||
// TODO create a Board class with all these functions
|
||||
|
||||
namespace Board {
|
||||
@@ -64,13 +70,15 @@ namespace Board {
|
||||
POT_NONE,
|
||||
POT_WITH_DETENT,
|
||||
POT_MULTIPOS_SWITCH,
|
||||
POT_WITHOUT_DETENT
|
||||
POT_WITHOUT_DETENT,
|
||||
POT_TYPE_COUNT
|
||||
};
|
||||
|
||||
enum SliderType
|
||||
{
|
||||
SLIDER_NONE,
|
||||
SLIDER_WITH_DETENT
|
||||
SLIDER_WITH_DETENT,
|
||||
SLIDER_TYPE_COUNT
|
||||
};
|
||||
|
||||
enum SwitchType
|
||||
@@ -78,7 +86,8 @@ namespace Board {
|
||||
SWITCH_NOT_AVAILABLE,
|
||||
SWITCH_TOGGLE,
|
||||
SWITCH_2POS,
|
||||
SWITCH_3POS
|
||||
SWITCH_3POS,
|
||||
SWITCH_TYPE_COUNT
|
||||
};
|
||||
|
||||
enum StickAxes {
|
||||
@@ -130,7 +139,8 @@ namespace Board {
|
||||
SwitchPositions,
|
||||
FactoryInstalledSwitches,
|
||||
NumTrims,
|
||||
NumTrimSwitches
|
||||
NumTrimSwitches,
|
||||
HasRTC
|
||||
};
|
||||
|
||||
struct SwitchInfo
|
||||
@@ -149,6 +159,13 @@ namespace Board {
|
||||
unsigned int position;
|
||||
};
|
||||
|
||||
enum SwitchTypeMasks {
|
||||
SwitchTypeFlag2Pos = 0x01,
|
||||
SwitchTypeFlag3Pos = 0x02,
|
||||
SwitchTypeContext2Pos = SwitchTypeFlag2Pos,
|
||||
SwitchTypeContext3Pos = SwitchTypeFlag2Pos | SwitchTypeFlag3Pos
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class Boards
|
||||
@@ -182,6 +199,12 @@ class Boards
|
||||
static QString getAnalogInputName(Board::Type board, int index);
|
||||
static bool isBoardCompatible(Board::Type board1, Board::Type board2);
|
||||
static QString getBoardName(Board::Type board);
|
||||
static QString potTypeToString(int value);
|
||||
static QString sliderTypeToString(int value);
|
||||
static QString switchTypeToString(int value);
|
||||
static AbstractStaticItemModel * potTypeItemModel();
|
||||
static AbstractStaticItemModel * sliderTypeItemModel();
|
||||
static AbstractStaticItemModel * switchTypeItemModel();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -361,5 +384,3 @@ inline bool IS_ACCESS_RADIO(Board::Type board, const QString & id)
|
||||
return (IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board) || board == Board::BOARD_TARANIS_X9DP_2019 || board == Board::BOARD_X10_EXPRESS || IS_TARANIS_X7_ACCESS(board) ||
|
||||
(IS_FAMILY_HORUS_OR_T16(board) && id.contains("internalaccess")));
|
||||
}
|
||||
|
||||
#endif // _BOARDS_H_
|
||||
|
||||
@@ -134,7 +134,6 @@ enum Capability {
|
||||
VirtualInputs,
|
||||
InputsLength,
|
||||
TrainerInputs,
|
||||
RtcTime,
|
||||
SportTelemetry,
|
||||
LuaScripts,
|
||||
LuaInputsPerScript,
|
||||
@@ -153,7 +152,13 @@ enum Capability {
|
||||
HasSwitchableJack,
|
||||
HasSportConnector,
|
||||
PwrButtonPress,
|
||||
Sensors
|
||||
Sensors,
|
||||
HasAuxSerialMode,
|
||||
HasAux2SerialMode,
|
||||
HasBluetooth,
|
||||
HasAntennaChoice,
|
||||
HasADCJitterFilter,
|
||||
HasTelemetryBaudrate
|
||||
};
|
||||
|
||||
class EEPROMInterface
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "appdata.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "compounditemmodels.h"
|
||||
|
||||
const uint8_t chout_ar[] = { // First number is 0..23 -> template setup, Second is relevant channel out
|
||||
1,2,3,4 , 1,2,4,3 , 1,3,2,4 , 1,3,4,2 , 1,4,2,3 , 1,4,3,2,
|
||||
@@ -36,7 +37,7 @@ bool GeneralSettings::switchPositionAllowedTaranis(int index) const
|
||||
if (index == 0)
|
||||
return true;
|
||||
|
||||
div_t qr = div(abs(index)-1, 3);
|
||||
div_t qr = div(abs(index) - 1, 3);
|
||||
|
||||
if (index < 0 && switchConfig[qr.quot] != Board::SWITCH_3POS)
|
||||
return false;
|
||||
@@ -53,14 +54,14 @@ bool GeneralSettings::switchSourceAllowedTaranis(int index) const
|
||||
|
||||
bool GeneralSettings::isPotAvailable(int index) const
|
||||
{
|
||||
if (index < 0 || index > getBoardCapability(getCurrentBoard(), Board::Pots))
|
||||
if (index < 0 || index > Boards::getCapability(getCurrentBoard(), Board::Pots))
|
||||
return false;
|
||||
return potConfig[index] != Board::POT_NONE;
|
||||
}
|
||||
|
||||
bool GeneralSettings::isSliderAvailable(int index) const
|
||||
{
|
||||
if (index < 0 || index > getBoardCapability(getCurrentBoard(), Board::Sliders))
|
||||
if (index < 0 || index > Boards::getCapability(getCurrentBoard(), Board::Sliders))
|
||||
return false;
|
||||
return sliderConfig[index] != Board::SLIDER_NONE;
|
||||
}
|
||||
@@ -71,7 +72,7 @@ GeneralSettings::GeneralSettings()
|
||||
|
||||
contrast = 25;
|
||||
|
||||
for (int i=0; i < CPN_MAX_ANALOGS; ++i) {
|
||||
for (int i = 0; i < CPN_MAX_ANALOGS; ++i) {
|
||||
calibMid[i] = 0x200;
|
||||
calibSpanNeg[i] = 0x180;
|
||||
calibSpanPos[i] = 0x180;
|
||||
@@ -128,7 +129,7 @@ GeneralSettings::GeneralSettings()
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
trainer.mix[i].mode = 2; // replace (:=)
|
||||
trainer.mix[i].mode = TrainerMix::TRN_MIX_MODE_SUBST;
|
||||
trainer.mix[i].src = i;
|
||||
trainer.mix[i].weight = 100;
|
||||
}
|
||||
@@ -387,3 +388,265 @@ void GeneralSettings::convert(RadioDataConversionState & cstate)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QString GeneralSettings::antennaModeToString() const
|
||||
{
|
||||
return antennaModeToString(antennaMode);
|
||||
}
|
||||
|
||||
QString GeneralSettings::bluetoothModeToString() const
|
||||
{
|
||||
return bluetoothModeToString(bluetoothMode);
|
||||
}
|
||||
|
||||
QString GeneralSettings::auxSerialModeToString() const
|
||||
{
|
||||
return auxSerialModeToString(auxSerialMode);
|
||||
}
|
||||
|
||||
QString GeneralSettings::telemetryBaudrateToString() const
|
||||
{
|
||||
return telemetryBaudrateToString(telemetryBaudrate);
|
||||
}
|
||||
|
||||
// static
|
||||
QString GeneralSettings::antennaModeToString(int value)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
|
||||
switch(value) {
|
||||
case ANTENNA_MODE_INTERNAL:
|
||||
return tr("Internal");
|
||||
case ANTENNA_MODE_ASK:
|
||||
return tr("Ask");
|
||||
case ANTENNA_MODE_PER_MODEL:
|
||||
return tr("Per model");
|
||||
case ANTENNA_MODE_EXTERNAL:
|
||||
// case ANTENNA_MODE_INTERNAL_EXTERNAL:
|
||||
return IS_HORUS_X12S(board) ? tr("Internal + External") : tr("External");
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
QString GeneralSettings::bluetoothModeToString(int value)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
|
||||
switch(value) {
|
||||
case BLUETOOTH_MODE_OFF:
|
||||
return tr("OFF");
|
||||
case BLUETOOTH_MODE_ENABLED:
|
||||
// case BLUETOOTH_MODE_TELEMETRY:
|
||||
return IS_TARANIS_X9E(board) ? tr("Enabled") : tr("Telemetry");
|
||||
case BLUETOOTH_MODE_TRAINER:
|
||||
return tr("Trainer");
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
QString GeneralSettings::auxSerialModeToString(int value)
|
||||
{
|
||||
switch(value) {
|
||||
case AUX_SERIAL_OFF:
|
||||
return tr("OFF");
|
||||
case AUX_SERIAL_TELE_MIRROR:
|
||||
return tr("Telemetry Mirror");
|
||||
case AUX_SERIAL_TELE_IN:
|
||||
return tr("Telemetry In");
|
||||
case AUX_SERIAL_SBUS_TRAINER:
|
||||
return tr("SBUS Trainer");
|
||||
case AUX_SERIAL_LUA:
|
||||
return tr("LUA");
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
QString GeneralSettings::telemetryBaudrateToString(int value)
|
||||
{
|
||||
switch(value) {
|
||||
case 0:
|
||||
return "400000";
|
||||
case 1:
|
||||
return "115200";
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
FieldRange GeneralSettings::getPPM_MultiplierRange()
|
||||
{
|
||||
FieldRange result;
|
||||
|
||||
result.min = 0;
|
||||
result.max = 5;
|
||||
result.decimals = 1;
|
||||
result.step = 0.1;
|
||||
result.offset = 10;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
FieldRange GeneralSettings::getTxVoltageCalibrationRange()
|
||||
{
|
||||
FieldRange result;
|
||||
|
||||
result.decimals = 1;
|
||||
result.max = 9.9;
|
||||
result.min = -result.max;
|
||||
result.step = 0.1;
|
||||
result.unit = tr("v");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
FieldRange GeneralSettings::getTxCurrentCalibration()
|
||||
{
|
||||
FieldRange result;
|
||||
|
||||
result.max = 49;
|
||||
result.min = -result.max;
|
||||
result.unit = tr("mA");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * GeneralSettings::antennaModeItemModel()
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName(AIM_GS_ANTENNAMODE);
|
||||
|
||||
for (int i = ANTENNA_MODE_FIRST; i <= ANTENNA_MODE_LAST; i++) {
|
||||
mdl->appendToItemList(antennaModeToString(i), i);
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * GeneralSettings::bluetoothModeItemModel()
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName(AIM_GS_BLUETOOTHMODE);
|
||||
|
||||
for (int i = 0; i < BLUETOOTH_MODE_COUNT; i++) {
|
||||
mdl->appendToItemList(bluetoothModeToString(i), i);
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * GeneralSettings::auxSerialModeItemModel()
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName(AIM_GS_AUXSERIALMODE);
|
||||
|
||||
for (int i = 0; i < AUX_SERIAL_COUNT; i++) {
|
||||
mdl->appendToItemList(auxSerialModeToString(i), i);
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * GeneralSettings::telemetryBaudrateItemModel()
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName(AIM_GS_TELEMETRYBAUDRATE);
|
||||
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
mdl->appendToItemList(telemetryBaudrateToString(i), i);
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
/*
|
||||
TrainerMix
|
||||
*/
|
||||
|
||||
QString TrainerMix::modeToString() const
|
||||
{
|
||||
return modeToString(mode);
|
||||
}
|
||||
|
||||
QString TrainerMix::srcToString() const
|
||||
{
|
||||
return srcToString(src);
|
||||
}
|
||||
|
||||
// static
|
||||
FieldRange TrainerMix::getWeightRange()
|
||||
{
|
||||
FieldRange result;
|
||||
|
||||
result.decimals = 0;
|
||||
result.max = 125;
|
||||
result.min = -result.max;
|
||||
result.step = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
QString TrainerMix::modeToString(int value)
|
||||
{
|
||||
switch(value) {
|
||||
case TRN_MIX_MODE_OFF:
|
||||
return tr("OFF");
|
||||
case TRN_MIX_MODE_ADD:
|
||||
return tr("+= (Sum)");
|
||||
case TRN_MIX_MODE_SUBST:
|
||||
return tr(":= (Replace)");
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
QString TrainerMix::srcToString(int value)
|
||||
{
|
||||
return tr("CH%1").arg(value + 1);
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * TrainerMix::modeItemModel()
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName(AIM_TRAINERMIX_MODE);
|
||||
|
||||
for (int i = 0; i < TRN_MIX_MODE_COUNT; i++) {
|
||||
mdl->appendToItemList(modeToString(i), i);
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * TrainerMix::srcItemModel()
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName(AIM_TRAINERMIX_SRC);
|
||||
|
||||
for (int i = 0; i < Boards::getCapability(getCurrentBoard(), Board::Sticks); i++) {
|
||||
mdl->appendToItemList(srcToString(i), i);
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef GENERALSETTINGS_H
|
||||
#define GENERALSETTINGS_H
|
||||
#pragma once
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
#include "customfunctiondata.h"
|
||||
#include "rawsource.h"
|
||||
#include "datahelpers.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
@@ -32,6 +32,15 @@ class Firmware;
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
class AbstractStaticItemModel;
|
||||
|
||||
// identiying names of static abstract item models
|
||||
constexpr char AIM_GS_ANTENNAMODE[] {"gs.antennamode"};
|
||||
constexpr char AIM_GS_BLUETOOTHMODE[] {"gs.bluetoothmode"};
|
||||
constexpr char AIM_GS_AUXSERIALMODE[] {"gs.auxserialmode"};
|
||||
constexpr char AIM_GS_TELEMETRYBAUDRATE[] {"gs.telemetrybaudrate"};
|
||||
constexpr char AIM_TRAINERMIX_MODE[] {"trainermix.mode"};
|
||||
constexpr char AIM_TRAINERMIX_SRC[] {"trainermix.src"};
|
||||
|
||||
enum UartModes {
|
||||
UART_MODE_NONE,
|
||||
@@ -42,23 +51,52 @@ enum UartModes {
|
||||
};
|
||||
|
||||
class TrainerMix {
|
||||
Q_DECLARE_TR_FUNCTIONS(TrainerMix)
|
||||
|
||||
public:
|
||||
enum TrainerMixModes {
|
||||
TRN_MIX_MODE_OFF,
|
||||
TRN_MIX_MODE_ADD,
|
||||
TRN_MIX_MODE_SUBST,
|
||||
TRN_MIX_MODE_COUNT
|
||||
};
|
||||
|
||||
TrainerMix() { clear(); }
|
||||
|
||||
unsigned int src; // 0-7 = ch1-8
|
||||
RawSwitch swtch;
|
||||
int weight;
|
||||
unsigned int mode; // off, add-mode, subst-mode
|
||||
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(TrainerMix)); }
|
||||
QString modeToString() const;
|
||||
QString srcToString() const;
|
||||
|
||||
static FieldRange getWeightRange();
|
||||
static QString modeToString(int value);
|
||||
static QString srcToString(int value);
|
||||
static AbstractStaticItemModel * modeItemModel();
|
||||
static AbstractStaticItemModel * srcItemModel();
|
||||
};
|
||||
|
||||
class TrainerData {
|
||||
public:
|
||||
TrainerData() { clear(); }
|
||||
int calib[4];
|
||||
TrainerMix mix[4];
|
||||
|
||||
int calib[4];
|
||||
TrainerMix mix[4];
|
||||
|
||||
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(TrainerData)); }
|
||||
};
|
||||
|
||||
constexpr int CURR_MODEL_FILENAME_LEN {16};
|
||||
constexpr int OWNER_NAME_LEN {10};
|
||||
constexpr int BLUETOOTH_NAME_LEN {10};
|
||||
constexpr int TTS_LANGUAGE_LEN {2};
|
||||
constexpr int HARDWARE_NAME_LEN {3};
|
||||
constexpr int THEME_NAME_LEN {8};
|
||||
constexpr int REGISTRATION_ID_LEN {8};
|
||||
|
||||
class GeneralSettings {
|
||||
Q_DECLARE_TR_FUNCTIONS(GeneralSettings)
|
||||
|
||||
@@ -71,6 +109,36 @@ class GeneralSettings {
|
||||
BEEPER_ALL = 1
|
||||
};
|
||||
|
||||
enum BluetoothMode {
|
||||
BLUETOOTH_MODE_OFF,
|
||||
BLUETOOTH_MODE_ENABLED,
|
||||
BLUETOOTH_MODE_TELEMETRY = BLUETOOTH_MODE_ENABLED,
|
||||
BLUETOOTH_MODE_TRAINER,
|
||||
BLUETOOTH_MODE_COUNT
|
||||
};
|
||||
|
||||
enum AntennaMode {
|
||||
ANTENNA_MODE_INTERNAL = -2,
|
||||
ANTENNA_MODE_FIRST = ANTENNA_MODE_INTERNAL,
|
||||
ANTENNA_MODE_ASK,
|
||||
ANTENNA_MODE_PER_MODEL,
|
||||
ANTENNA_MODE_EXTERNAL,
|
||||
ANTENNA_MODE_INTERNAL_EXTERNAL = ANTENNA_MODE_EXTERNAL,
|
||||
ANTENNA_MODE_LAST = ANTENNA_MODE_INTERNAL_EXTERNAL
|
||||
};
|
||||
|
||||
enum AuxSerialMode {
|
||||
AUX_SERIAL_OFF,
|
||||
AUX_SERIAL_TELE_MIRROR,
|
||||
AUX_SERIAL_TELE_IN,
|
||||
AUX_SERIAL_SBUS_TRAINER,
|
||||
AUX_SERIAL_LUA,
|
||||
AUX_SERIAL_COUNT
|
||||
};
|
||||
|
||||
enum TelemetryBaudrate {
|
||||
};
|
||||
|
||||
GeneralSettings();
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
@@ -81,61 +149,61 @@ class GeneralSettings {
|
||||
|
||||
unsigned int version;
|
||||
unsigned int variant;
|
||||
int calibMid[CPN_MAX_ANALOGS];
|
||||
int calibSpanNeg[CPN_MAX_ANALOGS];
|
||||
int calibSpanPos[CPN_MAX_ANALOGS];
|
||||
unsigned int currModelIndex;
|
||||
char currModelFilename[16+1];
|
||||
unsigned int contrast;
|
||||
unsigned int vBatWarn;
|
||||
int txVoltageCalibration;
|
||||
int txCurrentCalibration;
|
||||
int vBatMin;
|
||||
int vBatMax;
|
||||
int backlightMode;
|
||||
int calibMid[CPN_MAX_ANALOGS];
|
||||
int calibSpanNeg[CPN_MAX_ANALOGS];
|
||||
int calibSpanPos[CPN_MAX_ANALOGS];
|
||||
unsigned int currModelIndex;
|
||||
char currModelFilename[CURR_MODEL_FILENAME_LEN + 1];
|
||||
unsigned int contrast;
|
||||
unsigned int vBatWarn;
|
||||
int txVoltageCalibration;
|
||||
int txCurrentCalibration;
|
||||
int vBatMin;
|
||||
int vBatMax;
|
||||
int backlightMode;
|
||||
TrainerData trainer;
|
||||
unsigned int view; // main screen view // TODO enum
|
||||
bool disableThrottleWarning;
|
||||
bool fai;
|
||||
bool disableMemoryWarning;
|
||||
unsigned int view; // main screen view // TODO enum
|
||||
bool disableThrottleWarning;
|
||||
bool fai;
|
||||
bool disableMemoryWarning;
|
||||
BeeperMode beeperMode;
|
||||
bool disableAlarmWarning;
|
||||
bool disableRssiPoweroffAlarm;
|
||||
unsigned int usbMode;
|
||||
unsigned int jackMode;
|
||||
bool sportPower;
|
||||
bool disableAlarmWarning;
|
||||
bool disableRssiPoweroffAlarm;
|
||||
unsigned int usbMode;
|
||||
unsigned int jackMode;
|
||||
bool sportPower;
|
||||
BeeperMode hapticMode;
|
||||
unsigned int stickMode; // TODO enum
|
||||
int timezone;
|
||||
bool adjustRTC;
|
||||
bool optrexDisplay;
|
||||
unsigned int inactivityTimer;
|
||||
unsigned int telemetryBaudrate;
|
||||
bool minuteBeep;
|
||||
bool preBeep;
|
||||
bool flashBeep;
|
||||
unsigned int splashMode;
|
||||
unsigned int stickMode; // TODO enum
|
||||
int timezone;
|
||||
bool adjustRTC;
|
||||
bool optrexDisplay;
|
||||
unsigned int inactivityTimer;
|
||||
unsigned int telemetryBaudrate;
|
||||
bool minuteBeep;
|
||||
bool preBeep;
|
||||
bool flashBeep;
|
||||
unsigned int splashMode;
|
||||
int splashDuration;
|
||||
unsigned int backlightDelay;
|
||||
unsigned int templateSetup; //RETA order according to chout_ar array
|
||||
int PPM_Multiplier;
|
||||
int hapticLength;
|
||||
unsigned int reNavigation;
|
||||
unsigned int backlightDelay;
|
||||
unsigned int templateSetup; //RETA order according to chout_ar array
|
||||
int PPM_Multiplier;
|
||||
int hapticLength;
|
||||
unsigned int reNavigation;
|
||||
unsigned int stickReverse;
|
||||
unsigned int speakerPitch;
|
||||
int hapticStrength;
|
||||
unsigned int speakerMode;
|
||||
char ownerName[10+1];
|
||||
int beeperLength;
|
||||
unsigned int gpsFormat;
|
||||
int speakerVolume;
|
||||
unsigned int backlightBright;
|
||||
unsigned int backlightOffBright;
|
||||
unsigned int speakerPitch;
|
||||
int hapticStrength;
|
||||
unsigned int speakerMode;
|
||||
char ownerName[OWNER_NAME_LEN + 1];
|
||||
int beeperLength;
|
||||
unsigned int gpsFormat;
|
||||
int speakerVolume;
|
||||
unsigned int backlightBright;
|
||||
unsigned int backlightOffBright;
|
||||
int switchesDelay;
|
||||
unsigned int mAhWarn;
|
||||
unsigned int mAhUsed;
|
||||
unsigned int globalTimer;
|
||||
char bluetoothName[10+1];
|
||||
char bluetoothName[BLUETOOTH_NAME_LEN + 1];
|
||||
unsigned int bluetoothBaudrate;
|
||||
unsigned int bluetoothMode;
|
||||
unsigned int sticksGain;
|
||||
@@ -145,7 +213,7 @@ class GeneralSettings {
|
||||
bool rtcCheckDisable;
|
||||
bool keysBacklight;
|
||||
unsigned int imperial;
|
||||
char ttsLanguage[2+1];
|
||||
char ttsLanguage[TTS_LANGUAGE_LEN + 1];
|
||||
int beepVolume;
|
||||
int wavVolume;
|
||||
int varioVolume;
|
||||
@@ -156,33 +224,47 @@ class GeneralSettings {
|
||||
unsigned int mavbaud;
|
||||
unsigned int switchUnlockStates;
|
||||
unsigned int auxSerialMode;
|
||||
unsigned int aux2SerialMode;
|
||||
int antennaMode;
|
||||
unsigned int backlightColor;
|
||||
CustomFunctionData customFn[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
char switchName[CPN_MAX_SWITCHES][3+1];
|
||||
char switchName[CPN_MAX_SWITCHES][HARDWARE_NAME_LEN + 1];
|
||||
unsigned int switchConfig[CPN_MAX_SWITCHES];
|
||||
char stickName[CPN_MAX_STICKS][3+1];
|
||||
char potName[CPN_MAX_KNOBS][3+1];
|
||||
char stickName[CPN_MAX_STICKS][HARDWARE_NAME_LEN + 1];
|
||||
char potName[CPN_MAX_KNOBS][HARDWARE_NAME_LEN + 1];
|
||||
unsigned int potConfig[CPN_MAX_KNOBS];
|
||||
char sliderName[CPN_MAX_SLIDERS][3+1];
|
||||
char sliderName[CPN_MAX_SLIDERS][HARDWARE_NAME_LEN + 1];
|
||||
unsigned int sliderConfig[CPN_MAX_SLIDERS];
|
||||
|
||||
char themeName[8+1];
|
||||
typedef uint8_t ThemeOptionData[8+1];
|
||||
char themeName[THEME_NAME_LEN + 1];
|
||||
typedef uint8_t ThemeOptionData[8 + 1];
|
||||
ThemeOptionData themeOptionValue[5];
|
||||
|
||||
char registrationId[8+1];
|
||||
|
||||
char registrationId[REGISTRATION_ID_LEN + 1];
|
||||
int gyroMax;
|
||||
int gyroOffset;
|
||||
|
||||
int pwrOnSpeed;
|
||||
int pwrOffSpeed;
|
||||
|
||||
|
||||
bool switchPositionAllowedTaranis(int index) const;
|
||||
bool switchSourceAllowedTaranis(int index) const;
|
||||
bool isPotAvailable(int index) const;
|
||||
bool isSliderAvailable(int index) const;
|
||||
QString antennaModeToString() const;
|
||||
QString bluetoothModeToString() const;
|
||||
QString auxSerialModeToString() const;
|
||||
QString telemetryBaudrateToString() const;
|
||||
|
||||
static QString antennaModeToString(int value);
|
||||
static QString bluetoothModeToString(int value);
|
||||
static QString auxSerialModeToString(int value);
|
||||
static QString telemetryBaudrateToString(int value);
|
||||
static FieldRange getPPM_MultiplierRange();
|
||||
static FieldRange getTxVoltageCalibrationRange();
|
||||
static FieldRange getTxCurrentCalibration();
|
||||
static AbstractStaticItemModel * antennaModeItemModel();
|
||||
static AbstractStaticItemModel * bluetoothModeItemModel();
|
||||
static AbstractStaticItemModel * auxSerialModeItemModel();
|
||||
static AbstractStaticItemModel * telemetryBaudrateItemModel();
|
||||
};
|
||||
|
||||
|
||||
#endif // GENERALSETTINGS_H
|
||||
|
||||
@@ -45,19 +45,6 @@ bool ModuleData::isPxx2Module() const
|
||||
}
|
||||
}
|
||||
|
||||
bool ModuleData::isPxx1Module() const
|
||||
{
|
||||
switch(protocol){
|
||||
case PULSES_PXX_XJT_X16:
|
||||
case PULSES_PXX_R9M:
|
||||
case PULSES_PXX_R9M_LITE:
|
||||
case PULSES_PXX_R9M_LITE_PRO:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ModuleData::supportRxNum() const
|
||||
{
|
||||
switch (protocol) {
|
||||
|
||||
@@ -215,12 +215,12 @@ class ModuleData {
|
||||
struct Access {
|
||||
unsigned int receivers;
|
||||
char receiverName[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME+1];
|
||||
unsigned int racingMode;
|
||||
} access;
|
||||
|
||||
void clear() { memset(this, 0, sizeof(ModuleData)); }
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
bool isPxx2Module() const;
|
||||
bool isPxx1Module() const;
|
||||
bool supportRxNum() const;
|
||||
QString polarityToString() const { return ppm.pulsePol ? tr("Positive") : tr("Negative"); }
|
||||
QString rfProtocolToString() const;
|
||||
|
||||
@@ -2158,15 +2158,16 @@ class ModuleUnionField: public UnionField<unsigned int> {
|
||||
module(module)
|
||||
{
|
||||
internalField.Append(new UnsignedField<3>(this, module.access.receivers));
|
||||
internalField.Append(new SpareBitsField<5>(this));
|
||||
internalField.Append(new SpareBitsField<4>(this));
|
||||
internalField.Append(new UnsignedField<1>(this, module.access.racingMode));
|
||||
|
||||
for (int i=0; i<PXX2_MAX_RECEIVERS_PER_MODULE; i++)
|
||||
for (int i = 0; i < PXX2_MAX_RECEIVERS_PER_MODULE; i++)
|
||||
internalField.Append(new CharField<8>(this, receiverName[i]));
|
||||
|
||||
memset(receiverName, 0, sizeof(receiverName));
|
||||
}
|
||||
|
||||
bool select(const unsigned int& attr) const override
|
||||
bool select(const unsigned int & attr) const override
|
||||
{
|
||||
return attr >= PULSES_ACCESS_ISRM && attr <= PULSES_ACCESS_R9M_LITE_PRO;
|
||||
}
|
||||
@@ -2759,7 +2760,7 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
|
||||
if (version >= 218) {
|
||||
internalField.Append(new UnsignedField<4>(this, generalData.auxSerialMode));
|
||||
if (IS_FAMILY_HORUS_OR_T16(board) && version >= 219) {
|
||||
internalField.Append(new SpareBitsField<4>(this));
|
||||
internalField.Append(new UnsignedField<4>(this, generalData.aux2SerialMode));
|
||||
}
|
||||
else {
|
||||
for (uint8_t i=0; i<SLIDERS_CONFIG_SIZE(board,version); i++) {
|
||||
|
||||
@@ -663,8 +663,6 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
return HAS_LARGE_LCD(board) ? 4 : 3;
|
||||
case TrainerInputs:
|
||||
return 16;
|
||||
case RtcTime:
|
||||
return 1;
|
||||
case LuaScripts:
|
||||
return IS_HORUS_OR_TARANIS(board) && id.contains("lua") ? 7 : 0;
|
||||
case LuaInputsPerScript:
|
||||
@@ -725,6 +723,19 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
return 60;
|
||||
else
|
||||
return 40;
|
||||
case HasAuxSerialMode:
|
||||
return (IS_FAMILY_HORUS_OR_T16(board) && !IS_TARANIS_SMALL(board)) ? true : false;
|
||||
case HasAux2SerialMode:
|
||||
return (IS_FAMILY_HORUS_OR_T16(board) && !IS_TARANIS_SMALL(board)) ? true : false;
|
||||
case HasBluetooth:
|
||||
return (IS_FAMILY_HORUS_OR_T16(board) || IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board)|| IS_TARANIS_X9E(board) || IS_TARANIS_X9DP_2019(board)) ? true : false;
|
||||
case HasAntennaChoice:
|
||||
return ((IS_FAMILY_HORUS_OR_T16(board) && board != Board::BOARD_X10_EXPRESS) || (IS_TARANIS_XLITE(board) && !IS_TARANIS_XLITES(board))) ? true : false;
|
||||
case HasADCJitterFilter:
|
||||
return IS_HORUS_OR_TARANIS(board) ? true : false;
|
||||
case HasTelemetryBaudrate:
|
||||
return IS_HORUS_OR_TARANIS(board) ? true : false;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
result.min = -30000 * result.step;
|
||||
result.max = +30000 * result.step;
|
||||
result.decimals = sensor.prec;
|
||||
result.unit = SensorData::unitToString(qr.quot);
|
||||
result.unit = sensor.unitToString();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -351,8 +351,11 @@ RawSource RawSource::convert(RadioDataConversionState & cstate)
|
||||
if (type == SOURCE_TYPE_SWITCH) {
|
||||
QStringList fromSwitchList(getSwitchList(cstate.fromBoard));
|
||||
QStringList toSwitchList(getSwitchList(cstate.toBoard));
|
||||
index = toSwitchList.indexOf(fromSwitchList.at(oldData.id));
|
||||
// index set to -1 if no match found
|
||||
if (oldData.id < fromSwitchList.count())
|
||||
index = toSwitchList.indexOf(fromSwitchList.at(oldData.id));
|
||||
else
|
||||
index = -1;
|
||||
// perform forced mapping
|
||||
if (index < 0) {
|
||||
if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
|
||||
|
||||
@@ -191,7 +191,10 @@ RawSwitch RawSwitch::convert(RadioDataConversionState & cstate)
|
||||
QStringList fromSwitchList(getSwitchList(cstate.fromBoard));
|
||||
QStringList toSwitchList(getSwitchList(cstate.toBoard));
|
||||
// set to -1 if no match found
|
||||
newIdx = toSwitchList.indexOf(fromSwitchList.at(swtch.quot));
|
||||
if (swtch.quot < fromSwitchList.count())
|
||||
newIdx = toSwitchList.indexOf(fromSwitchList.at(swtch.quot));
|
||||
else
|
||||
newIdx = -1;
|
||||
// perform forced mapping
|
||||
if (newIdx < 0) {
|
||||
if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_FAMILY_HORUS_OR_T16(cstate.fromType))) {
|
||||
|
||||
@@ -75,9 +75,9 @@ QString SensorData::cellIndexToString() const
|
||||
return cellIndexToString(index);
|
||||
}
|
||||
|
||||
QString SensorData::unitToString() const
|
||||
QString SensorData::unitToString(bool hideRaw) const
|
||||
{
|
||||
return unitToString(unit);
|
||||
return unitToString(unit, hideRaw);
|
||||
}
|
||||
|
||||
QString SensorData::precToString() const
|
||||
@@ -342,11 +342,11 @@ QString SensorData::sourceToString(const ModelData * model, const int index, con
|
||||
}
|
||||
|
||||
// static
|
||||
QString SensorData::unitToString(const int value)
|
||||
QString SensorData::unitToString(const int value, bool hideRaw)
|
||||
{
|
||||
switch (value) {
|
||||
case UNIT_RAW:
|
||||
return tr("Raw (-)");
|
||||
return hideRaw ? QString() : tr("Raw (-)");
|
||||
case UNIT_VOLTS:
|
||||
return tr("V");
|
||||
case UNIT_AMPS:
|
||||
@@ -496,7 +496,7 @@ AbstractStaticItemModel * SensorData::unitItemModel()
|
||||
mdl->setName("sensordata.unit");
|
||||
|
||||
for (int i = 0; i <= UNIT_MAX; i++) {
|
||||
QString str = unitToString(i);
|
||||
QString str = unitToString(i, false);
|
||||
if (str != CPN_STR_UNKNOWN_ITEM)
|
||||
mdl->appendToItemList(str, i);
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ class SensorData {
|
||||
QString typeToString() const;
|
||||
QString formulaToString() const;
|
||||
QString cellIndexToString() const;
|
||||
QString unitToString() const;
|
||||
QString unitToString(bool hideRaw = true) const;
|
||||
QString precToString() const;
|
||||
int getMask() const;
|
||||
QString paramsToString(const ModelData * model) const;
|
||||
@@ -203,7 +203,7 @@ class SensorData {
|
||||
static QString typeToString(const int value);
|
||||
static QString formulaToString(const int value);
|
||||
static QString cellIndexToString(const int value);
|
||||
static QString unitToString(const int value);
|
||||
static QString unitToString(const int value, bool hideRaw = true);
|
||||
static QString precToString(const int value);
|
||||
static bool isRssiSensorAvailable(const ModelData * model, const int value);
|
||||
static QString rssiSensorToString(const ModelData * model, const int value);
|
||||
|
||||
@@ -3,16 +3,18 @@ include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(generaledit_NAMES
|
||||
generaledit
|
||||
generalsetup
|
||||
trainer
|
||||
hardware
|
||||
)
|
||||
|
||||
set(generaledit_SRCS
|
||||
calibration.cpp
|
||||
hardware.cpp
|
||||
trainer.cpp
|
||||
)
|
||||
|
||||
set(generaledit_HDRS
|
||||
calibration.h
|
||||
hardware.h
|
||||
trainer.h
|
||||
)
|
||||
|
||||
set(generaledit_UIS
|
||||
|
||||
@@ -18,93 +18,45 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QSpinBox>
|
||||
#include "calibration.h"
|
||||
|
||||
#include "autospinbox.h"
|
||||
#include "helpers.h"
|
||||
|
||||
CalibrationPanel::CalibrationPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
GeneralPanel(parent, generalSettings, firmware)
|
||||
{
|
||||
int rows = Boards::getCapability(getCurrentBoard(), Board::MaxAnalogs);
|
||||
|
||||
tableWidget = new QTableWidget();
|
||||
QVBoxLayout * layout = new QVBoxLayout();
|
||||
layout->addWidget(tableWidget);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->setLayout(layout);
|
||||
|
||||
tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
tableWidget->setColumnCount(3);
|
||||
tableWidget->setShowGrid(false);
|
||||
tableWidget->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
tableWidget->setFrameStyle(QFrame::NoFrame | QFrame::Plain);
|
||||
tableWidget->setStyleSheet("QTableWidget {background-color: transparent;}");
|
||||
QStringList headerLabels;
|
||||
headerLabels << tr("Negative span") << tr("Mid value") << tr("Positive span");
|
||||
tableWidget->setHorizontalHeaderLabels(headerLabels);
|
||||
headerLabels << "" << tr("Negative span") << tr("Mid value") << tr("Positive span");
|
||||
|
||||
int rows = getBoardCapability(getCurrentBoard(), Board::MaxAnalogs);
|
||||
tableWidget->setRowCount(rows);
|
||||
TableLayout * tableLayout = new TableLayout(this, rows, headerLabels);
|
||||
|
||||
for(int i = 0; i < rows; ++i) {
|
||||
for (int i = 0; i < rows; i++) {
|
||||
int col = 0;
|
||||
QLabel * label = new QLabel(this);
|
||||
label->setText(firmware->getAnalogInputName(i));
|
||||
tableLayout->addWidget(i, col++, label);
|
||||
|
||||
QTableWidgetItem *newItem = new QTableWidgetItem(firmware->getAnalogInputName(i));
|
||||
newItem->setTextAlignment(Qt::AlignLeft);
|
||||
tableWidget->setVerticalHeaderItem(i, newItem);
|
||||
QLineEdit * leNeg = new QLineEdit(this);
|
||||
leNeg->setText(QString("%1").arg(generalSettings.calibSpanNeg[i]));
|
||||
leNeg->setReadOnly(true);
|
||||
tableLayout->addWidget(i, col++, leNeg);
|
||||
|
||||
for(int j = 0; j < 3; ++j) {
|
||||
QSpinBox * newItem = new QSpinBox();
|
||||
newItem->setMinimum(-9999);
|
||||
newItem->setMaximum(9999);
|
||||
newItem->setSingleStep(1);
|
||||
newItem->setValue(getCalibrationValue(i, j));
|
||||
newItem->setProperty("row", i);
|
||||
newItem->setProperty("column", j);
|
||||
tableWidget->setCellWidget(i, j, newItem);
|
||||
connect(newItem, SIGNAL(valueChanged(int)), this, SLOT(onCellChanged(int)));
|
||||
}
|
||||
QLineEdit * leMid = new QLineEdit(this);
|
||||
leMid->setText(QString("%1").arg(generalSettings.calibMid[i]));
|
||||
leMid->setReadOnly(true);
|
||||
tableLayout->addWidget(i, col++, leMid);
|
||||
|
||||
QLineEdit * lePos = new QLineEdit(this);
|
||||
lePos->setText(QString("%1").arg(generalSettings.calibSpanPos[i]));
|
||||
lePos->setReadOnly(true);
|
||||
tableLayout->addWidget(i, col++, lePos);
|
||||
}
|
||||
|
||||
disableMouseScrolling();
|
||||
}
|
||||
|
||||
void CalibrationPanel::onCellChanged(int value)
|
||||
{
|
||||
QSpinBox * sb = qobject_cast<QSpinBox*>(sender());
|
||||
int row = sb->property("row").toInt();
|
||||
int column = sb->property("column").toInt();
|
||||
|
||||
if (value != getCalibrationValue(row, column)) {
|
||||
setCalibrationValue(row,column, value);
|
||||
qDebug() << "CalibrationPanel::onCellChanged" << row << column << "to" << value;
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
int CalibrationPanel::getCalibrationValue(int row, int column)
|
||||
{
|
||||
switch(column) {
|
||||
case 0:
|
||||
return generalSettings.calibSpanNeg[row];
|
||||
case 1:
|
||||
return generalSettings.calibMid[row];
|
||||
case 2:
|
||||
return generalSettings.calibSpanPos[row];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CalibrationPanel::setCalibrationValue(int row, int column, int value)
|
||||
{
|
||||
switch(column) {
|
||||
case 0:
|
||||
generalSettings.calibSpanNeg[row] = value;
|
||||
break;
|
||||
case 1:
|
||||
generalSettings.calibMid[row] = value;
|
||||
break;
|
||||
case 2:
|
||||
generalSettings.calibSpanPos[row] = value;
|
||||
break;
|
||||
}
|
||||
tableLayout->resizeColumnsToContents();
|
||||
tableLayout->setColumnWidth(0, QString(15, ' '));
|
||||
tableLayout->pushColumnsLeft(headerLabels.count());
|
||||
tableLayout->pushRowsUp(rows + 1);
|
||||
}
|
||||
|
||||
@@ -18,20 +18,10 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _CALIBRATION_H_
|
||||
#define _CALIBRATION_H_
|
||||
#pragma once
|
||||
|
||||
#include <QTableWidget>
|
||||
#include "generaledit.h"
|
||||
|
||||
namespace Ui {
|
||||
class Calibration;
|
||||
}
|
||||
|
||||
class QLabel;
|
||||
class AutoLineEdit;
|
||||
class AutoComboBox;
|
||||
|
||||
class CalibrationPanel : public GeneralPanel
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -40,14 +30,5 @@ class CalibrationPanel : public GeneralPanel
|
||||
CalibrationPanel(QWidget *parent, GeneralSettings & generalSettings, Firmware * firmware);
|
||||
virtual ~CalibrationPanel() {};
|
||||
|
||||
private slots:
|
||||
void onCellChanged(int value);
|
||||
|
||||
private:
|
||||
QTableWidget * tableWidget;
|
||||
|
||||
int getCalibrationValue(int row, int column);
|
||||
void setCalibrationValue(int row, int column, int value);
|
||||
};
|
||||
|
||||
#endif // _CALIBRATION_H_
|
||||
|
||||
@@ -46,26 +46,27 @@ GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * fir
|
||||
}
|
||||
|
||||
ui->profile_CB->clear();
|
||||
for (int i=0; i<MAX_PROFILES; ++i) {
|
||||
for (int i = 0; i < MAX_PROFILES; ++i) {
|
||||
QString name=g.profile[i].name();
|
||||
if (!name.isEmpty()) {
|
||||
ui->profile_CB->addItem(name, i);
|
||||
if (i==g.id()) {
|
||||
ui->profile_CB->setCurrentIndex(ui->profile_CB->count()-1);
|
||||
if (i == g.id()) {
|
||||
ui->profile_CB->setCurrentIndex(ui->profile_CB->count() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sharedItemModels = new CompoundItemModelFactory(&generalSettings, nullptr);
|
||||
sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSource);
|
||||
sharedItemModels->addItemModel(AbstractItemModel::IMID_RawSwitch);
|
||||
sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncAction);
|
||||
sharedItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncResetParam);
|
||||
editorItemModels = new CompoundItemModelFactory(&generalSettings, nullptr);
|
||||
// tabs created below expect these item models to be pre-registered
|
||||
editorItemModels->addItemModel(AbstractItemModel::IMID_RawSource);
|
||||
editorItemModels->addItemModel(AbstractItemModel::IMID_RawSwitch);
|
||||
editorItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncAction);
|
||||
editorItemModels->addItemModel(AbstractItemModel::IMID_CustomFuncResetParam);
|
||||
|
||||
addTab(new GeneralSetupPanel(this, generalSettings, firmware), tr("Setup"));
|
||||
addTab(new CustomFunctionsPanel(this, nullptr, generalSettings, firmware, sharedItemModels), tr("Global Functions"));
|
||||
addTab(new TrainerPanel(this, generalSettings, firmware), tr("Trainer"));
|
||||
addTab(new HardwarePanel(this, generalSettings, firmware), tr("Hardware"));
|
||||
addTab(new CustomFunctionsPanel(this, nullptr, generalSettings, firmware, editorItemModels), tr("Global Functions"));
|
||||
addTab(new TrainerPanel(this, generalSettings, firmware, editorItemModels), tr("Trainer"));
|
||||
addTab(new HardwarePanel(this, generalSettings, firmware, editorItemModels), tr("Hardware"));
|
||||
addTab(new CalibrationPanel(this, generalSettings, firmware), tr("Calibration"));
|
||||
|
||||
ui->tabWidget->setCurrentIndex( g.generalEditTab() );
|
||||
@@ -74,7 +75,7 @@ GeneralEdit::GeneralEdit(QWidget * parent, RadioData & radioData, Firmware * fir
|
||||
GeneralEdit::~GeneralEdit()
|
||||
{
|
||||
delete ui;
|
||||
delete sharedItemModels;
|
||||
delete editorItemModels; // cleans up item models registered by the tabs
|
||||
}
|
||||
|
||||
void GeneralEdit::closeEvent(QCloseEvent *event)
|
||||
@@ -90,7 +91,7 @@ void GeneralEdit::addTab(GenericPanel *panel, QString text)
|
||||
VerticalScrollArea * area = new VerticalScrollArea(widget, panel);
|
||||
baseLayout->addWidget(area);
|
||||
ui->tabWidget->addTab(widget, text);
|
||||
connect(panel, SIGNAL(modified()), this, SLOT(onTabModified()));
|
||||
connect(panel, &GenericPanel::modified, this, &GeneralEdit::onTabModified);
|
||||
}
|
||||
|
||||
void GeneralEdit::onTabModified()
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _GENERALEDIT_H_
|
||||
#define _GENERALEDIT_H_
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
#include "eeprominterface.h"
|
||||
@@ -35,7 +34,7 @@ class GeneralPanel : public GenericPanel
|
||||
{
|
||||
public:
|
||||
GeneralPanel(QWidget *parent, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
GenericPanel(parent, NULL, generalSettings, firmware)
|
||||
GenericPanel(parent, nullptr, generalSettings, firmware)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -73,7 +72,5 @@ class GeneralEdit : public QDialog
|
||||
QVector<GenericPanel *> panels;
|
||||
void addTab(GenericPanel *panel, QString text);
|
||||
void closeEvent(QCloseEvent *event);
|
||||
CompoundItemModelFactory *sharedItemModels;
|
||||
CompoundItemModelFactory *editorItemModels;
|
||||
};
|
||||
|
||||
#endif // _GENERALEDIT_H_
|
||||
|
||||
@@ -19,326 +19,268 @@
|
||||
*/
|
||||
|
||||
#include "hardware.h"
|
||||
#include "ui_hardware.h"
|
||||
#include "compounditemmodels.h"
|
||||
#include "filtereditemmodels.h"
|
||||
#include "autolineedit.h"
|
||||
#include "autocombobox.h"
|
||||
#include "autocheckbox.h"
|
||||
#include "autospinbox.h"
|
||||
#include "autodoublespinbox.h"
|
||||
|
||||
void HardwarePanel::setupSwitchType(int index, QLabel * label, AutoLineEdit * name, AutoComboBox * type, bool threePos)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_STM32(board) && index < getBoardCapability(board, Board::Switches)) {
|
||||
type->addItem(tr("None"), Board::SWITCH_NOT_AVAILABLE);
|
||||
type->addItem(tr("2 Positions Toggle"), Board::SWITCH_TOGGLE);
|
||||
type->addItem(tr("2 Positions"), Board::SWITCH_2POS);
|
||||
if (threePos) {
|
||||
type->addItem(tr("3 Positions"), Board::SWITCH_3POS);
|
||||
}
|
||||
name->setField(generalSettings.switchName[index], 3, this);
|
||||
type->setField(generalSettings.switchConfig[index], this);
|
||||
if (IS_TARANIS_X7(board)) {
|
||||
if (index == 4) {
|
||||
label->setText("SF");
|
||||
}
|
||||
else if (index == 5) {
|
||||
label->setText("SH");
|
||||
}
|
||||
if (index == 6) {
|
||||
label->setText("SI");
|
||||
}
|
||||
else if (index == 7) {
|
||||
label->setText("SJ");
|
||||
}
|
||||
}
|
||||
else if (IS_RADIOMASTER_TX12(board)) {
|
||||
if (index == 6) {
|
||||
label->setText("SI");
|
||||
}
|
||||
else if (index == 7) {
|
||||
label->setText("SJ");
|
||||
}
|
||||
}
|
||||
else if (IS_FAMILY_T12(board)) {
|
||||
if (index == 4) {
|
||||
label->setText("SG");
|
||||
}
|
||||
else if (index == 5) {
|
||||
label->setText("SH");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
label->hide();
|
||||
name->hide();
|
||||
type->hide();
|
||||
}
|
||||
}
|
||||
#include <QLabel>
|
||||
#include <QGridLayout>
|
||||
#include <QFrame>
|
||||
|
||||
void HardwarePanel::setupPotType(int index, QLabel * label, AutoLineEdit * name, AutoComboBox * type)
|
||||
{
|
||||
Board::Type board = firmware->getBoard();
|
||||
constexpr char FIM_SWITCHTYPE2POS[] {"Switch Type 2 Pos"};
|
||||
constexpr char FIM_SWITCHTYPE3POS[] {"Switch Type 3 Pos"};
|
||||
|
||||
if (IS_STM32(board) && index < getBoardCapability(board, Board::Pots)) {
|
||||
label->setText(RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+index).toString());
|
||||
type->addItem(tr("None"), Board::POT_NONE);
|
||||
type->addItem(tr("Pot with detent"), Board::POT_WITH_DETENT);
|
||||
type->addItem(tr("Multipos switch"), Board::POT_MULTIPOS_SWITCH);
|
||||
type->addItem(tr("Pot without detent"), Board::POT_WITHOUT_DETENT);
|
||||
name->setField(generalSettings.potName[index], 3, this);
|
||||
type->setField(generalSettings.potConfig[index], this);
|
||||
}
|
||||
else {
|
||||
label->hide();
|
||||
name->hide();
|
||||
type->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void HardwarePanel::setupSliderType(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type)
|
||||
{
|
||||
Board::Type board = firmware->getBoard();
|
||||
|
||||
if (IS_STM32(board) && index < getBoardCapability(board, Board::Sliders)) {
|
||||
label->setText(RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+getBoardCapability(board, Board::Pots)+index).toString());
|
||||
type->addItem(tr("None"), Board::SLIDER_NONE);
|
||||
type->addItem(tr("Slider with detent"), Board::SLIDER_WITH_DETENT);
|
||||
name->setField(generalSettings.sliderName[index], 3, this);
|
||||
type->setField(generalSettings.sliderConfig[index], this);
|
||||
}
|
||||
else {
|
||||
label->hide();
|
||||
name->hide();
|
||||
type->hide();
|
||||
}
|
||||
}
|
||||
|
||||
bool HardwarePanel::isSwitch3Pos(int idx)
|
||||
{
|
||||
Board::Type board = firmware->getBoard();
|
||||
Board::SwitchInfo switchInfo = Boards::getSwitchInfo(board, idx);
|
||||
|
||||
switchInfo.config = Board::SwitchType(generalSettings.switchConfig[idx]);
|
||||
return switchInfo.config == Board::SWITCH_3POS;
|
||||
};
|
||||
|
||||
HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels):
|
||||
GeneralPanel(parent, generalSettings, firmware),
|
||||
ui(new Ui::Hardware)
|
||||
board(firmware->getBoard()),
|
||||
editorItemModels(sharedItemModels)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
editorItemModels->registerItemModel(Boards::potTypeItemModel());
|
||||
editorItemModels->registerItemModel(Boards::sliderTypeItemModel());
|
||||
int id = editorItemModels->registerItemModel(Boards::switchTypeItemModel());
|
||||
|
||||
Board::Type board = firmware->getBoard();
|
||||
tabFilteredModels = new FilteredItemModelFactory();
|
||||
tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id), Board::SwitchTypeContext2Pos), FIM_SWITCHTYPE2POS);
|
||||
tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id), Board::SwitchTypeContext3Pos), FIM_SWITCHTYPE3POS);
|
||||
|
||||
if (IS_STM32(board)) {
|
||||
ui->rudName->setField(generalSettings.stickName[0], 3, this);
|
||||
ui->eleName->setField(generalSettings.stickName[1], 3, this);
|
||||
ui->thrName->setField(generalSettings.stickName[2], 3, this);
|
||||
ui->ailName->setField(generalSettings.stickName[3], 3, this);
|
||||
int antmodelid = editorItemModels->registerItemModel(GeneralSettings::antennaModeItemModel());
|
||||
int btmodelid = editorItemModels->registerItemModel(GeneralSettings::bluetoothModeItemModel());
|
||||
int auxmodelid = editorItemModels->registerItemModel(GeneralSettings::auxSerialModeItemModel());
|
||||
int baudmodelid = editorItemModels->registerItemModel(GeneralSettings::telemetryBaudrateItemModel());
|
||||
|
||||
grid = new QGridLayout(this);
|
||||
int count;
|
||||
int row = 0;
|
||||
|
||||
count = Boards::getCapability(board, Board::Sticks);
|
||||
if (count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
addStick(i, row);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui->rudLabel->hide();
|
||||
ui->rudName->hide();
|
||||
ui->eleLabel->hide();
|
||||
ui->eleName->hide();
|
||||
ui->thrLabel->hide();
|
||||
ui->thrName->hide();
|
||||
ui->ailLabel->hide();
|
||||
ui->ailName->hide();
|
||||
ui->potsTypeSeparator_1->hide();
|
||||
ui->potsTypeSeparator_2->hide();
|
||||
|
||||
count = Boards::getCapability(board, Board::Pots);
|
||||
if (count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
addPot(i, row);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
count = Boards::getCapability(board, Board::Sliders);
|
||||
if (count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
addSlider(i, row);
|
||||
}
|
||||
addLine(row);
|
||||
}
|
||||
|
||||
count = Boards::getCapability(board, Board::Switches);
|
||||
if (count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
addSwitch(i, row);
|
||||
}
|
||||
addLine(row);
|
||||
}
|
||||
|
||||
addLabel(tr("Battery Offset"), row, 0);
|
||||
AutoDoubleSpinBox *txVoltageCalibration = new AutoDoubleSpinBox(this);
|
||||
FieldRange txVCRng = GeneralSettings::getTxVoltageCalibrationRange();
|
||||
txVoltageCalibration->setDecimals(txVCRng.decimals);
|
||||
txVoltageCalibration->setSingleStep(txVCRng.step);
|
||||
txVoltageCalibration->setSuffix(txVCRng.unit);
|
||||
txVoltageCalibration->setField(generalSettings.txVoltageCalibration);
|
||||
addParams(row, txVoltageCalibration);
|
||||
|
||||
if (Boards::getCapability(board, Board::HasRTC)) {
|
||||
addLabel(tr("RTC Battery Check"), row, 0);
|
||||
AutoCheckBox *rtcCheckDisable = new AutoCheckBox(this);
|
||||
rtcCheckDisable->setField(generalSettings.rtcCheckDisable, this, true);
|
||||
addParams(row, rtcCheckDisable);
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HasBluetooth)) {
|
||||
addLabel(tr("Bluetooth"), row, 0);
|
||||
|
||||
QGridLayout *btlayout = new QGridLayout();
|
||||
|
||||
AutoComboBox *bluetoothMode = new AutoComboBox(this);
|
||||
bluetoothMode->setModel(editorItemModels->getItemModel(btmodelid));
|
||||
bluetoothMode->setField(generalSettings.bluetoothMode, this);
|
||||
btlayout->addWidget(bluetoothMode, 0, 0);
|
||||
|
||||
QSpacerItem * spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum );
|
||||
btlayout->addItem(spacer, 0, 1);
|
||||
|
||||
QLabel *btnamelabel = new QLabel(this);
|
||||
btnamelabel->setText(tr("Device Name:"));
|
||||
btlayout->addWidget(btnamelabel, 0, 2);
|
||||
|
||||
AutoLineEdit *bluetoothName = new AutoLineEdit(this);
|
||||
bluetoothName->setField(generalSettings.bluetoothName, BLUETOOTH_NAME_LEN, this);
|
||||
btlayout->addWidget(bluetoothName, 0, 3);
|
||||
|
||||
grid->addLayout(btlayout, row, 1);
|
||||
row++;
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HasAntennaChoice)) {
|
||||
addLabel(tr("Antenna"), row, 0);
|
||||
AutoComboBox *antennaMode = new AutoComboBox(this);
|
||||
antennaMode->setModel(editorItemModels->getItemModel(antmodelid));
|
||||
antennaMode->setField(generalSettings.antennaMode, this);
|
||||
addParams(row, antennaMode);
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HasAuxSerialMode)) {
|
||||
QString lbl = "Serial Port";
|
||||
if (IS_RADIOMASTER_TX16S(board))
|
||||
lbl.append(" (TTL)");
|
||||
addLabel(tr("%1").arg(lbl), row, 0);
|
||||
AutoComboBox *serialPortMode = new AutoComboBox(this);
|
||||
serialPortMode->setModel(editorItemModels->getItemModel(auxmodelid));
|
||||
serialPortMode->setField(generalSettings.auxSerialMode);
|
||||
addParams(row, serialPortMode);
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HasAux2SerialMode)) {
|
||||
QString lbl = "Serial Port 2";
|
||||
if (IS_RADIOMASTER_TX16S(board))
|
||||
lbl.append(" (TTL)");
|
||||
addLabel(tr("%1").arg(lbl), row, 0);
|
||||
AutoComboBox *serialPort2Mode = new AutoComboBox(this);
|
||||
serialPort2Mode->setModel(editorItemModels->getItemModel(auxmodelid));
|
||||
serialPort2Mode->setField(generalSettings.aux2SerialMode);
|
||||
addParams(row, serialPort2Mode);
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HasADCJitterFilter)) {
|
||||
addLabel(tr("ADC Filter"), row, 0);
|
||||
AutoCheckBox *filterEnable = new AutoCheckBox(this);
|
||||
filterEnable->setField(generalSettings.jitterFilter, this, true);
|
||||
addParams(row, filterEnable);
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HasSportConnector)) {
|
||||
ui->sportPower->setChecked(generalSettings.sportPower);
|
||||
}
|
||||
else {
|
||||
ui->sportPower->hide();
|
||||
ui->sportPowerLabel->hide();
|
||||
addLabel(tr("S.Port Power"), row, 0);
|
||||
AutoCheckBox *sportPower = new AutoCheckBox(this);
|
||||
sportPower->setField(generalSettings.sportPower, this);
|
||||
addParams(row, sportPower);
|
||||
}
|
||||
|
||||
setupPotType(0, ui->pot1Label, ui->pot1Name, ui->pot1Type);
|
||||
setupPotType(1, ui->pot2Label, ui->pot2Name, ui->pot2Type);
|
||||
setupPotType(2, ui->pot3Label, ui->pot3Name, ui->pot3Type);
|
||||
setupPotType(3, ui->pot4Label, ui->pot4Name, ui->pot4Type);
|
||||
setupPotType(4, ui->pot5Label, ui->pot5Name, ui->pot5Type);
|
||||
|
||||
setupSliderType(0, ui->lsLabel, ui->lsName, ui->lsType);
|
||||
setupSliderType(1, ui->rsLabel, ui->rsName, ui->rsType);
|
||||
setupSliderType(2, ui->ls2Label, ui->ls2Name, ui->ls2Type);
|
||||
setupSliderType(3, ui->rs2Label, ui->rs2Name, ui->rs2Type);
|
||||
|
||||
setupSwitchType(0, ui->saLabel, ui->saName, ui->saType, isSwitch3Pos(0));
|
||||
setupSwitchType(1, ui->sbLabel, ui->sbName, ui->sbType, isSwitch3Pos(1));
|
||||
setupSwitchType(2, ui->scLabel, ui->scName, ui->scType, isSwitch3Pos(2));
|
||||
setupSwitchType(3, ui->sdLabel, ui->sdName, ui->sdType, isSwitch3Pos(3));
|
||||
setupSwitchType(4, ui->seLabel, ui->seName, ui->seType, isSwitch3Pos(4));
|
||||
setupSwitchType(5, ui->sfLabel, ui->sfName, ui->sfType, isSwitch3Pos(5));
|
||||
setupSwitchType(6, ui->sgLabel, ui->sgName, ui->sgType, isSwitch3Pos(6));
|
||||
setupSwitchType(7, ui->shLabel, ui->shName, ui->shType, isSwitch3Pos(7));
|
||||
setupSwitchType(8, ui->siLabel, ui->siName, ui->siType, isSwitch3Pos(8));
|
||||
setupSwitchType(9, ui->sjLabel, ui->sjName, ui->sjType, isSwitch3Pos(9));
|
||||
setupSwitchType(10, ui->skLabel, ui->skName, ui->skType); // Here starts X9E, only 3 switches
|
||||
setupSwitchType(11, ui->slLabel, ui->slName, ui->slType);
|
||||
setupSwitchType(12, ui->smLabel, ui->smName, ui->smType);
|
||||
setupSwitchType(13, ui->snLabel, ui->snName, ui->snType);
|
||||
setupSwitchType(14, ui->soLabel, ui->soName, ui->soType);
|
||||
setupSwitchType(15, ui->spLabel, ui->spName, ui->spType);
|
||||
setupSwitchType(16, ui->sqLabel, ui->sqName, ui->sqType);
|
||||
setupSwitchType(17, ui->srLabel, ui->srName, ui->srType);
|
||||
|
||||
if (IS_TARANIS(board) && !IS_TARANIS_SMALL(board)) {
|
||||
ui->serialPortMode->setCurrentIndex(generalSettings.auxSerialMode);
|
||||
}
|
||||
else {
|
||||
ui->serialPortMode->setCurrentIndex(0);
|
||||
ui->serialPortMode->hide();
|
||||
ui->serialPortLabel->hide();
|
||||
if (firmware->getCapability(HasTelemetryBaudrate)) {
|
||||
addLabel(tr("Maximum Baud"), row, 0);
|
||||
AutoComboBox *maxBaudRate = new AutoComboBox(this);
|
||||
maxBaudRate->setModel(editorItemModels->getItemModel(baudmodelid));
|
||||
maxBaudRate->setField(generalSettings.telemetryBaudrate, this);
|
||||
addParams(row, maxBaudRate);
|
||||
}
|
||||
|
||||
if (!IS_SKY9X(board)) {
|
||||
ui->txCurrentCalibration->hide();
|
||||
ui->txCurrentCalibrationLabel->hide();
|
||||
}
|
||||
|
||||
if (IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board)|| IS_TARANIS_X9E(board) || IS_TARANIS_X9DP_2019(board) || IS_FAMILY_HORUS_OR_T16(board)) {
|
||||
ui->bluetoothMode->addItem(tr("OFF"), 0);
|
||||
if (IS_TARANIS_X9E(board)) {
|
||||
ui->bluetoothMode->addItem(tr("Enabled"), 1);
|
||||
}
|
||||
else {
|
||||
ui->bluetoothMode->addItem(tr("Telemetry"), 1);
|
||||
ui->bluetoothMode->addItem(tr("Trainer"), 2);
|
||||
}
|
||||
ui->bluetoothMode->setField(generalSettings.bluetoothMode, this);
|
||||
ui->bluetoothName->setField(generalSettings.bluetoothName, 10, this);
|
||||
}
|
||||
else {
|
||||
ui->bluetoothLabel->hide();
|
||||
ui->bluetoothWidget->hide();
|
||||
}
|
||||
|
||||
if ((IS_FAMILY_HORUS_OR_T16(board) && board != Board::BOARD_X10_EXPRESS) || (IS_TARANIS_XLITE(board) && !IS_TARANIS_XLITES(board))) {
|
||||
ui->antennaMode->addItem(tr("Internal"), -2);
|
||||
ui->antennaMode->addItem(tr("Ask"), -1);
|
||||
ui->antennaMode->addItem(tr("Per model"), 0);
|
||||
ui->antennaMode->addItem(IS_HORUS_X12S(board) ? tr("Internal + External") : tr("External"), 1);
|
||||
ui->antennaMode->setField(generalSettings.antennaMode, this);
|
||||
}
|
||||
else {
|
||||
ui->antennaLabel->hide();
|
||||
ui->antennaMode->hide();
|
||||
}
|
||||
|
||||
if (IS_HORUS_OR_TARANIS(board)) {
|
||||
ui->filterEnable->setChecked(!generalSettings.jitterFilter);
|
||||
}
|
||||
else {
|
||||
ui->filterEnable->hide();
|
||||
ui->filterLabel->hide();
|
||||
}
|
||||
|
||||
if (IS_STM32(board)) {
|
||||
ui->rtcCheckDisable->setChecked(!generalSettings.rtcCheckDisable);
|
||||
}
|
||||
else {
|
||||
ui->rtcCheckDisable->hide();
|
||||
ui->rtcCheckLabel->hide();
|
||||
if (firmware->getCapability(HastxCurrentCalibration)) {
|
||||
addLabel(tr("Current Offset"), row, 0);
|
||||
AutoSpinBox *txCurrentCalibration = new AutoSpinBox(this);
|
||||
FieldRange txCCRng = GeneralSettings::getTxCurrentCalibration();
|
||||
txCurrentCalibration->setSuffix(txVCRng.unit);
|
||||
txCurrentCalibration->setField(generalSettings.txCurrentCalibration);
|
||||
addParams(row, txCurrentCalibration);
|
||||
}
|
||||
|
||||
addVSpring(grid, 0, grid->rowCount());
|
||||
addHSpring(grid, grid->columnCount(), 0);
|
||||
disableMouseScrolling();
|
||||
|
||||
setValues();
|
||||
}
|
||||
|
||||
HardwarePanel::~HardwarePanel()
|
||||
{
|
||||
delete ui;
|
||||
delete tabFilteredModels;
|
||||
}
|
||||
|
||||
void HardwarePanel::on_filterEnable_stateChanged()
|
||||
void HardwarePanel::addStick(int index, int & row)
|
||||
{
|
||||
generalSettings.jitterFilter = !ui->filterEnable->isChecked();
|
||||
int col = 0;
|
||||
addLabel(Boards::getAnalogInputName(board, index), row, col++);
|
||||
|
||||
AutoLineEdit *name = new AutoLineEdit(this);
|
||||
name->setField(generalSettings.stickName[index], HARDWARE_NAME_LEN, this);
|
||||
|
||||
addParams(row, name);
|
||||
}
|
||||
|
||||
void HardwarePanel::on_sportPower_stateChanged()
|
||||
void HardwarePanel::addPot(int index, int & row)
|
||||
{
|
||||
generalSettings.sportPower = ui->sportPower->isChecked();
|
||||
addLabel(Boards::getAnalogInputName(board, Boards::getCapability(board, Board::Sticks) + index), row, 0);
|
||||
|
||||
AutoLineEdit *name = new AutoLineEdit(this);
|
||||
name->setField(generalSettings.potName[index], HARDWARE_NAME_LEN, this);
|
||||
|
||||
AutoComboBox *type = new AutoComboBox(this);
|
||||
type->setModel(editorItemModels->getItemModel(AIM_BOARDS_POT_TYPE));
|
||||
type->setField(generalSettings.potConfig[index], this);
|
||||
|
||||
addParams(row, name, type);
|
||||
}
|
||||
|
||||
void HardwarePanel::on_rtcCheckDisable_stateChanged()
|
||||
void HardwarePanel::addSlider(int index, int & row)
|
||||
{
|
||||
generalSettings.rtcCheckDisable = !ui->rtcCheckDisable->isChecked();
|
||||
addLabel(Boards::getAnalogInputName(board, Boards::getCapability(board, Board::Sticks) +
|
||||
Boards::getCapability(board, Board::Pots) + index), row, 0);
|
||||
|
||||
AutoLineEdit *name = new AutoLineEdit(this);
|
||||
name->setField(generalSettings.sliderName[index], HARDWARE_NAME_LEN, this);
|
||||
|
||||
AutoComboBox *type = new AutoComboBox(this);
|
||||
type->setModel(editorItemModels->getItemModel(AIM_BOARDS_SLIDER_TYPE));
|
||||
type->setField(generalSettings.sliderConfig[index], this);
|
||||
|
||||
addParams(row, name, type);
|
||||
}
|
||||
|
||||
void HardwarePanel::on_PPM_MultiplierDSB_editingFinished()
|
||||
void HardwarePanel::addSwitch(int index, int & row)
|
||||
{
|
||||
int val = (int)(ui->PPM_MultiplierDSB->value()*10)-10;
|
||||
if (generalSettings.PPM_Multiplier != val) {
|
||||
generalSettings.PPM_Multiplier = val;
|
||||
emit modified();
|
||||
}
|
||||
addLabel(Boards::getSwitchInfo(board, index).name, row, 0);
|
||||
|
||||
AutoLineEdit *name = new AutoLineEdit(this);
|
||||
name->setField(generalSettings.switchName[index], HARDWARE_NAME_LEN, this);
|
||||
|
||||
AutoComboBox *type = new AutoComboBox(this);
|
||||
Board::SwitchInfo switchInfo = Boards::getSwitchInfo(board, index);
|
||||
type->setModel(switchInfo.config < Board::SWITCH_3POS ? tabFilteredModels->getItemModel(FIM_SWITCHTYPE2POS) :
|
||||
tabFilteredModels->getItemModel(FIM_SWITCHTYPE3POS));
|
||||
type->setField(generalSettings.switchConfig[index], this);
|
||||
|
||||
addParams(row, name, type);
|
||||
}
|
||||
|
||||
void HardwarePanel::on_PPM1_editingFinished()
|
||||
void HardwarePanel::addLabel(QString text, int row, int col)
|
||||
{
|
||||
if (generalSettings.trainer.calib[0] != ui->PPM1->value()) {
|
||||
generalSettings.trainer.calib[0] = ui->PPM1->value();
|
||||
emit modified();
|
||||
}
|
||||
QLabel *label = new QLabel(this);
|
||||
label->setText(text);
|
||||
grid->addWidget(label, row, col);
|
||||
}
|
||||
|
||||
void HardwarePanel::on_PPM2_editingFinished()
|
||||
void HardwarePanel::addLine(int & row)
|
||||
{
|
||||
if (generalSettings.trainer.calib[1] != ui->PPM2->value()) {
|
||||
generalSettings.trainer.calib[1] = ui->PPM2->value();
|
||||
emit modified();
|
||||
}
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
line->setLineWidth(1);
|
||||
line->setMidLineWidth(0);
|
||||
grid->addWidget(line, row, 0, 1, grid->columnCount());
|
||||
row++;
|
||||
}
|
||||
|
||||
void HardwarePanel::on_PPM3_editingFinished()
|
||||
void HardwarePanel::addParams(int & row, QWidget * widget1, QWidget * widget2)
|
||||
{
|
||||
if (generalSettings.trainer.calib[2] != ui->PPM3->value()) {
|
||||
generalSettings.trainer.calib[2] = ui->PPM3->value();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
void HardwarePanel::on_PPM4_editingFinished()
|
||||
{
|
||||
if (generalSettings.trainer.calib[3] != ui->PPM4->value()) {
|
||||
generalSettings.trainer.calib[3] = ui->PPM4->value();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HardwarePanel::on_txCurrentCalibration_editingFinished()
|
||||
{
|
||||
if (generalSettings.txCurrentCalibration != ui->txCurrentCalibration->value()) {
|
||||
generalSettings.txCurrentCalibration = ui->txCurrentCalibration->value();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
void HardwarePanel::setValues()
|
||||
{
|
||||
ui->txVoltageCalibration->setValue((double)generalSettings.txVoltageCalibration/10);
|
||||
ui->txCurrentCalibration->setValue((double)generalSettings.txCurrentCalibration);
|
||||
|
||||
ui->PPM1->setValue(generalSettings.trainer.calib[0]);
|
||||
ui->PPM2->setValue(generalSettings.trainer.calib[1]);
|
||||
ui->PPM3->setValue(generalSettings.trainer.calib[2]);
|
||||
ui->PPM4->setValue(generalSettings.trainer.calib[3]);
|
||||
ui->PPM_MultiplierDSB->setValue((qreal)(generalSettings.PPM_Multiplier+10)/10);
|
||||
}
|
||||
|
||||
void HardwarePanel::on_txVoltageCalibration_editingFinished()
|
||||
{
|
||||
if (generalSettings.txVoltageCalibration != ui->txVoltageCalibration->value()*10) {
|
||||
generalSettings.txVoltageCalibration = ui->txVoltageCalibration->value()*10;
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
void HardwarePanel::on_serialPortMode_currentIndexChanged(int index)
|
||||
{
|
||||
generalSettings.auxSerialMode = index;
|
||||
emit modified();
|
||||
QGridLayout *subgrid = new QGridLayout();
|
||||
subgrid->addWidget(widget1, 0, 0);
|
||||
if (widget2)
|
||||
subgrid->addWidget(widget2, 0, 1);
|
||||
else
|
||||
addHSpring(subgrid, 1, 0);
|
||||
addHSpring(subgrid, 2, 0);
|
||||
grid->addLayout(subgrid, row, 1);
|
||||
row++;
|
||||
}
|
||||
|
||||
@@ -18,52 +18,33 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _HARDWARE_H_
|
||||
#define _HARDWARE_H_
|
||||
#pragma once
|
||||
|
||||
#include "generaledit.h"
|
||||
|
||||
namespace Ui {
|
||||
class Hardware;
|
||||
}
|
||||
|
||||
class QLabel;
|
||||
class AutoLineEdit;
|
||||
class AutoComboBox;
|
||||
class CompoundItemModelFactory;
|
||||
class FilteredItemModelFactory;
|
||||
class QGridLayout;
|
||||
|
||||
class HardwarePanel : public GeneralPanel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HardwarePanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware);
|
||||
HardwarePanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * editorItemModels);
|
||||
virtual ~HardwarePanel();
|
||||
|
||||
private slots:
|
||||
void on_PPM1_editingFinished();
|
||||
void on_PPM2_editingFinished();
|
||||
void on_PPM3_editingFinished();
|
||||
void on_PPM4_editingFinished();
|
||||
void on_PPM_MultiplierDSB_editingFinished();
|
||||
|
||||
void on_txCurrentCalibration_editingFinished();
|
||||
void on_txVoltageCalibration_editingFinished();
|
||||
void on_filterEnable_stateChanged();
|
||||
void on_rtcCheckDisable_stateChanged();
|
||||
void on_sportPower_stateChanged();
|
||||
|
||||
void on_serialPortMode_currentIndexChanged(int index);
|
||||
|
||||
protected:
|
||||
void setupPotType(int index, QLabel * label, AutoLineEdit * name, AutoComboBox * type);
|
||||
void setupSliderType(int index, QLabel * label, AutoLineEdit * name, AutoComboBox * type);
|
||||
void setupSwitchType(int index, QLabel * label, AutoLineEdit * name, AutoComboBox * type, bool threePos = true);
|
||||
|
||||
private:
|
||||
Ui::Hardware *ui;
|
||||
Board::Type board;
|
||||
CompoundItemModelFactory *editorItemModels;
|
||||
FilteredItemModelFactory *tabFilteredModels;
|
||||
QGridLayout *grid;
|
||||
|
||||
void setValues();
|
||||
bool isSwitch3Pos(int idx);
|
||||
void addStick(int index, int & row);
|
||||
void addPot(int index, int & row);
|
||||
void addSlider(int index, int & row);
|
||||
void addSwitch(int index, int & row);
|
||||
void addLabel(QString text, int row, int col);
|
||||
void addLine(int & row);
|
||||
void addParams(int & row, QWidget * widget1, QWidget * widget2 = nullptr);
|
||||
};
|
||||
|
||||
#endif // _HARDWARE_H_
|
||||
|
||||
@@ -19,103 +19,106 @@
|
||||
*/
|
||||
|
||||
#include "trainer.h"
|
||||
#include "ui_trainer.h"
|
||||
#include "compounditemmodels.h"
|
||||
#include "autocombobox.h"
|
||||
#include "autolineedit.h"
|
||||
#include "autospinbox.h"
|
||||
#include "autodoublespinbox.h"
|
||||
|
||||
TrainerPanel::TrainerPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
GeneralPanel(parent, generalSettings, firmware),
|
||||
ui(new Ui::Trainer)
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QStringList>
|
||||
|
||||
TrainerPanel::TrainerPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * editorItemModels):
|
||||
GeneralPanel(parent, generalSettings, firmware)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
int modeid = editorItemModels->registerItemModel(TrainerMix::modeItemModel());
|
||||
int srcid = editorItemModels->registerItemModel(TrainerMix::srcItemModel());
|
||||
|
||||
Board::Type board = getCurrentBoard();
|
||||
const int stickcnt = Boards::getCapability(board, Board::Sticks);
|
||||
|
||||
ui->trnMode_1->setCurrentIndex(generalSettings.trainer.mix[0].mode);
|
||||
ui->trnChn_1->setCurrentIndex(generalSettings.trainer.mix[0].src);
|
||||
ui->trnWeight_1->setValue(generalSettings.trainer.mix[0].weight);
|
||||
ui->trnMode_2->setCurrentIndex(generalSettings.trainer.mix[1].mode);
|
||||
ui->trnChn_2->setCurrentIndex(generalSettings.trainer.mix[1].src);
|
||||
ui->trnWeight_2->setValue(generalSettings.trainer.mix[1].weight);
|
||||
ui->trnMode_3->setCurrentIndex(generalSettings.trainer.mix[2].mode);
|
||||
ui->trnChn_3->setCurrentIndex(generalSettings.trainer.mix[2].src);
|
||||
ui->trnWeight_3->setValue(generalSettings.trainer.mix[2].weight);
|
||||
ui->trnMode_4->setCurrentIndex(generalSettings.trainer.mix[3].mode);
|
||||
ui->trnChn_4->setCurrentIndex(generalSettings.trainer.mix[3].src);
|
||||
ui->trnWeight_4->setValue(generalSettings.trainer.mix[3].weight);
|
||||
const FieldRange weightrng = TrainerMix::getWeightRange();
|
||||
|
||||
grid = new QGridLayout(this);
|
||||
|
||||
int col = 0;
|
||||
int row = 0;
|
||||
|
||||
if (stickcnt) {
|
||||
addLabel(tr("Mode"), row, 1);
|
||||
addLabel(tr("Weight"), row, 2);
|
||||
addLabel(tr("Source"), row++, 3);
|
||||
|
||||
for (int i = 0; i < 4; i++, row++) { // TODO constant
|
||||
col = 0;
|
||||
addLabel(Boards::getAnalogInputName(board, i), row, col++);
|
||||
|
||||
AutoComboBox *mode = new AutoComboBox(this);
|
||||
mode->setModel(editorItemModels->getItemModel(modeid));
|
||||
mode->setField(generalSettings.trainer.mix[i].mode, this);
|
||||
grid->addWidget(mode, row, col++);
|
||||
|
||||
AutoSpinBox *weight = new AutoSpinBox(this);
|
||||
weight->setRange(weightrng.min, weightrng.max);
|
||||
weight->setField(generalSettings.trainer.mix[i].weight, this);
|
||||
grid->addWidget(weight, row, col++);
|
||||
|
||||
AutoComboBox *src = new AutoComboBox(this);
|
||||
src->setModel(editorItemModels->getItemModel(srcid));
|
||||
src->setField(generalSettings.trainer.mix[i].src, this);
|
||||
grid->addWidget(src, row, col++);
|
||||
}
|
||||
|
||||
addLine(row++, 0, grid->columnCount());
|
||||
}
|
||||
|
||||
col = 0;
|
||||
addLabel(tr("Multiplier"), row, col++);
|
||||
|
||||
const FieldRange ppmmrng = GeneralSettings::getPPM_MultiplierRange();
|
||||
|
||||
AutoDoubleSpinBox *multi = new AutoDoubleSpinBox(this);
|
||||
multi->setDecimals(ppmmrng.decimals);
|
||||
multi->setOffset(ppmmrng.offset);
|
||||
multi->setSingleStep(ppmmrng.step);
|
||||
multi->setRange(ppmmrng.min, ppmmrng.max);
|
||||
multi->setField(generalSettings.PPM_Multiplier, this);
|
||||
grid->addWidget(multi, row++, col);
|
||||
|
||||
col = 0;
|
||||
|
||||
addLabel(tr("Calibration"), row, col++);
|
||||
|
||||
for (int i = 0; i < stickcnt; i++, col++) {
|
||||
AutoLineEdit *calib = new AutoLineEdit(this);
|
||||
calib->setText(QString("%1").arg(generalSettings.trainer.calib[i]));
|
||||
calib->setReadOnly(true);
|
||||
grid->addWidget(calib, row, col);
|
||||
}
|
||||
|
||||
addHSpring(grid, grid->columnCount(), 0);
|
||||
addVSpring(grid, 0, grid->rowCount());
|
||||
disableMouseScrolling();
|
||||
}
|
||||
|
||||
TrainerPanel::~TrainerPanel()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnMode_1_currentIndexChanged(int index)
|
||||
void TrainerPanel::addLabel(QString text, int row, int col)
|
||||
{
|
||||
generalSettings.trainer.mix[0].mode = index;
|
||||
emit modified();
|
||||
QLabel *label = new QLabel(this);
|
||||
label->setText(text);
|
||||
grid->addWidget(label, row, col);
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnChn_1_currentIndexChanged(int index)
|
||||
void TrainerPanel::addLine(int row, int col, int colspan)
|
||||
{
|
||||
generalSettings.trainer.mix[0].src = index;
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnWeight_1_editingFinished()
|
||||
{
|
||||
generalSettings.trainer.mix[0].weight = ui->trnWeight_1->value();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnMode_2_currentIndexChanged(int index)
|
||||
{
|
||||
generalSettings.trainer.mix[1].mode = index;
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnChn_2_currentIndexChanged(int index)
|
||||
{
|
||||
generalSettings.trainer.mix[1].src = index;
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnWeight_2_editingFinished()
|
||||
{
|
||||
generalSettings.trainer.mix[1].weight = ui->trnWeight_2->value();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnMode_3_currentIndexChanged(int index)
|
||||
{
|
||||
generalSettings.trainer.mix[2].mode = index;
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnChn_3_currentIndexChanged(int index)
|
||||
{
|
||||
generalSettings.trainer.mix[2].src = index;
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnWeight_3_editingFinished()
|
||||
{
|
||||
generalSettings.trainer.mix[2].weight = ui->trnWeight_3->value();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnMode_4_currentIndexChanged(int index)
|
||||
{
|
||||
generalSettings.trainer.mix[3].mode = index;
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnChn_4_currentIndexChanged(int index)
|
||||
{
|
||||
generalSettings.trainer.mix[3].src = index;
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TrainerPanel::on_trnWeight_4_editingFinished()
|
||||
{
|
||||
generalSettings.trainer.mix[3].weight = ui->trnWeight_4->value();
|
||||
emit modified();
|
||||
QFrame *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
line->setLineWidth(1);
|
||||
line->setMidLineWidth(0);
|
||||
grid->addWidget(line, row, col, 1, colspan);
|
||||
}
|
||||
|
||||
@@ -18,42 +18,23 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _TRAINER_H_
|
||||
#define _TRAINER_H_
|
||||
#pragma once
|
||||
|
||||
#include "generaledit.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
namespace Ui {
|
||||
class Trainer;
|
||||
}
|
||||
class CompoundItemModelFactory;
|
||||
|
||||
class TrainerPanel : public GeneralPanel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TrainerPanel(QWidget *parent, GeneralSettings & generalSettings, Firmware * firmware);
|
||||
TrainerPanel(QWidget *parent, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * editorItemModels);
|
||||
virtual ~TrainerPanel();
|
||||
|
||||
private slots:
|
||||
void on_trnMode_1_currentIndexChanged(int index);
|
||||
void on_trnChn_1_currentIndexChanged(int index);
|
||||
void on_trnWeight_1_editingFinished();
|
||||
void on_trnMode_2_currentIndexChanged(int index);
|
||||
void on_trnChn_2_currentIndexChanged(int index);
|
||||
void on_trnWeight_2_editingFinished();
|
||||
void on_trnMode_3_currentIndexChanged(int index);
|
||||
void on_trnChn_3_currentIndexChanged(int index);
|
||||
void on_trnWeight_3_editingFinished();
|
||||
void on_trnMode_4_currentIndexChanged(int index);
|
||||
void on_trnChn_4_currentIndexChanged(int index);
|
||||
void on_trnWeight_4_editingFinished();
|
||||
|
||||
private:
|
||||
Ui::Trainer *ui;
|
||||
|
||||
void setValues();
|
||||
QGridLayout * grid;
|
||||
void addLabel(QString text, int row, int col);
|
||||
void addLine(int row, int col, int colspan);
|
||||
};
|
||||
|
||||
#endif // _TRAINER_H_
|
||||
|
||||
@@ -1,475 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Trainer</class>
|
||||
<widget class="QWidget" name="Trainer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="3">
|
||||
<widget class="QSpinBox" name="trnWeight_3">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-125</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>125</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_36">
|
||||
<property name="text">
|
||||
<string>Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_37">
|
||||
<property name="text">
|
||||
<string>Input</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_38">
|
||||
<property name="text">
|
||||
<string>Weight</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="trnLabel_1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rud</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="trnMode_1">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Off</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>+= (Sum)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>:= (Replace)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QComboBox" name="trnChn_1">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn2</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn3</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn4</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QSpinBox" name="trnWeight_1">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-125</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>125</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="trnLabel_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Ele</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="trnMode_2">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Off</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>+= (Sum)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>:= (Replace)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QComboBox" name="trnChn_2">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn2</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn3</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn4</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QComboBox" name="trnChn_3">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn2</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn3</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn4</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QSpinBox" name="trnWeight_2">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-125</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>125</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="trnLabel_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Thr</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="trnMode_3">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Off</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>+= (Sum)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>:= (Replace)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="trnLabel_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Ail</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="trnMode_4">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Off</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>+= (Sum)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>:= (Replace)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QComboBox" name="trnChn_4">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Beeper volume
|
||||
|
||||
0 - Quiet. No beeps at all.
|
||||
1 - No Keys. Normal beeps but menu keys do not beep.
|
||||
2 - Normal.
|
||||
3 - Loud.
|
||||
4 - Extra loud.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn2</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn3</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>chn4</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QSpinBox" name="trnWeight_4">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-125</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>125</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -620,6 +620,17 @@ void TableLayout::setColumnWidth(int col, int width)
|
||||
#if defined(TABLE_LAYOUT)
|
||||
tableWidget->setColumnWidth(col, width);
|
||||
#else
|
||||
gridWidget->setColumnMinimumWidth(col, width);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TableLayout::setColumnWidth(int col, QString str)
|
||||
{
|
||||
#if defined(TABLE_LAYOUT)
|
||||
#else
|
||||
QFontMetrics *f = new QFontMetrics(QFont());
|
||||
QSize sz = f->size(Qt::TextSingleLine, str);
|
||||
setColumnWidth(col, sz.width());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -628,12 +639,19 @@ void TableLayout::pushRowsUp(int row)
|
||||
#if defined(TABLE_LAYOUT)
|
||||
#else
|
||||
// Push the rows up
|
||||
QSpacerItem * spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding );
|
||||
QSpacerItem * spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
gridWidget->addItem(spacer, row, 0);
|
||||
#endif
|
||||
// Push rows upward
|
||||
// addDoubleSpring(gridLayout, 5, num_fsw+1);
|
||||
}
|
||||
|
||||
void TableLayout::pushColumnsLeft(int col)
|
||||
{
|
||||
#if defined(TABLE_LAYOUT)
|
||||
#else
|
||||
// Push the columns to the left
|
||||
QSpacerItem * spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
gridWidget->addItem(spacer, 0, col);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString Helpers::getChecklistsPath()
|
||||
|
||||
@@ -191,7 +191,9 @@ public:
|
||||
|
||||
void resizeColumnsToContents();
|
||||
void setColumnWidth(int col, int width);
|
||||
void setColumnWidth(int col, QString str);
|
||||
void pushRowsUp(int row);
|
||||
void pushColumnsLeft(int col);
|
||||
|
||||
private:
|
||||
#if defined(TABLE_LAYOUT)
|
||||
|
||||
@@ -33,20 +33,20 @@
|
||||
|
||||
float curveLinear(float x, float coeff, float yMin, float yMid, float yMax)
|
||||
{
|
||||
float a = (yMax-yMin) / 200.0;
|
||||
return yMin + a * (x+100.0);
|
||||
float a = (yMax - yMin) / 200.0;
|
||||
return yMin + a * (x + 100.0);
|
||||
}
|
||||
|
||||
float c9xexpou(float point, float coeff)
|
||||
{
|
||||
float x = point*1024.0/100.0;
|
||||
float k = coeff*256.0/100.0;
|
||||
return ((k*x*x*x/(1024*1024) + x*(256-k) + 128) / 256) / 1024.0 * 100;
|
||||
float x = point * 1024.0 / 100.0;
|
||||
float k = coeff * 256.0 / 100.0;
|
||||
return ((k * x * x * x / (1024 * 1024) + x * (256 - k) + 128) / 256) / 1024.0 * 100;
|
||||
}
|
||||
|
||||
float curveExpo(float x, float coeff, float yMin, float yMid, float yMax)
|
||||
{
|
||||
float a = (yMax-yMin) / 100.0;
|
||||
float a = (yMax - yMin) / 100.0;
|
||||
|
||||
x += 100.0;
|
||||
x /= 2.0;
|
||||
@@ -57,14 +57,14 @@ float curveExpo(float x, float coeff, float yMin, float yMid, float yMax)
|
||||
else {
|
||||
coeff = -coeff;
|
||||
x = 100 - x;
|
||||
return round((100.0 - c9xexpou(x, coeff))*a + yMin);
|
||||
return round((100.0 - c9xexpou(x, coeff)) * a + yMin);
|
||||
}
|
||||
}
|
||||
|
||||
float curveSymmetricalY(float x, float coeff, float yMin, float yMid, float yMax)
|
||||
{
|
||||
bool invert;
|
||||
if (x<0) {
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
invert = 1;
|
||||
}
|
||||
@@ -74,12 +74,12 @@ float curveSymmetricalY(float x, float coeff, float yMin, float yMid, float yMax
|
||||
|
||||
float y;
|
||||
if (coeff >= 0) {
|
||||
y = round(c9xexpou(x, coeff) * (yMax/100.0));
|
||||
y = round(c9xexpou(x, coeff) * (yMax / 100.0));
|
||||
}
|
||||
else {
|
||||
coeff = -coeff;
|
||||
x = 100.0 - x;
|
||||
y = round((100.0-c9xexpou(x, coeff)) * (yMax/100.0));
|
||||
y = round((100.0 - c9xexpou(x, coeff)) * (yMax / 100.0));
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
@@ -91,9 +91,9 @@ float curveSymmetricalY(float x, float coeff, float yMin, float yMid, float yMax
|
||||
|
||||
float curveSymmetricalX(float x, float coeff, float yMin, float yMid, float yMax)
|
||||
{
|
||||
float a = (yMax-yMid) / 100.0;
|
||||
float a = (yMax - yMid) / 100.0;
|
||||
|
||||
if (x<0)
|
||||
if (x < 0)
|
||||
x = -x;
|
||||
|
||||
float y;
|
||||
@@ -102,8 +102,8 @@ float curveSymmetricalX(float x, float coeff, float yMin, float yMid, float yMax
|
||||
}
|
||||
else {
|
||||
coeff = -coeff;
|
||||
x = 100-x;
|
||||
y = round((100.0-c9xexpou(x, coeff)) * a + yMid);
|
||||
x = 100 - x;
|
||||
y = round((100.0 - c9xexpou(x, coeff)) * a + yMid);
|
||||
}
|
||||
|
||||
return y;
|
||||
@@ -148,17 +148,14 @@ CurvesPanel::CurvesPanel(QWidget * parent, ModelData & model, GeneralSettings &
|
||||
// The edit curve button
|
||||
QPushButton * edit = new QPushButton(this);
|
||||
edit->setProperty("index", i);
|
||||
QPalette palette;
|
||||
palette.setBrush(QPalette::Active, QPalette::Button, QBrush(colors[i]));
|
||||
palette.setBrush(QPalette::Active, QPalette::ButtonText, QBrush(Qt::white));
|
||||
#ifdef __APPLE__
|
||||
edit->setStyleSheet(QString("color: %1;").arg(colors[i].name()));
|
||||
#elif defined WIN32 || !defined __GNUC__
|
||||
edit->setStyleSheet(QString("background-color: %1; color: white;").arg(colors[i].name()));
|
||||
#else
|
||||
|
||||
#ifdef __GNUC__
|
||||
// creates more compact and likely consistent buttons across OS flavors
|
||||
edit->setStyleSheet(QString("background-color: %1; color: white; padding: 2px 3px; border-style: outset; border-width: 1px; border-radius: 2px; border-color: inherit;").arg(colors[i].name()));
|
||||
#else
|
||||
edit->setStyleSheet(QString("background-color: %1; color: white;").arg(colors[i].name()));
|
||||
#endif
|
||||
edit->setPalette(palette);
|
||||
|
||||
edit->setText(tr("Curve %1").arg(i + 1));
|
||||
edit->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
edit->setToolTip(tr("Popup menu available"));
|
||||
@@ -173,7 +170,6 @@ CurvesPanel::CurvesPanel(QWidget * parent, ModelData & model, GeneralSettings &
|
||||
// The curve plot checkbox
|
||||
QCheckBox * plot = new QCheckBox(this);
|
||||
plot->setProperty("index", i);
|
||||
plot->setPalette(palette);
|
||||
connect(plot, SIGNAL(toggled(bool)), this, SLOT(plotCurve(bool)));
|
||||
if (i < limit) {
|
||||
ui->curvesLayout->addWidget(plot, i, 2, 1, 1);
|
||||
@@ -332,9 +328,15 @@ void CurvesPanel::updateCurve()
|
||||
int numpoints = model->curves[k].count;
|
||||
for (int i = 0; i < numpoints - 1; i++) {
|
||||
if (model->curves[k].type == CurveData::CURVE_TYPE_CUSTOM)
|
||||
scene->addLine(centerX + (qreal)model->curves[k].points[i].x*width/200, centerY - (qreal)model->curves[k].points[i].y*height/200,centerX + (qreal)model->curves[k].points[i+1].x*width/200,centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen);
|
||||
scene->addLine(centerX + (qreal)model->curves[k].points[i].x * width / 200,
|
||||
centerY - (qreal)model->curves[k].points[i].y * height / 200,
|
||||
centerX + (qreal)model->curves[k].points[i + 1].x * width / 200,
|
||||
centerY - (qreal)model->curves[k].points[i + 1].y * height / 200, pen);
|
||||
else
|
||||
scene->addLine(GFX_MARGIN + i*width/(numpoints-1), centerY - (qreal)model->curves[k].points[i].y*height/200,GFX_MARGIN + (i+1)*width/(numpoints-1),centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen);
|
||||
scene->addLine(GFX_MARGIN + i * width / (numpoints - 1),
|
||||
centerY - (qreal)model->curves[k].points[i].y * height / 200,
|
||||
GFX_MARGIN + (i + 1) * width / (numpoints - 1),
|
||||
centerY - (qreal)model->curves[k].points[i + 1].y * height / 200, pen);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -356,11 +358,13 @@ void CurvesPanel::updateCurve()
|
||||
else {
|
||||
nodex->setFixedX(true);
|
||||
}
|
||||
nodex->setPos(centerX + (qreal)model->curves[currentCurve].points[i].x * width / 200, centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200);
|
||||
nodex->setPos(centerX + (qreal)model->curves[currentCurve].points[i].x * width / 200,
|
||||
centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200);
|
||||
}
|
||||
else {
|
||||
nodex->setFixedX(true);
|
||||
nodex->setPos(GFX_MARGIN + i * width / (numpoints - 1), centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200);
|
||||
nodex->setPos(GFX_MARGIN + i * width / (numpoints - 1),
|
||||
centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200);
|
||||
}
|
||||
connect(nodex, SIGNAL(moved(int, int)), this, SLOT(onNodeMoved(int, int)));
|
||||
connect(nodex, SIGNAL(focus()), this, SLOT(onNodeFocus()));
|
||||
@@ -592,7 +596,8 @@ void CurvesPanel::on_curveApply_clicked()
|
||||
}
|
||||
|
||||
if (apply) {
|
||||
model->curves[currentCurve].points[i].y = templates[index].function(x, ui->curveCoeff->value(), ui->yMin->value(), ui->yMid->value(), ui->yMax->value());
|
||||
model->curves[currentCurve].points[i].y = templates[index].function(x, ui->curveCoeff->value(), ui->yMin->value(), ui->yMid->value(),
|
||||
ui->yMax->value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,7 @@ void TimerPanel::onCountdownBeepChanged(int index)
|
||||
#define MASK_ACCESS (1<<13)
|
||||
#define MASK_RX_FREQ (1<<14)
|
||||
#define MASK_RF_POWER (1<<15)
|
||||
#define MASK_RF_RACING_MODE (1<<16)
|
||||
|
||||
quint8 ModulePanel::failsafesValueDisplayType = ModulePanel::FAILSAFE_DISPLAY_PERCENT;
|
||||
|
||||
@@ -371,9 +372,9 @@ void ModulePanel::setupFailsafes()
|
||||
|
||||
void ModulePanel::update()
|
||||
{
|
||||
const PulsesProtocol protocol = (PulsesProtocol)module.protocol;
|
||||
const Board::Type board = firmware->getBoard();
|
||||
const Multiprotocols::MultiProtocolDefinition & pdef = multiProtocols.getProtocol(module.multi.rfProtocol);
|
||||
const auto protocol = (PulsesProtocol)module.protocol;
|
||||
const auto board = firmware->getBoard();
|
||||
const auto & pdef = multiProtocols.getProtocol(module.multi.rfProtocol);
|
||||
unsigned int mask = 0;
|
||||
unsigned int max_rx_num = 63;
|
||||
|
||||
@@ -406,6 +407,8 @@ void ModulePanel::update()
|
||||
mask |= MASK_RX_NUMBER | MASK_ACCESS;
|
||||
if (moduleIdx == 0 && HAS_EXTERNAL_ANTENNA(board) && generalSettings.antennaMode == 0 /* per model */)
|
||||
mask |= MASK_ANTENNA;
|
||||
if (protocol == PULSES_ACCESS_ISRM && module.channelsCount == 8)
|
||||
mask |= MASK_RF_RACING_MODE;
|
||||
break;
|
||||
case PULSES_LP45:
|
||||
case PULSES_DSM2:
|
||||
@@ -447,8 +450,6 @@ void ModulePanel::update()
|
||||
mask |= MASK_CHANNELS_RANGE| MASK_CHANNELS_COUNT | MASK_FAILSAFES;
|
||||
mask |= MASK_SUBTYPES | MASK_RX_FREQ | MASK_RF_POWER;
|
||||
break;
|
||||
case PULSES_OFF:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -512,6 +513,14 @@ void ModulePanel::update()
|
||||
ui->antennaMode->hide();
|
||||
}
|
||||
|
||||
if (mask & MASK_RF_RACING_MODE) {
|
||||
ui->racingMode->show();
|
||||
ui->racingMode->setChecked(module.access.racingMode);
|
||||
}
|
||||
else {
|
||||
ui->racingMode->hide();
|
||||
}
|
||||
|
||||
// R9M options
|
||||
ui->r9mPower->setVisible(mask & MASK_RF_POWER);
|
||||
ui->label_r9mPower->setVisible(mask & MASK_RF_POWER);
|
||||
@@ -803,6 +812,11 @@ void ModulePanel::on_disableChMap_stateChanged(int state)
|
||||
module.multi.disableMapping = (state == Qt::Checked);
|
||||
}
|
||||
|
||||
void ModulePanel::on_racingMode_stateChanged(int state)
|
||||
{
|
||||
module.access.racingMode = (state == Qt::Checked);
|
||||
}
|
||||
|
||||
void ModulePanel::on_autoBind_stateChanged(int state)
|
||||
{
|
||||
module.multi.autoBindMode = (state == Qt::Checked);
|
||||
|
||||
@@ -95,6 +95,7 @@ class ModulePanel : public ModelPanel
|
||||
void onSubTypeChanged();
|
||||
void on_autoBind_stateChanged(int state);
|
||||
void on_disableChMap_stateChanged(int state);
|
||||
void on_racingMode_stateChanged(int state);
|
||||
void on_disableTelem_stateChanged(int state);
|
||||
void on_lowPower_stateChanged(int state);
|
||||
void on_r9mPower_currentIndexChanged(int index);
|
||||
|
||||
@@ -1077,7 +1077,21 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0" colspan="2">
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="disableTelem">
|
||||
<property name="text">
|
||||
<string>Disable Telemetry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="racingMode">
|
||||
<property name="text">
|
||||
<string>Racing Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" colspan="2">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
@@ -1090,13 +1104,6 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="disableTelem">
|
||||
<property name="text">
|
||||
<string>Disable Telemetry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="disableChMap">
|
||||
<property name="text">
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(shared_SRCS
|
||||
genericpanel.cpp
|
||||
hexspinbox.cpp
|
||||
verticalscrollarea.cpp
|
||||
set(shared_NAMES
|
||||
genericpanel
|
||||
verticalscrollarea
|
||||
autobitsetcheckbox
|
||||
autocheckbox
|
||||
autocombobox
|
||||
autodoublespinbox
|
||||
autohexspinbox
|
||||
autolabel
|
||||
autolineedit
|
||||
autoprecisioncombobox
|
||||
autoslider
|
||||
autospinbox
|
||||
autotimeedit
|
||||
)
|
||||
|
||||
set(shared_HDRS
|
||||
autobitsetcheckbox.h
|
||||
autocheckbox.h
|
||||
autocombobox.h
|
||||
autodoublespinbox.h
|
||||
autohexspinbox.h
|
||||
autolineedit.h
|
||||
genericpanel.h
|
||||
hexspinbox.h
|
||||
autoprecisioncombobox.h
|
||||
autotimeedit.h
|
||||
)
|
||||
foreach(name ${shared_NAMES})
|
||||
set(shared_SRCS ${shared_SRCS} ${name}.cpp)
|
||||
set(shared_HDRS ${shared_HDRS} ${name}.h)
|
||||
endforeach()
|
||||
|
||||
qt5_wrap_cpp(shared_SRCS ${shared_HDRS})
|
||||
|
||||
# add after moc generation to stop warnings
|
||||
set(shared_SRCS ${shared_SRCS}
|
||||
autowidget.h
|
||||
autowidget.cpp
|
||||
)
|
||||
|
||||
add_library(shared ${shared_SRCS})
|
||||
target_link_libraries(shared PRIVATE Qt5::Widgets ${CPN_COMMON_LIB})
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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 "autobitsetcheckbox.h"
|
||||
|
||||
AutoBitsetCheckBox::AutoBitsetCheckBox(QWidget * parent) :
|
||||
AutoBitsetCheckBox(QString(), parent)
|
||||
{
|
||||
}
|
||||
|
||||
AutoBitsetCheckBox::AutoBitsetCheckBox(const QString & text, QWidget * parent) :
|
||||
QCheckBox(text, parent),
|
||||
AutoWidget()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
// int field constructors
|
||||
AutoBitsetCheckBox::AutoBitsetCheckBox(int & field, int bitmask, const QString & text, QWidget * parent) :
|
||||
AutoBitsetCheckBox(field, bitmask, false, text, parent)
|
||||
{
|
||||
}
|
||||
|
||||
AutoBitsetCheckBox::AutoBitsetCheckBox(int & field, int bitmask, bool invert, const QString & text, QWidget * parent) :
|
||||
QCheckBox(text, parent),
|
||||
AutoWidget()
|
||||
{
|
||||
setField(field, bitmask, invert);
|
||||
init();
|
||||
}
|
||||
|
||||
AutoBitsetCheckBox::AutoBitsetCheckBox(int & field, int bitmask, int toggleMask, const QString & text, QWidget * parent) :
|
||||
QCheckBox(text, parent),
|
||||
AutoWidget()
|
||||
{
|
||||
setField(field, bitmask, false, toggleMask);
|
||||
init();
|
||||
}
|
||||
|
||||
// unsigned field constructors
|
||||
AutoBitsetCheckBox::AutoBitsetCheckBox(unsigned & field, int bitmask, const QString & text, QWidget * parent) :
|
||||
AutoBitsetCheckBox(field, bitmask, false, text, parent)
|
||||
{
|
||||
}
|
||||
|
||||
AutoBitsetCheckBox::AutoBitsetCheckBox(unsigned & field, int bitmask, bool invert, const QString & text, QWidget * parent) :
|
||||
QCheckBox(text, parent),
|
||||
AutoWidget()
|
||||
{
|
||||
setField(field, bitmask, invert);
|
||||
init();
|
||||
}
|
||||
|
||||
AutoBitsetCheckBox::AutoBitsetCheckBox(unsigned & field, int bitmask, int toggleMask, const QString & text, QWidget * parent) :
|
||||
QCheckBox(text, parent),
|
||||
AutoWidget()
|
||||
{
|
||||
setField(field, bitmask, false, toggleMask);
|
||||
init();
|
||||
}
|
||||
|
||||
AutoBitsetCheckBox::~AutoBitsetCheckBox()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoBitsetCheckBox::setField(int & field, int bitmask, bool invert, int toggleMask)
|
||||
{
|
||||
m_field = &field;
|
||||
initField(bitmask, invert, toggleMask);
|
||||
}
|
||||
|
||||
void AutoBitsetCheckBox::setField(unsigned & field, int bitmask, bool invert, int toggleMask)
|
||||
{
|
||||
m_field = (int *)&field;
|
||||
initField(bitmask, invert, toggleMask);
|
||||
}
|
||||
|
||||
void AutoBitsetCheckBox::setBitmask(int bitmask)
|
||||
{
|
||||
m_bitmask = bitmask;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoBitsetCheckBox::setToggleMask(int toggleMask)
|
||||
{
|
||||
m_toggleMask = toggleMask;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoBitsetCheckBox::setInverted(bool invert)
|
||||
{
|
||||
m_invert = invert;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoBitsetCheckBox::updateValue()
|
||||
{
|
||||
if (m_field)
|
||||
setLock(true);
|
||||
setChecked((m_invert && !m_toggleMask) != bool(*m_field & m_bitmask));
|
||||
setLock(false);
|
||||
}
|
||||
|
||||
void AutoBitsetCheckBox::onToggled(bool checked)
|
||||
{
|
||||
if (!m_field || lock())
|
||||
return;
|
||||
|
||||
if (m_toggleMask) {
|
||||
if (checked) {
|
||||
*m_field &= ~m_toggleMask;
|
||||
*m_field |= m_bitmask;
|
||||
}
|
||||
else {
|
||||
*m_field &= ~m_bitmask;
|
||||
*m_field |= m_toggleMask;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_invert)
|
||||
checked = !checked;
|
||||
if (checked)
|
||||
*m_field |= m_bitmask;
|
||||
else
|
||||
*m_field &= ~m_bitmask;
|
||||
}
|
||||
|
||||
emit currentDataChanged(checked);
|
||||
dataChanged();
|
||||
}
|
||||
|
||||
void AutoBitsetCheckBox::init()
|
||||
{
|
||||
connect(this, &QCheckBox::toggled, this, &AutoBitsetCheckBox::onToggled);
|
||||
}
|
||||
|
||||
void AutoBitsetCheckBox::initField(int bitmask, bool invert, int toggleMask)
|
||||
{
|
||||
m_bitmask = bitmask;
|
||||
m_toggleMask = toggleMask;
|
||||
m_invert = toggleMask ? false : invert;
|
||||
updateValue();
|
||||
}
|
||||
@@ -20,165 +20,50 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QCheckBox>
|
||||
#include "genericpanel.h"
|
||||
#include "autowidget.h"
|
||||
|
||||
class AutoBitsetCheckBox: public QCheckBox
|
||||
#include <QCheckBox>
|
||||
|
||||
class AutoBitsetCheckBox: public QCheckBox, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
//! \property bitmask The value (shifted bit(s)) to set/clear based on checked state.
|
||||
Q_PROPERTY(int bitmask READ bitmask WRITE setBitmask)
|
||||
//! \property inverted If \e true, then the \p bitmask is cleared when the checkbox is checked, and vice versa. Default behavior is to set the bitmask when checked.
|
||||
Q_PROPERTY(bool inverted READ inverted WRITE setInverted)
|
||||
//! \property toggleMask If > 0, then set this value when clearing the \p bitmask value (toggles between the two masks being set). \p inverted is ignored if \p toggleMask is set.
|
||||
Q_PROPERTY(int toggleMask READ toggleMask WRITE setToggleMask)
|
||||
|
||||
public:
|
||||
explicit AutoBitsetCheckBox(QWidget *parent = nullptr) :
|
||||
AutoBitsetCheckBox(QString(), parent) {}
|
||||
explicit AutoBitsetCheckBox(const QString &text, QWidget *parent = nullptr) :
|
||||
QCheckBox(text, parent)
|
||||
{
|
||||
init();
|
||||
}
|
||||
explicit AutoBitsetCheckBox(QWidget * parent = nullptr);
|
||||
explicit AutoBitsetCheckBox(const QString &text, QWidget * parent = nullptr);
|
||||
|
||||
// int field constructors
|
||||
explicit AutoBitsetCheckBox(int & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) :
|
||||
AutoBitsetCheckBox(field, bitmask, false, text, parent) {}
|
||||
explicit AutoBitsetCheckBox(int & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) :
|
||||
QCheckBox(text, parent)
|
||||
{
|
||||
setField(field, bitmask, invert);
|
||||
init();
|
||||
}
|
||||
explicit AutoBitsetCheckBox(int & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) :
|
||||
QCheckBox(text, parent)
|
||||
{
|
||||
setField(field, bitmask, false, toggleMask);
|
||||
init();
|
||||
}
|
||||
explicit AutoBitsetCheckBox(int & field, int bitmask, const QString & text = QString(), QWidget * parent = nullptr);
|
||||
explicit AutoBitsetCheckBox(int & field, int bitmask, bool invert, const QString & text = QString(), QWidget * parent = nullptr);
|
||||
explicit AutoBitsetCheckBox(int & field, int bitmask, int toggleMask, const QString & text = QString(), QWidget * parent = nullptr);
|
||||
|
||||
// unsigned field constructors
|
||||
explicit AutoBitsetCheckBox(unsigned & field, int bitmask, const QString &text = QString(), QWidget *parent = nullptr) :
|
||||
AutoBitsetCheckBox(field, bitmask, false, text, parent) {}
|
||||
explicit AutoBitsetCheckBox(unsigned & field, int bitmask, bool invert, const QString &text = QString(), QWidget *parent = nullptr) :
|
||||
QCheckBox(text, parent)
|
||||
{
|
||||
setField(field, bitmask, invert);
|
||||
init();
|
||||
}
|
||||
explicit AutoBitsetCheckBox(unsigned & field, int bitmask, int toggleMask, const QString &text = QString(), QWidget *parent = nullptr) :
|
||||
QCheckBox(text, parent)
|
||||
{
|
||||
setField(field, bitmask, false, toggleMask);
|
||||
init();
|
||||
}
|
||||
explicit AutoBitsetCheckBox(unsigned & field, int bitmask, const QString & text = QString(), QWidget * parent = nullptr);
|
||||
explicit AutoBitsetCheckBox(unsigned & field, int bitmask, bool invert, const QString & text = QString(), QWidget * parent = nullptr);
|
||||
explicit AutoBitsetCheckBox(unsigned & field, int bitmask, int toggleMask, const QString & text = QString(), QWidget * parent = nullptr);
|
||||
|
||||
inline int bitmask() const { return m_bitmask; }
|
||||
inline int toggleMask() const { return m_toggleMask; }
|
||||
inline bool inverted() const { return m_toggleMask ? false : m_invert; }
|
||||
virtual ~AutoBitsetCheckBox();
|
||||
|
||||
public slots:
|
||||
void setField(int & field, int bitmask = 0, bool invert = false, int toggleMask = 0)
|
||||
{
|
||||
m_field = &field;
|
||||
initField(bitmask, invert, toggleMask);
|
||||
}
|
||||
virtual void updateValue() override;
|
||||
|
||||
void setField(unsigned & field, int bitmask = 0, bool invert = false, int toggleMask = 0)
|
||||
{
|
||||
m_field = reinterpret_cast<int *>(&field);
|
||||
initField(bitmask, invert, toggleMask);
|
||||
}
|
||||
void setField(int & field, int bitmask = 0, bool invert = false, int toggleMask = 0);
|
||||
void setField(unsigned & field, int bitmask = 0, bool invert = false, int toggleMask = 0);
|
||||
void setBitmask(int bitmask);
|
||||
void setToggleMask(int toggleMask);
|
||||
void setInverted(bool invert);
|
||||
|
||||
void setBitmask(int bitmask)
|
||||
{
|
||||
m_bitmask = bitmask;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void setToggleMask(int toggleMask)
|
||||
{
|
||||
m_toggleMask = toggleMask;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void setInverted(bool invert)
|
||||
{
|
||||
m_invert = invert;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void updateValue()
|
||||
{
|
||||
if (m_panel && m_panel->lock)
|
||||
return;
|
||||
if (!m_field)
|
||||
return;
|
||||
const bool oldLock = setLocked(true);
|
||||
setChecked((m_invert && !m_toggleMask) != bool(*m_field & m_bitmask));
|
||||
setLocked(oldLock);
|
||||
}
|
||||
|
||||
void setPanel(GenericPanel * panel)
|
||||
{
|
||||
m_panel = panel;
|
||||
}
|
||||
signals:
|
||||
void currentDataChanged(bool checked);
|
||||
|
||||
protected slots:
|
||||
void init()
|
||||
{
|
||||
connect(this, &AutoBitsetCheckBox::toggled, this, &AutoBitsetCheckBox::onToggled);
|
||||
}
|
||||
void onToggled(bool checked);
|
||||
|
||||
void initField(int bitmask, bool invert, int toggleMask)
|
||||
{
|
||||
m_bitmask = bitmask;
|
||||
m_toggleMask = toggleMask;
|
||||
m_invert = toggleMask ? false : invert;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void onToggled(bool checked)
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
|
||||
if (m_toggleMask) {
|
||||
if (checked) {
|
||||
*m_field &= ~m_toggleMask;
|
||||
*m_field |= m_bitmask;
|
||||
}
|
||||
else {
|
||||
*m_field &= ~m_bitmask;
|
||||
*m_field |= m_toggleMask;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_invert)
|
||||
checked = !checked;
|
||||
if (checked)
|
||||
*m_field |= m_bitmask;
|
||||
else
|
||||
*m_field &= ~m_bitmask;
|
||||
}
|
||||
|
||||
if (m_panel && !m_lock)
|
||||
emit m_panel->modified();
|
||||
}
|
||||
|
||||
bool setLocked(bool lock)
|
||||
{
|
||||
const bool ret = m_lock;
|
||||
m_lock = lock;
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected:
|
||||
int * m_field = nullptr;
|
||||
private:
|
||||
int *m_field = nullptr;
|
||||
int m_bitmask = 0;
|
||||
int m_toggleMask = 0;
|
||||
bool m_invert = false;
|
||||
bool m_lock = false;
|
||||
GenericPanel * m_panel = nullptr;
|
||||
|
||||
void init();
|
||||
void initField(int bitmask, bool invert, int toggleMask);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 "autocheckbox.h"
|
||||
|
||||
AutoCheckBox::AutoCheckBox(QWidget * parent):
|
||||
QCheckBox(parent),
|
||||
AutoWidget(),
|
||||
m_field(nullptr),
|
||||
m_invert(false)
|
||||
{
|
||||
connect(this, &QCheckBox::toggled, this, &AutoCheckBox::onToggled);
|
||||
}
|
||||
|
||||
AutoCheckBox::~AutoCheckBox()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoCheckBox::setField(bool & field, GenericPanel * panel, bool invert)
|
||||
{
|
||||
m_field = &field;
|
||||
m_invert = invert;
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoCheckBox::setInvert(bool invert)
|
||||
{
|
||||
m_invert = invert;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoCheckBox::onToggled(bool checked)
|
||||
{
|
||||
if (m_field && !lock()) {
|
||||
const bool val = m_invert ? !checked : checked;
|
||||
*m_field = val;
|
||||
emit currentDataChanged(val);
|
||||
dataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AutoCheckBox::updateValue()
|
||||
{
|
||||
if (m_field) {
|
||||
setLock(true);
|
||||
setChecked(m_invert ? !(*m_field) : *m_field);
|
||||
setLock(false);
|
||||
}
|
||||
}
|
||||
@@ -20,62 +20,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QCheckBox>
|
||||
#include "genericpanel.h"
|
||||
#include "autowidget.h"
|
||||
|
||||
class AutoCheckBox: public QCheckBox
|
||||
#include <QCheckBox>
|
||||
|
||||
class AutoCheckBox : public QCheckBox, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoCheckBox(QWidget * parent = nullptr):
|
||||
QCheckBox(parent),
|
||||
field(nullptr),
|
||||
panel(nullptr),
|
||||
lock(false)
|
||||
{
|
||||
connect(this, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)));
|
||||
}
|
||||
explicit AutoCheckBox(QWidget * parent = nullptr);
|
||||
virtual ~AutoCheckBox();
|
||||
|
||||
void setField(bool & field, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->field = &field;
|
||||
this->panel = panel;
|
||||
updateValue();
|
||||
}
|
||||
virtual void updateValue() override;
|
||||
|
||||
void setEnabled(bool enabled)
|
||||
{
|
||||
QCheckBox::setEnabled(enabled);
|
||||
}
|
||||
|
||||
void updateValue()
|
||||
{
|
||||
if (field) {
|
||||
lock = true;
|
||||
setChecked(*field);
|
||||
lock = false;
|
||||
}
|
||||
}
|
||||
void setField(bool & field, GenericPanel * panel = nullptr, bool invert = false);
|
||||
void setInvert(bool invert);
|
||||
|
||||
signals:
|
||||
void currentDataChanged(bool value);
|
||||
|
||||
protected slots:
|
||||
void onToggled(bool checked)
|
||||
{
|
||||
if (panel && panel->lock)
|
||||
return;
|
||||
if (field && !lock) {
|
||||
*field = checked;
|
||||
emit currentDataChanged(checked);
|
||||
if (panel)
|
||||
emit panel->modified();
|
||||
}
|
||||
}
|
||||
void onToggled(bool checked);
|
||||
|
||||
protected:
|
||||
bool *field = nullptr;
|
||||
GenericPanel *panel = nullptr;
|
||||
bool lock = false;
|
||||
private:
|
||||
bool *m_field;
|
||||
bool m_invert;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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 "autocombobox.h"
|
||||
|
||||
AutoComboBox::AutoComboBox(QWidget * parent):
|
||||
QComboBox(parent),
|
||||
AutoWidget(),
|
||||
m_field(nullptr),
|
||||
m_next(0),
|
||||
m_hasModel(false),
|
||||
m_rawSource(nullptr),
|
||||
m_rawSwitch(nullptr)
|
||||
{
|
||||
connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int)));
|
||||
}
|
||||
|
||||
AutoComboBox::~AutoComboBox()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoComboBox::clear()
|
||||
{
|
||||
if (m_hasModel)
|
||||
return;
|
||||
|
||||
setLock(true);
|
||||
QComboBox::clear();
|
||||
m_next = 0;
|
||||
setLock(false);
|
||||
}
|
||||
|
||||
void AutoComboBox::insertItems(int index, const QStringList & items)
|
||||
{
|
||||
if (m_hasModel)
|
||||
return;
|
||||
|
||||
foreach(QString item, items) {
|
||||
addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
void AutoComboBox::addItem(const QString & item)
|
||||
{
|
||||
if (m_hasModel)
|
||||
return;
|
||||
|
||||
addItem(item, m_next++);
|
||||
}
|
||||
|
||||
void AutoComboBox::addItem(const QString & item, int value)
|
||||
{
|
||||
if (m_hasModel)
|
||||
return;
|
||||
|
||||
setLock(true);
|
||||
QComboBox::addItem(item, value);
|
||||
setLock(false);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoComboBox::setField(unsigned int & field, GenericPanel * panel)
|
||||
{
|
||||
m_field = (int *)&field;
|
||||
m_rawSource = nullptr;
|
||||
m_rawSwitch = nullptr;
|
||||
setFieldInit(panel);
|
||||
}
|
||||
|
||||
void AutoComboBox::setField(int & field, GenericPanel * panel)
|
||||
{
|
||||
m_field = &field;
|
||||
m_rawSource = nullptr;
|
||||
m_rawSwitch = nullptr;
|
||||
setFieldInit(panel);
|
||||
}
|
||||
|
||||
void AutoComboBox::setField(RawSource & field, GenericPanel * panel)
|
||||
{
|
||||
m_rawSource = &field;
|
||||
m_rawSwitch = nullptr;
|
||||
m_field = nullptr;
|
||||
setFieldInit(panel);
|
||||
}
|
||||
|
||||
void AutoComboBox::setField(RawSwitch & field, GenericPanel * panel)
|
||||
{
|
||||
m_rawSwitch = &field;
|
||||
m_rawSource = nullptr;
|
||||
m_field = nullptr;
|
||||
setFieldInit(panel);
|
||||
}
|
||||
|
||||
void AutoComboBox::setFieldInit(GenericPanel * panel)
|
||||
{
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoComboBox::setModel(QAbstractItemModel * model)
|
||||
{
|
||||
setLock(true);
|
||||
QComboBox::setModel(model);
|
||||
setLock(false);
|
||||
m_hasModel = true;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoComboBox::setAutoIndexes()
|
||||
{
|
||||
if (m_hasModel)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < count(); ++i)
|
||||
setItemData(i, i);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoComboBox::updateValue()
|
||||
{
|
||||
if (!m_field && !m_rawSource && !m_rawSwitch)
|
||||
return;
|
||||
|
||||
setLock(true);
|
||||
|
||||
if (m_field)
|
||||
setCurrentIndex(findData(*m_field));
|
||||
else if (m_rawSource)
|
||||
setCurrentIndex(findData(m_rawSource->toValue()));
|
||||
else if (m_rawSwitch)
|
||||
setCurrentIndex(findData(m_rawSwitch->toValue()));
|
||||
|
||||
setLock(false);
|
||||
}
|
||||
|
||||
void AutoComboBox::onCurrentIndexChanged(int index)
|
||||
{
|
||||
if (lock() || index < 0)
|
||||
return;
|
||||
|
||||
bool ok;
|
||||
const int val = itemData(index).toInt(&ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
if (m_field && *m_field != val) {
|
||||
*m_field = val;
|
||||
}
|
||||
else if (m_rawSource && m_rawSource->toValue() != val) {
|
||||
*m_rawSource = RawSource(val);
|
||||
}
|
||||
else if (m_rawSwitch && m_rawSwitch->toValue() != val) {
|
||||
*m_rawSwitch = RawSwitch(val);
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
emit currentDataChanged(val);
|
||||
dataChanged();
|
||||
}
|
||||
@@ -20,174 +20,49 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QComboBox>
|
||||
#include "genericpanel.h"
|
||||
#include "autowidget.h"
|
||||
#include "rawsource.h"
|
||||
#include "rawswitch.h"
|
||||
|
||||
class AutoComboBox: public QComboBox
|
||||
#include <QComboBox>
|
||||
|
||||
class AutoComboBox : public QComboBox, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoComboBox(QWidget * parent = nullptr):
|
||||
QComboBox(parent),
|
||||
field(nullptr),
|
||||
panel(nullptr),
|
||||
next(0),
|
||||
lock(false),
|
||||
hasModel(false),
|
||||
rawSource(nullptr),
|
||||
rawSwitch(nullptr)
|
||||
{
|
||||
connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int)));
|
||||
}
|
||||
explicit AutoComboBox(QWidget * parent = nullptr);
|
||||
virtual ~AutoComboBox();
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (!hasModel) {
|
||||
lock = true;
|
||||
QComboBox::clear();
|
||||
next = 0;
|
||||
lock = false;
|
||||
}
|
||||
}
|
||||
// QComboBox
|
||||
virtual void addItem(const QString & item);
|
||||
virtual void addItem(const QString & item, int value);
|
||||
virtual void insertItems(int index, const QStringList & items);
|
||||
// AutoWidget
|
||||
virtual void updateValue() override;
|
||||
|
||||
virtual void insertItems(int index, const QStringList & items)
|
||||
{
|
||||
if (!hasModel) {
|
||||
foreach(QString item, items) {
|
||||
addItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
void clear();
|
||||
|
||||
virtual void addItem(const QString & item)
|
||||
{
|
||||
if (!hasModel)
|
||||
addItem(item, next++);
|
||||
}
|
||||
void setField(unsigned int & field, GenericPanel * panel = nullptr);
|
||||
void setField(int & field, GenericPanel * panel = nullptr);
|
||||
void setField(RawSource & field, GenericPanel * panel = nullptr);
|
||||
void setField(RawSwitch & field, GenericPanel * panel = nullptr);
|
||||
|
||||
virtual void addItem(const QString & item, int value)
|
||||
{
|
||||
if (!hasModel) {
|
||||
lock = true;
|
||||
QComboBox::addItem(item, value);
|
||||
lock = false;
|
||||
updateValue();
|
||||
}
|
||||
}
|
||||
|
||||
void setField(unsigned int & field, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->field = (int *)&field;
|
||||
this->rawSource = nullptr;
|
||||
this->rawSwitch = nullptr;
|
||||
this->panel = panel;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void setField(int & field, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->field = &field;
|
||||
this->rawSource = nullptr;
|
||||
this->rawSwitch = nullptr;
|
||||
this->panel = panel;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void setField(RawSource & field, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->rawSource = &field;
|
||||
this->rawSwitch = nullptr;
|
||||
this->field = nullptr;
|
||||
this->panel = panel;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void setField(RawSwitch & field, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->rawSwitch = &field;
|
||||
this->rawSource = nullptr;
|
||||
this->field = nullptr;
|
||||
this->panel = panel;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void setModel(QAbstractItemModel * model)
|
||||
{
|
||||
lock = true;
|
||||
QComboBox::setModel(model);
|
||||
lock = false;
|
||||
hasModel = true;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void setAutoIndexes()
|
||||
{
|
||||
if (!hasModel) {
|
||||
for (int i = 0; i < count(); ++i)
|
||||
setItemData(i, i);
|
||||
updateValue();
|
||||
}
|
||||
}
|
||||
|
||||
void updateValue()
|
||||
{
|
||||
if (!field && !rawSource && !rawSwitch)
|
||||
return;
|
||||
|
||||
lock = true;
|
||||
|
||||
if (field)
|
||||
setCurrentIndex(findData(*field));
|
||||
else if (rawSource)
|
||||
setCurrentIndex(findData(rawSource->toValue()));
|
||||
else if (rawSwitch)
|
||||
setCurrentIndex(findData(rawSwitch->toValue()));
|
||||
|
||||
lock = false;
|
||||
}
|
||||
void setAutoIndexes();
|
||||
void setModel(QAbstractItemModel * model);
|
||||
|
||||
signals:
|
||||
void currentDataChanged(int value);
|
||||
|
||||
protected slots:
|
||||
void onCurrentIndexChanged(int index)
|
||||
{
|
||||
if (panel && panel->lock)
|
||||
return;
|
||||
if (lock || index < 0)
|
||||
return;
|
||||
void onCurrentIndexChanged(int index);
|
||||
|
||||
bool ok;
|
||||
const int val = itemData(index).toInt(&ok);
|
||||
if (!ok)
|
||||
return;
|
||||
private:
|
||||
int *m_field;
|
||||
int m_next;
|
||||
bool m_hasModel;
|
||||
RawSource *m_rawSource;
|
||||
RawSwitch *m_rawSwitch;
|
||||
|
||||
if (field && *field != val) {
|
||||
*field = val;
|
||||
}
|
||||
else if (rawSource && rawSource->toValue() != val) {
|
||||
*rawSource = RawSource(val);
|
||||
}
|
||||
else if (rawSwitch && rawSwitch->toValue() != val) {
|
||||
*rawSwitch = RawSwitch(val);
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
emit currentDataChanged(val);
|
||||
if (panel)
|
||||
emit panel->modified();
|
||||
}
|
||||
|
||||
protected:
|
||||
int *field = nullptr;
|
||||
GenericPanel *panel = nullptr;
|
||||
int next = 0;
|
||||
bool lock = false;
|
||||
bool hasModel = false;
|
||||
RawSource *rawSource = nullptr;
|
||||
RawSwitch *rawSwitch = nullptr;
|
||||
void setFieldInit(GenericPanel * panel);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 "autodoublespinbox.h"
|
||||
|
||||
AutoDoubleSpinBox::AutoDoubleSpinBox(QWidget * parent):
|
||||
QDoubleSpinBox(parent),
|
||||
AutoWidget(),
|
||||
m_field(nullptr),
|
||||
m_offset(0)
|
||||
{
|
||||
connect(this, SIGNAL(valueChanged(double)), this, SLOT(onValueChanged(double)));
|
||||
}
|
||||
|
||||
AutoDoubleSpinBox::~AutoDoubleSpinBox()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoDoubleSpinBox::setField(int & field, GenericPanel * panel)
|
||||
{
|
||||
m_field = &field;
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoDoubleSpinBox::setField(unsigned int & field, GenericPanel * panel)
|
||||
{
|
||||
m_field = (int *)&field;
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoDoubleSpinBox::setDecimals(int prec)
|
||||
{
|
||||
QDoubleSpinBox::setDecimals(prec);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoDoubleSpinBox::setOffset(int offset)
|
||||
{
|
||||
m_offset = offset;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoDoubleSpinBox::updateValue()
|
||||
{
|
||||
if (m_field) {
|
||||
setLock(true);
|
||||
setValue(float(*m_field + m_offset) / multiplier());
|
||||
setLock(false);
|
||||
}
|
||||
}
|
||||
|
||||
int AutoDoubleSpinBox::multiplier()
|
||||
{
|
||||
switch (decimals()) {
|
||||
case 1:
|
||||
return 10;
|
||||
case 2:
|
||||
return 100;
|
||||
case 3:
|
||||
return 1000;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void AutoDoubleSpinBox::onValueChanged(double value)
|
||||
{
|
||||
if (m_field && !lock()) {
|
||||
*m_field = round(value * multiplier() - m_offset);
|
||||
emit currentDataChanged(*m_field);
|
||||
dataChanged();
|
||||
}
|
||||
}
|
||||
@@ -20,87 +20,38 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "autowidget.h"
|
||||
|
||||
#include <QDoubleSpinBox>
|
||||
#include "genericpanel.h"
|
||||
|
||||
#if __GNUC__
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
class AutoDoubleSpinBox: public QDoubleSpinBox
|
||||
class AutoDoubleSpinBox : public QDoubleSpinBox, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoDoubleSpinBox(QWidget * parent = nullptr):
|
||||
QDoubleSpinBox(parent),
|
||||
field(nullptr),
|
||||
panel(nullptr),
|
||||
lock(false)
|
||||
{
|
||||
connect(this, SIGNAL(valueChanged(double)), this, SLOT(onValueChanged(double)));
|
||||
}
|
||||
explicit AutoDoubleSpinBox(QWidget * parent = nullptr);
|
||||
virtual ~AutoDoubleSpinBox();
|
||||
|
||||
void setField(int & field, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->field = &field;
|
||||
this->panel = panel;
|
||||
updateValue();
|
||||
}
|
||||
virtual void updateValue() override;
|
||||
|
||||
void setField(unsigned int & field, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->field = (int *)&field;
|
||||
this->panel = panel;
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void updateValue()
|
||||
{
|
||||
if (field) {
|
||||
lock = true;
|
||||
setValue(float(*field) / multiplier());
|
||||
lock = false;
|
||||
}
|
||||
}
|
||||
|
||||
void setDecimals(int prec)
|
||||
{
|
||||
QDoubleSpinBox::setDecimals(prec);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
protected:
|
||||
int multiplier()
|
||||
{
|
||||
switch (decimals()) {
|
||||
case 1:
|
||||
return 10;
|
||||
case 2:
|
||||
return 100;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
void setField(int & field, GenericPanel * panel = nullptr);
|
||||
void setField(unsigned int & field, GenericPanel * panel = nullptr);
|
||||
void setDecimals(int prec);
|
||||
void setOffset(int offset);
|
||||
|
||||
signals:
|
||||
void currentDataChanged(double value);
|
||||
|
||||
protected slots:
|
||||
void onValueChanged(double value)
|
||||
{
|
||||
if (panel && panel->lock)
|
||||
return;
|
||||
if (field && !lock) {
|
||||
*field = round(value * multiplier());
|
||||
emit currentDataChanged(value);
|
||||
if (panel) {
|
||||
emit panel->modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
void onValueChanged(double value);
|
||||
|
||||
protected:
|
||||
int * field = nullptr;
|
||||
GenericPanel * panel = nullptr;
|
||||
bool lock = false;
|
||||
private:
|
||||
int *m_field;
|
||||
int m_offset;
|
||||
|
||||
int multiplier();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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 "autohexspinbox.h"
|
||||
|
||||
AutoHexSpinBox::AutoHexSpinBox(QWidget * parent):
|
||||
QSpinBox(parent),
|
||||
AutoWidget(),
|
||||
m_field(nullptr)
|
||||
{
|
||||
setRange(0, AUTOHEXSPINBOX_MAX_VALUE);
|
||||
connect(this, QOverload<int>::of(&QSpinBox::valueChanged), this, &AutoHexSpinBox::onValueChanged);
|
||||
}
|
||||
|
||||
AutoHexSpinBox::~AutoHexSpinBox()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoHexSpinBox::setField(unsigned int & field, const unsigned int min, const unsigned int max, GenericPanel * panel)
|
||||
{
|
||||
m_field = &field;
|
||||
setRange(min, max);
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoHexSpinBox::setField(unsigned int & field, GenericPanel * panel)
|
||||
{
|
||||
m_field = &field;
|
||||
setRange(0, AUTOHEXSPINBOX_MAX_VALUE);
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoHexSpinBox::setRange(const unsigned int min, const unsigned int max)
|
||||
{
|
||||
QSpinBox::setRange(min, max);
|
||||
|
||||
m_length = QString("%1").arg(max, 0, 16).size();
|
||||
|
||||
m_validator = new QRegExpValidator(QRegExp(QString("[0-9A-Fa-f]{1,%1}").arg(m_length)), this);
|
||||
}
|
||||
|
||||
void AutoHexSpinBox::updateValue()
|
||||
{
|
||||
if (m_field) {
|
||||
setLock(true);
|
||||
setValue(*m_field);
|
||||
setLock(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AutoHexSpinBox::onValueChanged(int value)
|
||||
{
|
||||
if (m_field && !lock()) {
|
||||
if (*m_field != (unsigned)value) {
|
||||
*m_field = (unsigned)value;
|
||||
emit currentDataChanged(value);
|
||||
dataChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reimplemented
|
||||
QValidator::State AutoHexSpinBox::validate(QString &text, int &pos) const
|
||||
{
|
||||
return m_validator->validate(text, pos);
|
||||
}
|
||||
|
||||
int AutoHexSpinBox::valueFromText(const QString &text) const
|
||||
{
|
||||
return text.toInt(0, 16);
|
||||
}
|
||||
|
||||
QString AutoHexSpinBox::textFromValue(int value) const
|
||||
{
|
||||
return QString("%1").arg(value, m_length, 16, QChar('0')).toUpper();
|
||||
}
|
||||
@@ -20,58 +20,42 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hexspinbox.h"
|
||||
#include "genericpanel.h"
|
||||
#include "autowidget.h"
|
||||
|
||||
class AutoHexSpinBox: public HexSpinBox
|
||||
#include <QSpinBox>
|
||||
#include <QString>
|
||||
|
||||
class QRegExpValidator;
|
||||
|
||||
class AutoHexSpinBox : public QSpinBox, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoHexSpinBox(QWidget * parent = nullptr):
|
||||
HexSpinBox(parent),
|
||||
field(nullptr),
|
||||
panel(nullptr),
|
||||
lock(false)
|
||||
{
|
||||
connect(this, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged(int)));
|
||||
}
|
||||
constexpr static unsigned int AUTOHEXSPINBOX_MAX_VALUE {65535};
|
||||
|
||||
void setField(unsigned int & field, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->field = &field;
|
||||
this->panel = panel;
|
||||
updateValue();
|
||||
}
|
||||
explicit AutoHexSpinBox(QWidget * parent = nullptr);
|
||||
virtual ~AutoHexSpinBox();
|
||||
|
||||
void updateValue()
|
||||
{
|
||||
if (field) {
|
||||
lock = true;
|
||||
setValue(*field);
|
||||
lock = false;
|
||||
}
|
||||
}
|
||||
virtual void updateValue();
|
||||
|
||||
void setField(unsigned int & field, const unsigned int min = 0, const unsigned int max = AUTOHEXSPINBOX_MAX_VALUE, GenericPanel * panel = nullptr);
|
||||
void setField(unsigned int & field, GenericPanel * panel = nullptr);
|
||||
void setRange(unsigned int min = 0, unsigned int max = AUTOHEXSPINBOX_MAX_VALUE);
|
||||
|
||||
protected:
|
||||
QValidator::State validate(QString &text, int &pos) const;
|
||||
int valueFromText(const QString &text) const;
|
||||
QString textFromValue(int value) const;
|
||||
|
||||
signals:
|
||||
void currentDataChanged(int value);
|
||||
|
||||
protected slots:
|
||||
void onValueChanged(int value)
|
||||
{
|
||||
if (panel && panel->lock)
|
||||
return;
|
||||
if (field && !lock) {
|
||||
*field = value;
|
||||
emit currentDataChanged(value);
|
||||
if (panel) {
|
||||
emit panel->modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
void onValueChanged(int value);
|
||||
|
||||
protected:
|
||||
unsigned int * field = nullptr;
|
||||
GenericPanel * panel = nullptr;
|
||||
bool lock = false;
|
||||
private:
|
||||
unsigned int *m_field;
|
||||
QRegExpValidator *m_validator;
|
||||
unsigned int m_length;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 "autolabel.h"
|
||||
|
||||
#include <QFontMetrics>
|
||||
|
||||
AutoLabel::AutoLabel(QWidget * parent):
|
||||
QLabel(parent),
|
||||
AutoWidget(),
|
||||
m_charField(NULL),
|
||||
m_strField(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
AutoLabel::~AutoLabel()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoLabel::setField(char * field, GenericPanel * panel)
|
||||
{
|
||||
m_charField = field;
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoLabel::setField(QString & field, GenericPanel * panel)
|
||||
{
|
||||
m_strField = &field;
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoLabel::setWidth(int numChars)
|
||||
{
|
||||
QFontMetrics *f = new QFontMetrics(this->font());
|
||||
QSize sz = f->size(Qt::TextSingleLine, QString(numChars, QChar('X')));
|
||||
setMinimumWidth(sz.width());
|
||||
delete f;
|
||||
}
|
||||
|
||||
void AutoLabel::updateValue()
|
||||
{
|
||||
setLock(true);
|
||||
if (m_strField)
|
||||
setText(*m_strField);
|
||||
else if (m_charField)
|
||||
setText(m_charField);
|
||||
setLock(false);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "autowidget.h"
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
class AutoLabel: public QLabel, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoLabel(QWidget * parent = nullptr);
|
||||
virtual ~AutoLabel();
|
||||
|
||||
virtual void updateValue() override;
|
||||
|
||||
void setField(char * field, GenericPanel * panel = nullptr);
|
||||
void setField(QString & field, GenericPanel * panel = nullptr);
|
||||
void setWidth(int numChars);
|
||||
|
||||
private:
|
||||
char *m_charField;
|
||||
QString *m_strField;
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "autolineedit.h"
|
||||
|
||||
AutoLineEdit::AutoLineEdit(QWidget * parent, bool updateOnChange):
|
||||
QLineEdit(parent),
|
||||
AutoWidget(),
|
||||
m_charField(NULL),
|
||||
m_strField(nullptr)
|
||||
{
|
||||
if (updateOnChange)
|
||||
connect(this, &QLineEdit::textChanged, this, &AutoLineEdit::onEdited);
|
||||
else
|
||||
connect(this, &QLineEdit::editingFinished, this, &AutoLineEdit::onEdited);
|
||||
}
|
||||
|
||||
AutoLineEdit::~AutoLineEdit()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoLineEdit::setField(char * field, int len, GenericPanel * panel)
|
||||
{
|
||||
m_charField = field;
|
||||
setPanel(panel);
|
||||
setValidator(new QRegExpValidator(QRegExp("[ A-Za-z0-9_.-,]*"), this));
|
||||
if (len)
|
||||
setMaxLength(len);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoLineEdit::setField(QString & field, int len, GenericPanel * panel)
|
||||
{
|
||||
m_strField = &field;
|
||||
if (len)
|
||||
setMaxLength(len);
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoLineEdit::updateValue()
|
||||
{
|
||||
setLock(true);
|
||||
if (m_strField)
|
||||
setText(*m_strField);
|
||||
else if (m_charField)
|
||||
setText(m_charField);
|
||||
setLock(false);
|
||||
}
|
||||
|
||||
void AutoLineEdit::onEdited()
|
||||
{
|
||||
if (lock())
|
||||
return;
|
||||
|
||||
if (m_strField && *m_strField != text())
|
||||
*m_strField = text();
|
||||
else if (m_charField && strcmp(m_charField, text().toLatin1()))
|
||||
strcpy(m_charField, text().toLatin1());
|
||||
else
|
||||
return;
|
||||
|
||||
emit currentDataChanged();
|
||||
dataChanged();
|
||||
}
|
||||
@@ -20,83 +20,31 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "autowidget.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QRegExpValidator>
|
||||
#include "genericpanel.h"
|
||||
|
||||
class AutoLineEdit: public QLineEdit
|
||||
class AutoLineEdit: public QLineEdit, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoLineEdit(QWidget * parent = nullptr, bool updateOnChange = false):
|
||||
QLineEdit(parent),
|
||||
field(NULL),
|
||||
strField(nullptr),
|
||||
panel(nullptr),
|
||||
lock(false)
|
||||
{
|
||||
if (updateOnChange)
|
||||
connect(this, &AutoLineEdit::textChanged, this, &AutoLineEdit::onEdited);
|
||||
else
|
||||
connect(this, &AutoLineEdit::editingFinished, this, &AutoLineEdit::onEdited);
|
||||
}
|
||||
explicit AutoLineEdit(QWidget * parent = nullptr, bool updateOnChange = false);
|
||||
virtual ~AutoLineEdit();
|
||||
|
||||
void setField(char * field, int len, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->field = field;
|
||||
this->panel = panel;
|
||||
setValidator(new QRegExpValidator(QRegExp("[ A-Za-z0-9_.-,]*"), this));
|
||||
setMaxLength(len);
|
||||
updateValue();
|
||||
}
|
||||
virtual void updateValue() override;
|
||||
|
||||
void setField(QString & field, int len = 0, GenericPanel * panel = nullptr)
|
||||
{
|
||||
strField = &field;
|
||||
this->panel = panel;
|
||||
if (len)
|
||||
setMaxLength(len);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void updateValue()
|
||||
{
|
||||
lock = true;
|
||||
if (field)
|
||||
setText(field);
|
||||
else if (strField)
|
||||
setText(*strField);
|
||||
lock = false;
|
||||
}
|
||||
void setField(char * field, int len, GenericPanel * panel = nullptr);
|
||||
void setField(QString & field, int len = 0, GenericPanel * panel = nullptr);
|
||||
|
||||
signals:
|
||||
void currentDataChanged();
|
||||
|
||||
protected slots:
|
||||
void onEdited()
|
||||
{
|
||||
if (panel && panel->lock)
|
||||
return;
|
||||
if (lock)
|
||||
return;
|
||||
void onEdited();
|
||||
|
||||
if (field)
|
||||
strcpy(field, text().toLatin1());
|
||||
else if (strField)
|
||||
*strField = text();
|
||||
else
|
||||
return;
|
||||
|
||||
emit currentDataChanged();
|
||||
|
||||
if (panel)
|
||||
emit panel->modified();
|
||||
}
|
||||
|
||||
protected:
|
||||
char * field;
|
||||
QString * strField = nullptr;
|
||||
GenericPanel * panel = nullptr;
|
||||
bool lock = false;
|
||||
private:
|
||||
char *m_charField;
|
||||
QString *m_strField;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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 "autoprecisioncombobox.h"
|
||||
|
||||
constexpr unsigned int APCB_DECIMALS_MIN {0};
|
||||
constexpr unsigned int APCB_DECIMALS_MAX {6};
|
||||
|
||||
AutoPrecisionComboBox::AutoPrecisionComboBox(QWidget * parent):
|
||||
QComboBox(parent),
|
||||
AutoWidget()
|
||||
{
|
||||
setFieldInit();
|
||||
init();
|
||||
}
|
||||
|
||||
AutoPrecisionComboBox::AutoPrecisionComboBox(unsigned int & field, unsigned int minDecimals, unsigned int maxDecimals, bool padding, QString suffix, QWidget * parent, GenericPanel * panel):
|
||||
QComboBox(parent),
|
||||
AutoWidget()
|
||||
{
|
||||
m_field = &field;
|
||||
setFieldInit(minDecimals, maxDecimals, padding, suffix, panel);
|
||||
init();
|
||||
}
|
||||
|
||||
AutoPrecisionComboBox::AutoPrecisionComboBox(int & field, unsigned int minDecimals, unsigned int maxDecimals, bool padding, QString suffix, QWidget * parent, GenericPanel * panel):
|
||||
QComboBox(parent),
|
||||
AutoWidget()
|
||||
{
|
||||
m_field = (unsigned int *)&field;
|
||||
setFieldInit(minDecimals, maxDecimals, padding, suffix, panel);
|
||||
init();
|
||||
}
|
||||
|
||||
AutoPrecisionComboBox::~AutoPrecisionComboBox()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setField(int & field, unsigned int minDecimals, unsigned int maxDecimals, bool padding, QString suffix, GenericPanel * panel)
|
||||
{
|
||||
m_field = (unsigned int *)&field;
|
||||
setFieldInit(minDecimals, maxDecimals, padding, suffix, panel);
|
||||
setPanel(panel);
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setField(unsigned int & field, unsigned int minDecimals, unsigned int maxDecimals, bool padding, QString suffix, GenericPanel * panel)
|
||||
{
|
||||
m_field = &field;
|
||||
setFieldInit(minDecimals, maxDecimals, padding, suffix, panel);
|
||||
setPanel(panel);
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setMinDecimals(unsigned int minDecimals)
|
||||
{
|
||||
m_minDecimals = rangecheckDecimals(minDecimals);
|
||||
if (m_minDecimals > m_maxDecimals)
|
||||
m_minDecimals = m_maxDecimals;
|
||||
if (!lock())
|
||||
updateList();
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setMaxDecimals(unsigned int maxDecimals)
|
||||
{
|
||||
m_maxDecimals = rangecheckDecimals(maxDecimals);
|
||||
if (m_maxDecimals < m_minDecimals)
|
||||
m_maxDecimals = m_minDecimals;
|
||||
if (!lock())
|
||||
updateList();
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setDecimalsRange(unsigned int min, unsigned int max)
|
||||
{
|
||||
setMinDecimals(min);
|
||||
setMaxDecimals(max);
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setPadding(bool padding)
|
||||
{
|
||||
m_padding = padding;
|
||||
if (!lock())
|
||||
updateList();
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setSuffix(QString suffix)
|
||||
{
|
||||
m_suffix = suffix.trimmed();
|
||||
if (!lock())
|
||||
updateList();
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setValue(int value)
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
|
||||
const unsigned int val = (unsigned int)value;
|
||||
if (*m_field != val) {
|
||||
*m_field = rangecheckDecimals(val);
|
||||
updateValue();
|
||||
emit currentDataChanged(value);
|
||||
dataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setValue(unsigned int value)
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
|
||||
if (*m_field != value) {
|
||||
*m_field = rangecheckDecimals(value);
|
||||
updateValue();
|
||||
emit currentDataChanged((int)value);
|
||||
dataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::updateValue()
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
|
||||
if (!isValidDecimals(*m_field))
|
||||
return;
|
||||
|
||||
if (*m_field > m_maxDecimals)
|
||||
setMaxDecimals(*m_field);
|
||||
|
||||
setLock(true);
|
||||
setCurrentIndex(findData(*m_field));
|
||||
setLock(false);
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setAutoIndexes()
|
||||
{
|
||||
for (int i = 0; i < count(); ++i)
|
||||
setItemData(i, i);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::init()
|
||||
{
|
||||
connect(this, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AutoPrecisionComboBox::onCurrentIndexChanged);
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::setFieldInit(unsigned int minDecimals, unsigned int maxDecimals, bool padding, QString suffix, GenericPanel * panel)
|
||||
{
|
||||
setLock(true);
|
||||
setMinDecimals(minDecimals);
|
||||
setMaxDecimals(maxDecimals);
|
||||
setPadding(padding);
|
||||
setSuffix(suffix);
|
||||
setLock(false);
|
||||
setPanel(panel);
|
||||
updateList();
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::updateList()
|
||||
{
|
||||
setLock(true);
|
||||
unsigned int i;
|
||||
int j;
|
||||
clear();
|
||||
|
||||
for (i = APCB_DECIMALS_MIN, j = (int)m_maxDecimals; j >= 0; i++, j--) {
|
||||
if (i >= m_minDecimals) {
|
||||
QString str = QString("0.%1").arg(QString(i, '0'));
|
||||
if (m_padding)
|
||||
str.append(QString(j, '_'));
|
||||
if (m_suffix != "")
|
||||
str.append(QString(" %1").arg(m_suffix));
|
||||
addItem(str, i);
|
||||
}
|
||||
}
|
||||
|
||||
setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
setLock(false);
|
||||
}
|
||||
|
||||
void AutoPrecisionComboBox::onCurrentIndexChanged(int index)
|
||||
{
|
||||
if (!m_field || index < 0 || lock())
|
||||
return;
|
||||
|
||||
if (*m_field != itemData(index).toUInt()) {
|
||||
*m_field = itemData(index).toUInt();
|
||||
emit currentDataChanged(index);
|
||||
dataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int AutoPrecisionComboBox::rangecheckDecimals(unsigned int decimals)
|
||||
{
|
||||
unsigned int ret;
|
||||
if (decimals < APCB_DECIMALS_MIN)
|
||||
ret = APCB_DECIMALS_MIN;
|
||||
else if (decimals > APCB_DECIMALS_MAX)
|
||||
ret = APCB_DECIMALS_MAX;
|
||||
else
|
||||
ret = decimals;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AutoPrecisionComboBox::isValidDecimals(unsigned int value)
|
||||
{
|
||||
if (value >= APCB_DECIMALS_MIN && value <= APCB_DECIMALS_MAX)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@@ -20,235 +20,50 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "genericpanel.h"
|
||||
#include "autowidget.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QString>
|
||||
|
||||
class AutoPrecisionComboBox: public QComboBox
|
||||
class AutoPrecisionComboBox : public QComboBox, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
//! \property minDecimals Determines the first list item
|
||||
Q_PROPERTY(unsigned int minDecimals READ minDecimals WRITE setMinDecimals)
|
||||
//! \property maxDecimals Determines the last list item
|
||||
Q_PROPERTY(unsigned int maxDecimals READ maxDecimals WRITE setMaxDecimals)
|
||||
//! \property padding If true, add trailing underscore placeholders to each list item
|
||||
Q_PROPERTY(bool padding READ padding WRITE setPadding)
|
||||
//! \property suffix Optional text suffix to each list value
|
||||
Q_PROPERTY(QString suffix READ suffix WRITE setSuffix)
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoPrecisionComboBox(QWidget * parent = nullptr):
|
||||
QComboBox(parent)
|
||||
{
|
||||
init();
|
||||
}
|
||||
explicit AutoPrecisionComboBox(QWidget * parent = nullptr);
|
||||
explicit AutoPrecisionComboBox(unsigned int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", QWidget * parent = nullptr, GenericPanel * panel = nullptr);
|
||||
explicit AutoPrecisionComboBox(int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", QWidget * parent = nullptr, GenericPanel * panel = nullptr);
|
||||
virtual ~AutoPrecisionComboBox();
|
||||
|
||||
explicit AutoPrecisionComboBox(unsigned int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", QWidget * parent = nullptr, GenericPanel * panel = nullptr):
|
||||
QComboBox(parent)
|
||||
{
|
||||
setField(field, minDecimals, maxDecimals, padding, suffix, panel);
|
||||
init();
|
||||
}
|
||||
virtual void updateValue() override;
|
||||
|
||||
explicit AutoPrecisionComboBox(int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", QWidget * parent = nullptr, GenericPanel * panel = nullptr):
|
||||
QComboBox(parent)
|
||||
{
|
||||
setField(field, minDecimals, maxDecimals, padding, suffix, panel);
|
||||
init();
|
||||
}
|
||||
|
||||
inline int minDecimals() const { return m_minDecimals; }
|
||||
inline int maxDecimals() const { return m_maxDecimals; }
|
||||
inline bool padding() const { return m_padding; }
|
||||
inline QString suffix() const { return m_suffix; }
|
||||
|
||||
public slots:
|
||||
void setField(int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", GenericPanel * panel = nullptr)
|
||||
{
|
||||
m_field = reinterpret_cast<unsigned int *>(&field);
|
||||
initField(minDecimals, maxDecimals, padding, suffix);
|
||||
setPanel(panel);
|
||||
}
|
||||
|
||||
void setField(unsigned int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", GenericPanel * panel = nullptr)
|
||||
{
|
||||
m_field = &field;
|
||||
initField(minDecimals, maxDecimals, padding, suffix);
|
||||
setPanel(panel);
|
||||
}
|
||||
|
||||
void setMinDecimals(unsigned int minDecimals)
|
||||
{
|
||||
m_minDecimals = rangecheckDecimals(minDecimals);
|
||||
if (m_minDecimals > m_maxDecimals)
|
||||
m_minDecimals = m_maxDecimals;
|
||||
if (!m_lock)
|
||||
updateList();
|
||||
}
|
||||
|
||||
void setMaxDecimals(unsigned int maxDecimals)
|
||||
{
|
||||
m_maxDecimals = rangecheckDecimals(maxDecimals);
|
||||
if (m_maxDecimals < m_minDecimals)
|
||||
m_maxDecimals = m_minDecimals;
|
||||
if (!m_lock)
|
||||
updateList();
|
||||
}
|
||||
|
||||
void setPadding(bool padding)
|
||||
{
|
||||
m_padding = padding;
|
||||
if (!m_lock)
|
||||
updateList();
|
||||
}
|
||||
|
||||
void setSuffix(QString suffix)
|
||||
{
|
||||
m_suffix = suffix.trimmed();
|
||||
if (!m_lock)
|
||||
updateList();
|
||||
}
|
||||
|
||||
void setPanel(GenericPanel * panel)
|
||||
{
|
||||
m_panel = panel;
|
||||
}
|
||||
|
||||
void setValue(int value)
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
const unsigned int val = (unsigned int)value;
|
||||
if (*m_field != val) {
|
||||
*m_field = rangecheckDecimals(val);
|
||||
updateValue();
|
||||
emit currentDataChanged(value);
|
||||
}
|
||||
}
|
||||
|
||||
void setValue(unsigned int value)
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
if (*m_field != value) {
|
||||
*m_field = rangecheckDecimals(value);
|
||||
updateValue();
|
||||
emit currentDataChanged((int)value);
|
||||
}
|
||||
}
|
||||
|
||||
void updateValue()
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
if (!isValidDecimals(*m_field))
|
||||
return;
|
||||
if (*m_field > m_maxDecimals) {
|
||||
setMaxDecimals(*m_field);
|
||||
}
|
||||
const bool savedlock = setLocked(true);
|
||||
setCurrentIndex(findData(*m_field));
|
||||
setLocked(savedlock);
|
||||
}
|
||||
|
||||
void setAutoIndexes()
|
||||
{
|
||||
for (int i = 0; i < count(); ++i)
|
||||
setItemData(i, i);
|
||||
updateValue();
|
||||
}
|
||||
void setField(int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", GenericPanel * panel = nullptr);
|
||||
void setField(unsigned int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", GenericPanel * panel = nullptr);
|
||||
void setMinDecimals(unsigned int minDecimals);
|
||||
void setMaxDecimals(unsigned int maxDecimals);
|
||||
void setDecimalsRange(unsigned int min, unsigned int max);
|
||||
void setPadding(bool padding);
|
||||
void setSuffix(QString suffix);
|
||||
void setValue(int value);
|
||||
void setValue(unsigned int value);
|
||||
void setAutoIndexes();
|
||||
|
||||
signals:
|
||||
void currentDataChanged(int index);
|
||||
|
||||
protected slots:
|
||||
void init()
|
||||
{
|
||||
connect(this, QOverload<int>::of(&AutoPrecisionComboBox::currentIndexChanged), this, &AutoPrecisionComboBox::onCurrentIndexChanged);
|
||||
}
|
||||
void onCurrentIndexChanged(int index);
|
||||
|
||||
void initField(unsigned int minDecimals, unsigned int maxDecimals, bool padding, QString suffix)
|
||||
{
|
||||
const bool savedlock = setLocked(true);
|
||||
setMinDecimals(minDecimals);
|
||||
setMaxDecimals(maxDecimals);
|
||||
setPadding(padding);
|
||||
setSuffix(suffix);
|
||||
setLocked(savedlock);
|
||||
updateList();
|
||||
}
|
||||
|
||||
void updateList()
|
||||
{
|
||||
const bool savedlock = setLocked(true);
|
||||
unsigned int i;
|
||||
int j;
|
||||
clear();
|
||||
|
||||
for (i = APCB_DECIMALS_MIN, j = (int)m_maxDecimals; j >= 0; i++, j--) {
|
||||
if (i >= m_minDecimals) {
|
||||
QString str = QString("0.%1").arg(QString(i, '0'));
|
||||
if (m_padding)
|
||||
str.append(QString(j, '_'));
|
||||
if (m_suffix != "")
|
||||
str.append(QString(" %1").arg(m_suffix));
|
||||
addItem(str, i);
|
||||
}
|
||||
}
|
||||
|
||||
setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
setLocked(savedlock);
|
||||
}
|
||||
|
||||
void onCurrentIndexChanged(int index)
|
||||
{
|
||||
if (index < 0 || (m_panel && m_panel->lock) || m_lock)
|
||||
return;
|
||||
if (m_field) {
|
||||
*m_field = itemData(index).toUInt();
|
||||
emit currentDataChanged(index);
|
||||
if (m_panel)
|
||||
emit m_panel->modified();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int rangecheckDecimals(unsigned int decimals)
|
||||
{
|
||||
unsigned int ret;
|
||||
if (decimals < APCB_DECIMALS_MIN)
|
||||
ret = APCB_DECIMALS_MIN;
|
||||
else if (decimals > APCB_DECIMALS_MAX)
|
||||
ret = APCB_DECIMALS_MAX;
|
||||
else
|
||||
ret = decimals;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool isValidDecimals(unsigned int value)
|
||||
{
|
||||
if (value >= APCB_DECIMALS_MIN && value <= APCB_DECIMALS_MAX)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool setLocked(bool lock)
|
||||
{
|
||||
const bool ret = m_lock;
|
||||
m_lock = lock;
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected:
|
||||
constexpr static unsigned int APCB_DECIMALS_MIN = {0};
|
||||
constexpr static unsigned int APCB_DECIMALS_MAX = {6};
|
||||
|
||||
unsigned int * m_field = nullptr;
|
||||
GenericPanel * m_panel = nullptr;
|
||||
private:
|
||||
unsigned int *m_field = nullptr;
|
||||
unsigned int m_minDecimals = 0;
|
||||
unsigned int m_maxDecimals = 0;
|
||||
unsigned int m_maxDecimals = 1;
|
||||
bool m_padding = false;
|
||||
QString m_suffix = "";
|
||||
bool m_lock = false;
|
||||
|
||||
void init();
|
||||
void setFieldInit(unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", GenericPanel * panel = nullptr);
|
||||
bool isValidDecimals(unsigned int value);
|
||||
unsigned int rangecheckDecimals(unsigned int decimals);
|
||||
void updateList();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 "autoslider.h"
|
||||
|
||||
AutoSlider::AutoSlider(QWidget * parent):
|
||||
QSlider(parent),
|
||||
AutoWidget()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
AutoSlider::AutoSlider(Qt::Orientation orientation, QWidget * parent):
|
||||
QSlider(orientation, parent),
|
||||
AutoWidget()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
AutoSlider::~AutoSlider()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoSlider::setField(int & field, int min, int max, GenericPanel * panel)
|
||||
{
|
||||
m_field = &field;
|
||||
setFieldInit(min, max, panel);
|
||||
}
|
||||
|
||||
void AutoSlider::setField(unsigned int & field, int min, int max, GenericPanel * panel)
|
||||
{
|
||||
m_field = (int *)&field;
|
||||
setFieldInit(min, max, panel);
|
||||
}
|
||||
|
||||
void AutoSlider::setTick(int interval, QSlider::TickPosition position)
|
||||
{
|
||||
setTickInterval(interval);
|
||||
setTickPosition(position);
|
||||
}
|
||||
|
||||
void AutoSlider::updateValue()
|
||||
{
|
||||
if (m_field) {
|
||||
setLock(true);
|
||||
setValue(*m_field);
|
||||
setLock(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AutoSlider::init()
|
||||
{
|
||||
connect(this, &QSlider::valueChanged, this, &AutoSlider::onValueChanged);
|
||||
}
|
||||
|
||||
void AutoSlider::setFieldInit(int min, int max, GenericPanel * panel)
|
||||
{
|
||||
setPanel(panel);
|
||||
setRange(min, max);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoSlider::onValueChanged(int value)
|
||||
{
|
||||
if (m_field && !lock()) {
|
||||
if (*m_field != value) {
|
||||
*m_field = value;
|
||||
emit currentDataChanged(value);
|
||||
dataChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "autowidget.h"
|
||||
|
||||
#include <QSlider>
|
||||
|
||||
class AutoSlider : public QSlider, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoSlider(QWidget * parent = nullptr);
|
||||
explicit AutoSlider(Qt::Orientation orientation, QWidget * parent = nullptr);
|
||||
virtual ~AutoSlider();
|
||||
|
||||
virtual void updateValue() override;
|
||||
|
||||
void setField(int & field, int min, int max, GenericPanel * panel = nullptr);
|
||||
void setField(unsigned int & field, int min, int max, GenericPanel * panel = nullptr);
|
||||
void setTick(int interval, QSlider::TickPosition position);
|
||||
|
||||
signals:
|
||||
void currentDataChanged(int value);
|
||||
|
||||
protected slots:
|
||||
void onValueChanged(int value);
|
||||
|
||||
private:
|
||||
int *m_field = nullptr;
|
||||
|
||||
void init();
|
||||
void setFieldInit(int min, int max, GenericPanel * panel);
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 "autospinbox.h"
|
||||
|
||||
AutoSpinBox::AutoSpinBox(QWidget * parent):
|
||||
QSpinBox(parent),
|
||||
AutoWidget(),
|
||||
m_field(nullptr)
|
||||
{
|
||||
connect(this, QOverload<int>::of(&QSpinBox::valueChanged), this, &AutoSpinBox::onValueChanged);
|
||||
}
|
||||
|
||||
AutoSpinBox::~AutoSpinBox()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoSpinBox::setField(int & field, GenericPanel * panel)
|
||||
{
|
||||
m_field = &field;
|
||||
setFieldInit(panel);
|
||||
}
|
||||
|
||||
void AutoSpinBox::setField(unsigned int & field, GenericPanel * panel)
|
||||
{
|
||||
m_field = (int *)&field;
|
||||
setFieldInit(panel);
|
||||
}
|
||||
|
||||
void AutoSpinBox::setFieldInit(GenericPanel * panel)
|
||||
{
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoSpinBox::updateValue()
|
||||
{
|
||||
if (m_field) {
|
||||
setLock(true);
|
||||
setValue(*m_field);
|
||||
setLock(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AutoSpinBox::onValueChanged(int value)
|
||||
{
|
||||
if (m_field && !lock()) {
|
||||
if (*m_field != value) {
|
||||
*m_field = value;
|
||||
emit currentDataChanged(value);
|
||||
dataChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "autowidget.h"
|
||||
|
||||
#include <QSpinBox>
|
||||
|
||||
class AutoSpinBox : public QSpinBox, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoSpinBox(QWidget * parent = nullptr);
|
||||
virtual ~AutoSpinBox();
|
||||
|
||||
virtual void updateValue() override;
|
||||
|
||||
void setField(int & field, GenericPanel * panel = nullptr);
|
||||
void setField(unsigned int & field, GenericPanel * panel = nullptr);
|
||||
|
||||
signals:
|
||||
void currentDataChanged(int value);
|
||||
|
||||
protected slots:
|
||||
void onValueChanged(int value);
|
||||
|
||||
private:
|
||||
int *m_field;
|
||||
|
||||
void setFieldInit(GenericPanel * panel);
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 "autotimeedit.h"
|
||||
|
||||
AutoTimeEdit::AutoTimeEdit(QWidget * parent):
|
||||
QTimeEdit(parent),
|
||||
AutoWidget(),
|
||||
m_field(nullptr)
|
||||
{
|
||||
connect(this, &QTimeEdit::timeChanged, this, &AutoTimeEdit::onTimeChanged);
|
||||
}
|
||||
|
||||
AutoTimeEdit::~AutoTimeEdit()
|
||||
{
|
||||
}
|
||||
|
||||
void AutoTimeEdit::setField(unsigned int & field, GenericPanel * panel)
|
||||
{
|
||||
m_field = &field;
|
||||
setPanel(panel);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void AutoTimeEdit::setTimeRange(const QTime min, const QTime max)
|
||||
{
|
||||
QTimeEdit::setMinimumTime(min);
|
||||
QTimeEdit::setMaximumTime(max);
|
||||
}
|
||||
|
||||
void AutoTimeEdit::updateValue()
|
||||
{
|
||||
if (m_field) {
|
||||
setLock(true);
|
||||
int hour = *m_field / 3600;
|
||||
int min = (*m_field - (hour * 3600)) / 60;
|
||||
int sec = (*m_field - (hour * 3600)) % 60;
|
||||
setTime(QTime(hour, min, sec));
|
||||
setLock(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AutoTimeEdit::onTimeChanged(QTime time)
|
||||
{
|
||||
if (!m_field || lock())
|
||||
return;
|
||||
|
||||
unsigned int val = time.hour() * 3600 + time.minute() * 60 + time.second();
|
||||
if (*m_field != val) {
|
||||
*m_field = val;
|
||||
emit currentDataChanged(val);
|
||||
dataChanged();
|
||||
}
|
||||
}
|
||||
@@ -20,80 +20,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTimeEdit>
|
||||
#include "genericpanel.h"
|
||||
#include "autowidget.h"
|
||||
|
||||
class AutoTimeEdit: public QTimeEdit
|
||||
#include <QTimeEdit>
|
||||
|
||||
class AutoTimeEdit : public QTimeEdit, public AutoWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AutoTimeEdit(QWidget * parent = nullptr):
|
||||
QTimeEdit(parent),
|
||||
field(nullptr),
|
||||
panel(nullptr),
|
||||
lock(false)
|
||||
{
|
||||
connect(this, SIGNAL(timeChanged(QTime)), this, SLOT(onTimeChanged(QTime)));
|
||||
}
|
||||
explicit AutoTimeEdit(QWidget * parent = nullptr);
|
||||
virtual ~AutoTimeEdit();
|
||||
|
||||
void setField(unsigned int & field, GenericPanel * panel = nullptr)
|
||||
{
|
||||
this->field = &field;
|
||||
this->panel = panel;
|
||||
updateValue();
|
||||
}
|
||||
virtual void updateValue() override;
|
||||
|
||||
void setMinimumTime(const QTime time)
|
||||
{
|
||||
QTimeEdit::setMinimumTime(time);
|
||||
}
|
||||
|
||||
void setMaximumTime(const QTime time)
|
||||
{
|
||||
QTimeEdit::setMaximumTime(time);
|
||||
}
|
||||
|
||||
void setEnabled(bool enabled)
|
||||
{
|
||||
QTimeEdit::setEnabled(enabled);
|
||||
}
|
||||
|
||||
void updateValue()
|
||||
{
|
||||
if (field) {
|
||||
lock = true;
|
||||
int hour = *field / 3600;
|
||||
int min = (*field - (hour * 3600)) / 60;
|
||||
int sec = (*field - (hour * 3600)) % 60;
|
||||
setTime(QTime(hour, min, sec));
|
||||
lock = false;
|
||||
}
|
||||
}
|
||||
void setField(unsigned int & field, GenericPanel * panel = nullptr);
|
||||
void setTimeRange(const QTime min, const QTime max);
|
||||
|
||||
signals:
|
||||
void currentDataChanged(unsigned int value);
|
||||
void currentDataChanged(unsigned int val);
|
||||
|
||||
protected slots:
|
||||
void onTimeChanged(QTime time)
|
||||
{
|
||||
if (panel && panel->lock)
|
||||
return;
|
||||
if (!field || lock)
|
||||
return;
|
||||
void onTimeChanged(QTime time);
|
||||
|
||||
unsigned int val = time.hour() * 3600 + time.minute() * 60 + time.second();
|
||||
if (*field != val) {
|
||||
*field = val;
|
||||
emit currentDataChanged(val);
|
||||
if (panel)
|
||||
emit panel->modified();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned int *field = nullptr;
|
||||
GenericPanel *panel = nullptr;
|
||||
bool lock = false;
|
||||
private:
|
||||
unsigned int *m_field;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,30 +18,44 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "hexspinbox.h"
|
||||
#include "autowidget.h"
|
||||
#include "genericpanel.h"
|
||||
|
||||
HexSpinBox::HexSpinBox(QWidget *parent):
|
||||
QSpinBox(parent)
|
||||
AutoWidget::AutoWidget():
|
||||
m_panel(nullptr),
|
||||
m_lock(false)
|
||||
{
|
||||
validator = new QRegExpValidator(QRegExp("[0-9A-Fa-f]{1,8}"), this);
|
||||
}
|
||||
|
||||
QValidator::State HexSpinBox::validate(QString &text, int &pos) const
|
||||
AutoWidget::~AutoWidget()
|
||||
{
|
||||
return validator->validate(text, pos);
|
||||
}
|
||||
|
||||
int HexSpinBox::valueFromText(const QString &text) const
|
||||
bool AutoWidget::lock()
|
||||
{
|
||||
return text.toInt(0, 16);
|
||||
return panelLock() | m_lock;
|
||||
}
|
||||
|
||||
QString HexSpinBox::textFromValue(int value) const
|
||||
void AutoWidget::setLock(bool lock)
|
||||
{
|
||||
QString text;
|
||||
text.sprintf("%04X", value);
|
||||
return text;
|
||||
m_lock = lock;
|
||||
}
|
||||
|
||||
void AutoWidget::setPanel(GenericPanel * panel)
|
||||
{
|
||||
m_panel = panel;
|
||||
}
|
||||
|
||||
void AutoWidget::dataChanged()
|
||||
{
|
||||
if (m_panel)
|
||||
emit m_panel->modified();
|
||||
}
|
||||
|
||||
bool AutoWidget::panelLock()
|
||||
{
|
||||
if (m_panel)
|
||||
return m_panel->lock;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class GenericPanel;
|
||||
|
||||
// Note: cannot be a Qt object otherwise it will create a compiler ambiguity in the inheriting class
|
||||
class AutoWidget
|
||||
{
|
||||
friend class GenericPanel;
|
||||
|
||||
public:
|
||||
explicit AutoWidget();
|
||||
~AutoWidget();
|
||||
|
||||
protected:
|
||||
virtual void updateValue() = 0;
|
||||
|
||||
bool lock();
|
||||
void setLock(bool lock);
|
||||
void setPanel(GenericPanel * panel);
|
||||
|
||||
void dataChanged();
|
||||
bool panelLock();
|
||||
|
||||
private:
|
||||
GenericPanel *m_panel;
|
||||
bool m_lock;
|
||||
};
|
||||
@@ -20,22 +20,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSpinBox>
|
||||
|
||||
class QRegExpValidator;
|
||||
|
||||
class HexSpinBox : public QSpinBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HexSpinBox(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
QValidator::State validate(QString &text, int &pos) const;
|
||||
int valueFromText(const QString &text) const;
|
||||
QString textFromValue(int value) const;
|
||||
|
||||
private:
|
||||
QRegExpValidator *validator;
|
||||
};
|
||||
#include "autobitsetcheckbox.h"
|
||||
#include "autocheckbox.h"
|
||||
#include "autocombobox.h"
|
||||
#include "autodoublespinbox.h"
|
||||
#include "autohexspinbox.h"
|
||||
#include "autolineedit.h"
|
||||
#include "autoprecisioncombobox.h"
|
||||
#include "autoslider.h"
|
||||
#include "autospinbox.h"
|
||||
#include "autotimeedit.h"
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "genericpanel.h"
|
||||
#include "autowidget.h"
|
||||
|
||||
#include <TimerEdit>
|
||||
#include <QComboBox>
|
||||
@@ -127,3 +128,13 @@ void GenericPanel::disableMouseScrolling()
|
||||
foreach(QWidget * te, findChildren<TimerEdit*>())
|
||||
setFocusFilter(te);
|
||||
}
|
||||
|
||||
void GenericPanel::updateAutoWidgets()
|
||||
{
|
||||
foreach(QWidget *wdgt, findChildren<QWidget *>()) {
|
||||
AutoWidget *autowdgt = dynamic_cast<AutoWidget *>(wdgt);
|
||||
if (autowdgt) {
|
||||
autowdgt->updateValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,15 +32,8 @@ class GenericPanel : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class AutoComboBox;
|
||||
friend class AutoDoubleSpinBox;
|
||||
friend class AutoCheckBox;
|
||||
friend class AutoHexSpinBox;
|
||||
friend class AutoLineEdit;
|
||||
friend class GVarGroup;
|
||||
friend class AutoPrecisionComboBox;
|
||||
friend class AutoBitsetCheckBox;
|
||||
friend class AutoTimeEdit;
|
||||
friend class AutoWidget;
|
||||
|
||||
public:
|
||||
GenericPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware);
|
||||
@@ -65,4 +58,5 @@ class GenericPanel : public QWidget
|
||||
virtual bool eventFilter(QObject *obj, QEvent *event);
|
||||
void setFocusFilter(QWidget * w);
|
||||
void disableMouseScrolling();
|
||||
void updateAutoWidgets();
|
||||
};
|
||||
|
||||
@@ -26,6 +26,8 @@ class GenericPanel;
|
||||
|
||||
class VerticalScrollArea : public QScrollArea
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VerticalScrollArea(QWidget * parent, GenericPanel * panel);
|
||||
|
||||
|
||||
@@ -1631,7 +1631,7 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import
|
||||
<message>
|
||||
<location filename="../firmwares/customfunctiondata.cpp" line="67"/>
|
||||
<source>Trainer Sticks</source>
|
||||
<translation>Manches Écolage</translation>
|
||||
<translation>Écolage Manches</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/customfunctiondata.cpp" line="69"/>
|
||||
@@ -1656,7 +1656,7 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import
|
||||
<message>
|
||||
<location filename="../firmwares/customfunctiondata.cpp" line="77"/>
|
||||
<source>Trainer Channels</source>
|
||||
<translation>Écolage Channels</translation>
|
||||
<translation>Écolage Canaux</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/customfunctiondata.cpp" line="79"/>
|
||||
@@ -2233,7 +2233,7 @@ Si vous avez un fichier de sauvegarde des paramètres, vous pouvez l'import
|
||||
<translation>OpenTX ne supporte pas cette fonction sur cette carte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/opentx/opentxeeprom.cpp" line="2232"/>
|
||||
<location filename="../firmwares/opentx/opentxeeprom.cpp" line="2233"/>
|
||||
<source>OpenTX doesn't accept this radio protocol</source>
|
||||
<translation>OpenTX ne supporte pas ce protocole radio</translation>
|
||||
</message>
|
||||
@@ -8975,28 +8975,33 @@ Mixage actif par défaut si non-renseigné.</translation>
|
||||
<translation>Maître/Multi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup_module.ui" line="1096"/>
|
||||
<location filename="../modeledit/setup_module.ui" line="1083"/>
|
||||
<source>Disable Telemetry</source>
|
||||
<translation>Désactiver la télémétrie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup_module.ui" line="1103"/>
|
||||
<location filename="../modeledit/setup_module.ui" line="1090"/>
|
||||
<source>Racing Mode</source>
|
||||
<translation>Mode Course/Racing</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup_module.ui" line="1110"/>
|
||||
<source>Disable Ch. Map</source>
|
||||
<translation>Désactiver "Mapping" des VOIES</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup_module.ui" line="1171"/>
|
||||
<location filename="../modeledit/setup_module.ui" line="1178"/>
|
||||
<source>Show values in:</source>
|
||||
<translation>Afficher les valeurs en:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup_module.ui" line="1178"/>
|
||||
<location filename="../modeledit/setup_module.ui" line="1185"/>
|
||||
<source>%</source>
|
||||
<extracomment>abbreviation for percent</extracomment>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup_module.ui" line="1191"/>
|
||||
<location filename="../modeledit/setup_module.ui" line="1198"/>
|
||||
<source>μs</source>
|
||||
<extracomment>abbreviation for microseconds</extracomment>
|
||||
<translation></translation>
|
||||
@@ -9084,7 +9089,7 @@ Mixage actif par défaut si non-renseigné.</translation>
|
||||
<translation>ID d'enregistrement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup_module.ui" line="1129"/>
|
||||
<location filename="../modeledit/setup_module.ui" line="1136"/>
|
||||
<source>Failsafe Positions</source>
|
||||
<translation>Positions Failsafe</translation>
|
||||
</message>
|
||||
@@ -9137,100 +9142,100 @@ Mixage actif par défaut si non-renseigné.</translation>
|
||||
<translation>Négative</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="131"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="118"/>
|
||||
<source>Trainer Port</source>
|
||||
<translation>Port écolage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="135"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="122"/>
|
||||
<source>Internal Radio System</source>
|
||||
<translation>Module HF interne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="135"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="122"/>
|
||||
<source>External Radio Module</source>
|
||||
<translation>Module HF externe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="137"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="124"/>
|
||||
<source>Extra Radio System</source>
|
||||
<translation>Module HF supplémentaire</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="139"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="126"/>
|
||||
<source>Radio System</source>
|
||||
<translation>Module HF</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="175"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="162"/>
|
||||
<source>10mW - 16CH</source>
|
||||
<translation>10mW - 16 VOIES</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="175"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="177"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="162"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="164"/>
|
||||
<source>100mW - 16CH</source>
|
||||
<translation>100mW - 16 VOIES</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="175"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="162"/>
|
||||
<source>500mW - 16CH</source>
|
||||
<translation>500mW - 16 VOIES</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="175"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="162"/>
|
||||
<source>Auto <= 1W - 16CH</source>
|
||||
<translation>Auto <= 1W - 16 VOIES</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="176"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="178"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="163"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="165"/>
|
||||
<source>25mW - 8CH</source>
|
||||
<translation>25mW - 8 VOIES</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="176"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="178"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="163"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="165"/>
|
||||
<source>25mW - 16CH</source>
|
||||
<translation>25mW - 16 VOIES</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="176"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="163"/>
|
||||
<source>200mW - 16CH (no telemetry)</source>
|
||||
<translation>200mW - 16 VOIES (pas de télémétrie)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="176"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="163"/>
|
||||
<source>500mW - 16CH (no telemetry)</source>
|
||||
<translation>500mW - 16 VOIES (pas de télémétrie)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="178"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="165"/>
|
||||
<source>100mW - 16CH (no telemetry)</source>
|
||||
<translation>100mW - 16 VOIES (pas de télémétrie)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="181"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="168"/>
|
||||
<source>25 mW</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="181"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="168"/>
|
||||
<source>100 mW</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="181"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="168"/>
|
||||
<source>500 mW</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="181"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="168"/>
|
||||
<source>1 W</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firmwares/moduledata.cpp" line="181"/>
|
||||
<location filename="../firmwares/moduledata.cpp" line="168"/>
|
||||
<source>2 W</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
@@ -9238,42 +9243,42 @@ Mixage actif par défaut si non-renseigné.</translation>
|
||||
<context>
|
||||
<name>ModulePanel</name>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="325"/>
|
||||
<location filename="../modeledit/setup.cpp" line="326"/>
|
||||
<source>Value</source>
|
||||
<translation>Valeur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="326"/>
|
||||
<location filename="../modeledit/setup.cpp" line="327"/>
|
||||
<source>Hold</source>
|
||||
<translation>Maintien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="327"/>
|
||||
<location filename="../modeledit/setup.cpp" line="328"/>
|
||||
<source>No Pulse</source>
|
||||
<translation>Pas d'impulsion</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="505"/>
|
||||
<location filename="../modeledit/setup.cpp" line="506"/>
|
||||
<source>Ask</source>
|
||||
<translation>Demander</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="506"/>
|
||||
<location filename="../modeledit/setup.cpp" line="507"/>
|
||||
<source>Internal</source>
|
||||
<translation>Interne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="507"/>
|
||||
<location filename="../modeledit/setup.cpp" line="508"/>
|
||||
<source>Internal + External</source>
|
||||
<translation>Interne + Externe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="507"/>
|
||||
<location filename="../modeledit/setup.cpp" line="508"/>
|
||||
<source>External</source>
|
||||
<translation>Externe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="568"/>
|
||||
<location filename="../modeledit/setup.cpp" line="577"/>
|
||||
<source>Bind on channel</source>
|
||||
<translation>Bind avec VOIE</translation>
|
||||
</message>
|
||||
@@ -11031,87 +11036,87 @@ Si cette option est cochée, la voie des gaz est inversée: le ralenti est &apo
|
||||
<context>
|
||||
<name>SetupPanel</name>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1092"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1106"/>
|
||||
<source>Popup menu available</source>
|
||||
<translation>Menu contextuel disponible</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1108"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1122"/>
|
||||
<source>Timer %1</source>
|
||||
<translation>Chrono %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1555"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1569"/>
|
||||
<source>Profile Settings</source>
|
||||
<translation>Paramètres du profil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1555"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1569"/>
|
||||
<source>SD structure path not specified or invalid</source>
|
||||
<translation>Chemin de la structure SD non spécifié ou invalide</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1570"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1584"/>
|
||||
<source>Copy</source>
|
||||
<translation>Copier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1571"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1585"/>
|
||||
<source>Cut</source>
|
||||
<translation>Couper</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1572"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1586"/>
|
||||
<source>Paste</source>
|
||||
<translation>Coller</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1573"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1587"/>
|
||||
<source>Clear</source>
|
||||
<translation>Effacer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1575"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1589"/>
|
||||
<source>Insert</source>
|
||||
<translation>Insérer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1576"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1590"/>
|
||||
<source>Delete</source>
|
||||
<translation>Supprimer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1577"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1591"/>
|
||||
<source>Move Up</source>
|
||||
<translation>Monter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1578"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1592"/>
|
||||
<source>Move Down</source>
|
||||
<translation>Descendre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1580"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1594"/>
|
||||
<source>Clear All</source>
|
||||
<translation>Effacer Tout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1615"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1629"/>
|
||||
<source>Clear Timer. Are you sure?</source>
|
||||
<translation>Effacer le Chrono. Êtes-vous sûr?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1627"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1641"/>
|
||||
<source>Clear all Timers. Are you sure?</source>
|
||||
<translation>Effacer tous les Chronos. Êtes-vous sûr?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1649"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1663"/>
|
||||
<source>Cut Timer. Are you sure?</source>
|
||||
<translation>Couper le Chrono. Êtes-vous sûr?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/setup.cpp" line="1657"/>
|
||||
<location filename="../modeledit/setup.cpp" line="1671"/>
|
||||
<source>Delete Timer. Are you sure?</source>
|
||||
<translation>Supprimer le Chrono. Êtes-vous sûr?</translation>
|
||||
</message>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
59,1,BayangRX,CPPM,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
|
||||
@@ -34,9 +35,9 @@
|
||||
6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
70,1,DSM_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
|
||||
45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
|
||||
45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
|
||||
16,0,ESKY,Std,0,Gyro,Pitch
|
||||
16,1,ESKY,ET4,0,Gyro,Pitch
|
||||
35,0,ESKY150,4CH,0
|
||||
@@ -54,6 +55,7 @@
|
||||
28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
56,1,Flysky2A_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
53,0,Height,5ch,0,Gear
|
||||
53,1,Height,8ch,0,Gear,Gyro,Flap,Light
|
||||
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
|
||||
@@ -79,6 +81,8 @@
|
||||
65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
|
||||
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,1,FrSkyRX,CloneTX,0
|
||||
55,2,FrSkyRX,EraseTX,0
|
||||
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
58,0,FX816,P38,1
|
||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
|
||||
@@ -99,13 +103,14 @@
|
||||
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
||||
2,1,Hubsan,H301,0,RTH,Light,Stab,Video
|
||||
2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
|
||||
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
71,0,JJRC345,Std,1,Flip,HLess,RTH
|
||||
71,0,JJRC345,JJRC345,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
49,0,KF606,Std,1,Trim
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
@@ -122,6 +127,8 @@
|
||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
|
||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
|
||||
17,5,MT99XX,A180,0,3D_6G
|
||||
17,6,MT99XX,Dragon,0,Mode,RTH
|
||||
44,0,NCC1701,Std,1,Warp
|
||||
77,0,OMP,M2,0,THold,IdleUp,6G_3D
|
||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||
@@ -138,10 +145,11 @@
|
||||
72,0,Q90C,Std,0,FMode,VTX+
|
||||
74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,2,RadioLink,DumboRC,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
|
||||
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
|
||||
21,0,Futaba,SFHSS,0,CH5,CH6,CH7,CH8
|
||||
19,0,Shenqi,Cycle,1
|
||||
68,0,Skyartec,Std,0,CH5,CH6,CH7
|
||||
11,0,SLT,V1,0,Gear,Pitch
|
||||
@@ -174,3 +182,11 @@
|
||||
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
|
||||
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
|
||||
52,0,ZSX,280,1,Light
|
||||
78,0,M-Link,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
79,0,WFLY2,RF20x,0,CH5,CH6,CH7,CH8,CH9,CH10
|
||||
80,0,E016Hv2,E016Hv2,1,TakLan,EmStop,Flip,Calib,HLess,RTH
|
||||
81,0,E010r5,E010r5,1,Flip,LED,CALIB,HLess,RTH,GLIDE
|
||||
82,0,LOLI,Std,0,CH5,CH6,CH7,CH8,1SwSePpPw,2SwSePw,3SwSe,4SwSe,5SwSeSb,6SwSe,7SwSePw,8SwSe
|
||||
83,0,E129,E129,1,TakLan,EmStop,TrimA,TrimE,TrimR
|
||||
84,0,JOYSWAY,Std,0
|
||||
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
|
||||
local toolName = "TNS|Multi LOLI RX config|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local loli_nok = false
|
||||
local channels={ { 768, "PWM", 100, 102, "PPM", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH1
|
||||
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH2
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH3
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH4
|
||||
{ 102, "SBUS", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH5
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH6
|
||||
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH7
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 } } -- CH8
|
||||
|
||||
local sel = 1
|
||||
local edit = false
|
||||
|
||||
local blink = 0
|
||||
local BLINK_SPEED = 15
|
||||
|
||||
local function drawScreenTitle(title)
|
||||
if LCD_W == 480 then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawScreenTitle(title, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function LOLI_Draw_LCD(event)
|
||||
local line = 0
|
||||
|
||||
lcd.clear()
|
||||
|
||||
--Display settings
|
||||
local lcd_opt = 0
|
||||
if LCD_W == 480 then
|
||||
drawScreenTitle("Multi - LOLI RX configuration tool")
|
||||
x_pos = 152
|
||||
x_inc = 90
|
||||
y_pos = 40
|
||||
y_inc = 20
|
||||
else
|
||||
x_pos = 5
|
||||
x_inc = 30
|
||||
y_pos = 1
|
||||
y_inc = 8
|
||||
lcd_opt = SMLSIZE
|
||||
end
|
||||
|
||||
--Multi Module detection
|
||||
if loli_nok then
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,50,"The LOLI protocol is not selected...", lcd_opt)
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(2,17,"LOLI protocol not selected...",SMLSIZE)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
--Display current config
|
||||
if LCD_W == 480 then
|
||||
line = line + 1
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line -2, "Channel", lcd_opt)
|
||||
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line -2, "Function", lcd_opt)
|
||||
lcd.drawRectangle(x_pos-4, y_pos+y_inc*line -4 , 2*x_inc +2, 188)
|
||||
lcd.drawLine(x_pos-4, y_pos+y_inc*line +18, x_pos-4 +2*x_inc +1, y_pos+y_inc*line +18, SOLID, 0)
|
||||
lcd.drawLine(x_pos+x_inc -5, y_pos+y_inc*line -4, x_pos+x_inc -5, y_pos+y_inc*line -5 +188, SOLID, 0)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
local out
|
||||
for i = 1, 8 do
|
||||
out = getValue("ch"..(i+8))
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line, "CH"..i, lcd_opt)
|
||||
for j = 1, #channels[i], 3 do
|
||||
if out > channels[i][j] then
|
||||
if sel == i then
|
||||
invert = INVERS
|
||||
if edit == true then
|
||||
blink = blink + 1
|
||||
if blink > BLINK_SPEED then
|
||||
invert = 0
|
||||
if blink > BLINK_SPEED * 2 then
|
||||
blink = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
invert = 0
|
||||
end
|
||||
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line, channels[i][j+1], lcd_opt + invert)
|
||||
break
|
||||
end
|
||||
end
|
||||
line = line + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function LOLI_Change_Value(dir)
|
||||
local pos = 0
|
||||
local out
|
||||
--look for the current position
|
||||
out = getValue("ch"..(sel+8))
|
||||
for j = 1, #channels[sel], 3 do
|
||||
if out > channels[sel][j] then
|
||||
pos = j
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
--decrement or increment
|
||||
if dir < 0 and pos > 1 then
|
||||
pos = pos - 3
|
||||
elseif dir > 0 and pos + 3 < #channels[sel] then
|
||||
pos = pos + 3
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
--delete all mixers for the selected channel
|
||||
local num_mix = model.getMixesCount(sel-1 +8)
|
||||
for i = 1, num_mix do
|
||||
model.deleteMix(sel-1 +8, 0);
|
||||
end
|
||||
|
||||
--create new mixer
|
||||
local source_max = getFieldInfo("cyc1")
|
||||
|
||||
local val = { name = channels[sel][pos+1],
|
||||
source = source_max.id - 1, -- MAX=100 on TX16S
|
||||
weight = channels[sel][pos+2],
|
||||
offset = 0,
|
||||
switch = 0,
|
||||
multiplex = 0,
|
||||
curveType = 0,
|
||||
curveValue = 0,
|
||||
flightModes = 0,
|
||||
carryTrim = false,
|
||||
mixWarn = 0,
|
||||
delayUp = 0,
|
||||
delayDown = 0,
|
||||
speedUp = 0,
|
||||
speedDown = 0 }
|
||||
model.insertMix(sel-1 +8, 0, val)
|
||||
end
|
||||
|
||||
local function LOLI_Menu(event)
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
if edit == false then
|
||||
-- not changing a value
|
||||
if sel < 8 then
|
||||
sel = sel + 1
|
||||
end
|
||||
else
|
||||
-- need to inc the value
|
||||
LOLI_Change_Value(1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
if edit == false then
|
||||
-- not changing a value
|
||||
if sel > 1 then
|
||||
sel = sel - 1
|
||||
end
|
||||
else
|
||||
-- need to dec the value
|
||||
LOLI_Change_Value(-1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
if edit == false then
|
||||
edit = true
|
||||
blink = BLINK_SPEED
|
||||
else
|
||||
edit = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function LOLI_Init()
|
||||
local module_conf = model.getModule(0)
|
||||
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
|
||||
module_conf = model.getModule(1)
|
||||
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
|
||||
loli_nok = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function LOLI_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
return 2
|
||||
else
|
||||
LOLI_Menu(event)
|
||||
LOLI_Draw_LCD(event)
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=LOLI_Init, run=LOLI_Run }
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,499 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for Config description
|
||||
-- To start operation:
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write "Conf" at address 0..3
|
||||
-- Read
|
||||
-- Read at address 12 gives the current config page
|
||||
-- Read at address 13..172 gives the current data of the page = 8 lines * 20 caracters
|
||||
-- Write
|
||||
-- Write at address 5..11 the command
|
||||
-- Write 0x01 at address 4 will send the command to the module
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local Version = "v0.1"
|
||||
local Focus = -1
|
||||
local Page = 0
|
||||
local Edit = -1
|
||||
local Edit_pos = 1
|
||||
local Menu = { {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""} }
|
||||
local Menu_value = {}
|
||||
local Blink = 0
|
||||
local Module = {}
|
||||
local InitialProtocol = 0
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Config_Send(page, line, value)
|
||||
local i
|
||||
i = (page*16) + line
|
||||
multiBuffer( 5, i )
|
||||
for i = 1 , 6 , 1 do
|
||||
multiBuffer( 5+i, value[i] )
|
||||
end
|
||||
multiBuffer( 4, 1 )
|
||||
end
|
||||
|
||||
local function Config_Release()
|
||||
Module.protocol = InitialProtocol
|
||||
model.setModule(1, Module)
|
||||
|
||||
local i
|
||||
for i = 3 , 0 , -1 do
|
||||
multiBuffer( i, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Page( )
|
||||
Config_Send(Page, 0, { 0, 0, 0, 0, 0, 0 })
|
||||
end
|
||||
|
||||
local function Config_Draw_Edit( event )
|
||||
local i
|
||||
local text
|
||||
|
||||
if Menu[Focus].field_type == 0xD0 then
|
||||
-- Editable Hex value
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 1
|
||||
Blink = 0
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
Menu_value[i] = Menu[Focus].field_value[i]
|
||||
end
|
||||
end
|
||||
if Edit == 0 then
|
||||
-- Not editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
if Edit_pos > Menu[Focus].field_len then
|
||||
-- Save or Cancel
|
||||
Edit = -1
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
-- Save
|
||||
Config_Send(Page, Focus, Menu_value)
|
||||
end
|
||||
return
|
||||
else
|
||||
-- Switch to edit mode
|
||||
Edit = 1
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < Menu[Focus].field_len + 2 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
else
|
||||
-- Editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- End edit
|
||||
Edit = 0
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
|
||||
end
|
||||
--Blink
|
||||
Blink = Blink + 1
|
||||
if Blink > 30 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
--Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
if i==Edit_pos and (Edit ~= 1 or Blink > 15) then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170+12*2*(i-1), 110, string.format('%02X', Menu_value[i]), attrib)
|
||||
else
|
||||
lcd.drawText(17+6*2*(i-1), 10, string.format('%02X', Menu_value[i]), attrib + SMLSIZE)
|
||||
end
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Save", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Save", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "Cancel", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "Cancel", attrib + SMLSIZE)
|
||||
end
|
||||
|
||||
elseif Menu[Focus].field_type == 0x90 then
|
||||
-- Action text
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 2
|
||||
end
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- Exit
|
||||
Edit = -1
|
||||
if Edit_pos == 1 then
|
||||
-- Yes
|
||||
Config_Send(Page, Focus, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA } )
|
||||
end
|
||||
return
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Switch to Yes
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < 2 then
|
||||
-- Switch to No
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
-- Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 110, Menu[Focus].field_text .. "?")
|
||||
else
|
||||
lcd.drawText(17, 10, Menu[Focus].field_text .. "?", SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Yes", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Yes", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "No", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "No", attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Next_Prev( event )
|
||||
-- Next Prev on main menu
|
||||
local line
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
for line = Focus - 1, 1, -1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
for line = Focus + 1, 7, 1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Draw_Menu()
|
||||
-- Main menu
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local length
|
||||
local text
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Multi Config " .. Version, MENU_TITLE_COLOR)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(10,50,"No Config telemetry...", BLINK)
|
||||
end
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(1, 0, "Multi Config " .. Version, SMLSIZE)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(2,17,"No Config telemetry...",SMLSIZE)
|
||||
end
|
||||
end
|
||||
|
||||
if multiBuffer(13) ~= 0x00 then
|
||||
if LCD_W == 480 then
|
||||
--Draw firmware version and channels order
|
||||
local ch_order = multiBuffer(17)
|
||||
local channel_names = {}
|
||||
channel_names[bitand(ch_order,3)+1] = "A"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "E"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "T"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "R"
|
||||
lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16), MENU_TITLE_COLOR)
|
||||
--lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4], MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawText(76, 0, "/Fw" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16),SMLSIZE) -- .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4])
|
||||
end
|
||||
|
||||
--Draw Menu
|
||||
for line = 1, 7, 1 do
|
||||
--Clear line info
|
||||
Menu[line].text = ""
|
||||
Menu[line].field_type = 0
|
||||
Menu[line].field_len = 0
|
||||
for i = 1, 7, 1 do
|
||||
Menu[line].field_value[i] = 0
|
||||
end
|
||||
Menu[line].field_text = ""
|
||||
length = 0
|
||||
--Read line from buffer
|
||||
for i = 0, 20-1, 1 do
|
||||
value=multiBuffer( line*20+13+i )
|
||||
if value == 0 then
|
||||
break -- end of line
|
||||
end
|
||||
if value > 0x80 and Menu[line].field_type == 0 then
|
||||
-- Read field type
|
||||
Menu[line].field_type = bitand(value, 0xF0)
|
||||
Menu[line].field_len = bitand(value, 0x0F)
|
||||
length = Menu[line].field_len
|
||||
if Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 and Focus == -1 then
|
||||
-- First actionnable field if nothing was selected
|
||||
Focus = line;
|
||||
end
|
||||
else
|
||||
if Menu[line].field_type == 0 then
|
||||
-- Text
|
||||
Menu[line].text = Menu[line].text .. string.char(value)
|
||||
else
|
||||
-- Menu specific fields
|
||||
length = length - 1
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
Menu[line].field_text = Menu[line].field_text .. string.char(value)
|
||||
else
|
||||
Menu[line].field_value[Menu[line].field_len-length] = value
|
||||
end
|
||||
if length == 0 then
|
||||
-- End of fields
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Display menu text
|
||||
if Menu[line].text ~= "" then
|
||||
if Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 or Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
Menu[line].text = Menu[line].text .. ":"
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,32+20*line,Menu[line].text )
|
||||
else
|
||||
lcd.drawText(2,1+8*line,Menu[line].text,SMLSIZE)
|
||||
end
|
||||
end
|
||||
-- Display specific fields
|
||||
if line == Focus then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
-- Text
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, Menu[line].field_text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, Menu[line].field_text, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 then
|
||||
-- Decimal value
|
||||
value = 0
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
value = value*256 + value
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, value, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, value, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
-- Hex value
|
||||
text=""
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
text = text .. string.format('%02X ', Menu[line].field_value[i])
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, text, SMLSIZE + attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Config_Init()
|
||||
--get Module settings and set to config
|
||||
Module = model.getModule(1)
|
||||
InitialProtocol = Module.protocol
|
||||
Module.protocol = 86
|
||||
model.setModule(1, Module)
|
||||
for i = 0, 10, 1 do end
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('C') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('C') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Request init of the buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Continue buffer init
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('n') )
|
||||
multiBuffer( 3, string.byte('f') )
|
||||
|
||||
-- Test set
|
||||
-- multiBuffer( 12, 0 )
|
||||
-- multiBuffer( 13, 1 )
|
||||
-- multiBuffer( 14, 3 )
|
||||
-- multiBuffer( 15, 2 )
|
||||
-- multiBuffer( 16, 62 )
|
||||
-- multiBuffer( 17, 0 + 1*4 + 2*16 + 3*64)
|
||||
|
||||
-- multiBuffer( 33, string.byte('G') )
|
||||
-- multiBuffer( 34, string.byte('l') )
|
||||
-- multiBuffer( 35, string.byte('o') )
|
||||
-- multiBuffer( 36, string.byte('b') )
|
||||
-- multiBuffer( 37, string.byte('a') )
|
||||
-- multiBuffer( 38, string.byte('l') )
|
||||
-- multiBuffer( 39, string.byte(' ') )
|
||||
-- multiBuffer( 40, string.byte('I') )
|
||||
-- multiBuffer( 41, string.byte('D') )
|
||||
-- multiBuffer( 42, 0xD0 + 4 )
|
||||
-- multiBuffer( 43, 0x12 )
|
||||
-- multiBuffer( 44, 0x34 )
|
||||
-- multiBuffer( 45, 0x56 )
|
||||
-- multiBuffer( 46, 0x78 )
|
||||
-- multiBuffer( 47, 0x9A )
|
||||
-- multiBuffer( 48, 0xBC )
|
||||
|
||||
-- multiBuffer( 53, 0x90 + 9 )
|
||||
-- multiBuffer( 54, string.byte('R') )
|
||||
-- multiBuffer( 55, string.byte('e') )
|
||||
-- multiBuffer( 56, string.byte('s') )
|
||||
-- multiBuffer( 57, string.byte('e') )
|
||||
-- multiBuffer( 58, string.byte('t') )
|
||||
-- multiBuffer( 59, string.byte(' ') )
|
||||
-- multiBuffer( 60, string.byte('G') )
|
||||
-- multiBuffer( 61, string.byte('I') )
|
||||
-- multiBuffer( 62, string.byte('D') )
|
||||
-- multiBuffer( 63, 0x00 )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Config_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
Config_Release()
|
||||
return 2
|
||||
else
|
||||
Config_Draw_Menu()
|
||||
if ( event == EVT_VIRTUAL_PREV_PAGE or event == EVT_VIRTUAL_NEXT_PAGE ) and Edit < 1 then
|
||||
-- Not editing, ok to change page
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event)
|
||||
if Page > 0 then
|
||||
--Page = Page - 1
|
||||
--Config_Page()
|
||||
end
|
||||
else
|
||||
--Page = Page + 1
|
||||
--Config_Page()
|
||||
end
|
||||
end
|
||||
if Focus > 0 then
|
||||
-- At least one line has an action
|
||||
if Edit >= 0 then
|
||||
-- Currently editing
|
||||
Config_Draw_Edit( event )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
-- Switch to edit
|
||||
Config_Draw_Edit( 0 )
|
||||
elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_NEXT then
|
||||
-- Main menu selection
|
||||
Config_Next_Prev( event )
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=Config_Init, run=Config_Run }
|
||||
@@ -0,0 +1,499 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for Config description
|
||||
-- To start operation:
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write "Conf" at address 0..3
|
||||
-- Read
|
||||
-- Read at address 12 gives the current config page
|
||||
-- Read at address 13..172 gives the current data of the page = 8 lines * 20 caracters
|
||||
-- Write
|
||||
-- Write at address 5..11 the command
|
||||
-- Write 0x01 at address 4 will send the command to the module
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local Version = "v0.1"
|
||||
local Focus = -1
|
||||
local Page = 0
|
||||
local Edit = -1
|
||||
local Edit_pos = 1
|
||||
local Menu = { {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""} }
|
||||
local Menu_value = {}
|
||||
local Blink = 0
|
||||
local Module = {}
|
||||
local InitialProtocol = 0
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Config_Send(page, line, value)
|
||||
local i
|
||||
i = (page*16) + line
|
||||
multiBuffer( 5, i )
|
||||
for i = 1 , 6 , 1 do
|
||||
multiBuffer( 5+i, value[i] )
|
||||
end
|
||||
multiBuffer( 4, 1 )
|
||||
end
|
||||
|
||||
local function Config_Release()
|
||||
Module.protocol = InitialProtocol
|
||||
model.setModule(0, Module)
|
||||
|
||||
local i
|
||||
for i = 3 , 0 , -1 do
|
||||
multiBuffer( i, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Page( )
|
||||
Config_Send(Page, 0, { 0, 0, 0, 0, 0, 0 })
|
||||
end
|
||||
|
||||
local function Config_Draw_Edit( event )
|
||||
local i
|
||||
local text
|
||||
|
||||
if Menu[Focus].field_type == 0xD0 then
|
||||
-- Editable Hex value
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 1
|
||||
Blink = 0
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
Menu_value[i] = Menu[Focus].field_value[i]
|
||||
end
|
||||
end
|
||||
if Edit == 0 then
|
||||
-- Not editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
if Edit_pos > Menu[Focus].field_len then
|
||||
-- Save or Cancel
|
||||
Edit = -1
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
-- Save
|
||||
Config_Send(Page, Focus, Menu_value)
|
||||
end
|
||||
return
|
||||
else
|
||||
-- Switch to edit mode
|
||||
Edit = 1
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < Menu[Focus].field_len + 2 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
else
|
||||
-- Editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- End edit
|
||||
Edit = 0
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
|
||||
end
|
||||
--Blink
|
||||
Blink = Blink + 1
|
||||
if Blink > 30 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
--Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
if i==Edit_pos and (Edit ~= 1 or Blink > 15) then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170+12*2*(i-1), 110, string.format('%02X', Menu_value[i]), attrib)
|
||||
else
|
||||
lcd.drawText(17+6*2*(i-1), 10, string.format('%02X', Menu_value[i]), attrib + SMLSIZE)
|
||||
end
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Save", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Save", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "Cancel", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "Cancel", attrib + SMLSIZE)
|
||||
end
|
||||
|
||||
elseif Menu[Focus].field_type == 0x90 then
|
||||
-- Action text
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 2
|
||||
end
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- Exit
|
||||
Edit = -1
|
||||
if Edit_pos == 1 then
|
||||
-- Yes
|
||||
Config_Send(Page, Focus, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA } )
|
||||
end
|
||||
return
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Switch to Yes
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < 2 then
|
||||
-- Switch to No
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
-- Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 110, Menu[Focus].field_text .. "?")
|
||||
else
|
||||
lcd.drawText(17, 10, Menu[Focus].field_text .. "?", SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Yes", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Yes", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "No", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "No", attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Next_Prev( event )
|
||||
-- Next Prev on main menu
|
||||
local line
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
for line = Focus - 1, 1, -1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
for line = Focus + 1, 7, 1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Draw_Menu()
|
||||
-- Main menu
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local length
|
||||
local text
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Multi Config " .. Version, MENU_TITLE_COLOR)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(10,50,"No Config telemetry...", BLINK)
|
||||
end
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(1, 0, "Multi Config " .. Version, SMLSIZE)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(2,17,"No Config telemetry...",SMLSIZE)
|
||||
end
|
||||
end
|
||||
|
||||
if multiBuffer(13) ~= 0x00 then
|
||||
if LCD_W == 480 then
|
||||
--Draw firmware version and channels order
|
||||
local ch_order = multiBuffer(17)
|
||||
local channel_names = {}
|
||||
channel_names[bitand(ch_order,3)+1] = "A"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "E"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "T"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "R"
|
||||
lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16), MENU_TITLE_COLOR)
|
||||
--lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4], MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawText(76, 0, "/Fw" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16),SMLSIZE) -- .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4])
|
||||
end
|
||||
|
||||
--Draw Menu
|
||||
for line = 1, 7, 1 do
|
||||
--Clear line info
|
||||
Menu[line].text = ""
|
||||
Menu[line].field_type = 0
|
||||
Menu[line].field_len = 0
|
||||
for i = 1, 7, 1 do
|
||||
Menu[line].field_value[i] = 0
|
||||
end
|
||||
Menu[line].field_text = ""
|
||||
length = 0
|
||||
--Read line from buffer
|
||||
for i = 0, 20-1, 1 do
|
||||
value=multiBuffer( line*20+13+i )
|
||||
if value == 0 then
|
||||
break -- end of line
|
||||
end
|
||||
if value > 0x80 and Menu[line].field_type == 0 then
|
||||
-- Read field type
|
||||
Menu[line].field_type = bitand(value, 0xF0)
|
||||
Menu[line].field_len = bitand(value, 0x0F)
|
||||
length = Menu[line].field_len
|
||||
if Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 and Focus == -1 then
|
||||
-- First actionnable field if nothing was selected
|
||||
Focus = line;
|
||||
end
|
||||
else
|
||||
if Menu[line].field_type == 0 then
|
||||
-- Text
|
||||
Menu[line].text = Menu[line].text .. string.char(value)
|
||||
else
|
||||
-- Menu specific fields
|
||||
length = length - 1
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
Menu[line].field_text = Menu[line].field_text .. string.char(value)
|
||||
else
|
||||
Menu[line].field_value[Menu[line].field_len-length] = value
|
||||
end
|
||||
if length == 0 then
|
||||
-- End of fields
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Display menu text
|
||||
if Menu[line].text ~= "" then
|
||||
if Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 or Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
Menu[line].text = Menu[line].text .. ":"
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,32+20*line,Menu[line].text )
|
||||
else
|
||||
lcd.drawText(2,1+8*line,Menu[line].text,SMLSIZE)
|
||||
end
|
||||
end
|
||||
-- Display specific fields
|
||||
if line == Focus then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
-- Text
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, Menu[line].field_text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, Menu[line].field_text, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 then
|
||||
-- Decimal value
|
||||
value = 0
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
value = value*256 + value
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, value, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, value, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
-- Hex value
|
||||
text=""
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
text = text .. string.format('%02X ', Menu[line].field_value[i])
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, text, SMLSIZE + attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Config_Init()
|
||||
--get Module settings and set to config
|
||||
Module = model.getModule(0)
|
||||
InitialProtocol = Module.protocol
|
||||
Module.protocol = 86
|
||||
model.setModule(0, Module)
|
||||
for i = 0, 10, 1 do end
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('C') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('C') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Request init of the buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Continue buffer init
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('n') )
|
||||
multiBuffer( 3, string.byte('f') )
|
||||
|
||||
-- Test set
|
||||
-- multiBuffer( 12, 0 )
|
||||
-- multiBuffer( 13, 1 )
|
||||
-- multiBuffer( 14, 3 )
|
||||
-- multiBuffer( 15, 2 )
|
||||
-- multiBuffer( 16, 62 )
|
||||
-- multiBuffer( 17, 0 + 1*4 + 2*16 + 3*64)
|
||||
|
||||
-- multiBuffer( 33, string.byte('G') )
|
||||
-- multiBuffer( 34, string.byte('l') )
|
||||
-- multiBuffer( 35, string.byte('o') )
|
||||
-- multiBuffer( 36, string.byte('b') )
|
||||
-- multiBuffer( 37, string.byte('a') )
|
||||
-- multiBuffer( 38, string.byte('l') )
|
||||
-- multiBuffer( 39, string.byte(' ') )
|
||||
-- multiBuffer( 40, string.byte('I') )
|
||||
-- multiBuffer( 41, string.byte('D') )
|
||||
-- multiBuffer( 42, 0xD0 + 4 )
|
||||
-- multiBuffer( 43, 0x12 )
|
||||
-- multiBuffer( 44, 0x34 )
|
||||
-- multiBuffer( 45, 0x56 )
|
||||
-- multiBuffer( 46, 0x78 )
|
||||
-- multiBuffer( 47, 0x9A )
|
||||
-- multiBuffer( 48, 0xBC )
|
||||
|
||||
-- multiBuffer( 53, 0x90 + 9 )
|
||||
-- multiBuffer( 54, string.byte('R') )
|
||||
-- multiBuffer( 55, string.byte('e') )
|
||||
-- multiBuffer( 56, string.byte('s') )
|
||||
-- multiBuffer( 57, string.byte('e') )
|
||||
-- multiBuffer( 58, string.byte('t') )
|
||||
-- multiBuffer( 59, string.byte(' ') )
|
||||
-- multiBuffer( 60, string.byte('G') )
|
||||
-- multiBuffer( 61, string.byte('I') )
|
||||
-- multiBuffer( 62, string.byte('D') )
|
||||
-- multiBuffer( 63, 0x00 )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Config_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
Config_Release()
|
||||
return 2
|
||||
else
|
||||
Config_Draw_Menu()
|
||||
if ( event == EVT_VIRTUAL_PREV_PAGE or event == EVT_VIRTUAL_NEXT_PAGE ) and Edit < 1 then
|
||||
-- Not editing, ok to change page
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event)
|
||||
if Page > 0 then
|
||||
--Page = Page - 1
|
||||
--Config_Page()
|
||||
end
|
||||
else
|
||||
--Page = Page + 1
|
||||
--Config_Page()
|
||||
end
|
||||
end
|
||||
if Focus > 0 then
|
||||
-- At least one line has an action
|
||||
if Edit >= 0 then
|
||||
-- Currently editing
|
||||
Config_Draw_Edit( event )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
-- Switch to edit
|
||||
Config_Draw_Edit( 0 )
|
||||
elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_NEXT then
|
||||
-- Main menu selection
|
||||
Config_Next_Prev( event )
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=Config_Init, run=Config_Run }
|
||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@@ -6,6 +6,7 @@
|
||||
14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
59,1,BayangRX,CPPM,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
|
||||
@@ -34,9 +35,9 @@
|
||||
6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
70,1,DSM_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
|
||||
45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
|
||||
45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
|
||||
16,0,ESKY,Std,0,Gyro,Pitch
|
||||
16,1,ESKY,ET4,0,Gyro,Pitch
|
||||
35,0,ESKY150,4CH,0
|
||||
@@ -54,6 +55,7 @@
|
||||
28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
56,1,Flysky2A_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
53,0,Height,5ch,0,Gear
|
||||
53,1,Height,8ch,0,Gear,Gyro,Flap,Light
|
||||
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
|
||||
@@ -79,6 +81,8 @@
|
||||
65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
|
||||
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,1,FrSkyRX,CloneTX,0
|
||||
55,2,FrSkyRX,EraseTX,0
|
||||
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
58,0,FX816,P38,1
|
||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
|
||||
@@ -99,13 +103,14 @@
|
||||
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
||||
2,1,Hubsan,H301,0,RTH,Light,Stab,Video
|
||||
2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
|
||||
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
71,0,JJRC345,Std,1,Flip,HLess,RTH
|
||||
71,0,JJRC345,JJRC345,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
49,0,KF606,Std,1,Trim
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
@@ -122,6 +127,8 @@
|
||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
|
||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
|
||||
17,5,MT99XX,A180,0,3D_6G
|
||||
17,6,MT99XX,Dragon,0,Mode,RTH
|
||||
44,0,NCC1701,Std,1,Warp
|
||||
77,0,OMP,M2,0,THold,IdleUp,6G_3D
|
||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||
@@ -138,10 +145,11 @@
|
||||
72,0,Q90C,Std,0,FMode,VTX+
|
||||
74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,2,RadioLink,DumboRC,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
|
||||
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
|
||||
21,0,Futaba,SFHSS,0,CH5,CH6,CH7,CH8
|
||||
19,0,Shenqi,Cycle,1
|
||||
68,0,Skyartec,Std,0,CH5,CH6,CH7
|
||||
11,0,SLT,V1,0,Gear,Pitch
|
||||
@@ -174,3 +182,11 @@
|
||||
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
|
||||
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
|
||||
52,0,ZSX,280,1,Light
|
||||
78,0,M-Link,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
79,0,WFLY2,RF20x,0,CH5,CH6,CH7,CH8,CH9,CH10
|
||||
80,0,E016Hv2,E016Hv2,1,TakLan,EmStop,Flip,Calib,HLess,RTH
|
||||
81,0,E010r5,E010r5,1,Flip,LED,CALIB,HLess,RTH,GLIDE
|
||||
82,0,LOLI,Std,0,CH5,CH6,CH7,CH8,1SwSePpPw,2SwSePw,3SwSe,4SwSe,5SwSeSb,6SwSe,7SwSePw,8SwSe
|
||||
83,0,E129,E129,1,TakLan,EmStop,TrimA,TrimE,TrimR
|
||||
84,0,JOYSWAY,Std,0
|
||||
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
|
||||
local toolName = "TNS|Multi LOLI RX config|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local loli_nok = false
|
||||
local channels={ { 768, "PWM", 100, 102, "PPM", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH1
|
||||
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH2
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH3
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH4
|
||||
{ 102, "SBUS", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH5
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH6
|
||||
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH7
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 } } -- CH8
|
||||
|
||||
local sel = 1
|
||||
local edit = false
|
||||
|
||||
local blink = 0
|
||||
local BLINK_SPEED = 15
|
||||
|
||||
local function drawScreenTitle(title)
|
||||
if LCD_W == 480 then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawScreenTitle(title, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function LOLI_Draw_LCD(event)
|
||||
local line = 0
|
||||
|
||||
lcd.clear()
|
||||
|
||||
--Display settings
|
||||
local lcd_opt = 0
|
||||
if LCD_W == 480 then
|
||||
drawScreenTitle("Multi - LOLI RX configuration tool")
|
||||
x_pos = 152
|
||||
x_inc = 90
|
||||
y_pos = 40
|
||||
y_inc = 20
|
||||
else
|
||||
x_pos = 5
|
||||
x_inc = 30
|
||||
y_pos = 1
|
||||
y_inc = 8
|
||||
lcd_opt = SMLSIZE
|
||||
end
|
||||
|
||||
--Multi Module detection
|
||||
if loli_nok then
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,50,"The LOLI protocol is not selected...", lcd_opt)
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(2,17,"LOLI protocol not selected...",SMLSIZE)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
--Display current config
|
||||
if LCD_W == 480 then
|
||||
line = line + 1
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line -2, "Channel", lcd_opt)
|
||||
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line -2, "Function", lcd_opt)
|
||||
lcd.drawRectangle(x_pos-4, y_pos+y_inc*line -4 , 2*x_inc +2, 188)
|
||||
lcd.drawLine(x_pos-4, y_pos+y_inc*line +18, x_pos-4 +2*x_inc +1, y_pos+y_inc*line +18, SOLID, 0)
|
||||
lcd.drawLine(x_pos+x_inc -5, y_pos+y_inc*line -4, x_pos+x_inc -5, y_pos+y_inc*line -5 +188, SOLID, 0)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
local out
|
||||
for i = 1, 8 do
|
||||
out = getValue("ch"..(i+8))
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line, "CH"..i, lcd_opt)
|
||||
for j = 1, #channels[i], 3 do
|
||||
if out > channels[i][j] then
|
||||
if sel == i then
|
||||
invert = INVERS
|
||||
if edit == true then
|
||||
blink = blink + 1
|
||||
if blink > BLINK_SPEED then
|
||||
invert = 0
|
||||
if blink > BLINK_SPEED * 2 then
|
||||
blink = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
invert = 0
|
||||
end
|
||||
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line, channels[i][j+1], lcd_opt + invert)
|
||||
break
|
||||
end
|
||||
end
|
||||
line = line + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function LOLI_Change_Value(dir)
|
||||
local pos = 0
|
||||
local out
|
||||
--look for the current position
|
||||
out = getValue("ch"..(sel+8))
|
||||
for j = 1, #channels[sel], 3 do
|
||||
if out > channels[sel][j] then
|
||||
pos = j
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
--decrement or increment
|
||||
if dir < 0 and pos > 1 then
|
||||
pos = pos - 3
|
||||
elseif dir > 0 and pos + 3 < #channels[sel] then
|
||||
pos = pos + 3
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
--delete all mixers for the selected channel
|
||||
local num_mix = model.getMixesCount(sel-1 +8)
|
||||
for i = 1, num_mix do
|
||||
model.deleteMix(sel-1 +8, 0);
|
||||
end
|
||||
|
||||
--create new mixer
|
||||
local source_max = getFieldInfo("cyc1")
|
||||
|
||||
local val = { name = channels[sel][pos+1],
|
||||
source = source_max.id - 1, -- MAX=100 on TX16S
|
||||
weight = channels[sel][pos+2],
|
||||
offset = 0,
|
||||
switch = 0,
|
||||
multiplex = 0,
|
||||
curveType = 0,
|
||||
curveValue = 0,
|
||||
flightModes = 0,
|
||||
carryTrim = false,
|
||||
mixWarn = 0,
|
||||
delayUp = 0,
|
||||
delayDown = 0,
|
||||
speedUp = 0,
|
||||
speedDown = 0 }
|
||||
model.insertMix(sel-1 +8, 0, val)
|
||||
end
|
||||
|
||||
local function LOLI_Menu(event)
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
if edit == false then
|
||||
-- not changing a value
|
||||
if sel < 8 then
|
||||
sel = sel + 1
|
||||
end
|
||||
else
|
||||
-- need to inc the value
|
||||
LOLI_Change_Value(1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
if edit == false then
|
||||
-- not changing a value
|
||||
if sel > 1 then
|
||||
sel = sel - 1
|
||||
end
|
||||
else
|
||||
-- need to dec the value
|
||||
LOLI_Change_Value(-1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
if edit == false then
|
||||
edit = true
|
||||
blink = BLINK_SPEED
|
||||
else
|
||||
edit = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function LOLI_Init()
|
||||
local module_conf = model.getModule(0)
|
||||
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
|
||||
module_conf = model.getModule(1)
|
||||
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
|
||||
loli_nok = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function LOLI_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
return 2
|
||||
else
|
||||
LOLI_Menu(event)
|
||||
LOLI_Draw_LCD(event)
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=LOLI_Init, run=LOLI_Run }
|
||||
@@ -0,0 +1,499 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for Config description
|
||||
-- To start operation:
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write "Conf" at address 0..3
|
||||
-- Read
|
||||
-- Read at address 12 gives the current config page
|
||||
-- Read at address 13..172 gives the current data of the page = 8 lines * 20 caracters
|
||||
-- Write
|
||||
-- Write at address 5..11 the command
|
||||
-- Write 0x01 at address 4 will send the command to the module
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local Version = "v0.1"
|
||||
local Focus = -1
|
||||
local Page = 0
|
||||
local Edit = -1
|
||||
local Edit_pos = 1
|
||||
local Menu = { {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""} }
|
||||
local Menu_value = {}
|
||||
local Blink = 0
|
||||
local Module = {}
|
||||
local InitialProtocol = 0
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Config_Send(page, line, value)
|
||||
local i
|
||||
i = (page*16) + line
|
||||
multiBuffer( 5, i )
|
||||
for i = 1 , 6 , 1 do
|
||||
multiBuffer( 5+i, value[i] )
|
||||
end
|
||||
multiBuffer( 4, 1 )
|
||||
end
|
||||
|
||||
local function Config_Release()
|
||||
Module.protocol = InitialProtocol
|
||||
model.setModule(1, Module)
|
||||
|
||||
local i
|
||||
for i = 3 , 0 , -1 do
|
||||
multiBuffer( i, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Page( )
|
||||
Config_Send(Page, 0, { 0, 0, 0, 0, 0, 0 })
|
||||
end
|
||||
|
||||
local function Config_Draw_Edit( event )
|
||||
local i
|
||||
local text
|
||||
|
||||
if Menu[Focus].field_type == 0xD0 then
|
||||
-- Editable Hex value
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 1
|
||||
Blink = 0
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
Menu_value[i] = Menu[Focus].field_value[i]
|
||||
end
|
||||
end
|
||||
if Edit == 0 then
|
||||
-- Not editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
if Edit_pos > Menu[Focus].field_len then
|
||||
-- Save or Cancel
|
||||
Edit = -1
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
-- Save
|
||||
Config_Send(Page, Focus, Menu_value)
|
||||
end
|
||||
return
|
||||
else
|
||||
-- Switch to edit mode
|
||||
Edit = 1
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < Menu[Focus].field_len + 2 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
else
|
||||
-- Editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- End edit
|
||||
Edit = 0
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
|
||||
end
|
||||
--Blink
|
||||
Blink = Blink + 1
|
||||
if Blink > 30 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
--Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
if i==Edit_pos and (Edit ~= 1 or Blink > 15) then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170+12*2*(i-1), 110, string.format('%02X', Menu_value[i]), attrib)
|
||||
else
|
||||
lcd.drawText(17+6*2*(i-1), 10, string.format('%02X', Menu_value[i]), attrib + SMLSIZE)
|
||||
end
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Save", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Save", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "Cancel", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "Cancel", attrib + SMLSIZE)
|
||||
end
|
||||
|
||||
elseif Menu[Focus].field_type == 0x90 then
|
||||
-- Action text
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 2
|
||||
end
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- Exit
|
||||
Edit = -1
|
||||
if Edit_pos == 1 then
|
||||
-- Yes
|
||||
Config_Send(Page, Focus, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA } )
|
||||
end
|
||||
return
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Switch to Yes
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < 2 then
|
||||
-- Switch to No
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
-- Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 110, Menu[Focus].field_text .. "?")
|
||||
else
|
||||
lcd.drawText(17, 10, Menu[Focus].field_text .. "?", SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Yes", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Yes", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "No", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "No", attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Next_Prev( event )
|
||||
-- Next Prev on main menu
|
||||
local line
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
for line = Focus - 1, 1, -1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
for line = Focus + 1, 7, 1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Draw_Menu()
|
||||
-- Main menu
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local length
|
||||
local text
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Multi Config " .. Version, MENU_TITLE_COLOR)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(10,50,"No Config telemetry...", BLINK)
|
||||
end
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(1, 0, "Multi Config " .. Version, SMLSIZE)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(2,17,"No Config telemetry...",SMLSIZE)
|
||||
end
|
||||
end
|
||||
|
||||
if multiBuffer(13) ~= 0x00 then
|
||||
if LCD_W == 480 then
|
||||
--Draw firmware version and channels order
|
||||
local ch_order = multiBuffer(17)
|
||||
local channel_names = {}
|
||||
channel_names[bitand(ch_order,3)+1] = "A"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "E"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "T"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "R"
|
||||
lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16), MENU_TITLE_COLOR)
|
||||
--lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4], MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawText(76, 0, "/Fw" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16),SMLSIZE) -- .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4])
|
||||
end
|
||||
|
||||
--Draw Menu
|
||||
for line = 1, 7, 1 do
|
||||
--Clear line info
|
||||
Menu[line].text = ""
|
||||
Menu[line].field_type = 0
|
||||
Menu[line].field_len = 0
|
||||
for i = 1, 7, 1 do
|
||||
Menu[line].field_value[i] = 0
|
||||
end
|
||||
Menu[line].field_text = ""
|
||||
length = 0
|
||||
--Read line from buffer
|
||||
for i = 0, 20-1, 1 do
|
||||
value=multiBuffer( line*20+13+i )
|
||||
if value == 0 then
|
||||
break -- end of line
|
||||
end
|
||||
if value > 0x80 and Menu[line].field_type == 0 then
|
||||
-- Read field type
|
||||
Menu[line].field_type = bitand(value, 0xF0)
|
||||
Menu[line].field_len = bitand(value, 0x0F)
|
||||
length = Menu[line].field_len
|
||||
if Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 and Focus == -1 then
|
||||
-- First actionnable field if nothing was selected
|
||||
Focus = line;
|
||||
end
|
||||
else
|
||||
if Menu[line].field_type == 0 then
|
||||
-- Text
|
||||
Menu[line].text = Menu[line].text .. string.char(value)
|
||||
else
|
||||
-- Menu specific fields
|
||||
length = length - 1
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
Menu[line].field_text = Menu[line].field_text .. string.char(value)
|
||||
else
|
||||
Menu[line].field_value[Menu[line].field_len-length] = value
|
||||
end
|
||||
if length == 0 then
|
||||
-- End of fields
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Display menu text
|
||||
if Menu[line].text ~= "" then
|
||||
if Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 or Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
Menu[line].text = Menu[line].text .. ":"
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,32+20*line,Menu[line].text )
|
||||
else
|
||||
lcd.drawText(2,1+8*line,Menu[line].text,SMLSIZE)
|
||||
end
|
||||
end
|
||||
-- Display specific fields
|
||||
if line == Focus then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
-- Text
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, Menu[line].field_text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, Menu[line].field_text, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 then
|
||||
-- Decimal value
|
||||
value = 0
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
value = value*256 + value
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, value, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, value, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
-- Hex value
|
||||
text=""
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
text = text .. string.format('%02X ', Menu[line].field_value[i])
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, text, SMLSIZE + attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Config_Init()
|
||||
--get Module settings and set to config
|
||||
Module = model.getModule(1)
|
||||
InitialProtocol = Module.protocol
|
||||
Module.protocol = 86
|
||||
model.setModule(1, Module)
|
||||
for i = 0, 10, 1 do end
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('C') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('C') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Request init of the buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Continue buffer init
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('n') )
|
||||
multiBuffer( 3, string.byte('f') )
|
||||
|
||||
-- Test set
|
||||
-- multiBuffer( 12, 0 )
|
||||
-- multiBuffer( 13, 1 )
|
||||
-- multiBuffer( 14, 3 )
|
||||
-- multiBuffer( 15, 2 )
|
||||
-- multiBuffer( 16, 62 )
|
||||
-- multiBuffer( 17, 0 + 1*4 + 2*16 + 3*64)
|
||||
|
||||
-- multiBuffer( 33, string.byte('G') )
|
||||
-- multiBuffer( 34, string.byte('l') )
|
||||
-- multiBuffer( 35, string.byte('o') )
|
||||
-- multiBuffer( 36, string.byte('b') )
|
||||
-- multiBuffer( 37, string.byte('a') )
|
||||
-- multiBuffer( 38, string.byte('l') )
|
||||
-- multiBuffer( 39, string.byte(' ') )
|
||||
-- multiBuffer( 40, string.byte('I') )
|
||||
-- multiBuffer( 41, string.byte('D') )
|
||||
-- multiBuffer( 42, 0xD0 + 4 )
|
||||
-- multiBuffer( 43, 0x12 )
|
||||
-- multiBuffer( 44, 0x34 )
|
||||
-- multiBuffer( 45, 0x56 )
|
||||
-- multiBuffer( 46, 0x78 )
|
||||
-- multiBuffer( 47, 0x9A )
|
||||
-- multiBuffer( 48, 0xBC )
|
||||
|
||||
-- multiBuffer( 53, 0x90 + 9 )
|
||||
-- multiBuffer( 54, string.byte('R') )
|
||||
-- multiBuffer( 55, string.byte('e') )
|
||||
-- multiBuffer( 56, string.byte('s') )
|
||||
-- multiBuffer( 57, string.byte('e') )
|
||||
-- multiBuffer( 58, string.byte('t') )
|
||||
-- multiBuffer( 59, string.byte(' ') )
|
||||
-- multiBuffer( 60, string.byte('G') )
|
||||
-- multiBuffer( 61, string.byte('I') )
|
||||
-- multiBuffer( 62, string.byte('D') )
|
||||
-- multiBuffer( 63, 0x00 )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Config_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
Config_Release()
|
||||
return 2
|
||||
else
|
||||
Config_Draw_Menu()
|
||||
if ( event == EVT_VIRTUAL_PREV_PAGE or event == EVT_VIRTUAL_NEXT_PAGE ) and Edit < 1 then
|
||||
-- Not editing, ok to change page
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event)
|
||||
if Page > 0 then
|
||||
--Page = Page - 1
|
||||
--Config_Page()
|
||||
end
|
||||
else
|
||||
--Page = Page + 1
|
||||
--Config_Page()
|
||||
end
|
||||
end
|
||||
if Focus > 0 then
|
||||
-- At least one line has an action
|
||||
if Edit >= 0 then
|
||||
-- Currently editing
|
||||
Config_Draw_Edit( event )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
-- Switch to edit
|
||||
Config_Draw_Edit( 0 )
|
||||
elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_NEXT then
|
||||
-- Main menu selection
|
||||
Config_Next_Prev( event )
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=Config_Init, run=Config_Run }
|
||||
@@ -0,0 +1,499 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for Config description
|
||||
-- To start operation:
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write "Conf" at address 0..3
|
||||
-- Read
|
||||
-- Read at address 12 gives the current config page
|
||||
-- Read at address 13..172 gives the current data of the page = 8 lines * 20 caracters
|
||||
-- Write
|
||||
-- Write at address 5..11 the command
|
||||
-- Write 0x01 at address 4 will send the command to the module
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local Version = "v0.1"
|
||||
local Focus = -1
|
||||
local Page = 0
|
||||
local Edit = -1
|
||||
local Edit_pos = 1
|
||||
local Menu = { {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""} }
|
||||
local Menu_value = {}
|
||||
local Blink = 0
|
||||
local Module = {}
|
||||
local InitialProtocol = 0
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Config_Send(page, line, value)
|
||||
local i
|
||||
i = (page*16) + line
|
||||
multiBuffer( 5, i )
|
||||
for i = 1 , 6 , 1 do
|
||||
multiBuffer( 5+i, value[i] )
|
||||
end
|
||||
multiBuffer( 4, 1 )
|
||||
end
|
||||
|
||||
local function Config_Release()
|
||||
Module.protocol = InitialProtocol
|
||||
model.setModule(0, Module)
|
||||
|
||||
local i
|
||||
for i = 3 , 0 , -1 do
|
||||
multiBuffer( i, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Page( )
|
||||
Config_Send(Page, 0, { 0, 0, 0, 0, 0, 0 })
|
||||
end
|
||||
|
||||
local function Config_Draw_Edit( event )
|
||||
local i
|
||||
local text
|
||||
|
||||
if Menu[Focus].field_type == 0xD0 then
|
||||
-- Editable Hex value
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 1
|
||||
Blink = 0
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
Menu_value[i] = Menu[Focus].field_value[i]
|
||||
end
|
||||
end
|
||||
if Edit == 0 then
|
||||
-- Not editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
if Edit_pos > Menu[Focus].field_len then
|
||||
-- Save or Cancel
|
||||
Edit = -1
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
-- Save
|
||||
Config_Send(Page, Focus, Menu_value)
|
||||
end
|
||||
return
|
||||
else
|
||||
-- Switch to edit mode
|
||||
Edit = 1
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < Menu[Focus].field_len + 2 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
else
|
||||
-- Editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- End edit
|
||||
Edit = 0
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
|
||||
end
|
||||
--Blink
|
||||
Blink = Blink + 1
|
||||
if Blink > 30 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
--Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
if i==Edit_pos and (Edit ~= 1 or Blink > 15) then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170+12*2*(i-1), 110, string.format('%02X', Menu_value[i]), attrib)
|
||||
else
|
||||
lcd.drawText(17+6*2*(i-1), 10, string.format('%02X', Menu_value[i]), attrib + SMLSIZE)
|
||||
end
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Save", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Save", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "Cancel", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "Cancel", attrib + SMLSIZE)
|
||||
end
|
||||
|
||||
elseif Menu[Focus].field_type == 0x90 then
|
||||
-- Action text
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 2
|
||||
end
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- Exit
|
||||
Edit = -1
|
||||
if Edit_pos == 1 then
|
||||
-- Yes
|
||||
Config_Send(Page, Focus, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA } )
|
||||
end
|
||||
return
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Switch to Yes
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < 2 then
|
||||
-- Switch to No
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
-- Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 110, Menu[Focus].field_text .. "?")
|
||||
else
|
||||
lcd.drawText(17, 10, Menu[Focus].field_text .. "?", SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Yes", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Yes", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "No", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "No", attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Next_Prev( event )
|
||||
-- Next Prev on main menu
|
||||
local line
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
for line = Focus - 1, 1, -1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
for line = Focus + 1, 7, 1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Draw_Menu()
|
||||
-- Main menu
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local length
|
||||
local text
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Multi Config " .. Version, MENU_TITLE_COLOR)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(10,50,"No Config telemetry...", BLINK)
|
||||
end
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(1, 0, "Multi Config " .. Version, SMLSIZE)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(2,17,"No Config telemetry...",SMLSIZE)
|
||||
end
|
||||
end
|
||||
|
||||
if multiBuffer(13) ~= 0x00 then
|
||||
if LCD_W == 480 then
|
||||
--Draw firmware version and channels order
|
||||
local ch_order = multiBuffer(17)
|
||||
local channel_names = {}
|
||||
channel_names[bitand(ch_order,3)+1] = "A"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "E"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "T"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "R"
|
||||
lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16), MENU_TITLE_COLOR)
|
||||
--lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4], MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawText(76, 0, "/Fw" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16),SMLSIZE) -- .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4])
|
||||
end
|
||||
|
||||
--Draw Menu
|
||||
for line = 1, 7, 1 do
|
||||
--Clear line info
|
||||
Menu[line].text = ""
|
||||
Menu[line].field_type = 0
|
||||
Menu[line].field_len = 0
|
||||
for i = 1, 7, 1 do
|
||||
Menu[line].field_value[i] = 0
|
||||
end
|
||||
Menu[line].field_text = ""
|
||||
length = 0
|
||||
--Read line from buffer
|
||||
for i = 0, 20-1, 1 do
|
||||
value=multiBuffer( line*20+13+i )
|
||||
if value == 0 then
|
||||
break -- end of line
|
||||
end
|
||||
if value > 0x80 and Menu[line].field_type == 0 then
|
||||
-- Read field type
|
||||
Menu[line].field_type = bitand(value, 0xF0)
|
||||
Menu[line].field_len = bitand(value, 0x0F)
|
||||
length = Menu[line].field_len
|
||||
if Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 and Focus == -1 then
|
||||
-- First actionnable field if nothing was selected
|
||||
Focus = line;
|
||||
end
|
||||
else
|
||||
if Menu[line].field_type == 0 then
|
||||
-- Text
|
||||
Menu[line].text = Menu[line].text .. string.char(value)
|
||||
else
|
||||
-- Menu specific fields
|
||||
length = length - 1
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
Menu[line].field_text = Menu[line].field_text .. string.char(value)
|
||||
else
|
||||
Menu[line].field_value[Menu[line].field_len-length] = value
|
||||
end
|
||||
if length == 0 then
|
||||
-- End of fields
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Display menu text
|
||||
if Menu[line].text ~= "" then
|
||||
if Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 or Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
Menu[line].text = Menu[line].text .. ":"
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,32+20*line,Menu[line].text )
|
||||
else
|
||||
lcd.drawText(2,1+8*line,Menu[line].text,SMLSIZE)
|
||||
end
|
||||
end
|
||||
-- Display specific fields
|
||||
if line == Focus then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
-- Text
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, Menu[line].field_text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, Menu[line].field_text, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 then
|
||||
-- Decimal value
|
||||
value = 0
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
value = value*256 + value
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, value, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, value, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
-- Hex value
|
||||
text=""
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
text = text .. string.format('%02X ', Menu[line].field_value[i])
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, text, SMLSIZE + attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Config_Init()
|
||||
--get Module settings and set to config
|
||||
Module = model.getModule(0)
|
||||
InitialProtocol = Module.protocol
|
||||
Module.protocol = 86
|
||||
model.setModule(0, Module)
|
||||
for i = 0, 10, 1 do end
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('C') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('C') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Request init of the buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Continue buffer init
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('n') )
|
||||
multiBuffer( 3, string.byte('f') )
|
||||
|
||||
-- Test set
|
||||
-- multiBuffer( 12, 0 )
|
||||
-- multiBuffer( 13, 1 )
|
||||
-- multiBuffer( 14, 3 )
|
||||
-- multiBuffer( 15, 2 )
|
||||
-- multiBuffer( 16, 62 )
|
||||
-- multiBuffer( 17, 0 + 1*4 + 2*16 + 3*64)
|
||||
|
||||
-- multiBuffer( 33, string.byte('G') )
|
||||
-- multiBuffer( 34, string.byte('l') )
|
||||
-- multiBuffer( 35, string.byte('o') )
|
||||
-- multiBuffer( 36, string.byte('b') )
|
||||
-- multiBuffer( 37, string.byte('a') )
|
||||
-- multiBuffer( 38, string.byte('l') )
|
||||
-- multiBuffer( 39, string.byte(' ') )
|
||||
-- multiBuffer( 40, string.byte('I') )
|
||||
-- multiBuffer( 41, string.byte('D') )
|
||||
-- multiBuffer( 42, 0xD0 + 4 )
|
||||
-- multiBuffer( 43, 0x12 )
|
||||
-- multiBuffer( 44, 0x34 )
|
||||
-- multiBuffer( 45, 0x56 )
|
||||
-- multiBuffer( 46, 0x78 )
|
||||
-- multiBuffer( 47, 0x9A )
|
||||
-- multiBuffer( 48, 0xBC )
|
||||
|
||||
-- multiBuffer( 53, 0x90 + 9 )
|
||||
-- multiBuffer( 54, string.byte('R') )
|
||||
-- multiBuffer( 55, string.byte('e') )
|
||||
-- multiBuffer( 56, string.byte('s') )
|
||||
-- multiBuffer( 57, string.byte('e') )
|
||||
-- multiBuffer( 58, string.byte('t') )
|
||||
-- multiBuffer( 59, string.byte(' ') )
|
||||
-- multiBuffer( 60, string.byte('G') )
|
||||
-- multiBuffer( 61, string.byte('I') )
|
||||
-- multiBuffer( 62, string.byte('D') )
|
||||
-- multiBuffer( 63, 0x00 )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Config_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
Config_Release()
|
||||
return 2
|
||||
else
|
||||
Config_Draw_Menu()
|
||||
if ( event == EVT_VIRTUAL_PREV_PAGE or event == EVT_VIRTUAL_NEXT_PAGE ) and Edit < 1 then
|
||||
-- Not editing, ok to change page
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event)
|
||||
if Page > 0 then
|
||||
--Page = Page - 1
|
||||
--Config_Page()
|
||||
end
|
||||
else
|
||||
--Page = Page + 1
|
||||
--Config_Page()
|
||||
end
|
||||
end
|
||||
if Focus > 0 then
|
||||
-- At least one line has an action
|
||||
if Edit >= 0 then
|
||||
-- Currently editing
|
||||
Config_Draw_Edit( event )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
-- Switch to edit
|
||||
Config_Draw_Edit( 0 )
|
||||
elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_NEXT then
|
||||
-- Main menu selection
|
||||
Config_Next_Prev( event )
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=Config_Init, run=Config_Run }
|
||||
@@ -6,6 +6,7 @@
|
||||
14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
14,5,Bayang,QX100,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
59,1,BayangRX,CPPM,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
|
||||
@@ -34,9 +35,9 @@
|
||||
6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,4,DSM,AUTO,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
70,0,DSM_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
70,1,DSM_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
|
||||
45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
|
||||
45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
|
||||
16,0,ESKY,Std,0,Gyro,Pitch
|
||||
16,1,ESKY,ET4,0,Gyro,Pitch
|
||||
35,0,ESKY150,4CH,0
|
||||
@@ -54,6 +55,7 @@
|
||||
28,4,Flysky_AFHDS2A,PWM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
28,5,Flysky_AFHDS2A,PPM_IB16,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
56,1,Flysky2A_RX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
53,0,Height,5ch,0,Gear
|
||||
53,1,Height,8ch,0,Gear,Gyro,Flap,Light
|
||||
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
|
||||
@@ -79,6 +81,8 @@
|
||||
65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
|
||||
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,1,FrSkyRX,CloneTX,0
|
||||
55,2,FrSkyRX,EraseTX,0
|
||||
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
58,0,FX816,P38,1
|
||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
|
||||
@@ -99,13 +103,14 @@
|
||||
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
57,0,HoTT,Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
57,1,HoTT,No_Sync,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
||||
2,1,Hubsan,H301,0,RTH,Light,Stab,Video
|
||||
2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
|
||||
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
71,0,JJRC345,Std,1,Flip,HLess,RTH
|
||||
71,0,JJRC345,JJRC345,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3
|
||||
49,0,KF606,Std,1,Trim
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
@@ -122,6 +127,8 @@
|
||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
|
||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
|
||||
17,5,MT99XX,A180,0,3D_6G
|
||||
17,6,MT99XX,Dragon,0,Mode,RTH
|
||||
44,0,NCC1701,Std,1,Warp
|
||||
77,0,OMP,M2,0,THold,IdleUp,6G_3D
|
||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||
@@ -138,10 +145,11 @@
|
||||
72,0,Q90C,Std,0,FMode,VTX+
|
||||
74,0,RadioLink,Surface,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,1,RadioLink,Air,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
74,2,RadioLink,DumboRC,0,CH5,CH6,CH7,CH8,FS_CH1,FS_CH2,FS_CH3,FS_CH4,FS_CH5,FS_CH6,FS_CH7,FS_CH8
|
||||
76,0,Realacc,R11,1,Flip,Light,Calib,HLess,RTH,UNK
|
||||
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
|
||||
21,0,Futaba,SFHSS,0,CH5,CH6,CH7,CH8
|
||||
19,0,Shenqi,Cycle,1
|
||||
68,0,Skyartec,Std,0,CH5,CH6,CH7
|
||||
11,0,SLT,V1,0,Gear,Pitch
|
||||
@@ -174,3 +182,11 @@
|
||||
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
|
||||
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
|
||||
52,0,ZSX,280,1,Light
|
||||
78,0,M-Link,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
79,0,WFLY2,RF20x,0,CH5,CH6,CH7,CH8,CH9,CH10
|
||||
80,0,E016Hv2,E016Hv2,1,TakLan,EmStop,Flip,Calib,HLess,RTH
|
||||
81,0,E010r5,E010r5,1,Flip,LED,CALIB,HLess,RTH,GLIDE
|
||||
82,0,LOLI,Std,0,CH5,CH6,CH7,CH8,1SwSePpPw,2SwSePw,3SwSe,4SwSe,5SwSeSb,6SwSe,7SwSePw,8SwSe
|
||||
83,0,E129,E129,1,TakLan,EmStop,TrimA,TrimE,TrimR
|
||||
84,0,JOYSWAY,Std,0
|
||||
85,0,E016H,Std,1,Stop,Flip,n-a,HLess,RTH
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
|
||||
local toolName = "TNS|Multi LOLI RX config|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local loli_nok = false
|
||||
local channels={ { 768, "PWM", 100, 102, "PPM", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH1
|
||||
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH2
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH3
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH4
|
||||
{ 102, "SBUS", 50, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH5
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 }, -- CH6
|
||||
{ 768, "PWM", 100, -768, "Servo", 0, -2048, "Switch", -100 }, -- CH7
|
||||
{ -768, "Servo", 0, -2048, "Switch", -100 } } -- CH8
|
||||
|
||||
local sel = 1
|
||||
local edit = false
|
||||
|
||||
local blink = 0
|
||||
local BLINK_SPEED = 15
|
||||
|
||||
local function drawScreenTitle(title)
|
||||
if LCD_W == 480 then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawScreenTitle(title, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function LOLI_Draw_LCD(event)
|
||||
local line = 0
|
||||
|
||||
lcd.clear()
|
||||
|
||||
--Display settings
|
||||
local lcd_opt = 0
|
||||
if LCD_W == 480 then
|
||||
drawScreenTitle("Multi - LOLI RX configuration tool")
|
||||
x_pos = 152
|
||||
x_inc = 90
|
||||
y_pos = 40
|
||||
y_inc = 20
|
||||
else
|
||||
x_pos = 5
|
||||
x_inc = 30
|
||||
y_pos = 1
|
||||
y_inc = 8
|
||||
lcd_opt = SMLSIZE
|
||||
end
|
||||
|
||||
--Multi Module detection
|
||||
if loli_nok then
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,50,"The LOLI protocol is not selected...", lcd_opt)
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(2,17,"LOLI protocol not selected...",SMLSIZE)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
--Display current config
|
||||
if LCD_W == 480 then
|
||||
line = line + 1
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line -2, "Channel", lcd_opt)
|
||||
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line -2, "Function", lcd_opt)
|
||||
lcd.drawRectangle(x_pos-4, y_pos+y_inc*line -4 , 2*x_inc +2, 188)
|
||||
lcd.drawLine(x_pos-4, y_pos+y_inc*line +18, x_pos-4 +2*x_inc +1, y_pos+y_inc*line +18, SOLID, 0)
|
||||
lcd.drawLine(x_pos+x_inc -5, y_pos+y_inc*line -4, x_pos+x_inc -5, y_pos+y_inc*line -5 +188, SOLID, 0)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
local out
|
||||
for i = 1, 8 do
|
||||
out = getValue("ch"..(i+8))
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line, "CH"..i, lcd_opt)
|
||||
for j = 1, #channels[i], 3 do
|
||||
if out > channels[i][j] then
|
||||
if sel == i then
|
||||
invert = INVERS
|
||||
if edit == true then
|
||||
blink = blink + 1
|
||||
if blink > BLINK_SPEED then
|
||||
invert = 0
|
||||
if blink > BLINK_SPEED * 2 then
|
||||
blink = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
invert = 0
|
||||
end
|
||||
lcd.drawText(x_pos+x_inc, y_pos+y_inc*line, channels[i][j+1], lcd_opt + invert)
|
||||
break
|
||||
end
|
||||
end
|
||||
line = line + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function LOLI_Change_Value(dir)
|
||||
local pos = 0
|
||||
local out
|
||||
--look for the current position
|
||||
out = getValue("ch"..(sel+8))
|
||||
for j = 1, #channels[sel], 3 do
|
||||
if out > channels[sel][j] then
|
||||
pos = j
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
--decrement or increment
|
||||
if dir < 0 and pos > 1 then
|
||||
pos = pos - 3
|
||||
elseif dir > 0 and pos + 3 < #channels[sel] then
|
||||
pos = pos + 3
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
--delete all mixers for the selected channel
|
||||
local num_mix = model.getMixesCount(sel-1 +8)
|
||||
for i = 1, num_mix do
|
||||
model.deleteMix(sel-1 +8, 0);
|
||||
end
|
||||
|
||||
--create new mixer
|
||||
local source_max = getFieldInfo("cyc1")
|
||||
|
||||
local val = { name = channels[sel][pos+1],
|
||||
source = source_max.id - 1, -- MAX=100 on TX16S
|
||||
weight = channels[sel][pos+2],
|
||||
offset = 0,
|
||||
switch = 0,
|
||||
multiplex = 0,
|
||||
curveType = 0,
|
||||
curveValue = 0,
|
||||
flightModes = 0,
|
||||
carryTrim = false,
|
||||
mixWarn = 0,
|
||||
delayUp = 0,
|
||||
delayDown = 0,
|
||||
speedUp = 0,
|
||||
speedDown = 0 }
|
||||
model.insertMix(sel-1 +8, 0, val)
|
||||
end
|
||||
|
||||
local function LOLI_Menu(event)
|
||||
if event == EVT_VIRTUAL_NEXT then
|
||||
if edit == false then
|
||||
-- not changing a value
|
||||
if sel < 8 then
|
||||
sel = sel + 1
|
||||
end
|
||||
else
|
||||
-- need to inc the value
|
||||
LOLI_Change_Value(1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
if edit == false then
|
||||
-- not changing a value
|
||||
if sel > 1 then
|
||||
sel = sel - 1
|
||||
end
|
||||
else
|
||||
-- need to dec the value
|
||||
LOLI_Change_Value(-1)
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
if edit == false then
|
||||
edit = true
|
||||
blink = BLINK_SPEED
|
||||
else
|
||||
edit = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function LOLI_Init()
|
||||
local module_conf = model.getModule(0)
|
||||
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
|
||||
module_conf = model.getModule(1)
|
||||
if module_conf["Type"] ~= 6 or module_conf["protocol"] ~= 82 then
|
||||
loli_nok = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function LOLI_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
return 2
|
||||
else
|
||||
LOLI_Menu(event)
|
||||
LOLI_Draw_LCD(event)
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=LOLI_Init, run=LOLI_Run }
|
||||
@@ -0,0 +1,499 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for Config description
|
||||
-- To start operation:
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write "Conf" at address 0..3
|
||||
-- Read
|
||||
-- Read at address 12 gives the current config page
|
||||
-- Read at address 13..172 gives the current data of the page = 8 lines * 20 caracters
|
||||
-- Write
|
||||
-- Write at address 5..11 the command
|
||||
-- Write 0x01 at address 4 will send the command to the module
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local Version = "v0.1"
|
||||
local Focus = -1
|
||||
local Page = 0
|
||||
local Edit = -1
|
||||
local Edit_pos = 1
|
||||
local Menu = { {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""} }
|
||||
local Menu_value = {}
|
||||
local Blink = 0
|
||||
local Module = {}
|
||||
local InitialProtocol = 0
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Config_Send(page, line, value)
|
||||
local i
|
||||
i = (page*16) + line
|
||||
multiBuffer( 5, i )
|
||||
for i = 1 , 6 , 1 do
|
||||
multiBuffer( 5+i, value[i] )
|
||||
end
|
||||
multiBuffer( 4, 1 )
|
||||
end
|
||||
|
||||
local function Config_Release()
|
||||
Module.protocol = InitialProtocol
|
||||
model.setModule(1, Module)
|
||||
|
||||
local i
|
||||
for i = 3 , 0 , -1 do
|
||||
multiBuffer( i, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Page( )
|
||||
Config_Send(Page, 0, { 0, 0, 0, 0, 0, 0 })
|
||||
end
|
||||
|
||||
local function Config_Draw_Edit( event )
|
||||
local i
|
||||
local text
|
||||
|
||||
if Menu[Focus].field_type == 0xD0 then
|
||||
-- Editable Hex value
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 1
|
||||
Blink = 0
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
Menu_value[i] = Menu[Focus].field_value[i]
|
||||
end
|
||||
end
|
||||
if Edit == 0 then
|
||||
-- Not editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
if Edit_pos > Menu[Focus].field_len then
|
||||
-- Save or Cancel
|
||||
Edit = -1
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
-- Save
|
||||
Config_Send(Page, Focus, Menu_value)
|
||||
end
|
||||
return
|
||||
else
|
||||
-- Switch to edit mode
|
||||
Edit = 1
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < Menu[Focus].field_len + 2 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
else
|
||||
-- Editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- End edit
|
||||
Edit = 0
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
|
||||
end
|
||||
--Blink
|
||||
Blink = Blink + 1
|
||||
if Blink > 30 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
--Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
if i==Edit_pos and (Edit ~= 1 or Blink > 15) then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170+12*2*(i-1), 110, string.format('%02X', Menu_value[i]), attrib)
|
||||
else
|
||||
lcd.drawText(17+6*2*(i-1), 10, string.format('%02X', Menu_value[i]), attrib + SMLSIZE)
|
||||
end
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Save", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Save", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "Cancel", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "Cancel", attrib + SMLSIZE)
|
||||
end
|
||||
|
||||
elseif Menu[Focus].field_type == 0x90 then
|
||||
-- Action text
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 2
|
||||
end
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- Exit
|
||||
Edit = -1
|
||||
if Edit_pos == 1 then
|
||||
-- Yes
|
||||
Config_Send(Page, Focus, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA } )
|
||||
end
|
||||
return
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Switch to Yes
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < 2 then
|
||||
-- Switch to No
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
-- Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 110, Menu[Focus].field_text .. "?")
|
||||
else
|
||||
lcd.drawText(17, 10, Menu[Focus].field_text .. "?", SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Yes", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Yes", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "No", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "No", attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Next_Prev( event )
|
||||
-- Next Prev on main menu
|
||||
local line
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
for line = Focus - 1, 1, -1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
for line = Focus + 1, 7, 1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Draw_Menu()
|
||||
-- Main menu
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local length
|
||||
local text
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Multi Config " .. Version, MENU_TITLE_COLOR)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(10,50,"No Config telemetry...", BLINK)
|
||||
end
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(1, 0, "Multi Config " .. Version, SMLSIZE)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(2,17,"No Config telemetry...",SMLSIZE)
|
||||
end
|
||||
end
|
||||
|
||||
if multiBuffer(13) ~= 0x00 then
|
||||
if LCD_W == 480 then
|
||||
--Draw firmware version and channels order
|
||||
local ch_order = multiBuffer(17)
|
||||
local channel_names = {}
|
||||
channel_names[bitand(ch_order,3)+1] = "A"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "E"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "T"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "R"
|
||||
lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16), MENU_TITLE_COLOR)
|
||||
--lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4], MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawText(76, 0, "/Fw" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16),SMLSIZE) -- .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4])
|
||||
end
|
||||
|
||||
--Draw Menu
|
||||
for line = 1, 7, 1 do
|
||||
--Clear line info
|
||||
Menu[line].text = ""
|
||||
Menu[line].field_type = 0
|
||||
Menu[line].field_len = 0
|
||||
for i = 1, 7, 1 do
|
||||
Menu[line].field_value[i] = 0
|
||||
end
|
||||
Menu[line].field_text = ""
|
||||
length = 0
|
||||
--Read line from buffer
|
||||
for i = 0, 20-1, 1 do
|
||||
value=multiBuffer( line*20+13+i )
|
||||
if value == 0 then
|
||||
break -- end of line
|
||||
end
|
||||
if value > 0x80 and Menu[line].field_type == 0 then
|
||||
-- Read field type
|
||||
Menu[line].field_type = bitand(value, 0xF0)
|
||||
Menu[line].field_len = bitand(value, 0x0F)
|
||||
length = Menu[line].field_len
|
||||
if Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 and Focus == -1 then
|
||||
-- First actionnable field if nothing was selected
|
||||
Focus = line;
|
||||
end
|
||||
else
|
||||
if Menu[line].field_type == 0 then
|
||||
-- Text
|
||||
Menu[line].text = Menu[line].text .. string.char(value)
|
||||
else
|
||||
-- Menu specific fields
|
||||
length = length - 1
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
Menu[line].field_text = Menu[line].field_text .. string.char(value)
|
||||
else
|
||||
Menu[line].field_value[Menu[line].field_len-length] = value
|
||||
end
|
||||
if length == 0 then
|
||||
-- End of fields
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Display menu text
|
||||
if Menu[line].text ~= "" then
|
||||
if Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 or Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
Menu[line].text = Menu[line].text .. ":"
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,32+20*line,Menu[line].text )
|
||||
else
|
||||
lcd.drawText(2,1+8*line,Menu[line].text,SMLSIZE)
|
||||
end
|
||||
end
|
||||
-- Display specific fields
|
||||
if line == Focus then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
-- Text
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, Menu[line].field_text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, Menu[line].field_text, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 then
|
||||
-- Decimal value
|
||||
value = 0
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
value = value*256 + value
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, value, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, value, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
-- Hex value
|
||||
text=""
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
text = text .. string.format('%02X ', Menu[line].field_value[i])
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, text, SMLSIZE + attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Config_Init()
|
||||
--get Module settings and set to config
|
||||
Module = model.getModule(1)
|
||||
InitialProtocol = Module.protocol
|
||||
Module.protocol = 86
|
||||
model.setModule(1, Module)
|
||||
for i = 0, 10, 1 do end
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('C') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('C') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Request init of the buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Continue buffer init
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('n') )
|
||||
multiBuffer( 3, string.byte('f') )
|
||||
|
||||
-- Test set
|
||||
-- multiBuffer( 12, 0 )
|
||||
-- multiBuffer( 13, 1 )
|
||||
-- multiBuffer( 14, 3 )
|
||||
-- multiBuffer( 15, 2 )
|
||||
-- multiBuffer( 16, 62 )
|
||||
-- multiBuffer( 17, 0 + 1*4 + 2*16 + 3*64)
|
||||
|
||||
-- multiBuffer( 33, string.byte('G') )
|
||||
-- multiBuffer( 34, string.byte('l') )
|
||||
-- multiBuffer( 35, string.byte('o') )
|
||||
-- multiBuffer( 36, string.byte('b') )
|
||||
-- multiBuffer( 37, string.byte('a') )
|
||||
-- multiBuffer( 38, string.byte('l') )
|
||||
-- multiBuffer( 39, string.byte(' ') )
|
||||
-- multiBuffer( 40, string.byte('I') )
|
||||
-- multiBuffer( 41, string.byte('D') )
|
||||
-- multiBuffer( 42, 0xD0 + 4 )
|
||||
-- multiBuffer( 43, 0x12 )
|
||||
-- multiBuffer( 44, 0x34 )
|
||||
-- multiBuffer( 45, 0x56 )
|
||||
-- multiBuffer( 46, 0x78 )
|
||||
-- multiBuffer( 47, 0x9A )
|
||||
-- multiBuffer( 48, 0xBC )
|
||||
|
||||
-- multiBuffer( 53, 0x90 + 9 )
|
||||
-- multiBuffer( 54, string.byte('R') )
|
||||
-- multiBuffer( 55, string.byte('e') )
|
||||
-- multiBuffer( 56, string.byte('s') )
|
||||
-- multiBuffer( 57, string.byte('e') )
|
||||
-- multiBuffer( 58, string.byte('t') )
|
||||
-- multiBuffer( 59, string.byte(' ') )
|
||||
-- multiBuffer( 60, string.byte('G') )
|
||||
-- multiBuffer( 61, string.byte('I') )
|
||||
-- multiBuffer( 62, string.byte('D') )
|
||||
-- multiBuffer( 63, 0x00 )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Config_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
Config_Release()
|
||||
return 2
|
||||
else
|
||||
Config_Draw_Menu()
|
||||
if ( event == EVT_VIRTUAL_PREV_PAGE or event == EVT_VIRTUAL_NEXT_PAGE ) and Edit < 1 then
|
||||
-- Not editing, ok to change page
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event)
|
||||
if Page > 0 then
|
||||
--Page = Page - 1
|
||||
--Config_Page()
|
||||
end
|
||||
else
|
||||
--Page = Page + 1
|
||||
--Config_Page()
|
||||
end
|
||||
end
|
||||
if Focus > 0 then
|
||||
-- At least one line has an action
|
||||
if Edit >= 0 then
|
||||
-- Currently editing
|
||||
Config_Draw_Edit( event )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
-- Switch to edit
|
||||
Config_Draw_Edit( 0 )
|
||||
elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_NEXT then
|
||||
-- Main menu selection
|
||||
Config_Next_Prev( event )
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=Config_Init, run=Config_Run }
|
||||
@@ -0,0 +1,499 @@
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for Config description
|
||||
-- To start operation:
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write "Conf" at address 0..3
|
||||
-- Read
|
||||
-- Read at address 12 gives the current config page
|
||||
-- Read at address 13..172 gives the current data of the page = 8 lines * 20 caracters
|
||||
-- Write
|
||||
-- Write at address 5..11 the command
|
||||
-- Write 0x01 at address 4 will send the command to the module
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local Version = "v0.1"
|
||||
local Focus = -1
|
||||
local Page = 0
|
||||
local Edit = -1
|
||||
local Edit_pos = 1
|
||||
local Menu = { {text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""},
|
||||
{text = "", field_type = 0, field_len = 0, field_value = {}, field_text = ""} }
|
||||
local Menu_value = {}
|
||||
local Blink = 0
|
||||
local Module = {}
|
||||
local InitialProtocol = 0
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Config_Send(page, line, value)
|
||||
local i
|
||||
i = (page*16) + line
|
||||
multiBuffer( 5, i )
|
||||
for i = 1 , 6 , 1 do
|
||||
multiBuffer( 5+i, value[i] )
|
||||
end
|
||||
multiBuffer( 4, 1 )
|
||||
end
|
||||
|
||||
local function Config_Release()
|
||||
Module.protocol = InitialProtocol
|
||||
model.setModule(0, Module)
|
||||
|
||||
local i
|
||||
for i = 3 , 0 , -1 do
|
||||
multiBuffer( i, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Page( )
|
||||
Config_Send(Page, 0, { 0, 0, 0, 0, 0, 0 })
|
||||
end
|
||||
|
||||
local function Config_Draw_Edit( event )
|
||||
local i
|
||||
local text
|
||||
|
||||
if Menu[Focus].field_type == 0xD0 then
|
||||
-- Editable Hex value
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 1
|
||||
Blink = 0
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
Menu_value[i] = Menu[Focus].field_value[i]
|
||||
end
|
||||
end
|
||||
if Edit == 0 then
|
||||
-- Not editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
if Edit_pos > Menu[Focus].field_len then
|
||||
-- Save or Cancel
|
||||
Edit = -1
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
-- Save
|
||||
Config_Send(Page, Focus, Menu_value)
|
||||
end
|
||||
return
|
||||
else
|
||||
-- Switch to edit mode
|
||||
Edit = 1
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < Menu[Focus].field_len + 2 then
|
||||
-- Move cursor
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
else
|
||||
-- Editing value
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- End edit
|
||||
Edit = 0
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
-- Change value
|
||||
Menu_value[Edit_pos] = Menu_value[Edit_pos] + 1
|
||||
end
|
||||
--Blink
|
||||
Blink = Blink + 1
|
||||
if Blink > 30 then
|
||||
Blink = 0
|
||||
end
|
||||
end
|
||||
--Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
for i = 1, Menu[Focus].field_len, 1 do
|
||||
if i==Edit_pos and (Edit ~= 1 or Blink > 15) then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170+12*2*(i-1), 110, string.format('%02X', Menu_value[i]), attrib)
|
||||
else
|
||||
lcd.drawText(17+6*2*(i-1), 10, string.format('%02X', Menu_value[i]), attrib + SMLSIZE)
|
||||
end
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Save", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Save", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == Menu[Focus].field_len + 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "Cancel", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "Cancel", attrib + SMLSIZE)
|
||||
end
|
||||
|
||||
elseif Menu[Focus].field_type == 0x90 then
|
||||
-- Action text
|
||||
if Edit == -1 then
|
||||
-- Init
|
||||
Edit = 0
|
||||
Edit_pos = 2
|
||||
end
|
||||
if event == EVT_VIRTUAL_ENTER then
|
||||
-- Exit
|
||||
Edit = -1
|
||||
if Edit_pos == 1 then
|
||||
-- Yes
|
||||
Config_Send(Page, Focus, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA } )
|
||||
end
|
||||
return
|
||||
elseif event == EVT_VIRTUAL_PREV and Edit_pos > 1 then
|
||||
-- Switch to Yes
|
||||
Edit_pos = Edit_pos - 1
|
||||
elseif event == EVT_VIRTUAL_NEXT and Edit_pos < 2 then
|
||||
-- Switch to No
|
||||
Edit_pos = Edit_pos + 1
|
||||
end
|
||||
-- Display
|
||||
if LCD_W == 480 then
|
||||
lcd.drawRectangle(160-1, 100-1, 160+2, 55+2, TEXT_COLOR)
|
||||
lcd.drawFilledRectangle(160, 100, 160, 55, TEXT_BGCOLOR)
|
||||
else
|
||||
lcd.clear()
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 110, Menu[Focus].field_text .. "?")
|
||||
else
|
||||
lcd.drawText(17, 10, Menu[Focus].field_text .. "?", SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 1 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(170, 130, "Yes", attrib)
|
||||
else
|
||||
lcd.drawText(17, 30, "Yes", attrib + SMLSIZE)
|
||||
end
|
||||
if Edit_pos == 2 then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(260, 130, "No", attrib)
|
||||
else
|
||||
lcd.drawText(77, 30, "No", attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Next_Prev( event )
|
||||
-- Next Prev on main menu
|
||||
local line
|
||||
if event == EVT_VIRTUAL_PREV then
|
||||
for line = Focus - 1, 1, -1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
for line = Focus + 1, 7, 1 do
|
||||
if Menu[line].field_type >= 0x80 and Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 then
|
||||
Focus = line
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Config_Draw_Menu()
|
||||
-- Main menu
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local length
|
||||
local text
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Multi Config " .. Version, MENU_TITLE_COLOR)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(10,50,"No Config telemetry...", BLINK)
|
||||
end
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(1, 0, "Multi Config " .. Version, SMLSIZE)
|
||||
if multiBuffer(13) == 0x00 then
|
||||
lcd.drawText(2,17,"No Config telemetry...",SMLSIZE)
|
||||
end
|
||||
end
|
||||
|
||||
if multiBuffer(13) ~= 0x00 then
|
||||
if LCD_W == 480 then
|
||||
--Draw firmware version and channels order
|
||||
local ch_order = multiBuffer(17)
|
||||
local channel_names = {}
|
||||
channel_names[bitand(ch_order,3)+1] = "A"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "E"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "T"
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = "R"
|
||||
lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16), MENU_TITLE_COLOR)
|
||||
--lcd.drawText(150, 5, "Firmware v" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16) .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4], MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawText(76, 0, "/Fw" .. multiBuffer(13) .. "." .. multiBuffer(14) .. "." .. multiBuffer(15) .. "." .. multiBuffer(16),SMLSIZE) -- .. " " .. channel_names[1] .. channel_names[2] .. channel_names[3] .. channel_names[4])
|
||||
end
|
||||
|
||||
--Draw Menu
|
||||
for line = 1, 7, 1 do
|
||||
--Clear line info
|
||||
Menu[line].text = ""
|
||||
Menu[line].field_type = 0
|
||||
Menu[line].field_len = 0
|
||||
for i = 1, 7, 1 do
|
||||
Menu[line].field_value[i] = 0
|
||||
end
|
||||
Menu[line].field_text = ""
|
||||
length = 0
|
||||
--Read line from buffer
|
||||
for i = 0, 20-1, 1 do
|
||||
value=multiBuffer( line*20+13+i )
|
||||
if value == 0 then
|
||||
break -- end of line
|
||||
end
|
||||
if value > 0x80 and Menu[line].field_type == 0 then
|
||||
-- Read field type
|
||||
Menu[line].field_type = bitand(value, 0xF0)
|
||||
Menu[line].field_len = bitand(value, 0x0F)
|
||||
length = Menu[line].field_len
|
||||
if Menu[line].field_type ~= 0xA0 and Menu[line].field_type ~= 0xC0 and Focus == -1 then
|
||||
-- First actionnable field if nothing was selected
|
||||
Focus = line;
|
||||
end
|
||||
else
|
||||
if Menu[line].field_type == 0 then
|
||||
-- Text
|
||||
Menu[line].text = Menu[line].text .. string.char(value)
|
||||
else
|
||||
-- Menu specific fields
|
||||
length = length - 1
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
Menu[line].field_text = Menu[line].field_text .. string.char(value)
|
||||
else
|
||||
Menu[line].field_value[Menu[line].field_len-length] = value
|
||||
end
|
||||
if length == 0 then
|
||||
-- End of fields
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Display menu text
|
||||
if Menu[line].text ~= "" then
|
||||
if Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 or Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
Menu[line].text = Menu[line].text .. ":"
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,32+20*line,Menu[line].text )
|
||||
else
|
||||
lcd.drawText(2,1+8*line,Menu[line].text,SMLSIZE)
|
||||
end
|
||||
end
|
||||
-- Display specific fields
|
||||
if line == Focus then
|
||||
attrib = INVERS
|
||||
else
|
||||
attrib = 0
|
||||
end
|
||||
if Menu[line].field_type == 0x80 or Menu[line].field_type == 0x90 then
|
||||
-- Text
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, Menu[line].field_text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, Menu[line].field_text, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xA0 or Menu[line].field_type == 0xB0 then
|
||||
-- Decimal value
|
||||
value = 0
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
value = value*256 + value
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, value, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, value, SMLSIZE + attrib)
|
||||
end
|
||||
elseif Menu[line].field_type == 0xC0 or Menu[line].field_type == 0xD0 then
|
||||
-- Hex value
|
||||
text=""
|
||||
for i = 1, Menu[line].field_len, 1 do
|
||||
text = text .. string.format('%02X ', Menu[line].field_value[i])
|
||||
end
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10+9*#Menu[line].text, 32+20*line, text, attrib)
|
||||
else
|
||||
lcd.drawText(2+5*#Menu[line].text, 1+8*line, text, SMLSIZE + attrib)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Config_Init()
|
||||
--get Module settings and set to config
|
||||
Module = model.getModule(0)
|
||||
InitialProtocol = Module.protocol
|
||||
Module.protocol = 86
|
||||
model.setModule(0, Module)
|
||||
for i = 0, 10, 1 do end
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('C') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('C') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
--Request init of the buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Continue buffer init
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('n') )
|
||||
multiBuffer( 3, string.byte('f') )
|
||||
|
||||
-- Test set
|
||||
-- multiBuffer( 12, 0 )
|
||||
-- multiBuffer( 13, 1 )
|
||||
-- multiBuffer( 14, 3 )
|
||||
-- multiBuffer( 15, 2 )
|
||||
-- multiBuffer( 16, 62 )
|
||||
-- multiBuffer( 17, 0 + 1*4 + 2*16 + 3*64)
|
||||
|
||||
-- multiBuffer( 33, string.byte('G') )
|
||||
-- multiBuffer( 34, string.byte('l') )
|
||||
-- multiBuffer( 35, string.byte('o') )
|
||||
-- multiBuffer( 36, string.byte('b') )
|
||||
-- multiBuffer( 37, string.byte('a') )
|
||||
-- multiBuffer( 38, string.byte('l') )
|
||||
-- multiBuffer( 39, string.byte(' ') )
|
||||
-- multiBuffer( 40, string.byte('I') )
|
||||
-- multiBuffer( 41, string.byte('D') )
|
||||
-- multiBuffer( 42, 0xD0 + 4 )
|
||||
-- multiBuffer( 43, 0x12 )
|
||||
-- multiBuffer( 44, 0x34 )
|
||||
-- multiBuffer( 45, 0x56 )
|
||||
-- multiBuffer( 46, 0x78 )
|
||||
-- multiBuffer( 47, 0x9A )
|
||||
-- multiBuffer( 48, 0xBC )
|
||||
|
||||
-- multiBuffer( 53, 0x90 + 9 )
|
||||
-- multiBuffer( 54, string.byte('R') )
|
||||
-- multiBuffer( 55, string.byte('e') )
|
||||
-- multiBuffer( 56, string.byte('s') )
|
||||
-- multiBuffer( 57, string.byte('e') )
|
||||
-- multiBuffer( 58, string.byte('t') )
|
||||
-- multiBuffer( 59, string.byte(' ') )
|
||||
-- multiBuffer( 60, string.byte('G') )
|
||||
-- multiBuffer( 61, string.byte('I') )
|
||||
-- multiBuffer( 62, string.byte('D') )
|
||||
-- multiBuffer( 63, 0x00 )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Config_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
Config_Release()
|
||||
return 2
|
||||
else
|
||||
Config_Draw_Menu()
|
||||
if ( event == EVT_VIRTUAL_PREV_PAGE or event == EVT_VIRTUAL_NEXT_PAGE ) and Edit < 1 then
|
||||
-- Not editing, ok to change page
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event)
|
||||
if Page > 0 then
|
||||
--Page = Page - 1
|
||||
--Config_Page()
|
||||
end
|
||||
else
|
||||
--Page = Page + 1
|
||||
--Config_Page()
|
||||
end
|
||||
end
|
||||
if Focus > 0 then
|
||||
-- At least one line has an action
|
||||
if Edit >= 0 then
|
||||
-- Currently editing
|
||||
Config_Draw_Edit( event )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
-- Switch to edit
|
||||
Config_Draw_Edit( 0 )
|
||||
elseif event == EVT_VIRTUAL_PREV or event == EVT_VIRTUAL_NEXT then
|
||||
-- Main menu selection
|
||||
Config_Next_Prev( event )
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=Config_Init, run=Config_Run }
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |