mirror of
https://github.com/EdgeTX/edgetx.git
synced 2025-07-26 09:45:16 +03:00
[Companion] Radio data refactoring (#5551)
* [Companion] Refactor radio data classes to own files, out of eeprominterface.cpp. No functional changes. * Move files related to refactoring. No functional or code changes. * Fix clang warning and an include path. * Fix indents on curvereference.cpp. [ci skip]
This commit is contained in:
parent
727da06266
commit
59a835b1b3
40 changed files with 4632 additions and 3962 deletions
|
@ -161,19 +161,9 @@ endif()
|
|||
|
||||
set(common_SRCS
|
||||
appdebugmessagehandler.cpp
|
||||
boards.cpp
|
||||
customdebug.cpp
|
||||
eeprominterface.cpp
|
||||
helpers.cpp
|
||||
radiodata.cpp
|
||||
radiodataconversionstate.cpp
|
||||
translations.cpp
|
||||
firmwares/er9x/er9xeeprom.cpp
|
||||
firmwares/er9x/er9xinterface.cpp
|
||||
firmwares/ersky9x/ersky9xeeprom.cpp
|
||||
firmwares/ersky9x/ersky9xinterface.cpp
|
||||
firmwares/opentx/opentxeeprom.cpp
|
||||
firmwares/opentx/opentxinterface.cpp
|
||||
modeledit/node.cpp # used in simulator
|
||||
modeledit/edge.cpp # used by node
|
||||
)
|
||||
|
@ -193,12 +183,25 @@ qt5_wrap_cpp(common_SRCS ${common_MOC_HDRS})
|
|||
qt5_add_resources(common_RCC ${common_RESOURCES})
|
||||
|
||||
add_library(common ${common_SRCS} ${common_RCC})
|
||||
target_link_libraries(common simulation maxLibQtWidgets Qt5::Core Qt5::Xml Qt5::Widgets)
|
||||
|
||||
target_link_libraries(common
|
||||
firmwares
|
||||
storage
|
||||
simulation
|
||||
maxLibQtWidgets
|
||||
Qt5::Core
|
||||
Qt5::Xml
|
||||
Qt5::Widgets
|
||||
${PTHREAD_LIBRARY}
|
||||
${SDL_LIBRARY}
|
||||
${WIN_LINK_LIBRARIES}
|
||||
)
|
||||
|
||||
set(CPN_COMMON_LIB common)
|
||||
|
||||
############# Supporting libraries ###############
|
||||
|
||||
add_subdirectory(firmwares)
|
||||
add_subdirectory(shared)
|
||||
add_subdirectory(modeledit)
|
||||
add_subdirectory(generaledit)
|
||||
|
@ -241,7 +244,6 @@ set(companion_SRCS
|
|||
radionotfound.cpp
|
||||
wizarddata.cpp
|
||||
wizarddialog.cpp
|
||||
multiprotocols.cpp
|
||||
)
|
||||
|
||||
set(companion_MOC_HDRS
|
||||
|
@ -304,7 +306,7 @@ qt5_wrap_cpp(companion_SRCS ${companion_MOC_HDRS})
|
|||
|
||||
add_executable(${COMPANION_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${companion_SRCS} ${icon_RC})
|
||||
qt5_use_modules(${COMPANION_NAME} Core Widgets Network)
|
||||
target_link_libraries(${COMPANION_NAME} PRIVATE generaledit modeledit ${CPN_COMMON_LIB} qcustomplot shared storage ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
|
||||
target_link_libraries(${COMPANION_NAME} PRIVATE generaledit modeledit qcustomplot shared ${CPN_COMMON_LIB})
|
||||
|
||||
PrintTargetReport("${COMPANION_NAME}")
|
||||
|
||||
|
@ -313,7 +315,7 @@ PrintTargetReport("${COMPANION_NAME}")
|
|||
set(simu_SRCS simulator.cpp )
|
||||
|
||||
add_executable(${SIMULATOR_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${simu_SRCS} ${icon_RC})
|
||||
target_link_libraries(${SIMULATOR_NAME} PRIVATE ${CPN_COMMON_LIB} storage ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
|
||||
target_link_libraries(${SIMULATOR_NAME} PRIVATE ${CPN_COMMON_LIB})
|
||||
|
||||
############# Install ####################
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
45
companion/src/firmwares/CMakeLists.txt
Normal file
45
companion/src/firmwares/CMakeLists.txt
Normal file
|
@ -0,0 +1,45 @@
|
|||
|
||||
set(firmwares_SRCS
|
||||
boards.cpp
|
||||
curvereference.cpp
|
||||
customfunctiondata.cpp
|
||||
eeprominterface.cpp
|
||||
generalsettings.cpp
|
||||
gvardata.cpp
|
||||
io_data.cpp
|
||||
logicalswitchdata.cpp
|
||||
modeldata.cpp
|
||||
multiprotocols.cpp
|
||||
radiodata.cpp
|
||||
radiodataconversionstate.cpp
|
||||
rawsource.cpp
|
||||
rawswitch.cpp
|
||||
sensordata.cpp
|
||||
telem_data.cpp
|
||||
er9x/er9xeeprom.cpp
|
||||
er9x/er9xinterface.cpp
|
||||
ersky9x/ersky9xeeprom.cpp
|
||||
ersky9x/ersky9xinterface.cpp
|
||||
opentx/opentxeeprom.cpp
|
||||
opentx/opentxinterface.cpp
|
||||
)
|
||||
|
||||
string(REPLACE ".cpp" ".h" firmwares_HDRS "${firmwares_SRCS}")
|
||||
|
||||
list(APPEND firmwares_HDRS
|
||||
eepromimportexport.h
|
||||
moduledata.h
|
||||
)
|
||||
|
||||
add_library(firmwares ${firmwares_SRCS} ${firmwares_HDRS})
|
||||
target_link_libraries(firmwares ${CPN_COMMON_LIB} Qt5::Core Qt5::Xml Qt5::Widgets)
|
||||
target_include_directories(firmwares
|
||||
PRIVATE
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
PUBLIC
|
||||
"${CMAKE_CURRENT_LIST_DIR}"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/er9x"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ersky9x"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/opentx"
|
||||
)
|
63
companion/src/firmwares/curvereference.cpp
Normal file
63
companion/src/firmwares/curvereference.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 "curvereference.h"
|
||||
|
||||
#include "helpers.h" // for Helpers::getAdjustmentString()
|
||||
#include "radiodata.h" // for ModelData
|
||||
|
||||
QString CurveReference::toString(const ModelData * model, bool verbose) const
|
||||
{
|
||||
if (value == 0) {
|
||||
return "----";
|
||||
}
|
||||
|
||||
QString ret;
|
||||
unsigned idx = abs(value) - 1;
|
||||
|
||||
switch(type) {
|
||||
case CURVE_REF_DIFF:
|
||||
ret = QObject::tr("Diff(%1)").arg(Helpers::getAdjustmentString(value, model));
|
||||
break;
|
||||
|
||||
case CURVE_REF_EXPO:
|
||||
ret = QObject::tr("Expo(%1)").arg(Helpers::getAdjustmentString(value, model));
|
||||
break;
|
||||
|
||||
case CURVE_REF_FUNC:
|
||||
ret = QString("x>0" "x<0" "|x|" "f>0" "f<0" "|f|").mid(3*(value-1), 3);
|
||||
if (verbose)
|
||||
ret = QObject::tr("Function(%1)").arg(ret);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (model)
|
||||
ret = model->curves[idx].nameToString(idx);
|
||||
else
|
||||
ret = CurveData().nameToString(idx);
|
||||
if (verbose)
|
||||
ret = QObject::tr("Curve(%1)").arg(ret);
|
||||
if (value < 0)
|
||||
ret.prepend(CPN_STR_SW_INDICATOR_REV);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
53
companion/src/firmwares/curvereference.h
Normal file
53
companion/src/firmwares/curvereference.h
Normal file
|
@ -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.
|
||||
*/
|
||||
|
||||
#ifndef CURVEREFERENCE_H
|
||||
#define CURVEREFERENCE_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class ModelData;
|
||||
|
||||
class CurveReference {
|
||||
public:
|
||||
enum CurveRefType {
|
||||
CURVE_REF_DIFF,
|
||||
CURVE_REF_EXPO,
|
||||
CURVE_REF_FUNC,
|
||||
CURVE_REF_CUSTOM
|
||||
};
|
||||
|
||||
CurveReference() { clear(); }
|
||||
|
||||
CurveReference(CurveRefType type, int value):
|
||||
type(type),
|
||||
value(value)
|
||||
{
|
||||
}
|
||||
|
||||
void clear() { memset(this, 0, sizeof(CurveReference)); }
|
||||
|
||||
CurveRefType type;
|
||||
int value;
|
||||
|
||||
QString toString(const ModelData * model = NULL, bool verbose = true) const;
|
||||
};
|
||||
|
||||
#endif // CURVEREFERENCE_H
|
254
companion/src/firmwares/customfunctiondata.cpp
Normal file
254
companion/src/firmwares/customfunctiondata.cpp
Normal file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* 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 "customfunctiondata.h"
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
void CustomFunctionData::clear()
|
||||
{
|
||||
memset(this, 0, sizeof(CustomFunctionData));
|
||||
if (!getCurrentFirmware()->getCapability(SafetyChannelCustomFunction)) {
|
||||
func = FuncTrainer;
|
||||
}
|
||||
}
|
||||
|
||||
bool CustomFunctionData::isEmpty() const
|
||||
{
|
||||
return (swtch.type == SWITCH_TYPE_NONE);
|
||||
}
|
||||
|
||||
QString CustomFunctionData::toString(int index, bool globalContext) const
|
||||
{
|
||||
return RadioData::getElementName((globalContext ? QObject::tr("GF") : QObject::tr("SF")), index+1, 0, true);
|
||||
}
|
||||
|
||||
QString CustomFunctionData::funcToString(const ModelData * model) const
|
||||
{
|
||||
if (func >= FuncOverrideCH1 && func <= FuncOverrideCH32)
|
||||
return QObject::tr("Override %1").arg(RawSource(SOURCE_TYPE_CH, func).toString(model));
|
||||
else if (func == FuncTrainer)
|
||||
return QObject::tr("Trainer");
|
||||
else if (func == FuncTrainerRUD)
|
||||
return QObject::tr("Trainer RUD");
|
||||
else if (func == FuncTrainerELE)
|
||||
return QObject::tr("Trainer ELE");
|
||||
else if (func == FuncTrainerTHR)
|
||||
return QObject::tr("Trainer THR");
|
||||
else if (func == FuncTrainerAIL)
|
||||
return QObject::tr("Trainer AIL");
|
||||
else if (func == FuncInstantTrim)
|
||||
return QObject::tr("Instant Trim");
|
||||
else if (func == FuncPlaySound)
|
||||
return QObject::tr("Play Sound");
|
||||
else if (func == FuncPlayHaptic)
|
||||
return QObject::tr("Haptic");
|
||||
else if (func == FuncReset)
|
||||
return QObject::tr("Reset");
|
||||
else if (func >= FuncSetTimer1 && func <= FuncSetTimer3)
|
||||
return QObject::tr("Set Timer %1").arg(func-FuncSetTimer1+1);
|
||||
else if (func == FuncVario)
|
||||
return QObject::tr("Vario");
|
||||
else if (func == FuncPlayPrompt)
|
||||
return QObject::tr("Play Track");
|
||||
else if (func == FuncPlayBoth)
|
||||
return QObject::tr("Play Both");
|
||||
else if (func == FuncPlayValue)
|
||||
return QObject::tr("Play Value");
|
||||
else if (func == FuncPlayScript)
|
||||
return QObject::tr("Play Script");
|
||||
else if (func == FuncLogs)
|
||||
return QObject::tr("SD Logs");
|
||||
else if (func == FuncVolume)
|
||||
return QObject::tr("Volume");
|
||||
else if (func == FuncBacklight)
|
||||
return QObject::tr("Backlight");
|
||||
else if (func == FuncScreenshot)
|
||||
return QObject::tr("Screenshot");
|
||||
else if (func == FuncBackgroundMusic)
|
||||
return QObject::tr("Background Music");
|
||||
else if (func == FuncBackgroundMusicPause)
|
||||
return QObject::tr("Background Music Pause");
|
||||
else if (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast)
|
||||
return QObject::tr("Adjust %1").arg(RawSource(SOURCE_TYPE_GVAR, func-FuncAdjustGV1).toString(model));
|
||||
else if (func == FuncSetFailsafeInternalModule)
|
||||
return QObject::tr("SetFailsafe Int. Module");
|
||||
else if (func == FuncSetFailsafeExternalModule)
|
||||
return QObject::tr("SetFailsafe Ext. Module");
|
||||
else if (func == FuncRangeCheckInternalModule)
|
||||
return QObject::tr("RangeCheck Int. Module");
|
||||
else if (func == FuncRangeCheckExternalModule)
|
||||
return QObject::tr("RangeCheck Ext. Module");
|
||||
else if (func == FuncBindInternalModule)
|
||||
return QObject::tr("Bind Int. Module");
|
||||
else if (func == FuncBindExternalModule)
|
||||
return QObject::tr("Bind Ext. Module");
|
||||
else {
|
||||
return QString("???"); // Highlight unknown functions with output of question marks.(BTW should not happen that we do not know what a function is)
|
||||
}
|
||||
}
|
||||
|
||||
void CustomFunctionData::populateResetParams(const ModelData * model, QComboBox * b, unsigned int value = 0)
|
||||
{
|
||||
int val = 0;
|
||||
Firmware * firmware = Firmware::getCurrentVariant();
|
||||
Board::Type board = firmware->getBoard();
|
||||
|
||||
b->addItem(QObject::tr("Timer1"), val++);
|
||||
b->addItem(QObject::tr("Timer2"), val++);
|
||||
if (IS_ARM(board)) {
|
||||
b->addItem( QObject::tr("Timer3"), val++);
|
||||
}
|
||||
b->addItem(QObject::tr("Flight"), val++);
|
||||
b->addItem(QObject::tr("Telemetry"), val++);
|
||||
int reCount = firmware->getCapability(RotaryEncoders);
|
||||
if (reCount == 1) {
|
||||
b->addItem(QObject::tr("Rotary Encoder"), val++);
|
||||
}
|
||||
else if (reCount == 2) {
|
||||
b->addItem(QObject::tr("REa"), val++);
|
||||
b->addItem(QObject::tr("REb"), val++);
|
||||
}
|
||||
if ((int)value < b->count()) {
|
||||
b->setCurrentIndex(value);
|
||||
}
|
||||
if (model && IS_ARM(board)) {
|
||||
for (int i=0; i<CPN_MAX_SENSORS; ++i) {
|
||||
if (model->sensorData[i].isAvailable()) {
|
||||
RawSource item = RawSource(SOURCE_TYPE_TELEMETRY, 3*i);
|
||||
b->addItem(item.toString(model), val+i);
|
||||
if ((int)value == val+i) {
|
||||
b->setCurrentIndex(b->count()-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomFunctionData::populatePlaySoundParams(QStringList & qs)
|
||||
{
|
||||
qs <<"Beep 1" << "Beep 2" << "Beep 3" << "Warn1" << "Warn2" << "Cheep" << "Ratata" << "Tick" << "Siren" << "Ring" ;
|
||||
qs << "SciFi" << "Robot" << "Chirp" << "Tada" << "Crickt" << "AlmClk" ;
|
||||
}
|
||||
|
||||
void CustomFunctionData::populateHapticParams(QStringList & qs)
|
||||
{
|
||||
qs << "0" << "1" << "2" << "3";
|
||||
}
|
||||
|
||||
QString CustomFunctionData::paramToString(const ModelData * model) const
|
||||
{
|
||||
QStringList qs;
|
||||
if (func <= FuncInstantTrim) {
|
||||
return QString("%1").arg(param);
|
||||
}
|
||||
else if (func==FuncLogs) {
|
||||
return QString("%1").arg(param/10.0) + QObject::tr("s");
|
||||
}
|
||||
else if (func==FuncPlaySound) {
|
||||
CustomFunctionData::populatePlaySoundParams(qs);
|
||||
if (param>=0 && param<(int)qs.count())
|
||||
return qs.at(param);
|
||||
else
|
||||
return QObject::tr("<font color=red><b>Inconsistent parameter</b></font>");
|
||||
}
|
||||
else if (func==FuncPlayHaptic) {
|
||||
CustomFunctionData::populateHapticParams(qs);
|
||||
if (param>=0 && param<(int)qs.count())
|
||||
return qs.at(param);
|
||||
else
|
||||
return QObject::tr("<font color=red><b>Inconsistent parameter</b></font>");
|
||||
}
|
||||
else if (func==FuncReset) {
|
||||
QComboBox cb;
|
||||
CustomFunctionData::populateResetParams(model, &cb);
|
||||
int pos = cb.findData(param);
|
||||
if (pos >= 0)
|
||||
return cb.itemText(pos);
|
||||
else
|
||||
return QObject::tr("<font color=red><b>Inconsistent parameter</b></font>");
|
||||
}
|
||||
else if ((func==FuncVolume)|| (func==FuncPlayValue)) {
|
||||
RawSource item(param);
|
||||
return item.toString(model);
|
||||
}
|
||||
else if ((func==FuncPlayPrompt) || (func==FuncPlayBoth)) {
|
||||
if ( getCurrentFirmware()->getCapability(VoicesAsNumbers)) {
|
||||
return QString("%1").arg(param);
|
||||
}
|
||||
else {
|
||||
return paramarm;
|
||||
}
|
||||
}
|
||||
else if ((func>=FuncAdjustGV1) && (func<FuncCount)) {
|
||||
switch (adjustMode) {
|
||||
case FUNC_ADJUST_GVAR_CONSTANT:
|
||||
return QObject::tr("Value ")+QString("%1").arg(param);
|
||||
case FUNC_ADJUST_GVAR_SOURCE:
|
||||
case FUNC_ADJUST_GVAR_GVAR:
|
||||
return RawSource(param).toString();
|
||||
case FUNC_ADJUST_GVAR_INCDEC:
|
||||
if (param==0) return QObject::tr("Decr:") + " -1";
|
||||
else return QObject::tr("Incr:") + " +1";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QString CustomFunctionData::repeatToString() const
|
||||
{
|
||||
if (repeatParam == -1) {
|
||||
return QObject::tr("played once, not during startup");
|
||||
}
|
||||
else if (repeatParam == 0) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
unsigned int step = IS_ARM(getCurrentBoard()) ? 1 : 10;
|
||||
return QObject::tr("repeat(%1s)").arg(step*repeatParam);
|
||||
}
|
||||
}
|
||||
|
||||
QString CustomFunctionData::enabledToString() const
|
||||
{
|
||||
if ((func>=FuncOverrideCH1 && func<=FuncOverrideCH32) ||
|
||||
(func>=FuncAdjustGV1 && func<=FuncAdjustGVLast) ||
|
||||
(func==FuncReset) ||
|
||||
(func>=FuncSetTimer1 && func<=FuncSetTimer2) ||
|
||||
(func==FuncVolume) ||
|
||||
(func <= FuncInstantTrim)) {
|
||||
if (!enabled) {
|
||||
return QObject::tr("DISABLED");
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void CustomFunctionData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent("CFN", 8);
|
||||
cstate.setSubComp(toString(cstate.subCompIdx, (cstate.toModel() ? false : true)));
|
||||
swtch.convert(cstate);
|
||||
if (func == FuncVolume || func == FuncPlayValue || (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast && adjustMode == 1)) {
|
||||
param = RawSource(param).convert(cstate.withComponentField("PARAM")).toValue();
|
||||
}
|
||||
}
|
110
companion/src/firmwares/customfunctiondata.h
Normal file
110
companion/src/firmwares/customfunctiondata.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef CUSTOMFUNCTIONDATA_H
|
||||
#define CUSTOMFUNCTIONDATA_H
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
#include "rawswitch.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QComboBox>
|
||||
|
||||
class Firmware;
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum AssignFunc {
|
||||
FuncOverrideCH1 = 0,
|
||||
FuncOverrideCH32 = FuncOverrideCH1+CPN_MAX_CHNOUT-1,
|
||||
FuncTrainer,
|
||||
FuncTrainerRUD,
|
||||
FuncTrainerELE,
|
||||
FuncTrainerTHR,
|
||||
FuncTrainerAIL,
|
||||
FuncInstantTrim,
|
||||
FuncPlaySound,
|
||||
FuncPlayHaptic,
|
||||
FuncReset,
|
||||
FuncSetTimer1,
|
||||
FuncSetTimer2,
|
||||
FuncSetTimer3,
|
||||
FuncVario,
|
||||
FuncPlayPrompt,
|
||||
FuncPlayBoth,
|
||||
FuncPlayValue,
|
||||
FuncPlayScript,
|
||||
FuncLogs,
|
||||
FuncVolume,
|
||||
FuncBacklight,
|
||||
FuncScreenshot,
|
||||
FuncBackgroundMusic,
|
||||
FuncBackgroundMusicPause,
|
||||
FuncAdjustGV1,
|
||||
FuncAdjustGVLast = FuncAdjustGV1+CPN_MAX_GVARS-1,
|
||||
FuncSetFailsafeInternalModule,
|
||||
FuncSetFailsafeExternalModule,
|
||||
FuncRangeCheckInternalModule,
|
||||
FuncRangeCheckExternalModule,
|
||||
FuncBindInternalModule,
|
||||
FuncBindExternalModule,
|
||||
FuncCount,
|
||||
FuncReserve = -1
|
||||
};
|
||||
|
||||
enum GVarAdjustModes
|
||||
{
|
||||
FUNC_ADJUST_GVAR_CONSTANT,
|
||||
FUNC_ADJUST_GVAR_SOURCE,
|
||||
FUNC_ADJUST_GVAR_GVAR,
|
||||
FUNC_ADJUST_GVAR_INCDEC
|
||||
};
|
||||
|
||||
class CustomFunctionData { // Function Switches data
|
||||
public:
|
||||
CustomFunctionData(AssignFunc func=FuncOverrideCH1) { clear(); this->func = func; }
|
||||
RawSwitch swtch;
|
||||
AssignFunc func;
|
||||
int param;
|
||||
char paramarm[10];
|
||||
unsigned int enabled; // TODO perhaps not any more the right name
|
||||
unsigned int adjustMode;
|
||||
int repeatParam;
|
||||
|
||||
void clear();
|
||||
bool isEmpty() const;
|
||||
QString toString(int index, bool globalContext = false) const;
|
||||
QString funcToString(const ModelData * model = NULL) const;
|
||||
QString paramToString(const ModelData * model) const;
|
||||
QString repeatToString() const;
|
||||
QString enabledToString() const;
|
||||
|
||||
static void populateResetParams(const ModelData * model, QComboBox * b, unsigned int value);
|
||||
static void populatePlaySoundParams(QStringList & qs);
|
||||
static void populateHapticParams(QStringList & qs);
|
||||
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // CUSTOMFUNCTIONDATA_H
|
|
@ -382,8 +382,33 @@ class CharField: public DataField {
|
|||
bool truncate;
|
||||
};
|
||||
|
||||
int8_t char2idx(char c);
|
||||
char idx2char(int8_t idx);
|
||||
static const char specialCharsTab[] = "_-.,";
|
||||
static inline int8_t char2idx(char c)
|
||||
{
|
||||
if (c==' ') return 0;
|
||||
if (c>='A' && c<='Z') return 1+c-'A';
|
||||
if (c>='a' && c<='z') return -1-c+'a';
|
||||
if (c>='0' && c<='9') return 27+c-'0';
|
||||
for (int8_t i=0;;i++) {
|
||||
char cc = specialCharsTab[i];
|
||||
if (cc==0) return 0;
|
||||
if (cc==c) return 37+i;
|
||||
}
|
||||
}
|
||||
|
||||
#define ZCHAR_MAX 40
|
||||
static inline char idx2char(int8_t idx)
|
||||
{
|
||||
if (idx == 0) return ' ';
|
||||
if (idx < 0) {
|
||||
if (idx > -27) return 'a' - idx - 1;
|
||||
idx = -idx;
|
||||
}
|
||||
if (idx < 27) return 'A' + idx - 1;
|
||||
if (idx < 37) return '0' + idx - 27;
|
||||
if (idx <= ZCHAR_MAX) return specialCharsTab[idx-37];
|
||||
return ' ';
|
||||
}
|
||||
|
||||
template<int N>
|
||||
class ZCharField: public DataField {
|
183
companion/src/firmwares/eeprominterface.cpp
Normal file
183
companion/src/firmwares/eeprominterface.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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 "eeprominterface.h"
|
||||
#include "firmwares/opentx/opentxeeprom.h"
|
||||
#include "firmwareinterface.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QMessageBox>
|
||||
#include <bitset>
|
||||
|
||||
float ValToTim(int value)
|
||||
{
|
||||
return ((value < -109 ? 129+value : (value < 7 ? (113+value)*5 : (53+value)*10))/10.0);
|
||||
}
|
||||
|
||||
int TimToVal(float value)
|
||||
{
|
||||
int temp;
|
||||
if (value>60) {
|
||||
temp=136+round((value-60));
|
||||
}
|
||||
else if (value>2) {
|
||||
temp=20+round((value-2.0)*2.0);
|
||||
}
|
||||
else {
|
||||
temp=round(value*10.0);
|
||||
}
|
||||
return (temp-129);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* EEpromInterface globals
|
||||
*/
|
||||
|
||||
// TODO: No globals
|
||||
|
||||
QList<EEPROMInterface *> eepromInterfaces;
|
||||
|
||||
void unregisterEEpromInterfaces()
|
||||
{
|
||||
foreach(EEPROMInterface * intf, eepromInterfaces) {
|
||||
// qDebug() << "UnregisterEepromInterfaces(): deleting " << QString::number( reinterpret_cast<uint64_t>(intf), 16 );
|
||||
delete intf;
|
||||
}
|
||||
OpenTxEepromCleanup();
|
||||
}
|
||||
|
||||
// TODO: No GUI here, e.g. return string list instead
|
||||
void ShowEepromErrors(QWidget *parent, const QString &title, const QString &mainMessage, unsigned long errorsFound)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors((unsigned long long)errorsFound);
|
||||
QStringList errorsList;
|
||||
|
||||
errorsList << QT_TRANSLATE_NOOP("EepromInterface", "Possible causes for this:");
|
||||
|
||||
if (errors.test(UNSUPPORTED_NEWER_VERSION)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is from a newer version of OpenTX"); }
|
||||
if (errors.test(NOT_OPENTX)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from OpenTX"); }
|
||||
if (errors.test(NOT_TH9X)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from Th9X"); }
|
||||
if (errors.test(NOT_GRUVIN9X)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from Gruvin9X"); }
|
||||
if (errors.test(NOT_ERSKY9X)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from ErSky9X"); }
|
||||
if (errors.test(NOT_ER9X)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from Er9X"); }
|
||||
if (errors.test(WRONG_SIZE)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom size is invalid"); }
|
||||
if (errors.test(WRONG_FILE_SYSTEM)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom file system is invalid"); }
|
||||
if (errors.test(UNKNOWN_BOARD)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is from a unknown board"); }
|
||||
if (errors.test(WRONG_BOARD)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is from the wrong board"); }
|
||||
if (errors.test(BACKUP_NOT_SUPPORTED)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom backup not supported"); }
|
||||
|
||||
if (errors.test(UNKNOWN_ERROR)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Something that couldn't be guessed, sorry"); }
|
||||
|
||||
if (errors.test(HAS_WARNINGS)) {
|
||||
errorsList << QT_TRANSLATE_NOOP("EepromInterface", "Warning:");
|
||||
if (errors.test(WARNING_WRONG_FIRMWARE)) { errorsList << QT_TRANSLATE_NOOP("EepromInterface", "- Your radio probably uses a wrong firmware,\n eeprom size is 4096 but only the first 2048 are used"); }
|
||||
}
|
||||
|
||||
QMessageBox msgBox(parent);
|
||||
msgBox.setWindowTitle(title);
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setText(mainMessage);
|
||||
msgBox.setInformativeText(errorsList.join("\n"));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
// TODO: No GUI here, e.g. return string list instead
|
||||
void ShowEepromWarnings(QWidget *parent, const QString &title, unsigned long errorsFound)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors((unsigned long long)errorsFound);
|
||||
QStringList warningsList;
|
||||
if (errors.test(WARNING_WRONG_FIRMWARE)) { warningsList << QT_TRANSLATE_NOOP("EepromInterface", "- Your radio probably uses a wrong firmware,\n eeprom size is 4096 but only the first 2048 are used"); }
|
||||
if (errors.test(OLD_VERSION)) { warningsList << QT_TRANSLATE_NOOP("EepromInterface", "- Your eeprom is from an old version of OpenTX, upgrading!\n To keep your original file as a backup, please choose File -> Save As specifying a different name."); }
|
||||
|
||||
QMessageBox msgBox(parent);
|
||||
msgBox.setWindowTitle(title);
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setText(QT_TRANSLATE_NOOP("EepromInterface", "Warnings!"));
|
||||
msgBox.setInformativeText(warningsList.join("\n"));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Firmware
|
||||
*/
|
||||
|
||||
// static
|
||||
QVector<Firmware *> Firmware::registeredFirmwares;
|
||||
Firmware * Firmware::defaultVariant = NULL;
|
||||
Firmware * Firmware::currentVariant = NULL;
|
||||
|
||||
// static
|
||||
Firmware * Firmware::getFirmwareForId(const QString & id)
|
||||
{
|
||||
foreach(Firmware * firmware, registeredFirmwares) {
|
||||
Firmware * result = firmware->getFirmwareVariant(id);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultVariant;
|
||||
}
|
||||
|
||||
void Firmware::addOption(const char *option, QString tooltip, uint32_t variant)
|
||||
{
|
||||
Option options[] = { { option, tooltip, variant }, { NULL } };
|
||||
addOptions(options);
|
||||
}
|
||||
|
||||
unsigned int Firmware::getVariantNumber()
|
||||
{
|
||||
unsigned int result = 0;
|
||||
const Firmware * base = getFirmwareBase();
|
||||
QStringList options = id.mid(base->getId().length()+1).split("-", QString::SkipEmptyParts);
|
||||
foreach(QString option, options) {
|
||||
foreach(QList<Option> group, base->opts) {
|
||||
foreach(Option opt, group) {
|
||||
if (opt.name == option) {
|
||||
result += opt.variant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Firmware::addLanguage(const char *lang)
|
||||
{
|
||||
languages.push_back(lang);
|
||||
}
|
||||
|
||||
void Firmware::addTTSLanguage(const char *lang)
|
||||
{
|
||||
ttslanguages.push_back(lang);
|
||||
}
|
||||
|
||||
void Firmware::addOptions(Option options[])
|
||||
{
|
||||
QList<Option> opts;
|
||||
for (int i=0; options[i].name; i++) {
|
||||
opts.push_back(options[i]);
|
||||
}
|
||||
this->opts.push_back(opts);
|
||||
}
|
|
@ -177,13 +177,20 @@ class EEPROMInterface
|
|||
|
||||
};
|
||||
|
||||
/* EEPROM string conversion functions */
|
||||
void setEEPROMString(char *dst, const char *src, int size);
|
||||
void getEEPROMString(char *dst, const char *src, int size);
|
||||
|
||||
float ValToTim(int value);
|
||||
int TimToVal(float value);
|
||||
/* EEPROM string conversion function (used only by er9xeeprom and ersky9xeeprom) */
|
||||
inline void getEEPROMString(char *dst, const char *src, int size)
|
||||
{
|
||||
memcpy(dst, src, size);
|
||||
dst[size] = '\0';
|
||||
for (int i=size-1; i>=0; i--) {
|
||||
if (dst[i] == ' ')
|
||||
dst[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// (used only by er9xeeprom and ersky9xeeprom)
|
||||
inline int applyStickMode(int stick, unsigned int mode)
|
||||
{
|
||||
if (mode == 0 || mode > 4) {
|
||||
|
@ -197,6 +204,9 @@ inline int applyStickMode(int stick, unsigned int mode)
|
|||
return stick;
|
||||
}
|
||||
|
||||
float ValToTim(int value);
|
||||
int TimToVal(float value);
|
||||
|
||||
void registerEEpromInterfaces();
|
||||
void unregisterEEpromInterfaces();
|
||||
void registerOpenTxFirmwares();
|
346
companion/src/firmwares/generalsettings.cpp
Normal file
346
companion/src/firmwares/generalsettings.cpp
Normal file
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* 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 "generalsettings.h"
|
||||
|
||||
#include "appdata.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodataconversionstate.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,
|
||||
2,1,3,4 , 2,1,4,3 , 2,3,1,4 , 2,3,4,1 , 2,4,1,3 , 2,4,3,1,
|
||||
3,1,2,4 , 3,1,4,2 , 3,2,1,4 , 3,2,4,1 , 3,4,1,2 , 3,4,2,1,
|
||||
4,1,2,3 , 4,1,3,2 , 4,2,1,3 , 4,2,3,1 , 4,3,1,2 , 4,3,2,1
|
||||
};
|
||||
|
||||
bool GeneralSettings::switchPositionAllowedTaranis(int index) const
|
||||
{
|
||||
if (index == 0)
|
||||
return true;
|
||||
|
||||
div_t qr = div(abs(index)-1, 3);
|
||||
|
||||
if (index < 0 && switchConfig[qr.quot] != Board::SWITCH_3POS)
|
||||
return false;
|
||||
else if (qr.rem == 1)
|
||||
return switchConfig[qr.quot] == Board::SWITCH_3POS;
|
||||
else
|
||||
return switchConfig[qr.quot] != Board::SWITCH_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
bool GeneralSettings::switchSourceAllowedTaranis(int index) const
|
||||
{
|
||||
return switchConfig[index] != Board::SWITCH_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
bool GeneralSettings::isPotAvailable(int index) const
|
||||
{
|
||||
if (index<0 || index>getBoardCapability(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)) return false;
|
||||
return sliderConfig[index] != Board::SLIDER_NONE;
|
||||
}
|
||||
|
||||
GeneralSettings::GeneralSettings()
|
||||
{
|
||||
memset(this, 0, sizeof(GeneralSettings));
|
||||
|
||||
contrast = 25;
|
||||
|
||||
for (int i=0; i < CPN_MAX_ANALOGS; ++i) {
|
||||
calibMid[i] = 0x200;
|
||||
calibSpanNeg[i] = 0x180;
|
||||
calibSpanPos[i] = 0x180;
|
||||
}
|
||||
|
||||
Firmware * firmware = Firmware::getCurrentVariant();
|
||||
Board::Type board = firmware->getBoard();
|
||||
|
||||
// vBatWarn is voltage in 100mV, vBatMin is in 100mV but with -9V offset, vBatMax has a -12V offset
|
||||
vBatWarn = 90;
|
||||
if (IS_TARANIS_X9E(board) || IS_HORUS_X12S(board)) {
|
||||
// NI-MH 9.6V
|
||||
vBatWarn = 87;
|
||||
vBatMin = -5; //8,5V
|
||||
vBatMax = -5; //11,5V
|
||||
}
|
||||
else if (IS_HORUS_X10(board)) {
|
||||
// Lipo 2V
|
||||
vBatWarn = 66;
|
||||
vBatMin = -28; // 6.2V
|
||||
vBatMax = -38; // 8.2V
|
||||
}
|
||||
else if (IS_TARANIS(board)) {
|
||||
// NI-MH 7.2V, X9D, X9D+ and X7
|
||||
vBatWarn = 65;
|
||||
vBatMin = -30; //6V
|
||||
vBatMax = -40; //8V
|
||||
}
|
||||
|
||||
setDefaultControlTypes(board);
|
||||
|
||||
backlightMode = 3; // keys and sticks
|
||||
// backlightBright = 0; // 0 = 100%
|
||||
|
||||
if (IS_HORUS(board)) {
|
||||
backlightOffBright = 20;
|
||||
}
|
||||
|
||||
if (IS_ARM(board)) {
|
||||
speakerVolume = 12;
|
||||
}
|
||||
|
||||
if (IS_HORUS(board) || IS_TARANIS_X9E(board) || IS_TARANIS_X7(board)) {
|
||||
strcpy(bluetoothName, "Taranis");
|
||||
}
|
||||
|
||||
templateSetup = g.profile[g.sessionId()].channelOrder();
|
||||
stickMode = g.profile[g.sessionId()].defaultMode();
|
||||
|
||||
QString t_calib = g.profile[g.sessionId()].stickPotCalib();
|
||||
int potsnum = getBoardCapability(getCurrentBoard(), Board::Pots);
|
||||
if (!t_calib.isEmpty()) {
|
||||
QString t_trainercalib=g.profile[g.sessionId()].trainerCalib();
|
||||
int8_t t_txVoltageCalibration=(int8_t)g.profile[g.sessionId()].txVoltageCalibration();
|
||||
int8_t t_txCurrentCalibration=(int8_t)g.profile[g.sessionId()].txCurrentCalibration();
|
||||
int8_t t_PPM_Multiplier=(int8_t)g.profile[g.sessionId()].ppmMultiplier();
|
||||
uint8_t t_stickMode=(uint8_t)g.profile[g.sessionId()].gsStickMode();
|
||||
uint8_t t_vBatWarn=(uint8_t)g.profile[g.sessionId()].vBatWarn();
|
||||
QString t_DisplaySet=g.profile[g.sessionId()].display();
|
||||
QString t_BeeperSet=g.profile[g.sessionId()].beeper();
|
||||
QString t_HapticSet=g.profile[g.sessionId()].haptic();
|
||||
QString t_SpeakerSet=g.profile[g.sessionId()].speaker();
|
||||
QString t_CountrySet=g.profile[g.sessionId()].countryCode();
|
||||
|
||||
if ((t_calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (t_trainercalib.length()==16)) {
|
||||
QString Byte;
|
||||
int16_t byte16;
|
||||
bool ok;
|
||||
for (int i=0; i<(CPN_MAX_STICKS+potsnum); i++) {
|
||||
Byte=t_calib.mid(i*12,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
calibMid[i]=byte16;
|
||||
Byte=t_calib.mid(4+i*12,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
calibSpanNeg[i]=byte16;
|
||||
Byte=t_calib.mid(8+i*12,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
calibSpanPos[i]=byte16;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
Byte=t_trainercalib.mid(i*4,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
trainer.calib[i]=byte16;
|
||||
}
|
||||
txCurrentCalibration=t_txCurrentCalibration;
|
||||
txVoltageCalibration=t_txVoltageCalibration;
|
||||
vBatWarn=t_vBatWarn;
|
||||
PPM_Multiplier=t_PPM_Multiplier;
|
||||
stickMode = t_stickMode;
|
||||
}
|
||||
if ((t_DisplaySet.length()==6) && (t_BeeperSet.length()==4) && (t_HapticSet.length()==6) && (t_SpeakerSet.length()==6)) {
|
||||
uint8_t byte8u;
|
||||
int8_t byte8;
|
||||
bool ok;
|
||||
byte8=(int8_t)t_DisplaySet.mid(0,2).toInt(&ok,16);
|
||||
if (ok)
|
||||
optrexDisplay=(byte8==1 ? true : false);
|
||||
byte8u=(uint8_t)t_DisplaySet.mid(2,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
contrast=byte8u;
|
||||
byte8u=(uint8_t)t_DisplaySet.mid(4,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
backlightBright=byte8u;
|
||||
byte8=(int8_t)t_BeeperSet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
beeperMode=(BeeperMode)byte8;
|
||||
byte8=(int8_t)t_BeeperSet.mid(2,2).toInt(&ok,16);
|
||||
if (ok)
|
||||
beeperLength=byte8;
|
||||
byte8=(int8_t)t_HapticSet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
hapticMode=(BeeperMode)byte8;
|
||||
byte8=(int8_t)t_HapticSet.mid(2,2).toInt(&ok,16);
|
||||
if (ok)
|
||||
hapticStrength=byte8;
|
||||
byte8=(int8_t)t_HapticSet.mid(4,2).toInt(&ok,16);
|
||||
if (ok)
|
||||
hapticLength=byte8;
|
||||
byte8u=(uint8_t)t_SpeakerSet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
speakerMode=byte8u;
|
||||
byte8u=(uint8_t)t_SpeakerSet.mid(2,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
speakerPitch=byte8u;
|
||||
byte8u=(uint8_t)t_SpeakerSet.mid(4,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
speakerVolume=byte8u;
|
||||
if (t_CountrySet.length()==6) {
|
||||
byte8u=(uint8_t)t_CountrySet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
countryCode=byte8u;
|
||||
byte8u=(uint8_t)t_CountrySet.mid(2,2).toUInt(&ok,16);
|
||||
if (ok)
|
||||
imperial=byte8u;
|
||||
QString chars = t_CountrySet.mid(4, 2);
|
||||
ttsLanguage[0] = chars[0].toLatin1();
|
||||
ttsLanguage[1] = chars[1].toLatin1();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(themeName, "default");
|
||||
ThemeOptionData option1 = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 };
|
||||
memcpy(&themeOptionValue[0], option1, sizeof(ThemeOptionData));
|
||||
ThemeOptionData option2 = { 0x03, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 };
|
||||
memcpy(&themeOptionValue[1], option2, sizeof(ThemeOptionData));
|
||||
}
|
||||
|
||||
void GeneralSettings::setDefaultControlTypes(Board::Type board)
|
||||
{
|
||||
for (int i=0; i<getBoardCapability(board, Board::FactoryInstalledSwitches); i++) {
|
||||
switchConfig[i] = Boards::getSwitchInfo(board, i).config;
|
||||
}
|
||||
|
||||
// TODO: move to Boards, like with switches
|
||||
if (IS_HORUS(board)) {
|
||||
potConfig[0] = Board::POT_WITH_DETENT;
|
||||
potConfig[1] = Board::POT_MULTIPOS_SWITCH;
|
||||
potConfig[2] = Board::POT_WITH_DETENT;
|
||||
}
|
||||
else if (IS_TARANIS_X7(board)) {
|
||||
potConfig[0] = Board::POT_WITHOUT_DETENT;
|
||||
potConfig[1] = Board::POT_WITH_DETENT;
|
||||
}
|
||||
else if (IS_TARANIS(board)) {
|
||||
potConfig[0] = Board::POT_WITH_DETENT;
|
||||
potConfig[1] = Board::POT_WITH_DETENT;
|
||||
}
|
||||
else {
|
||||
potConfig[0] = Board::POT_WITHOUT_DETENT;
|
||||
potConfig[1] = Board::POT_WITHOUT_DETENT;
|
||||
potConfig[2] = Board::POT_WITHOUT_DETENT;
|
||||
}
|
||||
|
||||
if (IS_HORUS_X12S(board) || IS_TARANIS_X9E(board)) {
|
||||
sliderConfig[0] = Board::SLIDER_WITH_DETENT;
|
||||
sliderConfig[1] = Board::SLIDER_WITH_DETENT;
|
||||
sliderConfig[2] = Board::SLIDER_WITH_DETENT;
|
||||
sliderConfig[3] = Board::SLIDER_WITH_DETENT;
|
||||
}
|
||||
else if (IS_TARANIS_X9(board) || IS_HORUS_X10(board)) {
|
||||
sliderConfig[0] = Board::SLIDER_WITH_DETENT;
|
||||
sliderConfig[1] = Board::SLIDER_WITH_DETENT;
|
||||
}
|
||||
}
|
||||
|
||||
int GeneralSettings::getDefaultStick(unsigned int channel) const
|
||||
{
|
||||
if (channel >= CPN_MAX_STICKS)
|
||||
return -1;
|
||||
else
|
||||
return chout_ar[4*templateSetup + channel] - 1;
|
||||
}
|
||||
|
||||
RawSource GeneralSettings::getDefaultSource(unsigned int channel) const
|
||||
{
|
||||
int stick = getDefaultStick(channel);
|
||||
if (stick >= 0)
|
||||
return RawSource(SOURCE_TYPE_STICK, stick);
|
||||
else
|
||||
return RawSource(SOURCE_TYPE_NONE);
|
||||
}
|
||||
|
||||
int GeneralSettings::getDefaultChannel(unsigned int stick) const
|
||||
{
|
||||
for (int i=0; i<4; i++){
|
||||
if (getDefaultStick(i) == (int)stick)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GeneralSettings::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
// Here we can add explicit conversions when moving from one board to another
|
||||
|
||||
cstate.setOrigin(QObject::tr("Radio Settings"));
|
||||
|
||||
setDefaultControlTypes(cstate.toType); // start with default switches/pots/sliders
|
||||
|
||||
// Try to intelligently copy any custom control names
|
||||
|
||||
// SE and SG are skipped on X7 board
|
||||
if (IS_TARANIS_X7(cstate.toType)) {
|
||||
if (IS_TARANIS_X9(cstate.fromType) || IS_HORUS(cstate.fromType)) {
|
||||
strncpy(switchName[4], switchName[5], sizeof(switchName[0]));
|
||||
strncpy(switchName[5], switchName[7], sizeof(switchName[0]));
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_X7(cstate.fromType)) {
|
||||
if (IS_TARANIS_X9(cstate.toType) || IS_HORUS(cstate.toType)) {
|
||||
strncpy(switchName[5], switchName[4], sizeof(switchName[0]));
|
||||
strncpy(switchName[7], switchName[5], sizeof(switchName[0]));
|
||||
}
|
||||
}
|
||||
|
||||
// LS and RS sliders are after 2 aux sliders on X12 and X9E
|
||||
if ((IS_HORUS_X12S(cstate.toType) || IS_TARANIS_X9E(cstate.toType)) && !IS_HORUS_X12S(cstate.fromType) && !IS_TARANIS_X9E(cstate.fromType)) {
|
||||
strncpy(sliderName[0], sliderName[2], sizeof(sliderName[0]));
|
||||
strncpy(sliderName[1], sliderName[3], sizeof(sliderName[0]));
|
||||
}
|
||||
else if (!IS_TARANIS_X9E(cstate.toType) && !IS_HORUS_X12S(cstate.toType) && (IS_HORUS_X12S(cstate.fromType) || IS_TARANIS_X9E(cstate.fromType))) {
|
||||
strncpy(sliderName[2], sliderName[0], sizeof(sliderName[0]));
|
||||
strncpy(sliderName[3], sliderName[1], sizeof(sliderName[0]));
|
||||
}
|
||||
|
||||
if (IS_HORUS(cstate.toType)) {
|
||||
// 6P switch is only on Horus (by default)
|
||||
if (cstate.fromBoard.getCapability(Board::FactoryInstalledPots) == 2) {
|
||||
strncpy(potName[2], potName[1], sizeof(potName[0]));
|
||||
potName[1][0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_TARANIS(cstate.toType)) {
|
||||
// No S3 pot on Taranis boards by default
|
||||
if (cstate.fromBoard.getCapability(Board::FactoryInstalledPots) > 2)
|
||||
strncpy(potName[1], potName[2], sizeof(potName[0]));
|
||||
|
||||
contrast = qBound<int>(getCurrentFirmware()->getCapability(MinContrast), contrast, getCurrentFirmware()->getCapability(MaxContrast));
|
||||
}
|
||||
|
||||
// TODO: Would be nice at this point to have GUI pause and ask the user to set up any custom hardware they have on the destination radio.
|
||||
|
||||
// Convert all global functions (do this after HW adjustments)
|
||||
for (int i=0; i<CPN_MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
customFn[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
}
|
176
companion/src/firmwares/generalsettings.h
Normal file
176
companion/src/firmwares/generalsettings.h
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef GENERALSETTINGS_H
|
||||
#define GENERALSETTINGS_H
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
#include "customfunctiondata.h"
|
||||
#include "rawsource.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class Firmware;
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum UartModes {
|
||||
UART_MODE_NONE,
|
||||
UART_MODE_TELEMETRY_MIRROR,
|
||||
UART_MODE_TELEMETRY,
|
||||
UART_MODE_SBUS_TRAINER,
|
||||
UART_MODE_DEBUG
|
||||
};
|
||||
|
||||
class TrainerMix {
|
||||
public:
|
||||
TrainerMix() { clear(); }
|
||||
unsigned int src; // 0-7 = ch1-8
|
||||
RawSwitch swtch;
|
||||
int weight;
|
||||
unsigned int mode; // off, add-mode, subst-mode
|
||||
void clear() { memset(this, 0, sizeof(TrainerMix)); }
|
||||
};
|
||||
|
||||
class TrainerData {
|
||||
public:
|
||||
TrainerData() { clear(); }
|
||||
int calib[4];
|
||||
TrainerMix mix[4];
|
||||
void clear() { memset(this, 0, sizeof(TrainerData)); }
|
||||
};
|
||||
|
||||
class GeneralSettings {
|
||||
public:
|
||||
|
||||
enum BeeperMode {
|
||||
BEEPER_QUIET = -2,
|
||||
BEEPER_ALARMS_ONLY = -1,
|
||||
BEEPER_NOKEYS = 0,
|
||||
BEEPER_ALL = 1
|
||||
};
|
||||
|
||||
GeneralSettings();
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
void setDefaultControlTypes(Board::Type board);
|
||||
int getDefaultStick(unsigned int channel) const;
|
||||
RawSource getDefaultSource(unsigned int channel) const;
|
||||
int getDefaultChannel(unsigned int stick) const;
|
||||
|
||||
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;
|
||||
TrainerData trainer;
|
||||
unsigned int view; // main screen view // TODO enum
|
||||
bool disableThrottleWarning;
|
||||
bool fai;
|
||||
bool disableMemoryWarning;
|
||||
BeeperMode beeperMode;
|
||||
bool disableAlarmWarning;
|
||||
bool disableRssiPoweroffAlarm;
|
||||
unsigned int usbMode;
|
||||
BeeperMode hapticMode;
|
||||
unsigned int stickMode; // TODO enum
|
||||
int timezone;
|
||||
bool adjustRTC;
|
||||
bool optrexDisplay;
|
||||
unsigned int inactivityTimer;
|
||||
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 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;
|
||||
int switchesDelay;
|
||||
int temperatureCalib;
|
||||
int temperatureWarn;
|
||||
unsigned int mAhWarn;
|
||||
unsigned int mAhUsed;
|
||||
unsigned int globalTimer;
|
||||
bool bluetoothEnable;
|
||||
char bluetoothName[10+1];
|
||||
unsigned int bluetoothBaudrate;
|
||||
unsigned int bluetoothMode;
|
||||
unsigned int sticksGain;
|
||||
unsigned int rotarySteps;
|
||||
unsigned int countryCode;
|
||||
bool jitterFilter;
|
||||
unsigned int imperial;
|
||||
char ttsLanguage[2+1];
|
||||
int beepVolume;
|
||||
int wavVolume;
|
||||
int varioVolume;
|
||||
int varioPitch;
|
||||
int varioRange;
|
||||
int varioRepeat;
|
||||
int backgroundVolume;
|
||||
unsigned int mavbaud;
|
||||
unsigned int switchUnlockStates;
|
||||
unsigned int hw_uartMode; // UartModes
|
||||
unsigned int backlightColor;
|
||||
CustomFunctionData customFn[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
char switchName[CPN_MAX_SWITCHES][3+1];
|
||||
unsigned int switchConfig[CPN_MAX_SWITCHES];
|
||||
char stickName[CPN_MAX_STICKS][3+1];
|
||||
char potName[CPN_MAX_KNOBS][3+1];
|
||||
unsigned int potConfig[CPN_MAX_KNOBS];
|
||||
char sliderName[CPN_MAX_SLIDERS][3+1];
|
||||
unsigned int sliderConfig[CPN_MAX_SLIDERS];
|
||||
|
||||
char themeName[8+1];
|
||||
typedef uint8_t ThemeOptionData[8+1];
|
||||
ThemeOptionData themeOptionValue[5];
|
||||
|
||||
bool switchPositionAllowedTaranis(int index) const;
|
||||
bool switchSourceAllowedTaranis(int index) const;
|
||||
bool isPotAvailable(int index) const;
|
||||
bool isSliderAvailable(int index) const;
|
||||
};
|
||||
|
||||
|
||||
#endif // GENERALSETTINGS_H
|
85
companion/src/firmwares/gvardata.cpp
Normal file
85
companion/src/firmwares/gvardata.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 "gvardata.h"
|
||||
|
||||
QString GVarData::unitToString() const
|
||||
{
|
||||
switch (unit) {
|
||||
case GVAR_UNIT_NUMBER:
|
||||
return QObject::tr("");
|
||||
case GVAR_UNIT_PERCENT:
|
||||
return QObject::tr("%");
|
||||
default:
|
||||
return QObject::tr("?"); // highlight unknown value
|
||||
}
|
||||
}
|
||||
|
||||
QString GVarData::precToString() const
|
||||
{
|
||||
switch (prec) {
|
||||
case GVAR_PREC_MUL10:
|
||||
return QObject::tr("0._");
|
||||
case GVAR_PREC_MUL1:
|
||||
return QObject::tr("0.0");
|
||||
default:
|
||||
return QObject::tr("?.?"); // highlight unknown value
|
||||
}
|
||||
}
|
||||
|
||||
int GVarData::multiplierSet()
|
||||
{
|
||||
return (prec == 0 ? 1 : 10);
|
||||
}
|
||||
|
||||
float GVarData::multiplierGet() const
|
||||
{
|
||||
return (prec == 0 ? 1 : 0.1);
|
||||
}
|
||||
|
||||
void GVarData::setMin(float val)
|
||||
{
|
||||
min = (val * multiplierSet()) - GVAR_MIN_VALUE;
|
||||
}
|
||||
|
||||
void GVarData::setMax(float val)
|
||||
{
|
||||
max = GVAR_MAX_VALUE - (val * multiplierSet());
|
||||
}
|
||||
|
||||
int GVarData::getMin() const
|
||||
{
|
||||
return GVAR_MIN_VALUE + min;
|
||||
}
|
||||
|
||||
int GVarData::getMax() const
|
||||
{
|
||||
return GVAR_MAX_VALUE - max;
|
||||
}
|
||||
|
||||
float GVarData::getMinPrec() const
|
||||
{
|
||||
return getMin() * multiplierGet();
|
||||
}
|
||||
|
||||
float GVarData::getMaxPrec() const
|
||||
{
|
||||
return getMax() * multiplierGet();
|
||||
}
|
65
companion/src/firmwares/gvardata.h
Normal file
65
companion/src/firmwares/gvardata.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef GVARDATA_H
|
||||
#define GVARDATA_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
#define GVAR_NAME_LEN 3
|
||||
#define GVAR_MAX_VALUE 1024
|
||||
#define GVAR_MIN_VALUE -GVAR_MAX_VALUE
|
||||
|
||||
class GVarData {
|
||||
public:
|
||||
GVarData() { clear(); }
|
||||
|
||||
enum {
|
||||
GVAR_UNIT_NUMBER,
|
||||
GVAR_UNIT_PERCENT
|
||||
};
|
||||
|
||||
enum {
|
||||
GVAR_PREC_MUL10,
|
||||
GVAR_PREC_MUL1
|
||||
};
|
||||
|
||||
char name[GVAR_NAME_LEN+1];
|
||||
int min;
|
||||
int max;
|
||||
bool popup;
|
||||
unsigned int prec; // 0 0._ 1 0.0
|
||||
unsigned int unit; // 0 _ 1 %
|
||||
|
||||
void clear() {memset(this, 0, sizeof(GVarData)); }
|
||||
QString unitToString() const;
|
||||
QString precToString() const;
|
||||
int multiplierSet();
|
||||
float multiplierGet() const;
|
||||
void setMin(float val);
|
||||
void setMax(float val);
|
||||
int getMin() const;
|
||||
int getMax() const;
|
||||
float getMinPrec() const;
|
||||
float getMaxPrec() const;
|
||||
};
|
||||
|
||||
|
||||
#endif // GVARDATA_H
|
142
companion/src/firmwares/io_data.cpp
Normal file
142
companion/src/firmwares/io_data.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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 "io_data.h"
|
||||
|
||||
#include "radiodata.h" // for RadioData::getElementName
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
/*
|
||||
* ExpoData
|
||||
*/
|
||||
|
||||
void ExpoData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent(QObject::tr("INP"), 3);
|
||||
cstate.setSubComp(RawSource(SOURCE_TYPE_VIRTUAL_INPUT, chn).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % QObject::tr(" (@%1)").arg(cstate.subCompIdx));
|
||||
srcRaw.convert(cstate);
|
||||
swtch.convert(cstate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MixData
|
||||
*/
|
||||
|
||||
void MixData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent(QObject::tr("MIX"), 4);
|
||||
cstate.setSubComp(RawSource(SOURCE_TYPE_CH, destCh-1).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % QObject::tr(" (@%1)").arg(cstate.subCompIdx));
|
||||
srcRaw.convert(cstate);
|
||||
swtch.convert(cstate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* LimitData
|
||||
*/
|
||||
|
||||
QString LimitData::minToString() const
|
||||
{
|
||||
return QString::number((qreal)min/10);
|
||||
}
|
||||
|
||||
QString LimitData::maxToString() const
|
||||
{
|
||||
return QString::number((qreal)max/10);
|
||||
}
|
||||
|
||||
QString LimitData::revertToString() const
|
||||
{
|
||||
return revert ? QObject::tr("INV") : QObject::tr("NOR");
|
||||
}
|
||||
|
||||
QString LimitData::offsetToString() const
|
||||
{
|
||||
return QString::number((qreal)offset/10, 'f', 1);
|
||||
}
|
||||
|
||||
void LimitData::clear()
|
||||
{
|
||||
memset(this, 0, sizeof(LimitData));
|
||||
min = -1000;
|
||||
max = +1000;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CurveData
|
||||
*/
|
||||
|
||||
CurveData::CurveData()
|
||||
{
|
||||
clear(5);
|
||||
}
|
||||
|
||||
void CurveData::clear(int count)
|
||||
{
|
||||
memset(this, 0, sizeof(CurveData));
|
||||
this->count = count;
|
||||
}
|
||||
|
||||
bool CurveData::isEmpty() const
|
||||
{
|
||||
for (int i=0; i<count; i++) {
|
||||
if (points[i].y != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString CurveData::nameToString(const int idx) const
|
||||
{
|
||||
return RadioData::getElementName(QCoreApplication::translate("Curve", "CV"), idx + 1, name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FlightModeData
|
||||
*/
|
||||
|
||||
void FlightModeData::clear(const int phase)
|
||||
{
|
||||
memset(this, 0, sizeof(FlightModeData));
|
||||
if (phase != 0) {
|
||||
for (int idx=0; idx<CPN_MAX_GVARS; idx++) {
|
||||
gvars[idx] = 1025;
|
||||
}
|
||||
for (int idx=0; idx<CPN_MAX_ENCODERS; idx++) {
|
||||
rotaryEncoders[idx] = 1025;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString FlightModeData::toString(int index) const
|
||||
{
|
||||
return RadioData::getElementName(QObject::tr("FM"), index, name, true);
|
||||
}
|
||||
|
||||
void FlightModeData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent("FMD", 2);
|
||||
cstate.setSubComp(toString(cstate.subCompIdx));
|
||||
swtch.convert(cstate);
|
||||
}
|
166
companion/src/firmwares/io_data.h
Normal file
166
companion/src/firmwares/io_data.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef IO_DATA_H
|
||||
#define IO_DATA_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "curvereference.h"
|
||||
#include "rawsource.h"
|
||||
#include "rawswitch.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum InputMode {
|
||||
INPUT_MODE_NONE,
|
||||
INPUT_MODE_POS,
|
||||
INPUT_MODE_NEG,
|
||||
INPUT_MODE_BOTH
|
||||
};
|
||||
|
||||
class ExpoData {
|
||||
public:
|
||||
ExpoData() { clear(); }
|
||||
RawSource srcRaw;
|
||||
unsigned int scale;
|
||||
unsigned int mode; // InputMode
|
||||
unsigned int chn;
|
||||
RawSwitch swtch;
|
||||
unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4
|
||||
int weight;
|
||||
int offset;
|
||||
CurveReference curve;
|
||||
int carryTrim;
|
||||
char name[10+1];
|
||||
void clear() { memset(this, 0, sizeof(ExpoData)); }
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
};
|
||||
|
||||
enum MltpxValue {
|
||||
MLTPX_ADD=0,
|
||||
MLTPX_MUL=1,
|
||||
MLTPX_REP=2
|
||||
};
|
||||
|
||||
#define MIXDATA_NAME_LEN 10
|
||||
|
||||
class MixData {
|
||||
public:
|
||||
MixData() { clear(); }
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
unsigned int destCh; // 1..CPN_MAX_CHNOUT
|
||||
RawSource srcRaw;
|
||||
int weight;
|
||||
RawSwitch swtch;
|
||||
CurveReference curve; //0=symmetrisch
|
||||
unsigned int delayUp;
|
||||
unsigned int delayDown;
|
||||
unsigned int speedUp; // Servogeschwindigkeit aus Tabelle (10ms Cycle)
|
||||
unsigned int speedDown; // 0 nichts
|
||||
int carryTrim;
|
||||
bool noExpo;
|
||||
MltpxValue mltpx; // multiplex method 0=+ 1=* 2=replace
|
||||
unsigned int mixWarn; // mixer warning
|
||||
unsigned int flightModes; // -5=!FP4, 0=normal, 5=FP4
|
||||
int sOffset;
|
||||
char name[MIXDATA_NAME_LEN+1];
|
||||
|
||||
void clear() { memset(this, 0, sizeof(MixData)); }
|
||||
};
|
||||
|
||||
class LimitData {
|
||||
public:
|
||||
LimitData() { clear(); }
|
||||
int min;
|
||||
int max;
|
||||
bool revert;
|
||||
int offset;
|
||||
int ppmCenter;
|
||||
bool symetrical;
|
||||
char name[6+1];
|
||||
CurveReference curve;
|
||||
QString minToString() const;
|
||||
QString maxToString() const;
|
||||
QString offsetToString() const;
|
||||
QString revertToString() const;
|
||||
void clear();
|
||||
};
|
||||
|
||||
class CurvePoint {
|
||||
public:
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
};
|
||||
|
||||
class CurveData {
|
||||
public:
|
||||
enum CurveType {
|
||||
CURVE_TYPE_STANDARD,
|
||||
CURVE_TYPE_CUSTOM,
|
||||
CURVE_TYPE_LAST = CURVE_TYPE_CUSTOM
|
||||
};
|
||||
|
||||
CurveData();
|
||||
void clear(int count);
|
||||
bool isEmpty() const;
|
||||
QString nameToString(const int idx) const;
|
||||
|
||||
CurveType type;
|
||||
bool smooth;
|
||||
int count;
|
||||
CurvePoint points[CPN_MAX_POINTS];
|
||||
char name[6+1];
|
||||
};
|
||||
|
||||
class FlightModeData {
|
||||
public:
|
||||
FlightModeData() { clear(0); }
|
||||
int trimMode[CPN_MAX_TRIMS];
|
||||
int trimRef[CPN_MAX_TRIMS];
|
||||
int trim[CPN_MAX_TRIMS];
|
||||
RawSwitch swtch;
|
||||
char name[10+1];
|
||||
unsigned int fadeIn;
|
||||
unsigned int fadeOut;
|
||||
int rotaryEncoders[CPN_MAX_ENCODERS];
|
||||
int gvars[CPN_MAX_GVARS];
|
||||
void clear(const int phase);
|
||||
QString toString(int index) const;
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
};
|
||||
|
||||
class SwashRingData { // Swash Ring data
|
||||
public:
|
||||
SwashRingData() { clear(); }
|
||||
int elevatorWeight;
|
||||
int aileronWeight;
|
||||
int collectiveWeight;
|
||||
unsigned int type;
|
||||
RawSource collectiveSource;
|
||||
RawSource aileronSource;
|
||||
RawSource elevatorSource;
|
||||
unsigned int value;
|
||||
void clear() { memset(this, 0, sizeof(SwashRingData)); }
|
||||
};
|
||||
|
||||
#endif // IO_DATA_H
|
137
companion/src/firmwares/logicalswitchdata.cpp
Normal file
137
companion/src/firmwares/logicalswitchdata.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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 "logicalswitchdata.h"
|
||||
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "rawsource.h"
|
||||
#include "rawswitch.h"
|
||||
|
||||
bool LogicalSwitchData::isEmpty() const
|
||||
{
|
||||
return (func == 0);
|
||||
}
|
||||
|
||||
CSFunctionFamily LogicalSwitchData::getFunctionFamily() const
|
||||
{
|
||||
if (func == LS_FN_EDGE)
|
||||
return LS_FAMILY_EDGE;
|
||||
else if (func == LS_FN_TIMER)
|
||||
return LS_FAMILY_TIMER;
|
||||
else if (func == LS_FN_STICKY)
|
||||
return LS_FAMILY_STICKY;
|
||||
else if (func < LS_FN_AND || func > LS_FN_ELESS)
|
||||
return LS_FAMILY_VOFS;
|
||||
else if (func < LS_FN_EQUAL)
|
||||
return LS_FAMILY_VBOOL;
|
||||
else
|
||||
return LS_FAMILY_VCOMP;
|
||||
}
|
||||
|
||||
unsigned int LogicalSwitchData::getRangeFlags() const
|
||||
{
|
||||
int f = 0;
|
||||
|
||||
if (func == LS_FN_DPOS || func == LS_FN_DAPOS)
|
||||
f |= RANGE_DELTA_FUNCTION;
|
||||
|
||||
if (func == LS_FN_DAPOS || func == LS_FN_APOS || func == LS_FN_ANEG)
|
||||
f |= RANGE_ABS_FUNCTION;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
QString LogicalSwitchData::funcToString() const
|
||||
{
|
||||
switch (func) {
|
||||
case LS_FN_OFF:
|
||||
return QObject::tr("---");
|
||||
case LS_FN_VPOS:
|
||||
return QObject::tr("a>x");
|
||||
case LS_FN_VNEG:
|
||||
return QObject::tr("a<x");
|
||||
case LS_FN_APOS:
|
||||
return QObject::tr("|a|>x");
|
||||
case LS_FN_ANEG:
|
||||
return QObject::tr("|a|<x");
|
||||
case LS_FN_AND:
|
||||
return QObject::tr("AND");
|
||||
case LS_FN_OR:
|
||||
return QObject::tr("OR");
|
||||
case LS_FN_XOR:
|
||||
return QObject::tr("XOR");
|
||||
case LS_FN_EQUAL:
|
||||
return QObject::tr("a=b");
|
||||
case LS_FN_NEQUAL:
|
||||
return QObject::tr("a!=b");
|
||||
case LS_FN_GREATER:
|
||||
return QObject::tr("a>b");
|
||||
case LS_FN_LESS:
|
||||
return QObject::tr("a<b");
|
||||
case LS_FN_EGREATER:
|
||||
return QObject::tr("a>=b");
|
||||
case LS_FN_ELESS:
|
||||
return QObject::tr("a<=b");
|
||||
case LS_FN_DPOS:
|
||||
return QObject::tr("d>=x");
|
||||
case LS_FN_DAPOS:
|
||||
return QObject::tr("|d|>=x");
|
||||
case LS_FN_VEQUAL:
|
||||
return QObject::tr("a=x");
|
||||
case LS_FN_VALMOSTEQUAL:
|
||||
return QObject::tr("a~x");
|
||||
case LS_FN_TIMER:
|
||||
return QObject::tr("Timer");
|
||||
case LS_FN_STICKY:
|
||||
return QObject::tr("Sticky");
|
||||
case LS_FN_EDGE:
|
||||
return QObject::tr("Edge");
|
||||
default:
|
||||
return QObject::tr("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
void LogicalSwitchData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent("LSW", 7);
|
||||
cstate.setSubComp(RawSwitch(SWITCH_TYPE_VIRTUAL, cstate.subCompIdx + 1).toString(cstate.fromType, cstate.fromGS(), cstate.fromModel()));
|
||||
CSFunctionFamily family = getFunctionFamily();
|
||||
switch(family) {
|
||||
case LS_FAMILY_VOFS:
|
||||
val1 = RawSource(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
break;
|
||||
case LS_FAMILY_STICKY:
|
||||
case LS_FAMILY_VBOOL:
|
||||
val1 = RawSwitch(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
val2 = RawSwitch(val2).convert(cstate.withComponentField("V2")).toValue();
|
||||
break;
|
||||
case LS_FAMILY_EDGE:
|
||||
val1 = RawSwitch(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
break;
|
||||
case LS_FAMILY_VCOMP:
|
||||
val1 = RawSource(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
val2 = RawSource(val2).convert(cstate.withComponentField("V2")).toValue();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
andsw = RawSwitch(andsw).convert(cstate.withComponentField("AND")).toValue();
|
||||
}
|
86
companion/src/firmwares/logicalswitchdata.h
Normal file
86
companion/src/firmwares/logicalswitchdata.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef LOGICALSWITCHDATA_H
|
||||
#define LOGICALSWITCHDATA_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum CSFunction {
|
||||
LS_FN_OFF,
|
||||
LS_FN_VPOS,
|
||||
LS_FN_VNEG,
|
||||
LS_FN_APOS,
|
||||
LS_FN_ANEG,
|
||||
LS_FN_AND,
|
||||
LS_FN_OR,
|
||||
LS_FN_XOR,
|
||||
LS_FN_EQUAL,
|
||||
LS_FN_NEQUAL,
|
||||
LS_FN_GREATER,
|
||||
LS_FN_LESS,
|
||||
LS_FN_EGREATER,
|
||||
LS_FN_ELESS,
|
||||
LS_FN_DPOS,
|
||||
LS_FN_DAPOS,
|
||||
LS_FN_VEQUAL, // added at the end to avoid everything renumbered
|
||||
LS_FN_VALMOSTEQUAL,
|
||||
LS_FN_TIMER,
|
||||
LS_FN_STICKY,
|
||||
LS_FN_EDGE,
|
||||
// later ... LS_FN_RANGE,
|
||||
LS_FN_MAX
|
||||
};
|
||||
|
||||
enum CSFunctionFamily {
|
||||
LS_FAMILY_VOFS,
|
||||
LS_FAMILY_VBOOL,
|
||||
LS_FAMILY_VCOMP,
|
||||
LS_FAMILY_TIMER,
|
||||
LS_FAMILY_STICKY,
|
||||
LS_FAMILY_EDGE,
|
||||
};
|
||||
|
||||
class LogicalSwitchData { // Logical Switches data
|
||||
public:
|
||||
LogicalSwitchData(unsigned int func=0)
|
||||
{
|
||||
clear();
|
||||
this->func = func;
|
||||
}
|
||||
unsigned int func;
|
||||
int val1;
|
||||
int val2;
|
||||
int val3;
|
||||
unsigned int delay;
|
||||
unsigned int duration;
|
||||
int andsw;
|
||||
|
||||
void clear() { memset(this, 0, sizeof(LogicalSwitchData)); }
|
||||
bool isEmpty() const;
|
||||
CSFunctionFamily getFunctionFamily() const;
|
||||
unsigned int getRangeFlags() const;
|
||||
QString funcToString() const;
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
};
|
||||
|
||||
#endif // LOGICALSWITCHDATA_H
|
457
companion/src/firmwares/modeldata.cpp
Normal file
457
companion/src/firmwares/modeldata.cpp
Normal file
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
* 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 "modeldata.h"
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "generalsettings.h"
|
||||
#include "macros.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
|
||||
QString removeAccents(const QString & str)
|
||||
{
|
||||
QString result = str;
|
||||
|
||||
// UTF-8 ASCII Table
|
||||
const QString tA[] = { "á", "â", "ã", "à", "ä" };
|
||||
const QString tE[] = { "é", "è", "ê", "ě" };
|
||||
const QString tI[] = { "í" };
|
||||
const QString tO[] = { "ó", "ô", "õ", "ö" };
|
||||
const QString tU[] = { "ú", "ü" };
|
||||
const QString tC[] = { "ç" };
|
||||
const QString tY[] = { "ý" };
|
||||
const QString tS[] = { "š" };
|
||||
const QString tR[] = { "ř" };
|
||||
|
||||
for (unsigned int i = 0; i < DIM(tA); i++) result.replace(tA[i], "a");
|
||||
for (unsigned int i = 0; i < DIM(tE); i++) result.replace(tE[i], "e");
|
||||
for (unsigned int i = 0; i < DIM(tI); i++) result.replace(tI[i], "i");
|
||||
for (unsigned int i = 0; i < DIM(tO); i++) result.replace(tO[i], "o");
|
||||
for (unsigned int i = 0; i < DIM(tU); i++) result.replace(tU[i], "u");
|
||||
for (unsigned int i = 0; i < DIM(tC); i++) result.replace(tC[i], "c");
|
||||
for (unsigned int i = 0; i < DIM(tY); i++) result.replace(tY[i], "y");
|
||||
for (unsigned int i = 0; i < DIM(tS); i++) result.replace(tS[i], "s");
|
||||
for (unsigned int i = 0; i < DIM(tR); i++) result.replace(tR[i], "r");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* TimerData
|
||||
*/
|
||||
|
||||
void TimerData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent("TMR", 1);
|
||||
cstate.setSubComp(QObject::tr("Timer %1").arg(cstate.subCompIdx + 1));
|
||||
mode.convert(cstate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ModelData
|
||||
*/
|
||||
|
||||
ModelData::ModelData()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
ModelData::ModelData(const ModelData & src)
|
||||
{
|
||||
*this = src;
|
||||
}
|
||||
|
||||
ModelData & ModelData::operator = (const ModelData & src)
|
||||
{
|
||||
memcpy(this, &src, sizeof(ModelData));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ExpoData * ModelData::insertInput(const int idx)
|
||||
{
|
||||
memmove(&expoData[idx+1], &expoData[idx], (CPN_MAX_EXPOS-(idx+1))*sizeof(ExpoData));
|
||||
expoData[idx].clear();
|
||||
return &expoData[idx];
|
||||
}
|
||||
|
||||
bool ModelData::isInputValid(const unsigned int idx) const
|
||||
{
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
const ExpoData * expo = &expoData[i];
|
||||
if (expo->mode == 0) break;
|
||||
if (expo->chn == idx)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModelData::hasExpos(uint8_t inputIdx) const
|
||||
{
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
const ExpoData & expo = expoData[i];
|
||||
if (expo.chn==inputIdx && expo.mode!=0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModelData::hasMixes(uint8_t channelIdx) const
|
||||
{
|
||||
channelIdx += 1;
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++) {
|
||||
if (mixData[i].destCh == channelIdx) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVector<const ExpoData *> ModelData::expos(int input) const
|
||||
{
|
||||
QVector<const ExpoData *> result;
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
const ExpoData * ed = &expoData[i];
|
||||
if ((int)ed->chn==input && ed->mode!=0) {
|
||||
result << ed;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<const MixData *> ModelData::mixes(int channel) const
|
||||
{
|
||||
QVector<const MixData *> result;
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++) {
|
||||
const MixData * md = &mixData[i];
|
||||
if ((int)md->destCh == channel+1) {
|
||||
result << md;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ModelData::removeInput(const int idx)
|
||||
{
|
||||
unsigned int chn = expoData[idx].chn;
|
||||
|
||||
memmove(&expoData[idx], &expoData[idx+1], (CPN_MAX_EXPOS-(idx+1))*sizeof(ExpoData));
|
||||
expoData[CPN_MAX_EXPOS-1].clear();
|
||||
|
||||
//also remove input name if removing last line for this input
|
||||
bool found = false;
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
if (expoData[i].mode==0) continue;
|
||||
if (expoData[i].chn==chn) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) inputNames[chn][0] = 0;
|
||||
}
|
||||
|
||||
void ModelData::clearInputs()
|
||||
{
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++)
|
||||
expoData[i].clear();
|
||||
|
||||
//clear all input names
|
||||
if (getCurrentFirmware()->getCapability(VirtualInputs)) {
|
||||
for (int i=0; i<CPN_MAX_INPUTS; i++) {
|
||||
inputNames[i][0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::clearMixes()
|
||||
{
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++)
|
||||
mixData[i].clear();
|
||||
}
|
||||
|
||||
void ModelData::clear()
|
||||
{
|
||||
memset(this, 0, sizeof(ModelData));
|
||||
modelIndex = -1; // an invalid index, this is managed by the TreeView data model
|
||||
moduleData[0].channelsCount = 8;
|
||||
moduleData[1].channelsStart = 0;
|
||||
moduleData[1].channelsCount = 8;
|
||||
moduleData[0].ppm.delay = 300;
|
||||
moduleData[1].ppm.delay = 300;
|
||||
moduleData[2].ppm.delay = 300;
|
||||
int board = getCurrentBoard();
|
||||
if (IS_HORUS_OR_TARANIS(board)) {
|
||||
moduleData[0].protocol = PULSES_PXX_XJT_X16;
|
||||
moduleData[1].protocol = PULSES_OFF;
|
||||
}
|
||||
else if (IS_SKY9X(board)) {
|
||||
moduleData[0].protocol = PULSES_PPM;
|
||||
moduleData[1].protocol = PULSES_PPM;
|
||||
}
|
||||
else {
|
||||
moduleData[0].protocol = PULSES_PPM;
|
||||
moduleData[1].protocol = PULSES_OFF;
|
||||
}
|
||||
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
flightModeData[i].clear(i);
|
||||
}
|
||||
for (int i=0; i<CPN_MAX_GVARS; i++) {
|
||||
gvarData[i].clear();
|
||||
}
|
||||
clearInputs();
|
||||
clearMixes();
|
||||
for (int i=0; i<CPN_MAX_CHNOUT; i++)
|
||||
limitData[i].clear();
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++)
|
||||
expoData[i].clear();
|
||||
for (int i=0; i<CPN_MAX_LOGICAL_SWITCHES; i++)
|
||||
logicalSw[i].clear();
|
||||
for (int i=0; i<CPN_MAX_SPECIAL_FUNCTIONS; i++)
|
||||
customFn[i].clear();
|
||||
for (int i=0; i<CPN_MAX_CURVES; i++)
|
||||
curves[i].clear(5);
|
||||
for (int i=0; i<CPN_MAX_TIMERS; i++)
|
||||
timers[i].clear();
|
||||
swashRingData.clear();
|
||||
frsky.clear();
|
||||
rssiAlarms.clear();
|
||||
for (int i=0; i<CPN_MAX_SENSORS; i++)
|
||||
sensorData[i].clear();
|
||||
|
||||
static const uint8_t blob[] = { 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x32, 0x50, 0x31, 0x00, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x42, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
memcpy(customScreenData[0], blob, sizeof(blob));
|
||||
}
|
||||
|
||||
bool ModelData::isEmpty() const
|
||||
{
|
||||
return !used;
|
||||
}
|
||||
|
||||
void ModelData::setDefaultInputs(const GeneralSettings & settings)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_ARM(board)) {
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++) {
|
||||
ExpoData * expo = &expoData[i];
|
||||
expo->chn = i;
|
||||
expo->mode = INPUT_MODE_BOTH;
|
||||
expo->srcRaw = settings.getDefaultSource(i);
|
||||
expo->weight = 100;
|
||||
strncpy(inputNames[i], removeAccents(expo->srcRaw.toString(this)).toLatin1().constData(), sizeof(inputNames[i])-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::setDefaultMixes(const GeneralSettings & settings)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_ARM(board)) {
|
||||
setDefaultInputs(settings);
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++) {
|
||||
MixData * mix = &mixData[i];
|
||||
mix->destCh = i+1;
|
||||
mix->weight = 100;
|
||||
if (IS_ARM(board)) {
|
||||
mix->srcRaw = RawSource(SOURCE_TYPE_VIRTUAL_INPUT, i);
|
||||
}
|
||||
else {
|
||||
mix->srcRaw = RawSource(SOURCE_TYPE_STICK, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::setDefaultValues(unsigned int id, const GeneralSettings & settings)
|
||||
{
|
||||
clear();
|
||||
used = true;
|
||||
sprintf(name, "MODEL%02d", id+1);
|
||||
for (int i=0; i<CPN_MAX_MODULES; i++) {
|
||||
moduleData[i].modelId = id+1;
|
||||
}
|
||||
setDefaultMixes(settings);
|
||||
}
|
||||
|
||||
int ModelData::getTrimValue(int phaseIdx, int trimIdx)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
FlightModeData & phase = flightModeData[phaseIdx];
|
||||
if (phase.trimMode[trimIdx] < 0) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
if (phase.trimRef[trimIdx] == phaseIdx || phaseIdx == 0) {
|
||||
return result + phase.trim[trimIdx];
|
||||
}
|
||||
else {
|
||||
phaseIdx = phase.trimRef[trimIdx];
|
||||
if (phase.trimMode[trimIdx] != 0)
|
||||
result += phase.trim[trimIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ModelData::isGVarLinked(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
return flightModeData[phaseIdx].gvars[gvarIdx] > 1024;
|
||||
}
|
||||
|
||||
int ModelData::getGVarFieldValue(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
int idx = flightModeData[phaseIdx].gvars[gvarIdx];
|
||||
for (int i=0; idx>GVAR_MAX_VALUE && i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
int nextPhase = idx - GVAR_MAX_VALUE - 1;
|
||||
if (nextPhase >= phaseIdx) nextPhase += 1;
|
||||
phaseIdx = nextPhase;
|
||||
idx = flightModeData[phaseIdx].gvars[gvarIdx];
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
void ModelData::setTrimValue(int phaseIdx, int trimIdx, int value)
|
||||
{
|
||||
for (uint8_t i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
FlightModeData & phase = flightModeData[phaseIdx];
|
||||
int mode = phase.trimMode[trimIdx];
|
||||
int p = phase.trimRef[trimIdx];
|
||||
int & trim = phase.trim[trimIdx];
|
||||
if (mode < 0)
|
||||
return;
|
||||
if (p == phaseIdx || phaseIdx == 0) {
|
||||
trim = value;
|
||||
break;;
|
||||
}
|
||||
else if (mode == 0) {
|
||||
phaseIdx = p;
|
||||
}
|
||||
else {
|
||||
trim = value - getTrimValue(p, trimIdx);
|
||||
if (trim < -500)
|
||||
trim = -500;
|
||||
if (trim > 500)
|
||||
trim = 500;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::removeGlobalVar(int & var)
|
||||
{
|
||||
if (var >= 126 && var <= 130)
|
||||
var = flightModeData[0].gvars[var-126];
|
||||
else if (var <= -126 && var >= -130)
|
||||
var = - flightModeData[0].gvars[-126-var];
|
||||
}
|
||||
|
||||
ModelData ModelData::removeGlobalVars()
|
||||
{
|
||||
ModelData result = *this;
|
||||
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++) {
|
||||
removeGlobalVar(mixData[i].weight);
|
||||
removeGlobalVar(mixData[i].curve.value);
|
||||
removeGlobalVar(mixData[i].sOffset);
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
removeGlobalVar(expoData[i].weight);
|
||||
removeGlobalVar(expoData[i].curve.value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int ModelData::getChannelsMax(bool forceExtendedLimits) const
|
||||
{
|
||||
if (forceExtendedLimits || extendedLimits)
|
||||
return IS_HORUS_OR_TARANIS(getCurrentBoard()) ? 150 : 125;
|
||||
else
|
||||
return 100;
|
||||
}
|
||||
|
||||
bool ModelData::isAvailable(const RawSwitch & swtch) const
|
||||
{
|
||||
unsigned index = abs(swtch.index) - 1;
|
||||
|
||||
if (swtch.type == SWITCH_TYPE_VIRTUAL) {
|
||||
return logicalSw[index].func != LS_FN_OFF;
|
||||
}
|
||||
else if (swtch.type == SWITCH_TYPE_FLIGHT_MODE) {
|
||||
return index == 0 || flightModeData[index].swtch.type != SWITCH_TYPE_NONE;
|
||||
}
|
||||
else if (swtch.type == SWITCH_TYPE_SENSOR) {
|
||||
return strlen(sensorData[index].label) > 0;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
float ModelData::getGVarFieldValuePrec(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
return getGVarFieldValue(phaseIdx, gvarIdx) * gvarData[gvarIdx].multiplierGet();
|
||||
}
|
||||
|
||||
void ModelData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
// Here we can add explicit conversions when moving from one board to another
|
||||
|
||||
QString origin = QString(name);
|
||||
if (origin.isEmpty())
|
||||
origin = QString::number(cstate.modelIdx+1);
|
||||
cstate.setOrigin(QObject::tr("Model: ") % origin);
|
||||
|
||||
cstate.setComponent("SET", 0);
|
||||
if (thrTraceSrc && (int)thrTraceSrc < cstate.fromBoard.getCapability(Board::Pots) + cstate.fromBoard.getCapability(Board::Sliders)) {
|
||||
cstate.setSubComp(QObject::tr("Throttle Source"));
|
||||
thrTraceSrc = RawSource(SOURCE_TYPE_STICK, (int)thrTraceSrc + 3).convert(cstate).index - 3;
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_TIMERS; i++) {
|
||||
timers[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++) {
|
||||
mixData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
expoData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_LOGICAL_SWITCHES; i++) {
|
||||
logicalSw[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
customFn[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
flightModeData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
}
|
228
companion/src/firmwares/modeldata.h
Normal file
228
companion/src/firmwares/modeldata.h
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MODELDATA_H
|
||||
#define MODELDATA_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "customfunctiondata.h"
|
||||
#include "gvardata.h"
|
||||
#include "io_data.h"
|
||||
#include "logicalswitchdata.h"
|
||||
#include "moduledata.h"
|
||||
#include "sensordata.h"
|
||||
#include "telem_data.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
#define CHAR_FOR_NAMES " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-."
|
||||
#define CHAR_FOR_NAMES_REGEX "[ A-Za-z0-9_.-,]*"
|
||||
|
||||
class RSSIAlarmData {
|
||||
public:
|
||||
RSSIAlarmData() { clear(); }
|
||||
unsigned int level[2]; // AVR Only
|
||||
int warning;
|
||||
int critical;
|
||||
bool disabled;
|
||||
void clear() {
|
||||
this->level[0] = 2;
|
||||
this->level[1] = 3;
|
||||
this->warning = 45;
|
||||
this->critical = 42;
|
||||
this->disabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
#define TIMER_NAME_LEN 8
|
||||
|
||||
class TimerData {
|
||||
public:
|
||||
enum CountDownMode {
|
||||
COUNTDOWN_SILENT,
|
||||
COUNTDOWN_BEEPS,
|
||||
COUNTDOWN_VOICE,
|
||||
COUNTDOWN_HAPTIC
|
||||
};
|
||||
TimerData() { clear(); }
|
||||
RawSwitch mode;
|
||||
char name[TIMER_NAME_LEN+1];
|
||||
bool minuteBeep;
|
||||
unsigned int countdownBeep;
|
||||
unsigned int val;
|
||||
unsigned int persistent;
|
||||
int pvalue;
|
||||
void clear() { memset(this, 0, sizeof(TimerData)); mode = RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); }
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
};
|
||||
|
||||
#define CPN_MAX_SCRIPTS 9
|
||||
#define CPN_MAX_SCRIPT_INPUTS 10
|
||||
class ScriptData {
|
||||
public:
|
||||
ScriptData() { clear(); }
|
||||
char filename[10+1];
|
||||
char name[10+1];
|
||||
int inputs[CPN_MAX_SCRIPT_INPUTS];
|
||||
void clear() { memset(this, 0, sizeof(ScriptData)); }
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO ...
|
||||
*/
|
||||
#if 0
|
||||
class CustomScreenOptionData {
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
class CustomScreenZoneData {
|
||||
public:
|
||||
char widgetName[10+1];
|
||||
WidgetOptionData widgetOptions[5];
|
||||
};
|
||||
|
||||
class CustomScreenData {
|
||||
public:
|
||||
CustomScreenData();
|
||||
|
||||
char layoutName[10+1];
|
||||
CustomScreenZoneData zones[];
|
||||
CustomScreenOptionData options[];
|
||||
};
|
||||
#else
|
||||
typedef char CustomScreenData[610+1];
|
||||
typedef char TopbarData[216+1];
|
||||
#endif
|
||||
|
||||
enum TrainerMode {
|
||||
TRAINER_MODE_MASTER_TRAINER_JACK,
|
||||
TRAINER_MODE_SLAVE,
|
||||
TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE,
|
||||
TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE,
|
||||
TRAINER_MODE_MASTER_BATTERY_COMPARTMENT,
|
||||
};
|
||||
|
||||
class ModelData {
|
||||
public:
|
||||
ModelData();
|
||||
ModelData(const ModelData & src);
|
||||
ModelData & operator = (const ModelData & src);
|
||||
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
ExpoData * insertInput(const int idx);
|
||||
void removeInput(const int idx);
|
||||
|
||||
bool isInputValid(const unsigned int idx) const;
|
||||
bool hasExpos(uint8_t inputIdx) const;
|
||||
bool hasMixes(uint8_t output) const;
|
||||
|
||||
QVector<const ExpoData *> expos(int input) const;
|
||||
QVector<const MixData *> mixes(int channel) const;
|
||||
|
||||
bool used;
|
||||
int category;
|
||||
char name[15+1];
|
||||
char filename[16+1];
|
||||
int modelIndex; // Companion only, temporary index position managed by data model.
|
||||
|
||||
TimerData timers[CPN_MAX_TIMERS];
|
||||
bool noGlobalFunctions;
|
||||
bool thrTrim; // Enable Throttle Trim
|
||||
int trimInc; // Trim Increments
|
||||
unsigned int trimsDisplay;
|
||||
bool disableThrottleWarning;
|
||||
|
||||
unsigned int beepANACenter; // 1<<0->A1.. 1<<6->A7
|
||||
|
||||
bool extendedLimits; // TODO xml
|
||||
bool extendedTrims;
|
||||
bool throttleReversed;
|
||||
FlightModeData flightModeData[CPN_MAX_FLIGHT_MODES];
|
||||
MixData mixData[CPN_MAX_MIXERS];
|
||||
LimitData limitData[CPN_MAX_CHNOUT];
|
||||
|
||||
char inputNames[CPN_MAX_INPUTS][4+1];
|
||||
ExpoData expoData[CPN_MAX_EXPOS];
|
||||
|
||||
CurveData curves[CPN_MAX_CURVES];
|
||||
LogicalSwitchData logicalSw[CPN_MAX_LOGICAL_SWITCHES];
|
||||
CustomFunctionData customFn[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
SwashRingData swashRingData;
|
||||
unsigned int thrTraceSrc;
|
||||
uint64_t switchWarningStates;
|
||||
unsigned int switchWarningEnable;
|
||||
unsigned int potsWarningMode;
|
||||
bool potsWarningEnabled[CPN_MAX_POTS];
|
||||
int potPosition[CPN_MAX_POTS];
|
||||
bool displayChecklist;
|
||||
GVarData gvarData[CPN_MAX_GVARS];
|
||||
MavlinkData mavlink;
|
||||
unsigned int telemetryProtocol;
|
||||
FrSkyData frsky;
|
||||
RSSIAlarmData rssiAlarms;
|
||||
|
||||
char bitmap[10+1];
|
||||
|
||||
unsigned int trainerMode; // TrainerMode
|
||||
|
||||
ModuleData moduleData[CPN_MAX_MODULES+1/*trainer*/];
|
||||
|
||||
ScriptData scriptData[CPN_MAX_SCRIPTS];
|
||||
|
||||
SensorData sensorData[CPN_MAX_SENSORS];
|
||||
|
||||
unsigned int toplcdTimer;
|
||||
|
||||
CustomScreenData customScreenData[5];
|
||||
|
||||
TopbarData topbarData;
|
||||
|
||||
void clear();
|
||||
bool isEmpty() const;
|
||||
void setDefaultInputs(const GeneralSettings & settings);
|
||||
void setDefaultMixes(const GeneralSettings & settings);
|
||||
void setDefaultValues(unsigned int id, const GeneralSettings & settings);
|
||||
|
||||
int getTrimValue(int phaseIdx, int trimIdx);
|
||||
void setTrimValue(int phaseIdx, int trimIdx, int value);
|
||||
|
||||
bool isGVarLinked(int phaseIdx, int gvarIdx);
|
||||
int getGVarFieldValue(int phaseIdx, int gvarIdx);
|
||||
float getGVarFieldValuePrec(int phaseIdx, int gvarIdx);
|
||||
|
||||
ModelData removeGlobalVars();
|
||||
|
||||
void clearMixes();
|
||||
void clearInputs();
|
||||
|
||||
int getChannelsMax(bool forceExtendedLimits=false) const;
|
||||
|
||||
bool isAvailable(const RawSwitch & swtch) const;
|
||||
|
||||
protected:
|
||||
void removeGlobalVar(int & var);
|
||||
};
|
||||
|
||||
#endif // MODELDATA_H
|
139
companion/src/firmwares/moduledata.h
Normal file
139
companion/src/firmwares/moduledata.h
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MODULEDATA_H
|
||||
#define MODULEDATA_H
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
enum PulsesProtocol {
|
||||
PULSES_OFF,
|
||||
PULSES_PPM,
|
||||
PULSES_SILV_A,
|
||||
PULSES_SILV_B,
|
||||
PULSES_SILV_C,
|
||||
PULSES_CTP1009,
|
||||
PULSES_LP45,
|
||||
PULSES_DSM2,
|
||||
PULSES_DSMX,
|
||||
PULSES_PPM16,
|
||||
PULSES_PPMSIM,
|
||||
PULSES_PXX_XJT_X16,
|
||||
PULSES_PXX_XJT_D8,
|
||||
PULSES_PXX_XJT_LR12,
|
||||
PULSES_PXX_DJT,
|
||||
PULSES_CROSSFIRE,
|
||||
PULSES_MULTIMODULE,
|
||||
PULSES_PXX_R9M,
|
||||
PULSES_SBUS,
|
||||
PULSES_PROTOCOL_LAST
|
||||
};
|
||||
|
||||
enum MultiModuleRFProtocols {
|
||||
MM_RF_PROTO_FLYSKY=0,
|
||||
MM_RF_PROTO_FIRST=MM_RF_PROTO_FLYSKY,
|
||||
MM_RF_PROTO_HUBSAN,
|
||||
MM_RF_PROTO_FRSKY,
|
||||
MM_RF_PROTO_HISKY,
|
||||
MM_RF_PROTO_V2X2,
|
||||
MM_RF_PROTO_DSM2,
|
||||
MM_RF_PROTO_DEVO,
|
||||
MM_RF_PROTO_YD717,
|
||||
MM_RF_PROTO_KN,
|
||||
MM_RF_PROTO_SYMAX,
|
||||
MM_RF_PROTO_SLT,
|
||||
MM_RF_PROTO_CX10,
|
||||
MM_RF_PROTO_CG023,
|
||||
MM_RF_PROTO_BAYANG,
|
||||
MM_RF_PROTO_ESky,
|
||||
MM_RF_PROTO_MT99XX,
|
||||
MM_RF_PROTO_MJXQ,
|
||||
MM_RF_PROTO_SHENQI,
|
||||
MM_RF_PROTO_FY326,
|
||||
MM_RF_PROTO_SFHSS,
|
||||
MM_RF_PROTO_J6PRO,
|
||||
MM_RF_PROTO_FQ777,
|
||||
MM_RF_PROTO_ASSAN,
|
||||
MM_RF_PROTO_HONTAI,
|
||||
MM_RF_PROTO_OLRS,
|
||||
MM_RF_PROTO_FS_AFHDS2A,
|
||||
MM_RF_PROTO_Q2X2,
|
||||
MM_RF_PROTO_WK_2X01,
|
||||
MM_RF_PROTO_Q303,
|
||||
MM_RF_PROTO_GW008,
|
||||
MM_RF_PROTO_DM002,
|
||||
MM_RF_PROTO_CABELL,
|
||||
MM_RF_PROTO_ESKY150,
|
||||
MM_RF_PROTO_H83D,
|
||||
MM_RF_PROTO_LAST=MM_RF_PROTO_H83D
|
||||
};
|
||||
|
||||
enum TrainerProtocol {
|
||||
TRAINER_MASTER_JACK,
|
||||
TRAINER_SLAVE_JACK,
|
||||
TRAINER_MASTER_SBUS_MODULE,
|
||||
TRAINER_MASTER_CPPM_MODULE,
|
||||
TRAINER_MASTER_SBUS_BATT_COMPARTMENT
|
||||
};
|
||||
|
||||
class ModuleData {
|
||||
public:
|
||||
ModuleData() { clear(); }
|
||||
unsigned int modelId;
|
||||
int protocol;
|
||||
unsigned int subType;
|
||||
bool invertedSerial;
|
||||
unsigned int channelsStart;
|
||||
int channelsCount; // 0=8 channels
|
||||
unsigned int failsafeMode;
|
||||
int failsafeChannels[CPN_MAX_CHNOUT];
|
||||
|
||||
|
||||
struct {
|
||||
int delay;
|
||||
bool pulsePol; // false = positive
|
||||
bool outputType; // false = open drain, true = push pull
|
||||
int frameLength;
|
||||
} ppm;
|
||||
|
||||
struct {
|
||||
unsigned int rfProtocol;
|
||||
bool autoBindMode;
|
||||
bool lowPowerMode;
|
||||
bool customProto;
|
||||
int optionValue;
|
||||
} multi;
|
||||
|
||||
struct {
|
||||
int power; // 0 10 mW, 1 100 mW, 2 500 mW, 3 1W
|
||||
bool receiver_telem_off; // false = receiver telem enabled
|
||||
bool receiver_channel_9_16; // false = pwm out 1-8, true 9-16
|
||||
bool external_antenna; // false = internal antenna, true = external antenna
|
||||
bool sport_out;
|
||||
} pxx;
|
||||
|
||||
|
||||
void clear() { memset(this, 0, sizeof(ModuleData)); }
|
||||
QString polarityToString() const { return ppm.pulsePol ? QObject::tr("Positive") : QObject::tr("Negative"); } // TODO ModelPrinter
|
||||
};
|
||||
|
||||
#endif // MODULEDATA_H
|
127
companion/src/firmwares/radiodata.cpp
Normal file
127
companion/src/firmwares/radiodata.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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 "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
// static
|
||||
QString RadioData::getElementName(const QString & prefix, unsigned int index, const char * name, bool padding)
|
||||
{
|
||||
QString result = prefix;
|
||||
if (padding)
|
||||
result += QString("%1").arg(index, 2, 10, QChar('0'));
|
||||
else
|
||||
result += QString("%1").arg(index);
|
||||
if (name) {
|
||||
QString trimmed = QString(name).trimmed();
|
||||
if (trimmed.length() > 0) {
|
||||
result += ":" + QString(name).trimmed();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RadioData::RadioData()
|
||||
{
|
||||
models.resize(getCurrentFirmware()->getCapability(Models));
|
||||
}
|
||||
|
||||
void RadioData::setCurrentModel(unsigned int index)
|
||||
{
|
||||
generalSettings.currModelIndex = index;
|
||||
if (index < models.size()) {
|
||||
strcpy(generalSettings.currModelFilename, models[index].filename);
|
||||
}
|
||||
}
|
||||
|
||||
void RadioData::fixModelFilename(unsigned int index)
|
||||
{
|
||||
ModelData & model = models[index];
|
||||
QString filename(model.filename);
|
||||
bool ok = filename.endsWith(".bin");
|
||||
if (ok) {
|
||||
if (filename.startsWith("model") && filename.mid(5, filename.length()-9).toInt() > 0) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
for (unsigned i=0; i<index; i++) {
|
||||
if (strcmp(models[i].filename, model.filename) == 0) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
sprintf(model.filename, "model%d.bin", index+1);
|
||||
}
|
||||
}
|
||||
|
||||
void RadioData::fixModelFilenames()
|
||||
{
|
||||
for (unsigned int i=0; i<models.size(); i++) {
|
||||
fixModelFilename(i);
|
||||
}
|
||||
setCurrentModel(generalSettings.currModelIndex);
|
||||
}
|
||||
|
||||
QString RadioData::getNextModelFilename()
|
||||
{
|
||||
char filename[sizeof(ModelData::filename)];
|
||||
int index = 0;
|
||||
bool found = true;
|
||||
while (found) {
|
||||
sprintf(filename, "model%d.bin", ++index);
|
||||
found = false;
|
||||
for (unsigned int i=0; i<models.size(); i++) {
|
||||
if (strcmp(filename, models[i].filename) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
void RadioData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
generalSettings.convert(cstate.withModelIndex(-1));
|
||||
|
||||
for (unsigned i=0; i<models.size(); i++) {
|
||||
models[i].convert(cstate.withModelIndex(i));
|
||||
}
|
||||
|
||||
if (categories.size() == 0) {
|
||||
categories.push_back(CategoryData(qPrintable(QObject::tr("Models"))));
|
||||
for (unsigned i=0; i<models.size(); i++) {
|
||||
models[i].category = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_HORUS(cstate.toType)) {
|
||||
fixModelFilenames();
|
||||
}
|
||||
|
||||
// ensure proper number of model slots
|
||||
if (getCurrentFirmware()->getCapability(Models) && getCurrentFirmware()->getCapability(Models) != (int)models.size()) {
|
||||
models.resize(getCurrentFirmware()->getCapability(Models));
|
||||
}
|
||||
}
|
39
companion/src/firmwares/radiodata.h
Normal file
39
companion/src/firmwares/radiodata.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef _RADIODATA_H_
|
||||
#define _RADIODATA_H_
|
||||
|
||||
#include "generalsettings.h"
|
||||
#include "modeldata.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class RadioDataConversionState;
|
||||
|
||||
class CategoryData {
|
||||
public:
|
||||
CategoryData(const char * name) {
|
||||
strncpy(this->name, name, sizeof(CategoryData::name));
|
||||
}
|
||||
char name[15+1];
|
||||
};
|
||||
|
||||
class RadioData {
|
||||
public:
|
||||
RadioData();
|
||||
|
||||
GeneralSettings generalSettings;
|
||||
std::vector<CategoryData> categories;
|
||||
std::vector<ModelData> models;
|
||||
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
|
||||
void setCurrentModel(unsigned int index);
|
||||
void fixModelFilenames();
|
||||
QString getNextModelFilename();
|
||||
|
||||
static QString getElementName(const QString & prefix, unsigned int index, const char * name = 0, bool padding = false);
|
||||
|
||||
protected:
|
||||
void fixModelFilename(unsigned int index);
|
||||
};
|
||||
|
||||
#endif // _RADIODATA_H_
|
639
companion/src/firmwares/rawsource.cpp
Normal file
639
companion/src/firmwares/rawsource.cpp
Normal file
|
@ -0,0 +1,639 @@
|
|||
/*
|
||||
* 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 "rawsource.h"
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
/*
|
||||
* RawSourceRange
|
||||
*/
|
||||
|
||||
float RawSourceRange::getValue(int value)
|
||||
{
|
||||
if (IS_ARM(getCurrentBoard()))
|
||||
return float(value) * step;
|
||||
else
|
||||
return min + float(value) * step;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RawSource
|
||||
*/
|
||||
|
||||
RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSettings & settings, unsigned int flags) const
|
||||
{
|
||||
RawSourceRange result;
|
||||
|
||||
Firmware * firmware = Firmware::getCurrentVariant();
|
||||
int board = firmware->getBoard();
|
||||
|
||||
switch (type) {
|
||||
case SOURCE_TYPE_TELEMETRY:
|
||||
if (IS_ARM(board)) {
|
||||
div_t qr = div(index, 3);
|
||||
const SensorData & sensor = model->sensorData[qr.quot];
|
||||
if (sensor.prec == 2)
|
||||
result.step = 0.01;
|
||||
else if (sensor.prec == 1)
|
||||
result.step = 0.1;
|
||||
else
|
||||
result.step = 1;
|
||||
result.min = -30000 * result.step;
|
||||
result.max = +30000 * result.step;
|
||||
result.decimals = sensor.prec;
|
||||
result.unit = sensor.unitString();
|
||||
}
|
||||
else {
|
||||
result.offset = -DBL_MAX;
|
||||
|
||||
switch (index) {
|
||||
case TELEMETRY_SOURCE_TX_BATT:
|
||||
result.step = 0.1;
|
||||
result.decimals = 1;
|
||||
result.max = 25.5;
|
||||
result.unit = QObject::tr("V");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_TX_TIME:
|
||||
result.step = 60;
|
||||
result.max = 24 * 60 * result.step - 60; // 23:59:00 with 1-minute resolution
|
||||
result.unit = QObject::tr("s");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_TIMER1:
|
||||
case TELEMETRY_SOURCE_TIMER2:
|
||||
case TELEMETRY_SOURCE_TIMER3:
|
||||
result.step = 5;
|
||||
result.max = 255 * result.step;
|
||||
result.unit = QObject::tr("s");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_RSSI_TX:
|
||||
case TELEMETRY_SOURCE_RSSI_RX:
|
||||
result.max = 100;
|
||||
result.offset = 128;
|
||||
break;
|
||||
case TELEMETRY_SOURCE_A1_MIN:
|
||||
case TELEMETRY_SOURCE_A2_MIN:
|
||||
case TELEMETRY_SOURCE_A3_MIN:
|
||||
case TELEMETRY_SOURCE_A4_MIN:
|
||||
if (model) result = model->frsky.channels[index-TELEMETRY_SOURCE_A1_MIN].getRange();
|
||||
break;
|
||||
case TELEMETRY_SOURCE_A1:
|
||||
case TELEMETRY_SOURCE_A2:
|
||||
case TELEMETRY_SOURCE_A3:
|
||||
case TELEMETRY_SOURCE_A4:
|
||||
if (model) result = model->frsky.channels[index-TELEMETRY_SOURCE_A1].getRange();
|
||||
break;
|
||||
case TELEMETRY_SOURCE_ALT:
|
||||
case TELEMETRY_SOURCE_ALT_MIN:
|
||||
case TELEMETRY_SOURCE_ALT_MAX:
|
||||
case TELEMETRY_SOURCE_GPS_ALT:
|
||||
result.step = 8;
|
||||
result.min = -500;
|
||||
result.max = 1540;
|
||||
if (firmware->getCapability(Imperial) || settings.imperial) {
|
||||
result.step = (result.step * 105) / 32;
|
||||
result.min = (result.min * 105) / 32;
|
||||
result.max = (result.max * 105) / 32;
|
||||
result.unit = QObject::tr("ft");
|
||||
}
|
||||
else {
|
||||
result.unit = QObject::tr("m");
|
||||
}
|
||||
break;
|
||||
case TELEMETRY_SOURCE_T1:
|
||||
case TELEMETRY_SOURCE_T1_MAX:
|
||||
case TELEMETRY_SOURCE_T2:
|
||||
case TELEMETRY_SOURCE_T2_MAX:
|
||||
result.min = -30;
|
||||
result.max = 225;
|
||||
result.unit = QObject::trUtf8("°C");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_HDG:
|
||||
result.step = 2;
|
||||
result.max = 360;
|
||||
result.offset = 256;
|
||||
result.unit = QObject::trUtf8("°");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_RPM:
|
||||
case TELEMETRY_SOURCE_RPM_MAX:
|
||||
result.step = 50;
|
||||
result.max = 12750;
|
||||
break;
|
||||
case TELEMETRY_SOURCE_FUEL:
|
||||
result.max = 100;
|
||||
result.unit = QObject::tr("%");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_ASPEED:
|
||||
case TELEMETRY_SOURCE_ASPEED_MAX:
|
||||
result.decimals = 1;
|
||||
result.step = 2.0;
|
||||
result.max = (2*255);
|
||||
if (firmware->getCapability(Imperial) || settings.imperial) {
|
||||
result.step *= 1.150779;
|
||||
result.max *= 1.150779;
|
||||
result.unit = QObject::tr("mph");
|
||||
}
|
||||
else {
|
||||
result.step *= 1.852;
|
||||
result.max *= 1.852;
|
||||
result.unit = QObject::tr("km/h");
|
||||
}
|
||||
break;
|
||||
case TELEMETRY_SOURCE_SPEED:
|
||||
case TELEMETRY_SOURCE_SPEED_MAX:
|
||||
result.step = 2;
|
||||
result.max = (2*255);
|
||||
if (firmware->getCapability(Imperial) || settings.imperial) {
|
||||
result.step *= 1.150779;
|
||||
result.max *= 1.150779;
|
||||
result.unit = QObject::tr("mph");
|
||||
}
|
||||
else {
|
||||
result.step *= 1.852;
|
||||
result.max *= 1.852;
|
||||
result.unit = QObject::tr("km/h");
|
||||
}
|
||||
break;
|
||||
case TELEMETRY_SOURCE_VERTICAL_SPEED:
|
||||
result.step = 0.1;
|
||||
result.min = -12.5;
|
||||
result.max = 13.0;
|
||||
result.decimals = 1;
|
||||
result.unit = QObject::tr("m/s");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_DTE:
|
||||
result.max = 30000;
|
||||
break;
|
||||
case TELEMETRY_SOURCE_DIST:
|
||||
case TELEMETRY_SOURCE_DIST_MAX:
|
||||
result.step = 8;
|
||||
result.max = 2040;
|
||||
result.unit = QObject::tr("m");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CELL:
|
||||
case TELEMETRY_SOURCE_CELL_MIN:
|
||||
result.step = 0.02;
|
||||
result.max = 5.1;
|
||||
result.decimals = 2;
|
||||
result.unit = QObject::tr("V");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CELLS_SUM:
|
||||
case TELEMETRY_SOURCE_CELLS_MIN:
|
||||
case TELEMETRY_SOURCE_VFAS:
|
||||
case TELEMETRY_SOURCE_VFAS_MIN:
|
||||
result.step = 0.1;
|
||||
result.max = 25.5;
|
||||
result.decimals = 1;
|
||||
result.unit = QObject::tr("V");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CURRENT:
|
||||
case TELEMETRY_SOURCE_CURRENT_MAX:
|
||||
result.step = 0.5;
|
||||
result.max = 127.5;
|
||||
result.decimals = 1;
|
||||
result.unit = QObject::tr("A");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CONSUMPTION:
|
||||
result.step = 100;
|
||||
result.max = 25500;
|
||||
result.unit = QObject::tr("mAh");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_POWER:
|
||||
case TELEMETRY_SOURCE_POWER_MAX:
|
||||
result.step = 5;
|
||||
result.max = 1275;
|
||||
result.unit = QObject::tr("W");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_ACCX:
|
||||
case TELEMETRY_SOURCE_ACCY:
|
||||
case TELEMETRY_SOURCE_ACCZ:
|
||||
result.step = 0.01;
|
||||
result.decimals = 2;
|
||||
result.max = 2.55;
|
||||
result.min = 0;
|
||||
result.unit = QObject::tr("g");
|
||||
break;
|
||||
default:
|
||||
result.max = 125;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.offset == -DBL_MAX) {
|
||||
result.offset = result.max - (127*result.step);
|
||||
}
|
||||
|
||||
if (flags & (RANGE_DELTA_FUNCTION | RANGE_ABS_FUNCTION)) {
|
||||
result.offset = 0;
|
||||
result.min = result.step * -127;
|
||||
result.max = result.step * 127;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_LUA_OUTPUT:
|
||||
result.max = 30000;
|
||||
result.min = -result.max;
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_TRIM:
|
||||
result.max = (model && model->extendedTrims ? firmware->getCapability(ExtendedTrimsRange) : firmware->getCapability(TrimsRange));
|
||||
result.min = -result.max;
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_GVAR: {
|
||||
GVarData gv = model->gvarData[index];
|
||||
result.step = gv.multiplierGet();
|
||||
result.decimals = gv.prec;
|
||||
result.max = gv.getMaxPrec();
|
||||
result.min = gv.getMinPrec();
|
||||
result.unit = gv.unitToString();
|
||||
break;
|
||||
}
|
||||
|
||||
case SOURCE_TYPE_SPECIAL:
|
||||
if (index == 0) { //Batt
|
||||
result.step = 0.1;
|
||||
result.decimals = 1;
|
||||
result.max = 25.5;
|
||||
result.unit = QObject::tr("V");
|
||||
}
|
||||
else if (index == 1) { //Time
|
||||
result.step = 60;
|
||||
result.max = 24 * 60 * result.step - 60; // 23:59:00 with 1-minute resolution
|
||||
result.unit = QObject::tr("s");
|
||||
}
|
||||
else { // Timers 1 - 3
|
||||
result.step = 1;
|
||||
result.max = 9 * 60 * 60 - 1; // 8:59:59 (to match firmware)
|
||||
result.min = -result.max;
|
||||
result.unit = QObject::tr("s");
|
||||
}
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_CH:
|
||||
result.max = model->getChannelsMax(false);
|
||||
result.min = -result.max;
|
||||
break;
|
||||
|
||||
default:
|
||||
result.max = 100;
|
||||
result.min = -result.max;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & RANGE_ABS_FUNCTION) {
|
||||
result.min = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString RawSource::toString(const ModelData * model, const GeneralSettings * const generalSettings, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN) {
|
||||
board = getCurrentBoard();
|
||||
}
|
||||
|
||||
static const QString trims[] = {
|
||||
QObject::tr("TrmR"), QObject::tr("TrmE"), QObject::tr("TrmT"), QObject::tr("TrmA"), QObject::tr("Trm5"), QObject::tr("Trm6")
|
||||
};
|
||||
|
||||
static const QString special[] = {
|
||||
QObject::tr("Batt"), QObject::tr("Time"), QObject::tr("Timer1"), QObject::tr("Timer2"), QObject::tr("Timer3"),
|
||||
};
|
||||
|
||||
static const QString telemetry[] = {
|
||||
QObject::tr("Batt"), QObject::tr("Time"), QObject::tr("Timer1"), QObject::tr("Timer2"), QObject::tr("Timer3"),
|
||||
QObject::tr("SWR"), QObject::tr("RSSI Tx"), QObject::tr("RSSI Rx"),
|
||||
QObject::tr("A1"), QObject::tr("A2"), QObject::tr("A3"), QObject::tr("A4"),
|
||||
QObject::tr("Alt"), QObject::tr("Rpm"), QObject::tr("Fuel"), QObject::tr("T1"), QObject::tr("T2"),
|
||||
QObject::tr("Speed"), QObject::tr("Dist"), QObject::tr("GPS Alt"),
|
||||
QObject::tr("Cell"), QObject::tr("Cells"), QObject::tr("Vfas"), QObject::tr("Curr"), QObject::tr("Cnsp"), QObject::tr("Powr"),
|
||||
QObject::tr("AccX"), QObject::tr("AccY"), QObject::tr("AccZ"),
|
||||
QObject::tr("Hdg "), QObject::tr("VSpd"), QObject::tr("AirSpeed"), QObject::tr("dTE"),
|
||||
QObject::tr("A1-"), QObject::tr("A2-"), QObject::tr("A3-"), QObject::tr("A4-"),
|
||||
QObject::tr("Alt-"), QObject::tr("Alt+"), QObject::tr("Rpm+"), QObject::tr("T1+"), QObject::tr("T2+"), QObject::tr("Speed+"), QObject::tr("Dist+"), QObject::tr("AirSpeed+"),
|
||||
QObject::tr("Cell-"), QObject::tr("Cells-"), QObject::tr("Vfas-"), QObject::tr("Curr+"), QObject::tr("Powr+"),
|
||||
QObject::tr("ACC"), QObject::tr("GPS Time"),
|
||||
};
|
||||
|
||||
static const QString rotary[] = { QObject::tr("REa"), QObject::tr("REb") };
|
||||
|
||||
if (index<0) {
|
||||
return QObject::tr("???");
|
||||
}
|
||||
|
||||
QString result;
|
||||
int genAryIdx = 0;
|
||||
switch (type) {
|
||||
case SOURCE_TYPE_NONE:
|
||||
return QObject::tr("----");
|
||||
|
||||
case SOURCE_TYPE_VIRTUAL_INPUT:
|
||||
{
|
||||
const char * name = NULL;
|
||||
if (model)
|
||||
name = model->inputNames[index];
|
||||
return RadioData::getElementName(QCoreApplication::translate("Input", "I"), index + 1, name);
|
||||
}
|
||||
|
||||
case SOURCE_TYPE_LUA_OUTPUT:
|
||||
return QObject::tr("LUA%1%2").arg(index/16+1).arg(QChar('a'+index%16));
|
||||
|
||||
case SOURCE_TYPE_STICK:
|
||||
if (generalSettings) {
|
||||
if (isPot(&genAryIdx))
|
||||
result = QString(generalSettings->potName[genAryIdx]);
|
||||
else if (isSlider(&genAryIdx))
|
||||
result = QString(generalSettings->sliderName[genAryIdx]);
|
||||
else if (isStick(&genAryIdx))
|
||||
result = QString(generalSettings->stickName[genAryIdx]);
|
||||
}
|
||||
if (result.isEmpty())
|
||||
result = Boards::getAnalogInputName(board, index);
|
||||
return result;
|
||||
|
||||
case SOURCE_TYPE_TRIM:
|
||||
return CHECK_IN_ARRAY(trims, index);
|
||||
case SOURCE_TYPE_ROTARY_ENCODER:
|
||||
return CHECK_IN_ARRAY(rotary, index);
|
||||
case SOURCE_TYPE_MAX:
|
||||
return QObject::tr("MAX");
|
||||
|
||||
case SOURCE_TYPE_SWITCH:
|
||||
if (generalSettings)
|
||||
result = QString(generalSettings->switchName[index]);
|
||||
if (result.isEmpty())
|
||||
result = Boards::getSwitchInfo(board, index).name;
|
||||
return result;
|
||||
|
||||
case SOURCE_TYPE_CUSTOM_SWITCH:
|
||||
return RawSwitch(SWITCH_TYPE_VIRTUAL, index+1).toString();
|
||||
|
||||
case SOURCE_TYPE_CYC:
|
||||
return QObject::tr("CYC%1").arg(index+1);
|
||||
|
||||
case SOURCE_TYPE_PPM:
|
||||
return RadioData::getElementName(QCoreApplication::translate("Trainer", "TR"), index + 1);
|
||||
|
||||
case SOURCE_TYPE_CH:
|
||||
{
|
||||
const char * name = NULL;
|
||||
if (getCurrentFirmware()->getCapability(ChannelsName) && model)
|
||||
name = model->limitData[index].name;
|
||||
return RadioData::getElementName(QCoreApplication::translate("Channel", "CH"), index + 1, name);
|
||||
}
|
||||
|
||||
case SOURCE_TYPE_SPECIAL:
|
||||
return CHECK_IN_ARRAY(special, index);
|
||||
|
||||
case SOURCE_TYPE_TELEMETRY:
|
||||
if (IS_ARM(board)) {
|
||||
div_t qr = div(index, 3);
|
||||
result = RadioData::getElementName(QCoreApplication::translate("Telemetry", "TELE"), qr.quot+1, model ? model->sensorData[qr.quot].label : NULL);
|
||||
if (qr.rem)
|
||||
result += (qr.rem == 1 ? "-" : "+");
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return CHECK_IN_ARRAY(telemetry, index);
|
||||
}
|
||||
|
||||
case SOURCE_TYPE_GVAR:
|
||||
{
|
||||
const char * name = NULL;
|
||||
if (getCurrentFirmware()->getCapability(GvarsName) && model)
|
||||
name = model->gvarData[index].name;
|
||||
return RadioData::getElementName(QCoreApplication::translate("Global Variable", "GV"), index + 1, name);
|
||||
}
|
||||
|
||||
default:
|
||||
return QObject::tr("???");
|
||||
}
|
||||
}
|
||||
|
||||
bool RawSource::isStick(int * stickIndex, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
if (type == SOURCE_TYPE_STICK && index < Boards::getCapability(board, Board::Sticks)) {
|
||||
if (stickIndex)
|
||||
*stickIndex = index;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSource::isPot(int * potsIndex, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
Boards b(board);
|
||||
if (type == SOURCE_TYPE_STICK &&
|
||||
index >= b.getCapability(Board::Sticks) &&
|
||||
index < b.getCapability(Board::Sticks) + b.getCapability(Board::Pots)) {
|
||||
if (potsIndex)
|
||||
*potsIndex = index - b.getCapability(Board::Sticks);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSource::isSlider(int * sliderIndex, Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
Boards b(board);
|
||||
if (type == SOURCE_TYPE_STICK &&
|
||||
index >= b.getCapability(Board::Sticks) + b.getCapability(Board::Pots) &&
|
||||
index < b.getCapability(Board::Sticks) + b.getCapability(Board::Pots) + b.getCapability(Board::Sliders)) {
|
||||
if (sliderIndex)
|
||||
*sliderIndex = index - b.getCapability(Board::Sticks) - b.getCapability(Board::Pots);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSource::isTimeBased(Board::Type board) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
if (IS_ARM(board))
|
||||
return (type == SOURCE_TYPE_SPECIAL && index > 0);
|
||||
else
|
||||
return (type==SOURCE_TYPE_TELEMETRY && (index==TELEMETRY_SOURCE_TX_TIME || index==TELEMETRY_SOURCE_TIMER1 || index==TELEMETRY_SOURCE_TIMER2 || index==TELEMETRY_SOURCE_TIMER3));
|
||||
}
|
||||
|
||||
bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings * const gs, Board::Type board)
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
Boards b(board);
|
||||
|
||||
if (type == SOURCE_TYPE_STICK && index >= b.getCapability(Board::MaxAnalogs))
|
||||
return false;
|
||||
|
||||
if (type == SOURCE_TYPE_SWITCH && index >= b.getCapability(Board::Switches))
|
||||
return false;
|
||||
|
||||
if (model) {
|
||||
if (type == SOURCE_TYPE_VIRTUAL_INPUT && !model->isInputValid(index))
|
||||
return false;
|
||||
|
||||
if (type == SOURCE_TYPE_CUSTOM_SWITCH && model->logicalSw[index].isEmpty())
|
||||
return false;
|
||||
|
||||
if (type == SOURCE_TYPE_TELEMETRY) {
|
||||
if (IS_ARM(board) && !model->sensorData[div(index, 3).quot].isAvailable()) {
|
||||
return false;
|
||||
}
|
||||
else if (!IS_ARM(board)) {
|
||||
Firmware * fw = getCurrentFirmware();
|
||||
if (type == (int)TELEMETRY_SOURCE_TX_TIME && !fw->getCapability(RtcTime))
|
||||
return false;
|
||||
|
||||
if (type == (int)TELEMETRY_SOURCE_SWR && !fw->getCapability(SportTelemetry))
|
||||
return false;
|
||||
|
||||
if (type == (int)TELEMETRY_SOURCE_TIMER3 && fw->getCapability(Timers) < 3)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gs) {
|
||||
int gsIdx = 0;
|
||||
if (type == SOURCE_TYPE_STICK && ((isPot(&gsIdx) && !gs->isPotAvailable(gsIdx)) || (isSlider(&gsIdx) && !gs->isSliderAvailable(gsIdx))))
|
||||
return false;
|
||||
|
||||
if (type == SOURCE_TYPE_SWITCH && IS_HORUS_OR_TARANIS(board) && !gs->switchSourceAllowedTaranis(index))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == SOURCE_TYPE_TRIM && index >= b.getCapability(Board::NumTrims))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RawSource RawSource::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setItemType("SRC", 1);
|
||||
RadioDataConversionState::EventType evt = RadioDataConversionState::EVT_NONE;
|
||||
RadioDataConversionState::LogField oldData(index, toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType));
|
||||
|
||||
if (type == SOURCE_TYPE_STICK) {
|
||||
if (cstate.toBoard.getCapability(Board::Sliders)) {
|
||||
if (index >= cstate.fromBoard.getCapability(Board::Sticks) + cstate.fromBoard.getCapability(Board::Pots)) {
|
||||
// 1st slider alignment
|
||||
index += cstate.toBoard.getCapability(Board::Pots) - cstate.fromBoard.getCapability(Board::Pots);
|
||||
}
|
||||
|
||||
if (isSlider(0, cstate.fromType)) {
|
||||
// LS and RS sliders are after 2 aux sliders on X12 and X9E
|
||||
if ((IS_HORUS_X12S(cstate.toType) || IS_TARANIS_X9E(cstate.toType)) && !IS_HORUS_X12S(cstate.fromType) && !IS_TARANIS_X9E(cstate.fromType)) {
|
||||
if (index >= 7) {
|
||||
index += 2; // LS/RS to LS/RS
|
||||
}
|
||||
}
|
||||
else if (!IS_TARANIS_X9E(cstate.toType) && !IS_HORUS_X12S(cstate.toType) && (IS_HORUS_X12S(cstate.fromType) || IS_TARANIS_X9E(cstate.fromType))) {
|
||||
if (index >= 7 && index <= 8) {
|
||||
index += 2; // aux sliders to spare analogs (which may not exist, this is validated later)
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (index >= 9 && index <= 10) {
|
||||
index -= 2; // LS/RS to LS/RS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_TARANIS(cstate.toType) && IS_HORUS(cstate.fromType)) {
|
||||
if (index == 6)
|
||||
index = 5; // pot S2 to S2
|
||||
else if (index == 5)
|
||||
index = -1; // 6P on Horus doesn't exist on Taranis
|
||||
}
|
||||
else if (IS_HORUS(cstate.toType) && IS_TARANIS(cstate.fromType) && index == 5)
|
||||
{
|
||||
index = 6; // pot S2 to S2
|
||||
}
|
||||
|
||||
} // SOURCE_TYPE_STICK
|
||||
|
||||
if (type == SOURCE_TYPE_SWITCH) {
|
||||
// SWI to SWR don't exist on !X9E board
|
||||
if (!IS_TARANIS_X9E(cstate.toType) && IS_TARANIS_X9E(cstate.fromType)) {
|
||||
if (index >= 8) {
|
||||
index = index % 8;
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_HORUS(cstate.fromType))) {
|
||||
// No SE and SG on X7 board
|
||||
if (index == 4 || index == 6) {
|
||||
index = 3; // SG and SE to SD
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (index == 5) {
|
||||
index = 4; // SF to SF
|
||||
}
|
||||
else if (index == 7) {
|
||||
index = 5; // SH to SH
|
||||
}
|
||||
}
|
||||
// Compensate for SE and SG on X9/Horus board if converting from X7
|
||||
else if ((IS_TARANIS_X9(cstate.toType) || IS_HORUS(cstate.toType)) && IS_TARANIS_X7(cstate.fromType)) {
|
||||
if (index == 4) {
|
||||
index = 5; // SF to SF
|
||||
}
|
||||
else if (index == 5) {
|
||||
index = 7; // SH to SH
|
||||
}
|
||||
}
|
||||
} // SOURCE_TYPE_SWITCH
|
||||
|
||||
// final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted)
|
||||
if (!isAvailable(NULL, cstate.toGS(), cstate.toType)) {
|
||||
cstate.setInvalid(oldData);
|
||||
index = -1; // TODO: better way to flag invalid sources?
|
||||
type = MAX_SOURCE_TYPE;
|
||||
}
|
||||
else if (evt == RadioDataConversionState::EVT_CVRT) {
|
||||
cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toModel(), cstate.toGS(), cstate.toType)));
|
||||
}
|
||||
else if (oldData.id != index) {
|
||||
// provide info by default if anything changed
|
||||
cstate.setMoved(oldData, RadioDataConversionState::LogField(index, toString(cstate.toModel(), cstate.toGS(), cstate.toType)));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
256
companion/src/firmwares/rawsource.h
Normal file
256
companion/src/firmwares/rawsource.h
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RAWSOURCE_H
|
||||
#define RAWSOURCE_H
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class Firmware;
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum Switches {
|
||||
SWITCH_NONE,
|
||||
|
||||
SWITCH_THR = SWITCH_NONE+1,
|
||||
SWITCH_RUD,
|
||||
SWITCH_ELE,
|
||||
SWITCH_ID0,
|
||||
SWITCH_ID1,
|
||||
SWITCH_ID2,
|
||||
SWITCH_AIL,
|
||||
SWITCH_GEA,
|
||||
SWITCH_TRN,
|
||||
|
||||
SWITCH_SA0 = SWITCH_NONE+1,
|
||||
SWITCH_SA1,
|
||||
SWITCH_SA2,
|
||||
SWITCH_SB0,
|
||||
SWITCH_SB1,
|
||||
SWITCH_SB2,
|
||||
SWITCH_SC0,
|
||||
SWITCH_SC1,
|
||||
SWITCH_SC2,
|
||||
SWITCH_SD0,
|
||||
SWITCH_SD1,
|
||||
SWITCH_SD2,
|
||||
SWITCH_SE0,
|
||||
SWITCH_SE1,
|
||||
SWITCH_SE2,
|
||||
SWITCH_SF0,
|
||||
SWITCH_SF1,
|
||||
SWITCH_SG0,
|
||||
SWITCH_SG1,
|
||||
SWITCH_SG2,
|
||||
SWITCH_SH0,
|
||||
SWITCH_SH2,
|
||||
SWITCH_SI0,
|
||||
SWITCH_SI2,
|
||||
SWITCH_SJ0,
|
||||
SWITCH_SJ2,
|
||||
SWITCH_SK0,
|
||||
SWITCH_SK2,
|
||||
};
|
||||
|
||||
enum TimerModes {
|
||||
TMRMODE_NONE,
|
||||
TMRMODE_ABS,
|
||||
TMRMODE_THR,
|
||||
TMRMODE_THR_REL,
|
||||
TMRMODE_THR_TRG,
|
||||
TMRMODE_FIRST_SWITCH
|
||||
};
|
||||
|
||||
enum FailsafeModes {
|
||||
FAILSAFE_NOT_SET,
|
||||
FAILSAFE_HOLD,
|
||||
FAILSAFE_CUSTOM,
|
||||
FAILSAFE_NOPULSES,
|
||||
FAILSAFE_RECEIVER,
|
||||
FAILSAFE_LAST = FAILSAFE_RECEIVER
|
||||
};
|
||||
|
||||
enum HeliSwashTypes {
|
||||
HELI_SWASH_TYPE_NONE=0,
|
||||
HELI_SWASH_TYPE_120,
|
||||
HELI_SWASH_TYPE_120X,
|
||||
HELI_SWASH_TYPE_140,
|
||||
HELI_SWASH_TYPE_90
|
||||
};
|
||||
|
||||
enum TelemetrySource {
|
||||
TELEMETRY_SOURCE_TX_BATT,
|
||||
TELEMETRY_SOURCE_TX_TIME,
|
||||
TELEMETRY_SOURCE_TIMER1,
|
||||
TELEMETRY_SOURCE_TIMER2,
|
||||
TELEMETRY_SOURCE_TIMER3,
|
||||
TELEMETRY_SOURCE_SWR,
|
||||
TELEMETRY_SOURCE_RSSI_TX,
|
||||
TELEMETRY_SOURCE_RSSI_RX,
|
||||
TELEMETRY_SOURCE_A1,
|
||||
TELEMETRY_SOURCE_A2,
|
||||
TELEMETRY_SOURCE_A3,
|
||||
TELEMETRY_SOURCE_A4,
|
||||
TELEMETRY_SOURCE_ALT,
|
||||
TELEMETRY_SOURCE_RPM,
|
||||
TELEMETRY_SOURCE_FUEL,
|
||||
TELEMETRY_SOURCE_T1,
|
||||
TELEMETRY_SOURCE_T2,
|
||||
TELEMETRY_SOURCE_SPEED,
|
||||
TELEMETRY_SOURCE_DIST,
|
||||
TELEMETRY_SOURCE_GPS_ALT,
|
||||
TELEMETRY_SOURCE_CELL,
|
||||
TELEMETRY_SOURCE_CELLS_SUM,
|
||||
TELEMETRY_SOURCE_VFAS,
|
||||
TELEMETRY_SOURCE_CURRENT,
|
||||
TELEMETRY_SOURCE_CONSUMPTION,
|
||||
TELEMETRY_SOURCE_POWER,
|
||||
TELEMETRY_SOURCE_ACCX,
|
||||
TELEMETRY_SOURCE_ACCY,
|
||||
TELEMETRY_SOURCE_ACCZ,
|
||||
TELEMETRY_SOURCE_HDG,
|
||||
TELEMETRY_SOURCE_VERTICAL_SPEED,
|
||||
TELEMETRY_SOURCE_ASPEED,
|
||||
TELEMETRY_SOURCE_DTE,
|
||||
TELEMETRY_SOURCE_A1_MIN,
|
||||
TELEMETRY_SOURCE_A2_MIN,
|
||||
TELEMETRY_SOURCE_A3_MIN,
|
||||
TELEMETRY_SOURCE_A4_MIN,
|
||||
TELEMETRY_SOURCE_ALT_MIN,
|
||||
TELEMETRY_SOURCE_ALT_MAX,
|
||||
TELEMETRY_SOURCE_RPM_MAX,
|
||||
TELEMETRY_SOURCE_T1_MAX,
|
||||
TELEMETRY_SOURCE_T2_MAX,
|
||||
TELEMETRY_SOURCE_SPEED_MAX,
|
||||
TELEMETRY_SOURCE_DIST_MAX,
|
||||
TELEMETRY_SOURCE_ASPEED_MAX,
|
||||
TELEMETRY_SOURCE_CELL_MIN,
|
||||
TELEMETRY_SOURCE_CELLS_MIN,
|
||||
TELEMETRY_SOURCE_VFAS_MIN,
|
||||
TELEMETRY_SOURCE_CURRENT_MAX,
|
||||
TELEMETRY_SOURCE_POWER_MAX,
|
||||
TELEMETRY_SOURCE_ACC,
|
||||
TELEMETRY_SOURCE_GPS_TIME,
|
||||
TELEMETRY_SOURCES_STATUS_COUNT = TELEMETRY_SOURCE_GPS_TIME+1,
|
||||
TELEMETRY_SOURCES_DISPLAY_COUNT = TELEMETRY_SOURCE_POWER_MAX+1,
|
||||
TELEMETRY_SOURCES_COUNT = TELEMETRY_SOURCE_POWER_MAX+1,
|
||||
TELEMETRY_SOURCE_RESERVE = -1
|
||||
};
|
||||
|
||||
#define TM_HASTELEMETRY 0x01
|
||||
#define TM_HASOFFSET 0x02
|
||||
#define TM_HASWSHH 0x04
|
||||
|
||||
enum RawSourceType {
|
||||
SOURCE_TYPE_NONE,
|
||||
SOURCE_TYPE_VIRTUAL_INPUT,
|
||||
SOURCE_TYPE_LUA_OUTPUT,
|
||||
SOURCE_TYPE_STICK, // and POTS
|
||||
SOURCE_TYPE_ROTARY_ENCODER,
|
||||
SOURCE_TYPE_TRIM,
|
||||
SOURCE_TYPE_MAX,
|
||||
SOURCE_TYPE_SWITCH,
|
||||
SOURCE_TYPE_CUSTOM_SWITCH,
|
||||
SOURCE_TYPE_CYC,
|
||||
SOURCE_TYPE_PPM,
|
||||
SOURCE_TYPE_CH,
|
||||
SOURCE_TYPE_GVAR,
|
||||
SOURCE_TYPE_SPECIAL,
|
||||
SOURCE_TYPE_TELEMETRY,
|
||||
MAX_SOURCE_TYPE
|
||||
};
|
||||
|
||||
class RawSourceRange
|
||||
{
|
||||
public:
|
||||
RawSourceRange():
|
||||
decimals(0),
|
||||
min(0.0),
|
||||
max(0.0),
|
||||
step(1.0),
|
||||
offset(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
float getValue(int value);
|
||||
|
||||
int decimals;
|
||||
double min;
|
||||
double max;
|
||||
double step;
|
||||
double offset;
|
||||
QString unit;
|
||||
};
|
||||
|
||||
#define RANGE_DELTA_FUNCTION 1
|
||||
#define RANGE_ABS_FUNCTION 2
|
||||
|
||||
class RawSource {
|
||||
public:
|
||||
RawSource():
|
||||
type(SOURCE_TYPE_NONE),
|
||||
index(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit RawSource(int value):
|
||||
type(RawSourceType(abs(value)/65536)),
|
||||
index(value >= 0 ? abs(value)%65536 : -(abs(value)%65536))
|
||||
{
|
||||
}
|
||||
|
||||
RawSource(RawSourceType type, int index=0):
|
||||
type(type),
|
||||
index(index)
|
||||
{
|
||||
}
|
||||
|
||||
inline const int toValue() const
|
||||
{
|
||||
return index >= 0 ? (type * 65536 + index) : -(type * 65536 - index);
|
||||
}
|
||||
|
||||
RawSource convert(RadioDataConversionState & cstate);
|
||||
QString toString(const ModelData * model = NULL, const GeneralSettings * const generalSettings = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
RawSourceRange getRange(const ModelData * model, const GeneralSettings & settings, unsigned int flags=0) const;
|
||||
bool isStick(int * potsIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
bool isPot(int * potsIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
bool isSlider(int * sliderIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
bool isTimeBased(Board::Type board = Board::BOARD_UNKNOWN) const;
|
||||
bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN);
|
||||
|
||||
bool operator == ( const RawSource & other) {
|
||||
return (this->type == other.type) && (this->index == other.index);
|
||||
}
|
||||
|
||||
bool operator != ( const RawSource & other) {
|
||||
return (this->type != other.type) || (this->index != other.index);
|
||||
}
|
||||
|
||||
RawSourceType type;
|
||||
int index;
|
||||
};
|
||||
|
||||
#endif // RAWSOURCE_H
|
229
companion/src/firmwares/rawswitch.cpp
Normal file
229
companion/src/firmwares/rawswitch.cpp
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* 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 "rawswitch.h"
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
|
||||
QString RawSwitch::toString(Board::Type board, const GeneralSettings * const generalSettings, const ModelData * const modelData) const
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN) {
|
||||
board = getCurrentBoard();
|
||||
}
|
||||
|
||||
static const QString switches9X[] = {
|
||||
QString("THR"), QString("RUD"), QString("ELE"),
|
||||
QString("ID0"), QString("ID1"), QString("ID2"),
|
||||
QString("AIL"), QString("GEA"), QString("TRN")
|
||||
};
|
||||
|
||||
static const QString trimsSwitches[] = {
|
||||
QObject::tr("RudTrim Left"), QObject::tr("RudTrim Right"),
|
||||
QObject::tr("EleTrim Down"), QObject::tr("EleTrim Up"),
|
||||
QObject::tr("ThrTrim Down"), QObject::tr("ThrTrim Up"),
|
||||
QObject::tr("AilTrim Left"), QObject::tr("AilTrim Right"),
|
||||
QObject::tr("Trim 5 Down"), QObject::tr("Trim 5 Up"),
|
||||
QObject::tr("Trim 6 Down"), QObject::tr("Trim 6 Up")
|
||||
};
|
||||
|
||||
static const QString rotaryEncoders[] = {
|
||||
QObject::tr("REa"), QObject::tr("REb")
|
||||
};
|
||||
|
||||
static const QString timerModes[] = {
|
||||
QObject::tr("OFF"), QObject::tr("ON"),
|
||||
QObject::tr("THs"), QObject::tr("TH%"), QObject::tr("THt")
|
||||
};
|
||||
|
||||
const QStringList directionIndicators = QStringList()
|
||||
<< CPN_STR_SW_INDICATOR_UP
|
||||
<< CPN_STR_SW_INDICATOR_NEUT
|
||||
<< CPN_STR_SW_INDICATOR_DN;
|
||||
|
||||
if (index < 0) {
|
||||
return CPN_STR_SW_INDICATOR_REV % RawSwitch(type, -index).toString(board, generalSettings, modelData);
|
||||
}
|
||||
else {
|
||||
QString swName;
|
||||
div_t qr;
|
||||
switch(type) {
|
||||
case SWITCH_TYPE_SWITCH:
|
||||
if (IS_HORUS_OR_TARANIS(board)) {
|
||||
qr = div(index-1, 3);
|
||||
if (generalSettings)
|
||||
swName = QString(generalSettings->switchName[qr.quot]);
|
||||
if (swName.isEmpty())
|
||||
swName = getSwitchInfo(board, qr.quot).name;
|
||||
return swName + directionIndicators.at(qr.rem > -1 && qr.rem < directionIndicators.size() ? qr.rem : 1);
|
||||
}
|
||||
else {
|
||||
return CHECK_IN_ARRAY(switches9X, index - 1);
|
||||
}
|
||||
|
||||
case SWITCH_TYPE_VIRTUAL:
|
||||
return RadioData::getElementName(QCoreApplication::translate("Logic Switch", "L"), index, NULL, true);
|
||||
|
||||
case SWITCH_TYPE_MULTIPOS_POT:
|
||||
if (!Boards::getCapability(board, Board::MultiposPotsPositions))
|
||||
return QObject::tr("???");
|
||||
qr = div(index - 1, Boards::getCapability(board, Board::MultiposPotsPositions));
|
||||
if (generalSettings && qr.quot < (int)DIM(generalSettings->potConfig))
|
||||
swName = QString(generalSettings->potName[qr.quot]);
|
||||
if (swName.isEmpty())
|
||||
swName = Boards::getAnalogInputName(board, qr.quot + Boards::getCapability(board, Board::Sticks));
|
||||
return swName + "_" + QString::number(qr.rem + 1);
|
||||
|
||||
case SWITCH_TYPE_TRIM:
|
||||
return CHECK_IN_ARRAY(trimsSwitches, index-1);
|
||||
|
||||
case SWITCH_TYPE_ROTARY_ENCODER:
|
||||
return CHECK_IN_ARRAY(rotaryEncoders, index-1);
|
||||
|
||||
case SWITCH_TYPE_ON:
|
||||
return QObject::tr("ON");
|
||||
|
||||
case SWITCH_TYPE_OFF:
|
||||
return QObject::tr("OFF");
|
||||
|
||||
case SWITCH_TYPE_ONE:
|
||||
return QObject::tr("One");
|
||||
|
||||
case SWITCH_TYPE_FLIGHT_MODE:
|
||||
return RadioData::getElementName(QCoreApplication::translate("Flight mode", "FM"), index - 1, modelData ? modelData->flightModeData[index-1].name : NULL);
|
||||
|
||||
case SWITCH_TYPE_NONE:
|
||||
return QObject::tr("----");
|
||||
|
||||
case SWITCH_TYPE_TIMER_MODE:
|
||||
return CHECK_IN_ARRAY(timerModes, index);
|
||||
|
||||
case SWITCH_TYPE_SENSOR:
|
||||
return RadioData::getElementName(QCoreApplication::translate("Telemetry", "TELE"), index, modelData ? modelData->sensorData[index-1].label : NULL);
|
||||
|
||||
case SWITCH_TYPE_TELEMETRY:
|
||||
return QObject::tr("Telemetry");
|
||||
|
||||
default:
|
||||
return QObject::tr("???");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RawSwitch::isAvailable(const ModelData * const model, const GeneralSettings * const gs, Board::Type board)
|
||||
{
|
||||
if (board == Board::BOARD_UNKNOWN)
|
||||
board = getCurrentBoard();
|
||||
|
||||
Boards b(board);
|
||||
|
||||
if (type == SWITCH_TYPE_SWITCH && abs(index) > b.getCapability(Board::SwitchPositions))
|
||||
return false;
|
||||
|
||||
if (type == SWITCH_TYPE_TRIM && abs(index) > b.getCapability(Board::NumTrimSwitches))
|
||||
return false;
|
||||
|
||||
if (gs) {
|
||||
if (type == SWITCH_TYPE_SWITCH && IS_HORUS_OR_TARANIS(board) && !gs->switchPositionAllowedTaranis(abs(index)))
|
||||
return false;
|
||||
|
||||
if (type == SWITCH_TYPE_MULTIPOS_POT) {
|
||||
int pot = div(abs(index) - 1, b.getCapability(Board::MultiposPotsPositions)).quot;
|
||||
if (!gs->isPotAvailable(pot) || gs->potConfig[pot] != Board::POT_MULTIPOS_SWITCH)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (model && !model->isAvailable(*this))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RawSwitch RawSwitch::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
if (!index)
|
||||
return *this;
|
||||
|
||||
cstate.setItemType("SW", 2);
|
||||
RadioDataConversionState::EventType evt = RadioDataConversionState::EVT_NONE;
|
||||
RadioDataConversionState::LogField oldData(index, toString(cstate.fromType, cstate.fromGS(), cstate.fromModel()));
|
||||
|
||||
if (type == SWITCH_TYPE_SWITCH) {
|
||||
int srcIdx = div(abs(index)-1, 3).quot; // raw source index
|
||||
int delta = 0;
|
||||
|
||||
// SWI to SWR don't exist on !X9E board
|
||||
if (!IS_TARANIS_X9E(cstate.toType) && IS_TARANIS_X9E(cstate.fromType)) {
|
||||
if (srcIdx > 7) {
|
||||
index %= 24;
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
}
|
||||
|
||||
// No SE and SG on X7 board
|
||||
if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_HORUS(cstate.fromType))) {
|
||||
if (srcIdx == 4 || srcIdx == 5) {
|
||||
delta = 3; // SE to SD & SF to SF
|
||||
if (srcIdx == 4)
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (srcIdx == 6) {
|
||||
delta = 9; // SG to SD
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (srcIdx == 7) {
|
||||
delta = 6; // SH to SH
|
||||
}
|
||||
}
|
||||
// Compensate for SE and SG on X9/Horus board if converting from X7
|
||||
else if ((IS_TARANIS_X9(cstate.toType) || IS_HORUS(cstate.toType)) && IS_TARANIS_X7(cstate.fromType)) {
|
||||
if (srcIdx == 4) {
|
||||
delta = -3; // SF to SF
|
||||
}
|
||||
else if (srcIdx == 5) {
|
||||
delta = -6; // SH to SH
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
delta = -delta; // invert for !switch
|
||||
}
|
||||
|
||||
index -= delta;
|
||||
|
||||
} // SWITCH_TYPE_SWITCH
|
||||
|
||||
// final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted)
|
||||
if (!isAvailable(NULL, cstate.toGS(), cstate.toType)) {
|
||||
cstate.setInvalid(oldData);
|
||||
type = MAX_SWITCH_TYPE; // TODO: better way to flag invalid switches?
|
||||
}
|
||||
else if (evt == RadioDataConversionState::EVT_CVRT) {
|
||||
cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toType, cstate.toGS(), cstate.toModel())));
|
||||
}
|
||||
else if (oldData.id != index) {
|
||||
// provide info by default if anything changed
|
||||
cstate.setMoved(oldData, RadioDataConversionState::LogField(index, toString(cstate.toType, cstate.toGS(), cstate.toModel())));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
93
companion/src/firmwares/rawswitch.h
Normal file
93
companion/src/firmwares/rawswitch.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RAWSWITCH_H
|
||||
#define RAWSWITCH_H
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class Firmware;
|
||||
class ModelData;
|
||||
class GeneralSettings;
|
||||
class RadioDataConversionState;
|
||||
|
||||
enum RawSwitchType {
|
||||
SWITCH_TYPE_NONE,
|
||||
SWITCH_TYPE_SWITCH,
|
||||
SWITCH_TYPE_VIRTUAL,
|
||||
SWITCH_TYPE_MULTIPOS_POT,
|
||||
SWITCH_TYPE_TRIM,
|
||||
SWITCH_TYPE_ROTARY_ENCODER,
|
||||
SWITCH_TYPE_ON,
|
||||
SWITCH_TYPE_OFF,
|
||||
SWITCH_TYPE_ONE,
|
||||
SWITCH_TYPE_FLIGHT_MODE,
|
||||
SWITCH_TYPE_TIMER_MODE,
|
||||
SWITCH_TYPE_TELEMETRY,
|
||||
SWITCH_TYPE_SENSOR,
|
||||
MAX_SWITCH_TYPE
|
||||
};
|
||||
|
||||
class RawSwitch {
|
||||
public:
|
||||
RawSwitch():
|
||||
type(SWITCH_TYPE_NONE),
|
||||
index(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit RawSwitch(int value):
|
||||
type(RawSwitchType(abs(value)/256)),
|
||||
index(value >= 0 ? abs(value)%256 : -(abs(value)%256))
|
||||
{
|
||||
}
|
||||
|
||||
RawSwitch(RawSwitchType type, int index=0):
|
||||
type(type),
|
||||
index(index)
|
||||
{
|
||||
}
|
||||
|
||||
inline const int toValue() const
|
||||
{
|
||||
return index >= 0 ? (type * 256 + index) : -(type * 256 - index);
|
||||
}
|
||||
|
||||
RawSwitch convert(RadioDataConversionState & cstate);
|
||||
QString toString(Board::Type board = Board::BOARD_UNKNOWN, const GeneralSettings * const generalSettings = NULL, const ModelData * const modelData = NULL) const;
|
||||
bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN);
|
||||
|
||||
bool operator== ( const RawSwitch& other) {
|
||||
return (this->type == other.type) && (this->index == other.index);
|
||||
}
|
||||
|
||||
bool operator!= ( const RawSwitch& other) {
|
||||
return (this->type != other.type) || (this->index != other.index);
|
||||
}
|
||||
|
||||
|
||||
RawSwitchType type;
|
||||
int index;
|
||||
};
|
||||
|
||||
#endif // RAWSWITCH_H
|
85
companion/src/firmwares/sensordata.cpp
Normal file
85
companion/src/firmwares/sensordata.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 "sensordata.h"
|
||||
|
||||
void SensorData::updateUnit()
|
||||
{
|
||||
if (type == TELEM_TYPE_CALCULATED) {
|
||||
if (formula == TELEM_FORMULA_CONSUMPTION)
|
||||
unit = UNIT_MAH;
|
||||
}
|
||||
}
|
||||
|
||||
QString SensorData::unitString() const
|
||||
{
|
||||
switch (unit) {
|
||||
case UNIT_VOLTS:
|
||||
return QObject::tr("V");
|
||||
case UNIT_AMPS:
|
||||
return QObject::tr("A");
|
||||
case UNIT_MILLIAMPS:
|
||||
return QObject::tr("mA");
|
||||
case UNIT_KTS:
|
||||
return QObject::tr("kts");
|
||||
case UNIT_METERS_PER_SECOND:
|
||||
return QObject::tr("m/s");
|
||||
case UNIT_KMH:
|
||||
return QObject::tr("km/h");
|
||||
case UNIT_MPH:
|
||||
return QObject::tr("mph");
|
||||
case UNIT_METERS:
|
||||
return QObject::tr("m");
|
||||
case UNIT_FEET:
|
||||
return QObject::tr("f");
|
||||
case UNIT_CELSIUS:
|
||||
return QObject::trUtf8("°C");
|
||||
case UNIT_FAHRENHEIT:
|
||||
return QObject::trUtf8("°F");
|
||||
case UNIT_PERCENT:
|
||||
return QObject::tr("%");
|
||||
case UNIT_MAH:
|
||||
return QObject::tr("mAh");
|
||||
case UNIT_WATTS:
|
||||
return QObject::tr("W");
|
||||
case UNIT_MILLIWATTS:
|
||||
return QObject::tr("mW");
|
||||
case UNIT_DB:
|
||||
return QObject::tr("dB");
|
||||
case UNIT_RPMS:
|
||||
return QObject::tr("rpms");
|
||||
case UNIT_G:
|
||||
return QObject::tr("g");
|
||||
case UNIT_DEGREE:
|
||||
return QObject::trUtf8("°");
|
||||
case UNIT_RADIANS:
|
||||
return QObject::trUtf8("Rad");
|
||||
case UNIT_HOURS:
|
||||
return QObject::tr("hours");
|
||||
case UNIT_MINUTES:
|
||||
return QObject::tr("minutes");
|
||||
case UNIT_SECONDS:
|
||||
return QObject::tr("seconds");
|
||||
case UNIT_CELLS:
|
||||
return QObject::tr("V");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
147
companion/src/firmwares/sensordata.h
Normal file
147
companion/src/firmwares/sensordata.h
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef SENSORDATA_H
|
||||
#define SENSORDATA_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
#define CPN_MAX_SENSORS 32
|
||||
class SensorData {
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
TELEM_TYPE_CUSTOM,
|
||||
TELEM_TYPE_CALCULATED
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TELEM_FORMULA_ADD,
|
||||
TELEM_FORMULA_AVERAGE,
|
||||
TELEM_FORMULA_MIN,
|
||||
TELEM_FORMULA_MAX,
|
||||
TELEM_FORMULA_MULTIPLY,
|
||||
TELEM_FORMULA_TOTALIZE,
|
||||
TELEM_FORMULA_CELL,
|
||||
TELEM_FORMULA_CONSUMPTION,
|
||||
TELEM_FORMULA_DIST,
|
||||
TELEM_FORMULA_LAST = TELEM_FORMULA_DIST
|
||||
};
|
||||
|
||||
enum {
|
||||
TELEM_CELL_INDEX_LOWEST,
|
||||
TELEM_CELL_INDEX_1,
|
||||
TELEM_CELL_INDEX_2,
|
||||
TELEM_CELL_INDEX_3,
|
||||
TELEM_CELL_INDEX_4,
|
||||
TELEM_CELL_INDEX_5,
|
||||
TELEM_CELL_INDEX_6,
|
||||
TELEM_CELL_INDEX_HIGHEST,
|
||||
TELEM_CELL_INDEX_DELTA,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
UNIT_RAW,
|
||||
UNIT_VOLTS,
|
||||
UNIT_AMPS,
|
||||
UNIT_MILLIAMPS,
|
||||
UNIT_KTS,
|
||||
UNIT_METERS_PER_SECOND,
|
||||
UNIT_FEET_PER_SECOND,
|
||||
UNIT_KMH,
|
||||
UNIT_MPH,
|
||||
UNIT_METERS,
|
||||
UNIT_FEET,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_FAHRENHEIT,
|
||||
UNIT_PERCENT,
|
||||
UNIT_MAH,
|
||||
UNIT_WATTS,
|
||||
UNIT_MILLIWATTS,
|
||||
UNIT_DB,
|
||||
UNIT_RPMS,
|
||||
UNIT_G,
|
||||
UNIT_DEGREE,
|
||||
UNIT_RADIANS,
|
||||
UNIT_MILLILITERS,
|
||||
UNIT_FLOZ,
|
||||
UNIT_HOURS,
|
||||
UNIT_MINUTES,
|
||||
UNIT_SECONDS,
|
||||
// FrSky format used for these fields, could be another format in the future
|
||||
UNIT_FIRST_VIRTUAL,
|
||||
UNIT_CELLS = UNIT_FIRST_VIRTUAL,
|
||||
UNIT_DATETIME,
|
||||
UNIT_GPS,
|
||||
UNIT_GPS_LONGITUDE,
|
||||
UNIT_GPS_LATITUDE,
|
||||
UNIT_GPS_LONGITUDE_EW,
|
||||
UNIT_GPS_LATITUDE_NS,
|
||||
UNIT_DATETIME_YEAR,
|
||||
UNIT_DATETIME_DAY_MONTH,
|
||||
UNIT_DATETIME_HOUR_MIN,
|
||||
UNIT_DATETIME_SEC
|
||||
};
|
||||
|
||||
SensorData() { clear(); }
|
||||
unsigned int type; // custom / formula
|
||||
unsigned int id;
|
||||
unsigned int subid;
|
||||
unsigned int instance;
|
||||
unsigned int persistentValue;
|
||||
unsigned int formula;
|
||||
char label[4+1];
|
||||
unsigned int unit;
|
||||
unsigned int prec;
|
||||
bool autoOffset;
|
||||
bool filter;
|
||||
bool logs;
|
||||
bool persistent;
|
||||
bool onlyPositive;
|
||||
|
||||
// for custom sensors
|
||||
unsigned int ratio;
|
||||
int offset;
|
||||
|
||||
// for consumption
|
||||
unsigned int amps;
|
||||
|
||||
// for cell
|
||||
unsigned int source;
|
||||
unsigned int index;
|
||||
|
||||
// for calculations
|
||||
int sources[4];
|
||||
|
||||
// for GPS dist
|
||||
unsigned int gps;
|
||||
unsigned int alt;
|
||||
|
||||
bool isAvailable() const { return strlen(label) > 0; }
|
||||
void updateUnit();
|
||||
QString unitString() const;
|
||||
void clear() { memset(this, 0, sizeof(SensorData)); }
|
||||
};
|
||||
|
||||
#endif // SENSORDATA_H
|
74
companion/src/firmwares/telem_data.cpp
Normal file
74
companion/src/firmwares/telem_data.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 "telem_data.h"
|
||||
|
||||
#include "eeprominterface.h" // for getCurrentBoard()
|
||||
|
||||
float FrSkyChannelData::getRatio() const
|
||||
{
|
||||
if (type==0 || type==1 || type==2)
|
||||
return float(ratio << multiplier) / 10.0;
|
||||
else
|
||||
return ratio << multiplier;
|
||||
}
|
||||
|
||||
RawSourceRange FrSkyChannelData::getRange() const
|
||||
{
|
||||
RawSourceRange result;
|
||||
float ratio = getRatio();
|
||||
if (type==0 || type==1 || type==2)
|
||||
result.decimals = 2;
|
||||
else
|
||||
result.decimals = 0;
|
||||
result.step = ratio / 255;
|
||||
result.min = offset * result.step;
|
||||
result.max = ratio + result.min;
|
||||
result.unit = QObject::tr("V");
|
||||
return result;
|
||||
}
|
||||
|
||||
void FrSkyScreenData::clear()
|
||||
{
|
||||
memset(this, 0, sizeof(FrSkyScreenData));
|
||||
if (!IS_ARM(getCurrentBoard())) {
|
||||
type = TELEMETRY_SCREEN_NUMBERS;
|
||||
}
|
||||
}
|
||||
|
||||
void FrSkyData::clear()
|
||||
{
|
||||
usrProto = 0;
|
||||
voltsSource = 0;
|
||||
altitudeSource = 0;
|
||||
currentSource = 0;
|
||||
varioMin = 0;
|
||||
varioCenterMin = 0; // if increment in 0.2m/s = 3.0m/s max
|
||||
varioCenterMax = 0;
|
||||
varioMax = 0;
|
||||
mAhPersistent = 0;
|
||||
storedMah = 0;
|
||||
fasOffset = 0;
|
||||
for (int i=0; i<4; i++)
|
||||
screens[i].clear();
|
||||
varioSource = 2/*VARIO*/;
|
||||
blades = 2;
|
||||
}
|
||||
|
148
companion/src/firmwares/telem_data.h
Normal file
148
companion/src/firmwares/telem_data.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef TELEMETRYDATA_H
|
||||
#define TELEMETRYDATA_H
|
||||
|
||||
#include "rawsource.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class FrSkyAlarmData {
|
||||
public:
|
||||
FrSkyAlarmData() { clear(); }
|
||||
unsigned int level; // 0=none, 1=Yellow, 2=Orange, 3=Red
|
||||
unsigned int greater; // 0=LT(<), 1=GT(>)
|
||||
unsigned int value; // 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
|
||||
void clear() { memset(this, 0, sizeof(FrSkyAlarmData)); }
|
||||
};
|
||||
|
||||
class FrSkyChannelData {
|
||||
public:
|
||||
FrSkyChannelData() { clear(); }
|
||||
unsigned int ratio; // 0.0 means not used, 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
unsigned int type; // future use: 0=volts, 1=ml...
|
||||
int offset;
|
||||
unsigned int multiplier;
|
||||
FrSkyAlarmData alarms[2];
|
||||
|
||||
float getRatio() const;
|
||||
RawSourceRange getRange() const;
|
||||
void clear() { memset(this, 0, sizeof(FrSkyChannelData)); }
|
||||
};
|
||||
|
||||
struct FrSkyBarData {
|
||||
RawSource source;
|
||||
int barMin; // minimum for bar display
|
||||
int barMax; // ditto for max display (would usually = ratio)
|
||||
};
|
||||
|
||||
struct FrSkyLineData {
|
||||
RawSource source[3];
|
||||
};
|
||||
|
||||
struct TelemetryScriptData {
|
||||
char filename[8+1];
|
||||
};
|
||||
|
||||
enum TelemetryScreenEnum {
|
||||
TELEMETRY_SCREEN_NONE,
|
||||
TELEMETRY_SCREEN_NUMBERS,
|
||||
TELEMETRY_SCREEN_BARS,
|
||||
TELEMETRY_SCREEN_SCRIPT
|
||||
};
|
||||
|
||||
class FrSkyScreenData {
|
||||
public:
|
||||
FrSkyScreenData() { clear(); }
|
||||
|
||||
typedef struct {
|
||||
FrSkyBarData bars[4];
|
||||
FrSkyLineData lines[4];
|
||||
TelemetryScriptData script;
|
||||
} FrSkyScreenBody;
|
||||
|
||||
unsigned int type;
|
||||
FrSkyScreenBody body;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
enum TelemetryVarioSources {
|
||||
TELEMETRY_VARIO_SOURCE_ALTI,
|
||||
TELEMETRY_VARIO_SOURCE_ALTI_PLUS,
|
||||
TELEMETRY_VARIO_SOURCE_VSPEED,
|
||||
TELEMETRY_VARIO_SOURCE_A1,
|
||||
TELEMETRY_VARIO_SOURCE_A2,
|
||||
TELEMETRY_VARIO_SOURCE_DTE,
|
||||
};
|
||||
|
||||
enum TelemetryVoltsSources {
|
||||
TELEMETRY_VOLTS_SOURCE_A1,
|
||||
TELEMETRY_VOLTS_SOURCE_A2,
|
||||
TELEMETRY_VOLTS_SOURCE_A3,
|
||||
TELEMETRY_VOLTS_SOURCE_A4,
|
||||
TELEMETRY_VOLTS_SOURCE_FAS,
|
||||
TELEMETRY_VOLTS_SOURCE_CELLS
|
||||
};
|
||||
|
||||
enum TelemetryCurrentSources {
|
||||
TELEMETRY_CURRENT_SOURCE_NONE,
|
||||
TELEMETRY_CURRENT_SOURCE_A1,
|
||||
TELEMETRY_CURRENT_SOURCE_A2,
|
||||
TELEMETRY_CURRENT_SOURCE_A3,
|
||||
TELEMETRY_CURRENT_SOURCE_A4,
|
||||
TELEMETRY_CURRENT_SOURCE_FAS
|
||||
};
|
||||
|
||||
class FrSkyData {
|
||||
public:
|
||||
FrSkyData() { clear(); }
|
||||
FrSkyChannelData channels[4];
|
||||
unsigned int usrProto;
|
||||
int blades;
|
||||
unsigned int voltsSource;
|
||||
unsigned int altitudeSource;
|
||||
unsigned int currentSource;
|
||||
FrSkyScreenData screens[4];
|
||||
unsigned int varioSource;
|
||||
bool varioCenterSilent;
|
||||
int varioMin;
|
||||
int varioCenterMin; // if increment in 0.2m/s = 3.0m/s max
|
||||
int varioCenterMax;
|
||||
int varioMax;
|
||||
bool mAhPersistent;
|
||||
unsigned int storedMah;
|
||||
int fasOffset;
|
||||
bool ignoreSensorIds;
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
class MavlinkData {
|
||||
public:
|
||||
MavlinkData() { clear();}
|
||||
unsigned int rc_rssi_scale;
|
||||
unsigned int pc_rssi_en;
|
||||
void clear() { memset(this, 0, sizeof(MavlinkData)); }
|
||||
};
|
||||
|
||||
#endif // TELEMETRYDATA_H
|
|
@ -1,449 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "radiodata.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
// TODO here we will move a lot of functions from eeprominterface.cpp when no merge risk
|
||||
|
||||
RawSource RawSource::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setItemType("SRC", 1);
|
||||
RadioDataConversionState::EventType evt = RadioDataConversionState::EVT_NONE;
|
||||
RadioDataConversionState::LogField oldData(index, toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType));
|
||||
|
||||
if (type == SOURCE_TYPE_STICK) {
|
||||
if (cstate.toBoard.getCapability(Board::Sliders)) {
|
||||
if (index >= cstate.fromBoard.getCapability(Board::Sticks) + cstate.fromBoard.getCapability(Board::Pots)) {
|
||||
// 1st slider alignment
|
||||
index += cstate.toBoard.getCapability(Board::Pots) - cstate.fromBoard.getCapability(Board::Pots);
|
||||
}
|
||||
|
||||
if (isSlider(0, cstate.fromType)) {
|
||||
// LS and RS sliders are after 2 aux sliders on X12 and X9E
|
||||
if ((IS_HORUS_X12S(cstate.toType) || IS_TARANIS_X9E(cstate.toType)) && !IS_HORUS_X12S(cstate.fromType) && !IS_TARANIS_X9E(cstate.fromType)) {
|
||||
if (index >= 7) {
|
||||
index += 2; // LS/RS to LS/RS
|
||||
}
|
||||
}
|
||||
else if (!IS_TARANIS_X9E(cstate.toType) && !IS_HORUS_X12S(cstate.toType) && (IS_HORUS_X12S(cstate.fromType) || IS_TARANIS_X9E(cstate.fromType))) {
|
||||
if (index >= 7 && index <= 8) {
|
||||
index += 2; // aux sliders to spare analogs (which may not exist, this is validated later)
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (index >= 9 && index <= 10) {
|
||||
index -= 2; // LS/RS to LS/RS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_TARANIS(cstate.toType) && IS_HORUS(cstate.fromType)) {
|
||||
if (index == 6)
|
||||
index = 5; // pot S2 to S2
|
||||
else if (index == 5)
|
||||
index = -1; // 6P on Horus doesn't exist on Taranis
|
||||
}
|
||||
else if (IS_HORUS(cstate.toType) && IS_TARANIS(cstate.fromType) && index == 5)
|
||||
{
|
||||
index = 6; // pot S2 to S2
|
||||
}
|
||||
|
||||
} // SOURCE_TYPE_STICK
|
||||
|
||||
if (type == SOURCE_TYPE_SWITCH) {
|
||||
// SWI to SWR don't exist on !X9E board
|
||||
if (!IS_TARANIS_X9E(cstate.toType) && IS_TARANIS_X9E(cstate.fromType)) {
|
||||
if (index >= 8) {
|
||||
index = index % 8;
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_HORUS(cstate.fromType))) {
|
||||
// No SE and SG on X7 board
|
||||
if (index == 4 || index == 6) {
|
||||
index = 3; // SG and SE to SD
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (index == 5) {
|
||||
index = 4; // SF to SF
|
||||
}
|
||||
else if (index == 7) {
|
||||
index = 5; // SH to SH
|
||||
}
|
||||
}
|
||||
// Compensate for SE and SG on X9/Horus board if converting from X7
|
||||
else if ((IS_TARANIS_X9(cstate.toType) || IS_HORUS(cstate.toType)) && IS_TARANIS_X7(cstate.fromType)) {
|
||||
if (index == 4) {
|
||||
index = 5; // SF to SF
|
||||
}
|
||||
else if (index == 5) {
|
||||
index = 7; // SH to SH
|
||||
}
|
||||
}
|
||||
} // SOURCE_TYPE_SWITCH
|
||||
|
||||
// final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted)
|
||||
if (!isAvailable(NULL, cstate.toGS(), cstate.toType)) {
|
||||
cstate.setInvalid(oldData);
|
||||
index = -1; // TODO: better way to flag invalid sources?
|
||||
type = MAX_SOURCE_TYPE;
|
||||
}
|
||||
else if (evt == RadioDataConversionState::EVT_CVRT) {
|
||||
cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toModel(), cstate.toGS(), cstate.toType)));
|
||||
}
|
||||
else if (oldData.id != index) {
|
||||
// provide info by default if anything changed
|
||||
cstate.setMoved(oldData, RadioDataConversionState::LogField(index, toString(cstate.toModel(), cstate.toGS(), cstate.toType)));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
RawSwitch RawSwitch::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
if (!index)
|
||||
return *this;
|
||||
|
||||
cstate.setItemType("SW", 2);
|
||||
RadioDataConversionState::EventType evt = RadioDataConversionState::EVT_NONE;
|
||||
RadioDataConversionState::LogField oldData(index, toString(cstate.fromType, cstate.fromGS(), cstate.fromModel()));
|
||||
|
||||
if (type == SWITCH_TYPE_SWITCH) {
|
||||
int srcIdx = div(abs(index)-1, 3).quot; // raw source index
|
||||
int delta = 0;
|
||||
|
||||
// SWI to SWR don't exist on !X9E board
|
||||
if (!IS_TARANIS_X9E(cstate.toType) && IS_TARANIS_X9E(cstate.fromType)) {
|
||||
if (srcIdx > 7) {
|
||||
index %= 24;
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
}
|
||||
|
||||
// No SE and SG on X7 board
|
||||
if (IS_TARANIS_X7(cstate.toType) && (IS_TARANIS_X9(cstate.fromType) || IS_HORUS(cstate.fromType))) {
|
||||
if (srcIdx == 4 || srcIdx == 5) {
|
||||
delta = 3; // SE to SD & SF to SF
|
||||
if (srcIdx == 4)
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (srcIdx == 6) {
|
||||
delta = 9; // SG to SD
|
||||
evt = RadioDataConversionState::EVT_CVRT;
|
||||
}
|
||||
else if (srcIdx == 7) {
|
||||
delta = 6; // SH to SH
|
||||
}
|
||||
}
|
||||
// Compensate for SE and SG on X9/Horus board if converting from X7
|
||||
else if ((IS_TARANIS_X9(cstate.toType) || IS_HORUS(cstate.toType)) && IS_TARANIS_X7(cstate.fromType)) {
|
||||
if (srcIdx == 4) {
|
||||
delta = -3; // SF to SF
|
||||
}
|
||||
else if (srcIdx == 5) {
|
||||
delta = -6; // SH to SH
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
delta = -delta; // invert for !switch
|
||||
}
|
||||
|
||||
index -= delta;
|
||||
|
||||
} // SWITCH_TYPE_SWITCH
|
||||
|
||||
// final validation (we do not pass model to isAvailable() because we don't know what has or hasn't been converted)
|
||||
if (!isAvailable(NULL, cstate.toGS(), cstate.toType)) {
|
||||
cstate.setInvalid(oldData);
|
||||
type = MAX_SWITCH_TYPE; // TODO: better way to flag invalid switches?
|
||||
}
|
||||
else if (evt == RadioDataConversionState::EVT_CVRT) {
|
||||
cstate.setConverted(oldData, RadioDataConversionState::LogField(index, toString(cstate.toType, cstate.toGS(), cstate.toModel())));
|
||||
}
|
||||
else if (oldData.id != index) {
|
||||
// provide info by default if anything changed
|
||||
cstate.setMoved(oldData, RadioDataConversionState::LogField(index, toString(cstate.toType, cstate.toGS(), cstate.toModel())));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ExpoData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent(QObject::tr("INP"), 3);
|
||||
cstate.setSubComp(RawSource(SOURCE_TYPE_VIRTUAL_INPUT, chn).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % QObject::tr(" (@%1)").arg(cstate.subCompIdx));
|
||||
srcRaw.convert(cstate);
|
||||
swtch.convert(cstate);
|
||||
}
|
||||
|
||||
void MixData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent(QObject::tr("MIX"), 4);
|
||||
cstate.setSubComp(RawSource(SOURCE_TYPE_CH, destCh-1).toString(cstate.fromModel(), cstate.fromGS(), cstate.fromType) % QObject::tr(" (@%1)").arg(cstate.subCompIdx));
|
||||
srcRaw.convert(cstate);
|
||||
swtch.convert(cstate);
|
||||
}
|
||||
|
||||
void LogicalSwitchData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent("LSW", 7);
|
||||
cstate.setSubComp(RawSwitch(SWITCH_TYPE_VIRTUAL, cstate.subCompIdx + 1).toString(cstate.fromType, cstate.fromGS(), cstate.fromModel()));
|
||||
CSFunctionFamily family = getFunctionFamily();
|
||||
switch(family) {
|
||||
case LS_FAMILY_VOFS:
|
||||
val1 = RawSource(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
break;
|
||||
case LS_FAMILY_STICKY:
|
||||
case LS_FAMILY_VBOOL:
|
||||
val1 = RawSwitch(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
val2 = RawSwitch(val2).convert(cstate.withComponentField("V2")).toValue();
|
||||
break;
|
||||
case LS_FAMILY_EDGE:
|
||||
val1 = RawSwitch(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
break;
|
||||
case LS_FAMILY_VCOMP:
|
||||
val1 = RawSource(val1).convert(cstate.withComponentField("V1")).toValue();
|
||||
val2 = RawSource(val2).convert(cstate.withComponentField("V2")).toValue();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
andsw = RawSwitch(andsw).convert(cstate.withComponentField("AND")).toValue();
|
||||
}
|
||||
|
||||
void CustomFunctionData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent("CFN", 8);
|
||||
cstate.setSubComp(toString(cstate.subCompIdx, (cstate.toModel() ? false : true)));
|
||||
swtch.convert(cstate);
|
||||
if (func == FuncVolume || func == FuncPlayValue || (func >= FuncAdjustGV1 && func <= FuncAdjustGVLast && adjustMode == 1)) {
|
||||
param = RawSource(param).convert(cstate.withComponentField("PARAM")).toValue();
|
||||
}
|
||||
}
|
||||
|
||||
void FlightModeData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent("FMD", 2);
|
||||
cstate.setSubComp(toString(cstate.subCompIdx));
|
||||
swtch.convert(cstate);
|
||||
}
|
||||
|
||||
void TimerData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
cstate.setComponent("TMR", 1);
|
||||
cstate.setSubComp(QObject::tr("Timer %1").arg(cstate.subCompIdx + 1));
|
||||
mode.convert(cstate);
|
||||
}
|
||||
|
||||
void ModelData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
// Here we can add explicit conversions when moving from one board to another
|
||||
|
||||
QString origin = QString(name);
|
||||
if (origin.isEmpty())
|
||||
origin = QString::number(cstate.modelIdx+1);
|
||||
cstate.setOrigin(QObject::tr("Model: ") % origin);
|
||||
|
||||
cstate.setComponent("SET", 0);
|
||||
if (thrTraceSrc && (int)thrTraceSrc < cstate.fromBoard.getCapability(Board::Pots) + cstate.fromBoard.getCapability(Board::Sliders)) {
|
||||
cstate.setSubComp(QObject::tr("Throttle Source"));
|
||||
thrTraceSrc = RawSource(SOURCE_TYPE_STICK, (int)thrTraceSrc + 3).convert(cstate).index - 3;
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_TIMERS; i++) {
|
||||
timers[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_MIXERS; i++) {
|
||||
mixData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_EXPOS; i++) {
|
||||
expoData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_LOGICAL_SWITCHES; i++) {
|
||||
logicalSw[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
customFn[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
flightModeData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralSettings::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
// Here we can add explicit conversions when moving from one board to another
|
||||
|
||||
cstate.setOrigin(QObject::tr("Radio Settings"));
|
||||
|
||||
setDefaultControlTypes(cstate.toType); // start with default switches/pots/sliders
|
||||
|
||||
// Try to intelligently copy any custom control names
|
||||
|
||||
// SE and SG are skipped on X7 board
|
||||
if (IS_TARANIS_X7(cstate.toType)) {
|
||||
if (IS_TARANIS_X9(cstate.fromType) || IS_HORUS(cstate.fromType)) {
|
||||
strncpy(switchName[4], switchName[5], sizeof(switchName[0]));
|
||||
strncpy(switchName[5], switchName[7], sizeof(switchName[0]));
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_X7(cstate.fromType)) {
|
||||
if (IS_TARANIS_X9(cstate.toType) || IS_HORUS(cstate.toType)) {
|
||||
strncpy(switchName[5], switchName[4], sizeof(switchName[0]));
|
||||
strncpy(switchName[7], switchName[5], sizeof(switchName[0]));
|
||||
}
|
||||
}
|
||||
|
||||
// LS and RS sliders are after 2 aux sliders on X12 and X9E
|
||||
if ((IS_HORUS_X12S(cstate.toType) || IS_TARANIS_X9E(cstate.toType)) && !IS_HORUS_X12S(cstate.fromType) && !IS_TARANIS_X9E(cstate.fromType)) {
|
||||
strncpy(sliderName[0], sliderName[2], sizeof(sliderName[0]));
|
||||
strncpy(sliderName[1], sliderName[3], sizeof(sliderName[0]));
|
||||
}
|
||||
else if (!IS_TARANIS_X9E(cstate.toType) && !IS_HORUS_X12S(cstate.toType) && (IS_HORUS_X12S(cstate.fromType) || IS_TARANIS_X9E(cstate.fromType))) {
|
||||
strncpy(sliderName[2], sliderName[0], sizeof(sliderName[0]));
|
||||
strncpy(sliderName[3], sliderName[1], sizeof(sliderName[0]));
|
||||
}
|
||||
|
||||
if (IS_HORUS(cstate.toType)) {
|
||||
// 6P switch is only on Horus (by default)
|
||||
if (cstate.fromBoard.getCapability(Board::FactoryInstalledPots) == 2) {
|
||||
strncpy(potName[2], potName[1], sizeof(potName[0]));
|
||||
potName[1][0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_TARANIS(cstate.toType)) {
|
||||
// No S3 pot on Taranis boards by default
|
||||
if (cstate.fromBoard.getCapability(Board::FactoryInstalledPots) > 2)
|
||||
strncpy(potName[1], potName[2], sizeof(potName[0]));
|
||||
|
||||
contrast = qBound<int>(getCurrentFirmware()->getCapability(MinContrast), contrast, getCurrentFirmware()->getCapability(MaxContrast));
|
||||
}
|
||||
|
||||
// TODO: Would be nice at this point to have GUI pause and ask the user to set up any custom hardware they have on the destination radio.
|
||||
|
||||
// Convert all global functions (do this after HW adjustments)
|
||||
for (int i=0; i<CPN_MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
customFn[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RadioData
|
||||
*/
|
||||
|
||||
RadioData::RadioData()
|
||||
{
|
||||
models.resize(getCurrentFirmware()->getCapability(Models));
|
||||
}
|
||||
|
||||
void RadioData::setCurrentModel(unsigned int index)
|
||||
{
|
||||
generalSettings.currModelIndex = index;
|
||||
if (index < models.size()) {
|
||||
strcpy(generalSettings.currModelFilename, models[index].filename);
|
||||
}
|
||||
}
|
||||
|
||||
void RadioData::fixModelFilename(unsigned int index)
|
||||
{
|
||||
ModelData & model = models[index];
|
||||
QString filename(model.filename);
|
||||
bool ok = filename.endsWith(".bin");
|
||||
if (ok) {
|
||||
if (filename.startsWith("model") && filename.mid(5, filename.length()-9).toInt() > 0) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
for (unsigned i=0; i<index; i++) {
|
||||
if (strcmp(models[i].filename, model.filename) == 0) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
sprintf(model.filename, "model%d.bin", index+1);
|
||||
}
|
||||
}
|
||||
|
||||
void RadioData::fixModelFilenames()
|
||||
{
|
||||
for (unsigned int i=0; i<models.size(); i++) {
|
||||
fixModelFilename(i);
|
||||
}
|
||||
setCurrentModel(generalSettings.currModelIndex);
|
||||
}
|
||||
|
||||
QString RadioData::getNextModelFilename()
|
||||
{
|
||||
char filename[sizeof(ModelData::filename)];
|
||||
int index = 0;
|
||||
bool found = true;
|
||||
while (found) {
|
||||
sprintf(filename, "model%d.bin", ++index);
|
||||
found = false;
|
||||
for (unsigned int i=0; i<models.size(); i++) {
|
||||
if (strcmp(filename, models[i].filename) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
void RadioData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
generalSettings.convert(cstate.withModelIndex(-1));
|
||||
|
||||
for (unsigned i=0; i<models.size(); i++) {
|
||||
models[i].convert(cstate.withModelIndex(i));
|
||||
}
|
||||
|
||||
if (categories.size() == 0) {
|
||||
categories.push_back(CategoryData(qPrintable(QObject::tr("Models"))));
|
||||
for (unsigned i=0; i<models.size(); i++) {
|
||||
models[i].category = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_HORUS(cstate.toType)) {
|
||||
fixModelFilenames();
|
||||
}
|
||||
|
||||
// ensure proper number of model slots
|
||||
if (getCurrentFirmware()->getCapability(Models) && getCurrentFirmware()->getCapability(Models) != (int)models.size()) {
|
||||
models.resize(getCurrentFirmware()->getCapability(Models));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -21,7 +21,7 @@
|
|||
#ifndef _SIMULATORINTERFACE_H_
|
||||
#define _SIMULATORINTERFACE_H_
|
||||
|
||||
#include "boards.h"
|
||||
#include "firmwares/boards.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue