Merge pull request #1186 from EdgeTX/cpn-storage-fmts
Companion YaML support
This commit is contained in:
@@ -5,3 +5,6 @@
|
||||
[submodule "radio/src/thirdparty/AccessDenied"]
|
||||
path = radio/src/thirdparty/AccessDenied
|
||||
url = https://github.com/raphaelcoeffic/AccessDenied.git
|
||||
[submodule "companion/src/thirdparty/yaml-cpp"]
|
||||
path = companion/src/thirdparty/yaml-cpp
|
||||
url = https://github.com/jbeder/yaml-cpp.git
|
||||
|
||||
@@ -198,6 +198,12 @@ add_subdirectory(storage)
|
||||
add_subdirectory(thirdparty/qcustomplot)
|
||||
add_subdirectory(thirdparty/maxlibqt/src/widgets)
|
||||
|
||||
set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "Enable testing" FORCE)
|
||||
set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "Enable parse tools" FORCE)
|
||||
set(YAML_CPP_BUILD_CONTRIB OFF CACHE BOOL "Enable contrib stuff in library" FORCE)
|
||||
set(YAML_CPP_INSTALL OFF CACHE BOOL "Enable generation of install target" FORCE)
|
||||
add_subdirectory(thirdparty/yaml-cpp)
|
||||
|
||||
############# Companion ###############
|
||||
|
||||
set(companion_SRCS
|
||||
@@ -313,7 +319,7 @@ add_subdirectory(tests)
|
||||
############# Install ####################
|
||||
|
||||
# Generate list of simulator plugins, used by all platforms
|
||||
file(GLOB simulator_plugins "${CMAKE_BINARY_DIR}/*opentx-*simulator${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
file(GLOB simulator_plugins "${CMAKE_BINARY_DIR}/*edgetx-*simulator${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
|
||||
# the current flavour is not automatically added if build in the current cmake iteration, so always
|
||||
# add its library name to be sure
|
||||
@@ -349,7 +355,7 @@ if(POLICY CMP0026)
|
||||
endif()
|
||||
|
||||
if(SIMU_TARGET)
|
||||
get_property(current_plugin TARGET opentx-${FLAVOUR}-simulator PROPERTY LOCATION)
|
||||
get_property(current_plugin TARGET edgetx-${FLAVOUR}-simulator PROPERTY LOCATION)
|
||||
list(APPEND simulator_plugins "${current_plugin}")
|
||||
endif()
|
||||
|
||||
@@ -529,7 +535,7 @@ IF(APPLE)
|
||||
# technically a hack (that is already is in the Bundle library ...)
|
||||
install(CODE "
|
||||
include(BundleUtilities)
|
||||
file(GLOB bundle_simulator_libs \"\${CMAKE_INSTALL_PREFIX}/${companion_res_dir}/libopentx-*${CMAKE_SHARED_LIBRARY_SUFFIX}\")
|
||||
file(GLOB bundle_simulator_libs \"\${CMAKE_INSTALL_PREFIX}/${companion_res_dir}/libedgetx-*${CMAKE_SHARED_LIBRARY_SUFFIX}\")
|
||||
set(BU_CHMOD_BUNDLE_ITEMS on)
|
||||
fixup_bundle(\"${APPS}\" \"\${bundle_simulator_libs};${bundle_qt_libs};${bundle_tools_path}\" \"${QT_LIB_DIR}\")
|
||||
file(RENAME \"\${CMAKE_INSTALL_PREFIX}/${COMPANION_NAME}.app\" \"\${CMAKE_INSTALL_PREFIX}/${COMPANION_OSX_APP_BUNDLE_NAME}.app\")
|
||||
@@ -543,9 +549,9 @@ if(APPLE)
|
||||
set(CPACK_DMG_BACKGROUND_IMAGE ${COMPANION_SRC_DIRECTORY}/images/splash_dmg.png)
|
||||
set(CPACK_DMG_VOLUME_NAME "EdgeTX Companion")
|
||||
set(CPACK_DMG_DS_STORE ${PROJECT_SOURCE_DIR}/companion/targets/mac/DS_Store)
|
||||
set(CPACK_PACKAGE_FILE_NAME "opentx-${CPACK_PACKAGE_NAME_LOWERCASE}-${VERSION}")
|
||||
set(CPACK_PACKAGE_FILE_NAME "edgetx-${CPACK_PACKAGE_NAME_LOWERCASE}-${VERSION}")
|
||||
endif(APPLE)
|
||||
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
get_filename_component(_qt_bin_dir "${QT_QMAKE_EXECUTABLE}" DIRECTORY)
|
||||
find_program(LINUXDEPLOY_EXECUTABLE linuxdeployqt HINTS "${_qt_bin_dir}")
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
#include "joystick.h"
|
||||
#include "joystickdialog.h"
|
||||
#endif
|
||||
#include "moduledata.h"
|
||||
#include "compounditemmodels.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
AppPreferencesDialog::AppPreferencesDialog(QWidget * parent) :
|
||||
QDialog(parent),
|
||||
@@ -97,6 +101,7 @@ void AppPreferencesDialog::accept()
|
||||
g.jsSupport(false);
|
||||
g.jsCtrl(0);
|
||||
}
|
||||
profile.defaultInternalModule(ui->defaultInternalModuleCB->currentData().toInt());
|
||||
profile.channelOrder(ui->channelorderCB->currentIndex());
|
||||
profile.defaultMode(ui->stickmodeCB->currentIndex());
|
||||
profile.renameFwFiles(ui->renameFirmware->isChecked());
|
||||
@@ -256,6 +261,8 @@ void AppPreferencesDialog::initSettings()
|
||||
}
|
||||
#endif
|
||||
// Profile Tab Inits
|
||||
ui->defaultInternalModuleCB->setModel(ModuleData::internalModuleItemModel());
|
||||
ui->defaultInternalModuleCB->setCurrentIndex(ui->defaultInternalModuleCB->findData(profile.defaultInternalModule()));
|
||||
ui->channelorderCB->setCurrentIndex(profile.channelOrder());
|
||||
ui->stickmodeCB->setCurrentIndex(profile.defaultMode());
|
||||
ui->renameFirmware->setChecked(profile.renameFwFiles());
|
||||
@@ -453,6 +460,12 @@ void AppPreferencesDialog::on_clearImageButton_clicked()
|
||||
void AppPreferencesDialog::onBaseFirmwareChanged()
|
||||
{
|
||||
populateFirmwareOptions(getBaseFirmware());
|
||||
|
||||
Firmware *newfw = getFirmwareVariant();
|
||||
Profile & profile = g.currentProfile();
|
||||
profile.defaultInternalModule(Boards::getDefaultInternalModules(newfw->getBoard()));
|
||||
ui->defaultInternalModuleCB->setModel(ModuleData::internalModuleItemModel(newfw->getBoard()));
|
||||
ui->defaultInternalModuleCB->setCurrentIndex(ui->defaultInternalModuleCB->findData(profile.defaultInternalModule()));
|
||||
}
|
||||
|
||||
Firmware *AppPreferencesDialog::getBaseFirmware() const
|
||||
|
||||
@@ -51,178 +51,21 @@
|
||||
<attribute name="title">
|
||||
<string>Radio Profile</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,0,0">
|
||||
<item row="5" column="1">
|
||||
<widget class="QWidget" name="optionsWidget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,0,0,0">
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="optionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="4">
|
||||
<widget class="QWidget" name="widget_splashImage" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="splashLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Splash Screen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="SplashFileName">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="SplashSelect">
|
||||
<property name="text">
|
||||
<string>Select Image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="imageLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>212</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="clearImageButton">
|
||||
<property name="text">
|
||||
<string>Clear Image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="Line" name="line_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<widget class="QCheckBox" name="burnFirmware">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Offer to write FW to Tx after download</string>
|
||||
<string>Default Stick Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="4">
|
||||
<widget class="Line" name="line_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<item row="15" column="2">
|
||||
<widget class="QComboBox" name="channelorderCB">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@@ -358,88 +201,27 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="boardCB">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
<item row="10" column="2">
|
||||
<widget class="QLineEdit" name="profilebackupPath">
|
||||
<property name="toolTip">
|
||||
<string>If set it will override the application general setting</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Build Options</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="renameFirmware">
|
||||
<item row="4" column="2">
|
||||
<widget class="QComboBox" name="langCombo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Append version number to FW file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="sdPathButton">
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Profile Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="profileNameLE"/>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="profilebackupPathLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The profile specific folder, if set, will override general Backup folder</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Backup folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<item row="12" column="2">
|
||||
<widget class="QLabel" name="lblGeneralSettings">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
@@ -455,39 +237,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
<item row="10" column="3" colspan="2">
|
||||
<widget class="QPushButton" name="ProfilebackupPathButton">
|
||||
<property name="toolTip">
|
||||
<string>The profile specific folder, if set, will override general Backup folder</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Other Settings</string>
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Stick Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<item row="14" column="2">
|
||||
<widget class="QComboBox" name="stickmodeCB">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
@@ -541,61 +301,61 @@ Mode 4:
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<item row="9" column="2">
|
||||
<widget class="QLineEdit" name="sdPath">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Channel Order</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="pbackupEnable">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>if set, will override general backup enable</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable automatic backup before writing firmware</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="4">
|
||||
<widget class="Line" name="splashSeparator">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QLineEdit" name="profilebackupPath">
|
||||
<property name="toolTip">
|
||||
<string>If set it will override the application general setting</string>
|
||||
<string/>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="profileNameLE"/>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QComboBox" name="boardCB">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Profile Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="2">
|
||||
<widget class="QCheckBox" name="renameFirmware">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Append version number to FW file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="sdPathLabel">
|
||||
<property name="sizePolicy">
|
||||
@@ -612,16 +372,6 @@ Mode 4:
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="ProfilebackupPathButton">
|
||||
<property name="toolTip">
|
||||
<string>The profile specific folder, if set, will override general Backup folder</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
@@ -635,6 +385,136 @@ Mode 4:
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="profilebackupPathLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The profile specific folder, if set, will override general Backup folder</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Backup folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Channel Order</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>Default Int. Module</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="5">
|
||||
<widget class="Line" name="line_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="2">
|
||||
<widget class="QCheckBox" name="burnFirmware">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Offer to write FW to Tx after download</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Build Options</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="langLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Menu Language</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="3" colspan="2">
|
||||
<widget class="QPushButton" name="sdPathButton">
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="2">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="5">
|
||||
<widget class="Line" name="splashSeparator">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="sizePolicy">
|
||||
@@ -658,58 +538,188 @@ Mode 4:
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="langLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Menu Language</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLineEdit" name="sdPath">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="langCombo">
|
||||
<item row="11" column="2">
|
||||
<widget class="QCheckBox" name="pbackupEnable">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>if set, will override general backup enable</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable automatic backup before writing firmware</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="5">
|
||||
<widget class="QWidget" name="widget_splashImage" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="splashLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Splash Screen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="SplashFileName">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="SplashSelect">
|
||||
<property name="text">
|
||||
<string>Select Image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="imageLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>212</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="clearImageButton">
|
||||
<property name="text">
|
||||
<string>Clear Image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="Line" name="line_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QWidget" name="optionsWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="optionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Other Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="2">
|
||||
<widget class="QComboBox" name="defaultInternalModuleCB"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="applicationTab">
|
||||
|
||||
@@ -69,28 +69,22 @@ void checkSettingsImport(bool force = false)
|
||||
if (!found && !force)
|
||||
return;
|
||||
|
||||
const QString impFileBtn = QCoreApplication::translate("Companion", "Import from File");
|
||||
const QString impPrevBtn = QCoreApplication::translate("Companion", "Import from v%1").arg(previousVersion);
|
||||
const QString impNoneBtn = QCoreApplication::translate("Companion", "Do not import");
|
||||
|
||||
QString msg;
|
||||
if (previousVersion.isEmpty()) {
|
||||
const QString impFileBtn = QCoreApplication::translate("Companion", "Import from File");
|
||||
const QString impNoneBtn = QCoreApplication::translate("Companion", "Do not import");
|
||||
|
||||
if (found)
|
||||
msg = QCoreApplication::translate("Companion", "We have found possible Companion settings backup file(s).\nDo you want to import settings from a file?");
|
||||
else
|
||||
msg = QCoreApplication::translate("Companion", "Import settings from a file, or start with current values.");
|
||||
|
||||
const int ret = QMessageBox::question(nullptr, CPN_STR_APP_NAME, msg, impNoneBtn, impFileBtn, 0, 0);
|
||||
|
||||
if (!ret)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
msg = QCoreApplication::translate("Companion", "We have found existing settings for Companion version: %1.\nDo you want to import them?\n\n" \
|
||||
"If you have a settings backup file, you may import that instead.").arg(previousVersion);
|
||||
}
|
||||
|
||||
const int ret = QMessageBox::question(nullptr, CPN_STR_APP_NAME, msg, impNoneBtn, impFileBtn, (previousVersion.isEmpty() ? QString() : impPrevBtn), 0, 0);
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
// Import from previous version
|
||||
if (ret == 2) {
|
||||
if (!g.importSettings(previousVersion)) {
|
||||
// very unlikely, but just in case of unexpected error, restart the import
|
||||
importError();
|
||||
|
||||
@@ -38,15 +38,17 @@
|
||||
#define CPN_MAX_MODULES 2
|
||||
#define CPN_MAX_STICKS Board::STICK_AXIS_COUNT
|
||||
#define CPN_MAX_TRIMS Board::TRIM_AXIS_COUNT
|
||||
#define CPN_MAX_KNOBS 8
|
||||
#define CPN_MAX_POTS 8
|
||||
#define CPN_MAX_SLIDERS 4
|
||||
#define CPN_MAX_POTS (CPN_MAX_KNOBS + CPN_MAX_SLIDERS)
|
||||
#define CPN_MAX_CYC 3
|
||||
#define CPN_MAX_SWITCHES 32
|
||||
#define CPN_MAX_FUNCTION_SWITCHES 6
|
||||
#define CPN_MAX_MOUSE_ANALOGS 2
|
||||
#define CPN_MAX_GYRO_ANALOGS 2
|
||||
#define CPN_MAX_ANALOGS (CPN_MAX_STICKS + CPN_MAX_POTS + CPN_MAX_MOUSE_ANALOGS + CPN_MAX_GYRO_ANALOGS)
|
||||
#define CPN_MAX_ANALOGS (CPN_MAX_STICKS + CPN_MAX_POTS + CPN_MAX_SLIDERS + CPN_MAX_MOUSE_ANALOGS + CPN_MAX_GYRO_ANALOGS)
|
||||
#define CPN_MAX_SENSORS 60
|
||||
#define CPN_MAX_SCRIPTS 9
|
||||
#define CPN_MAX_SCRIPT_INPUTS 10
|
||||
|
||||
#define CPN_STR_APP_NAME QCoreApplication::translate("Companion", "EdgeTX Companion")
|
||||
#define CPN_STR_TTL_INFO QCoreApplication::translate("Companion", "Information") // shared Title Case words, eg. for a window title or section heading
|
||||
@@ -60,8 +62,9 @@
|
||||
#define DFU_FILES_FILTER "DFU " % CPN_STR_FILES % " (*.dfu);;"
|
||||
#define EEPE_FILES_FILTER "EEPE " % CPN_STR_FILES % " (*.eepe);;"
|
||||
#define OTX_FILES_FILTER "OpenTX " % CPN_STR_FILES % " (*.otx);;"
|
||||
#define YML_FILES_FILTER "YAML " % CPN_STR_FILES % " (*.yml);;"
|
||||
#define EEPROM_FILES_FILTER CPN_STR_RAD_MOD_SETTINGS % " " % CPN_STR_FILES % " (*.otx *.yml *.eepe *.bin *.hex);;" % OTX_FILES_FILTER % YML_FILES_FILTER % EEPE_FILES_FILTER % BIN_FILES_FILTER % HEX_FILES_FILTER
|
||||
#define ETX_FILES_FILTER "EdgeTX " % CPN_STR_FILES % " (*.etx);;"
|
||||
#define YML_FILES_FILTER "EdgeTX YAML " % CPN_STR_FILES % " (*.yml);;"
|
||||
#define EEPROM_FILES_FILTER CPN_STR_RAD_MOD_SETTINGS % " " % CPN_STR_FILES % " (*.etx *.yml *.otx *.eepe *.bin *.hex);;" % ETX_FILES_FILTER % YML_FILES_FILTER % OTX_FILES_FILTER % EEPE_FILES_FILTER % BIN_FILES_FILTER % HEX_FILES_FILTER
|
||||
#define FLASH_FILES_FILTER "FLASH " % CPN_STR_FILES % " (*.bin *.hex *.dfu);;" % BIN_FILES_FILTER % HEX_FILES_FILTER % DFU_FILES_FILTER
|
||||
#define EXTERNAL_EEPROM_FILES_FILTER "EEPROM " % CPN_STR_FILES % " (*.bin *.hex);;" % BIN_FILES_FILTER % HEX_FILES_FILTER
|
||||
#define ER9X_EEPROM_FILE_TYPE "ER9X_EEPROM_FILE"
|
||||
|
||||
@@ -118,7 +118,7 @@ RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSett
|
||||
addItems(SOURCE_TYPE_CYC, RawSource::SourcesGroup, CPN_MAX_CYC);
|
||||
addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, firmware->getCapability(TrainerInputs));
|
||||
addItems(SOURCE_TYPE_CH, RawSource::SourcesGroup, firmware->getCapability(Outputs));
|
||||
addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, 5);
|
||||
addItems(SOURCE_TYPE_SPECIAL, RawSource::TelemGroup, SOURCE_TYPE_SPECIAL_COUNT);
|
||||
addItems(SOURCE_TYPE_TELEMETRY, RawSource::TelemGroup, firmware->getCapability(Sensors) * 3);
|
||||
addItems(SOURCE_TYPE_GVAR, RawSource::GVarsGroup, firmware->getCapability(Gvars));
|
||||
}
|
||||
|
||||
@@ -29,6 +29,23 @@ set(firmwares_SRCS
|
||||
ersky9x/ersky9xinterface.cpp
|
||||
opentx/opentxeeprom.cpp
|
||||
opentx/opentxinterface.cpp
|
||||
edgetx/edgetxinterface.cpp
|
||||
edgetx/yaml_ops.cpp
|
||||
edgetx/yaml_generalsettings.cpp
|
||||
edgetx/yaml_calibdata.cpp
|
||||
edgetx/yaml_trainerdata.cpp
|
||||
edgetx/yaml_switchconfig.cpp
|
||||
edgetx/yaml_modeldata.cpp
|
||||
edgetx/yaml_rawswitch.cpp
|
||||
edgetx/yaml_rawsource.cpp
|
||||
edgetx/yaml_mixdata.cpp
|
||||
edgetx/yaml_expodata.cpp
|
||||
edgetx/yaml_curvedata.cpp
|
||||
edgetx/yaml_moduledata.cpp
|
||||
edgetx/yaml_logicalswitchdata.cpp
|
||||
edgetx/yaml_customfunctiondata.cpp
|
||||
edgetx/yaml_sensordata.cpp
|
||||
edgetx/yaml_screendata.cpp
|
||||
datahelpers.cpp
|
||||
customisation_data.cpp
|
||||
)
|
||||
@@ -48,14 +65,19 @@ set(firmwares_QT
|
||||
qt5_wrap_cpp(firmwares_SRCS ${firmwares_QT})
|
||||
|
||||
add_library(firmwares ${firmwares_SRCS} ${firmwares_HDRS})
|
||||
|
||||
target_link_libraries(firmwares ${CPN_COMMON_LIB} datamodels Qt5::Core Qt5::Xml Qt5::Widgets)
|
||||
target_link_libraries(firmwares yaml-cpp)
|
||||
|
||||
target_include_directories(firmwares
|
||||
PRIVATE
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${COMPANION_SRC_DIRECTORY}/thirdparty/yaml-cpp/include
|
||||
PUBLIC
|
||||
"${CMAKE_CURRENT_LIST_DIR}"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/er9x"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ersky9x"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/opentx"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/edgetx"
|
||||
)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "boards.h"
|
||||
#include "macros.h"
|
||||
#include "compounditemmodels.h"
|
||||
#include "moduledata.h"
|
||||
|
||||
// TODO remove all those constants
|
||||
// Update: These are now all only used within this class.
|
||||
@@ -374,7 +375,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
|
||||
else if (IS_TARANIS_X9E(board))
|
||||
return 4;
|
||||
else if (IS_HORUS_X10(board) || IS_FAMILY_T16(board))
|
||||
return 5;
|
||||
return 7;
|
||||
else if (IS_HORUS_X12S(board))
|
||||
return 3;
|
||||
else if (IS_FLYSKY_NV14(board))
|
||||
@@ -486,6 +487,12 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
|
||||
case NumFunctionSwitches:
|
||||
return IS_JUMPER_TPRO(board) ? 6 : 0;
|
||||
|
||||
case HasSDCard:
|
||||
return IS_STM32(board);
|
||||
|
||||
case HasInternalModuleSupport:
|
||||
return (IS_STM32(board) && !IS_TARANIS_X9(board));
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -507,104 +514,82 @@ QString Boards::getAxisName(int index)
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
|
||||
QString Boards::getAnalogInputName(Board::Type board, int index)
|
||||
StringTagMappingTable Boards::getAnalogNamesLookupTable(Board::Type board)
|
||||
{
|
||||
if (index < 0)
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
StringTagMappingTable tbl;
|
||||
|
||||
if (index < getBoardCapability(board, Board::Sticks)) {
|
||||
const QString sticks[] = {
|
||||
tr("Rud"),
|
||||
tr("Ele"),
|
||||
tr("Thr"),
|
||||
tr("Ail")
|
||||
};
|
||||
return sticks[index];
|
||||
if (getBoardCapability(board, Board::Sticks)) {
|
||||
tbl.insert(tbl.end(), {"Rud", "Ele", "Thr", "Ail"});
|
||||
}
|
||||
|
||||
index -= getCapability(board, Board::Sticks);
|
||||
|
||||
if (IS_SKY9X(board)) {
|
||||
const QString pots[] = {
|
||||
"P1",
|
||||
"P2",
|
||||
"P3"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_TARANIS_X9E(board)) {
|
||||
const QString pots[] = {
|
||||
"F1",
|
||||
"F2",
|
||||
"F3",
|
||||
"F4",
|
||||
"S1",
|
||||
"S2",
|
||||
"LS",
|
||||
"RS"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_TARANIS_XLITE(board)) {
|
||||
const QString pots[] = {
|
||||
"S1",
|
||||
"S2",
|
||||
"GyrX",
|
||||
"GyrY"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_TARANIS(board)) {
|
||||
const QString pots[] = {
|
||||
"S1",
|
||||
"S2",
|
||||
"S3",
|
||||
"LS",
|
||||
"RS"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_HORUS_X12S(board)) {
|
||||
const QString pots[] = {
|
||||
"S1",
|
||||
"6P",
|
||||
"S2",
|
||||
"L1",
|
||||
"L2",
|
||||
"LS",
|
||||
"RS",
|
||||
"JSx",
|
||||
"JSy"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_FLYSKY_NV14(board)) {
|
||||
const QString pots[] = {
|
||||
"VRA",
|
||||
"VRB",
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
}
|
||||
else if (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) {
|
||||
const QString pots[] = {
|
||||
"S1",
|
||||
"6P",
|
||||
"S2",
|
||||
"EX1",
|
||||
"EX2",
|
||||
"LS",
|
||||
"RS"
|
||||
};
|
||||
if (index < DIM(pots))
|
||||
return pots[index];
|
||||
tbl.insert(tbl.end(), {"P1", "P2", "P3"});
|
||||
} else if (IS_TARANIS_X9E(board)) {
|
||||
tbl.insert(tbl.end(), {
|
||||
{"F1", "POT1"},
|
||||
{"F2", "POT2"},
|
||||
{"F3", "POT3"},
|
||||
{"F4", "POT4"},
|
||||
{"S1", "SLIDER1"},
|
||||
{"S2", "SLIDER2"},
|
||||
{"LS", "SLIDER3"},
|
||||
{"RS", "SLIDER4"},
|
||||
});
|
||||
} else if (IS_TARANIS_XLITE(board)) {
|
||||
tbl.insert(tbl.end(), {
|
||||
{"S1", "POT1"},
|
||||
{"S2", "POT2"},
|
||||
{"GyrX", "GYRO1"},
|
||||
{"GyrY", "GYRO2"},
|
||||
});
|
||||
} else if (IS_TARANIS(board)) {
|
||||
tbl.insert(tbl.end(), {
|
||||
{"S1", "POT1"},
|
||||
{"S2", "POT2"},
|
||||
{"S3", "POT3"},
|
||||
{"LS", "SLIDER1"},
|
||||
{"RS", "SLIDER2"},
|
||||
});
|
||||
} else if (IS_HORUS_X12S(board)) {
|
||||
tbl.insert(tbl.end(), {
|
||||
{"S1", "S1"},
|
||||
{"6P", "6POS"},
|
||||
{"S2", "S2"},
|
||||
{"L1", "S3"},
|
||||
{"L2", "S4"},
|
||||
{"LS", "LS"},
|
||||
{"RS", "RS"},
|
||||
{"JSx", "MOUSE1"},
|
||||
{"JSy", "MOUSE2"},
|
||||
});
|
||||
} else if (IS_FLYSKY_NV14(board)) {
|
||||
tbl.insert(tbl.end(), {
|
||||
{"VRA", "POT1"},
|
||||
{"VRB", "POT2"},
|
||||
});
|
||||
} else if (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) {
|
||||
tbl.insert(tbl.end(), {
|
||||
{"S1", "S1"},
|
||||
{"6P", "6POS"},
|
||||
{"S2", "S2"},
|
||||
{"EX1", "EXT1"},
|
||||
{"EX2", "EXT2"},
|
||||
{"EX3", "EXT3"},
|
||||
{"EX4", "EXT4"},
|
||||
{"LS", "LS"},
|
||||
{"RS", "RS"},
|
||||
});
|
||||
}
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
QString Boards::getAnalogInputName(Board::Type board, int index)
|
||||
{
|
||||
const StringTagMappingTable& lut = getAnalogNamesLookupTable(board);
|
||||
if (index < (int)lut.size())
|
||||
return QString::fromStdString(lut[index].name);
|
||||
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
}
|
||||
|
||||
@@ -762,3 +747,126 @@ AbstractStaticItemModel * Boards::switchTypeItemModel()
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
// static
|
||||
StringTagMappingTable Boards::getSwitchesLookupTable(Board::Type board)
|
||||
{
|
||||
StringTagMappingTable tbl;
|
||||
|
||||
for (int i = 0; i < Boards::getCapability(board, Board::Switches); i++) {
|
||||
SwitchInfo si = Boards::getSwitchInfo(board, i);
|
||||
if (si.config != SWITCH_NOT_AVAILABLE) // safety check in case Switches does not align
|
||||
tbl.insert(tbl.end(), si.name.toStdString());
|
||||
}
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
// static
|
||||
StringTagMappingTable Boards::getTrimSwitchesLookupTable(Board::Type board)
|
||||
{
|
||||
StringTagMappingTable tbl;
|
||||
|
||||
tbl.insert(tbl.end(), {
|
||||
{std::to_string(TRIM_SW_LH_DEC), "TrimRudLeft"},
|
||||
{std::to_string(TRIM_SW_LH_INC), "TrimRudRight"},
|
||||
{std::to_string(TRIM_SW_LV_DEC), "TrimEleDown"},
|
||||
{std::to_string(TRIM_SW_LV_INC), "TrimEleUp"},
|
||||
{std::to_string(TRIM_SW_RV_DEC), "TrimThrDown"},
|
||||
{std::to_string(TRIM_SW_RV_INC), "TrimThrUp"},
|
||||
{std::to_string(TRIM_SW_RH_DEC), "TrimAilLeft"},
|
||||
{std::to_string(TRIM_SW_RH_INC), "TrimAilRight"},
|
||||
});
|
||||
|
||||
if (getCapability(board, Board::NumTrims) > 4)
|
||||
tbl.insert(tbl.end(), {
|
||||
{std::to_string(TRIM_SW_T5_DEC), "TrimT5Down"},
|
||||
{std::to_string(TRIM_SW_T5_INC), "TrimT5Up"},
|
||||
{std::to_string(TRIM_SW_T6_DEC), "TrimT6Down"},
|
||||
{std::to_string(TRIM_SW_T6_INC), "TrimT6Up"},
|
||||
});
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
// static
|
||||
StringTagMappingTable Boards::getTrimSourcesLookupTable(Board::Type board)
|
||||
{
|
||||
StringTagMappingTable tbl;
|
||||
|
||||
tbl.insert(tbl.end(), {
|
||||
{std::to_string(TRIM_AXIS_LH), "TrimRud"},
|
||||
{std::to_string(TRIM_AXIS_LV), "TrimEle"},
|
||||
{std::to_string(TRIM_AXIS_RV), "TrimThr"},
|
||||
{std::to_string(TRIM_AXIS_RH), "TrimAil"},
|
||||
});
|
||||
|
||||
if (getCapability(board, Board::NumTrims) > 4)
|
||||
tbl.insert(tbl.end(), {
|
||||
{std::to_string(TRIM_AXIS_T5), "TrimT5"},
|
||||
{std::to_string(TRIM_AXIS_T6), "TrimT6"},
|
||||
});
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
QList<ModuleType> Boards::getSupportedInternalModules(Board::Type board)
|
||||
{
|
||||
QList<ModuleType> modules;
|
||||
if (IS_TARANIS_X9DP_2019(board) || IS_TARANIS_X7_ACCESS(board)) {
|
||||
modules = {MODULE_TYPE_ISRM_PXX2};
|
||||
} else if (IS_FLYSKY_NV14(board)) {
|
||||
modules = {MODULE_TYPE_FLYSKY};
|
||||
} else if (IS_FAMILY_HORUS_OR_T16(board) || IS_FAMILY_T12(board)
|
||||
|| (IS_TARANIS_SMALL(board) && IS_ACCESS_RADIO(board))) {
|
||||
modules.append({
|
||||
MODULE_TYPE_XJT_PXX1,
|
||||
MODULE_TYPE_ISRM_PXX2,
|
||||
MODULE_TYPE_CROSSFIRE,
|
||||
MODULE_TYPE_MULTIMODULE,
|
||||
});
|
||||
} else if (IS_TARANIS(board)) {
|
||||
modules = {MODULE_TYPE_XJT_PXX1};
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
ModuleType Boards::getDefaultInternalModules(Board::Type board)
|
||||
{
|
||||
switch(board) {
|
||||
case BOARD_TARANIS_X7:
|
||||
case BOARD_TARANIS_X9D:
|
||||
case BOARD_TARANIS_X9DP:
|
||||
case BOARD_TARANIS_X9E:
|
||||
case BOARD_HORUS_X12S:
|
||||
case BOARD_X10:
|
||||
case BOARD_TARANIS_XLITE:
|
||||
return MODULE_TYPE_XJT_PXX1;
|
||||
|
||||
case BOARD_TARANIS_X7_ACCESS:
|
||||
case BOARD_TARANIS_X9DP_2019:
|
||||
case BOARD_X10_EXPRESS:
|
||||
case BOARD_TARANIS_XLITES:
|
||||
case BOARD_TARANIS_X9LITE:
|
||||
case BOARD_TARANIS_X9LITES:
|
||||
return MODULE_TYPE_ISRM_PXX2;
|
||||
|
||||
case BOARD_JUMPER_T12:
|
||||
case BOARD_JUMPER_T16:
|
||||
case BOARD_RADIOMASTER_TX16S:
|
||||
case BOARD_JUMPER_T18:
|
||||
case BOARD_RADIOMASTER_TX12:
|
||||
case BOARD_RADIOMASTER_T8:
|
||||
case BOARD_JUMPER_TLITE:
|
||||
case BOARD_RADIOMASTER_ZORRO:
|
||||
case BOARD_JUMPER_TPRO:
|
||||
return MODULE_TYPE_MULTIMODULE;
|
||||
|
||||
case BOARD_FLYSKY_NV14:
|
||||
return MODULE_TYPE_FLYSKY;
|
||||
|
||||
default:
|
||||
return MODULE_TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "datahelpers.h"
|
||||
#include "moduledata.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QObject>
|
||||
@@ -145,7 +147,9 @@ namespace Board {
|
||||
NumTrimSwitches,
|
||||
HasRTC,
|
||||
HasColorLcd,
|
||||
NumFunctionSwitches
|
||||
NumFunctionSwitches,
|
||||
HasSDCard,
|
||||
HasInternalModuleSupport
|
||||
};
|
||||
|
||||
struct SwitchInfo
|
||||
@@ -199,18 +203,26 @@ class Boards
|
||||
static int getEEpromSize(Board::Type board);
|
||||
static int getFlashSize(Board::Type board);
|
||||
static Board::SwitchInfo getSwitchInfo(Board::Type board, int index);
|
||||
static StringTagMappingTable getSwitchesLookupTable(Board::Type board);
|
||||
static int getCapability(Board::Type board, Board::Capability capability);
|
||||
static QString getAxisName(int index);
|
||||
static StringTagMappingTable getAnalogNamesLookupTable(Board::Type board);
|
||||
static QString getAnalogInputName(Board::Type board, int index);
|
||||
static bool isBoardCompatible(Board::Type board1, Board::Type board2);
|
||||
static QString getBoardName(Board::Type board);
|
||||
static QString potTypeToString(int value);
|
||||
static QString sliderTypeToString(int value);
|
||||
static QString switchTypeToString(int value);
|
||||
static QString intModuleTypeToString(int value);
|
||||
static AbstractStaticItemModel * potTypeItemModel();
|
||||
static AbstractStaticItemModel * sliderTypeItemModel();
|
||||
static AbstractStaticItemModel * switchTypeItemModel();
|
||||
|
||||
static AbstractStaticItemModel * intModuleTypeItemModel();
|
||||
static StringTagMappingTable getTrimSwitchesLookupTable(Board::Type board);
|
||||
static StringTagMappingTable getTrimSourcesLookupTable(Board::Type board);
|
||||
static QList<ModuleType> getSupportedInternalModules(Board::Type board);
|
||||
static ModuleType getDefaultInternalModules(Board::Type board);
|
||||
|
||||
protected:
|
||||
|
||||
Board::Type m_boardType;
|
||||
@@ -282,7 +294,12 @@ inline bool IS_FAMILY_T16(Board::Type board)
|
||||
|
||||
inline bool IS_FAMILY_T12(Board::Type board)
|
||||
{
|
||||
return board == Board::BOARD_JUMPER_T12 || board == Board::BOARD_RADIOMASTER_TX12 || board == Board::BOARD_RADIOMASTER_ZORRO || board == Board::BOARD_RADIOMASTER_T8 || board == Board::BOARD_JUMPER_TLITE;
|
||||
return board == Board::BOARD_JUMPER_T12 ||
|
||||
board == Board::BOARD_RADIOMASTER_TX12 ||
|
||||
board == Board::BOARD_RADIOMASTER_ZORRO ||
|
||||
board == Board::BOARD_RADIOMASTER_T8 ||
|
||||
board == Board::BOARD_JUMPER_TLITE ||
|
||||
board == Board::BOARD_JUMPER_TPRO;
|
||||
}
|
||||
|
||||
inline bool IS_FLYSKY_NV14(Board::Type board)
|
||||
@@ -400,10 +417,17 @@ inline bool IS_TARANIS_X9DP_2019(Board::Type board)
|
||||
return (board == Board::BOARD_TARANIS_X9DP_2019);
|
||||
}
|
||||
|
||||
inline bool IS_ACCESS_RADIO(Board::Type board)
|
||||
{
|
||||
return IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board) ||
|
||||
board == Board::BOARD_TARANIS_X9DP_2019 ||
|
||||
board == Board::BOARD_X10_EXPRESS || IS_TARANIS_X7_ACCESS(board);
|
||||
}
|
||||
|
||||
inline bool IS_ACCESS_RADIO(Board::Type board, const QString & id)
|
||||
{
|
||||
return (IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board) || board == Board::BOARD_TARANIS_X9DP_2019 || board == Board::BOARD_X10_EXPRESS || IS_TARANIS_X7_ACCESS(board) ||
|
||||
(IS_FAMILY_HORUS_OR_T16(board) && id.contains("internalaccess")));
|
||||
return IS_ACCESS_RADIO(board) ||
|
||||
(IS_FAMILY_HORUS_OR_T16(board) && id.contains("internalaccess"));
|
||||
}
|
||||
|
||||
inline bool HAS_EEPROM_YAML(Board::Type board)
|
||||
|
||||
@@ -30,18 +30,6 @@ void CurveData::clear(int count)
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(CurveData));
|
||||
this->count = count;
|
||||
|
||||
int incr = 200 / (count - 1);
|
||||
|
||||
// points[0].x must be -100
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (i < count - 1)
|
||||
points[i].x = -100 + incr * i;
|
||||
else
|
||||
points[i].x = 100; // points[last].x must be +100 do not risk a rounding issue using incr
|
||||
|
||||
points[i].y = points[i].x;
|
||||
}
|
||||
}
|
||||
|
||||
bool CurveData::isEmpty() const
|
||||
|
||||
@@ -84,7 +84,7 @@ QString CustomFunctionData::funcToString(const AssignFunc func, const ModelData
|
||||
else if (func == FuncReset)
|
||||
return tr("Reset");
|
||||
else if (func >= FuncSetTimer1 && func <= FuncSetTimerLast)
|
||||
return tr("Set %1").arg(RawSource(SOURCE_TYPE_SPECIAL, SOURCE_TYPE_SPECIAL_TIMER1_IDX + func - FuncSetTimer1).toString(model));
|
||||
return tr("Set %1").arg(RawSource(SOURCE_TYPE_SPECIAL, SOURCE_TYPE_SPECIAL_FIRST_TIMER + func - FuncSetTimer1).toString(model));
|
||||
else if (func == FuncVario)
|
||||
return tr("Vario");
|
||||
else if (func == FuncPlayPrompt)
|
||||
@@ -249,7 +249,7 @@ QString CustomFunctionData::resetToString(const int value, const ModelData * mod
|
||||
|
||||
if (value < step) {
|
||||
if (value < firmware->getCapability(Timers))
|
||||
return RawSource(SOURCE_TYPE_SPECIAL, value + SOURCE_TYPE_SPECIAL_TIMER1_IDX).toString(model);
|
||||
return RawSource(SOURCE_TYPE_SPECIAL, value + SOURCE_TYPE_SPECIAL_FIRST_TIMER).toString(model);
|
||||
else
|
||||
return QString(CPN_STR_UNKNOWN_ITEM);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,26 @@
|
||||
#define WHITE RADIO_RGB(0xFF, 0xFF, 0xFF)
|
||||
#define RED RADIO_RGB(229, 32, 30)
|
||||
|
||||
ZoneOptionValue::ZoneOptionValue()
|
||||
{
|
||||
memset((void*)this, 0, sizeof(ZoneOptionValue));
|
||||
}
|
||||
|
||||
ZoneOptionValueTyped::ZoneOptionValueTyped()
|
||||
{
|
||||
memset((void*)this, 0, sizeof(ZoneOptionValueTyped));
|
||||
}
|
||||
|
||||
WidgetPersistentData::WidgetPersistentData()
|
||||
{
|
||||
memset((void*)this, 0, sizeof(WidgetPersistentData));
|
||||
}
|
||||
|
||||
ZonePersistentData::ZonePersistentData()
|
||||
{
|
||||
memset((void*)this, 0, sizeof(ZonePersistentData));
|
||||
}
|
||||
|
||||
inline void setZoneOptionValue(ZoneOptionValue& zov, bool value)
|
||||
{
|
||||
zov.boolValue = value;
|
||||
@@ -61,9 +81,13 @@ inline ZoneOptionValueEnum zoneValueEnumFromType(ZoneOption::Type type)
|
||||
return ZOV_Bool;
|
||||
|
||||
case ZoneOption::Color:
|
||||
return ZOV_Color;
|
||||
|
||||
case ZoneOption::Source:
|
||||
return ZOV_Source;
|
||||
|
||||
case ZoneOption::Timer:
|
||||
case ZoneOption::Switch:
|
||||
case ZoneOption::Source:
|
||||
case ZoneOption::TextSize:
|
||||
default:
|
||||
return ZOV_Unsigned;
|
||||
@@ -85,6 +109,28 @@ inline const char * zoneOptionValueEnumToString(ZoneOptionValueEnum zovenum) {
|
||||
}
|
||||
}
|
||||
|
||||
static const ZoneOptionValueTyped zero_widget_option = {};
|
||||
|
||||
bool ZoneOptionValueTyped::isEmpty() const
|
||||
{
|
||||
return !memcmp((void*)this, &zero_widget_option, sizeof(zero_widget_option));
|
||||
}
|
||||
|
||||
bool ZonePersistentData::isEmpty() const
|
||||
{
|
||||
return strlen(widgetName) == 0;
|
||||
}
|
||||
|
||||
RadioLayout::CustomScreenData::CustomScreenData()
|
||||
{
|
||||
memset((void*)this, 0, sizeof(RadioLayout::CustomScreenData));
|
||||
}
|
||||
|
||||
bool RadioLayout::CustomScreenData::isEmpty() const
|
||||
{
|
||||
return strlen(layoutId) == 0;
|
||||
}
|
||||
|
||||
void RadioTheme::init(const char* themeName, ThemeData& themeData)
|
||||
{
|
||||
memset(&themeData, 0, sizeof(ThemeData));
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "constants.h"
|
||||
#include "rawsource.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
@@ -58,6 +59,10 @@ struct ZoneOptionValue // union in radio/src/datastructs.h
|
||||
int signedValue;
|
||||
unsigned int boolValue;
|
||||
char stringValue[LEN_ZONE_OPTION_STRING + 1];
|
||||
RawSource sourceValue;
|
||||
unsigned int colorValue;
|
||||
|
||||
ZoneOptionValue();
|
||||
};
|
||||
|
||||
enum ZoneOptionValueEnum {
|
||||
@@ -65,7 +70,9 @@ enum ZoneOptionValueEnum {
|
||||
ZOV_Signed,
|
||||
ZOV_Bool,
|
||||
ZOV_String,
|
||||
ZOV_LAST = ZOV_String
|
||||
ZOV_Source,
|
||||
ZOV_Color,
|
||||
ZOV_LAST = ZOV_Color
|
||||
};
|
||||
|
||||
struct ZoneOption
|
||||
@@ -93,21 +100,33 @@ struct ZoneOptionValueTyped
|
||||
{
|
||||
ZoneOptionValueEnum type;
|
||||
ZoneOptionValue value;
|
||||
|
||||
ZoneOptionValueTyped();
|
||||
bool isEmpty() const;
|
||||
};
|
||||
|
||||
struct WidgetPersistentData {
|
||||
ZoneOptionValueTyped options[MAX_WIDGET_OPTIONS];
|
||||
|
||||
WidgetPersistentData();
|
||||
};
|
||||
|
||||
struct ZonePersistentData {
|
||||
char widgetName[WIDGET_NAME_LEN + 1];
|
||||
WidgetPersistentData widgetData;
|
||||
|
||||
ZonePersistentData();
|
||||
bool isEmpty() const;
|
||||
};
|
||||
|
||||
template<int N, int O>
|
||||
struct WidgetsContainerPersistentData {
|
||||
ZonePersistentData zones[N];
|
||||
ZoneOptionValueTyped options[O];
|
||||
|
||||
WidgetsContainerPersistentData() {
|
||||
memset((void*)this, 0, sizeof(WidgetsContainerPersistentData));
|
||||
}
|
||||
};
|
||||
|
||||
typedef WidgetsContainerPersistentData<MAX_LAYOUT_ZONES, MAX_LAYOUT_OPTIONS>
|
||||
@@ -141,6 +160,9 @@ class RadioLayout
|
||||
struct CustomScreenData {
|
||||
char layoutId[LAYOUT_ID_LEN + 1];
|
||||
LayoutPersistentData layoutPersistentData;
|
||||
|
||||
CustomScreenData();
|
||||
bool isEmpty() const;
|
||||
};
|
||||
|
||||
struct CustomScreens {
|
||||
|
||||
@@ -68,3 +68,26 @@ QString DataHelpers::timeToString(const int value, const unsigned int mask)
|
||||
result.append(QString("%1:%2").arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0')));
|
||||
return result;
|
||||
}
|
||||
|
||||
int DataHelpers::getStringTagMappingIndex(const StringTagMappingTable& lut, const char * tag)
|
||||
{
|
||||
auto it =
|
||||
find_if(lut.begin(), lut.end(), [=](const StringTagMapping& elmt) {
|
||||
if (elmt.tag == tag) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (it != lut.end()) {
|
||||
return it - lut.begin();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string DataHelpers::getStringTagMappingTag(const StringTagMappingTable& lut, unsigned int index)
|
||||
{
|
||||
if (index < lut.size())
|
||||
return lut[index].tag;
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct StringTagMapping {
|
||||
std::string name;
|
||||
std::string tag;
|
||||
|
||||
StringTagMapping() = default;
|
||||
StringTagMapping(const char* name) :
|
||||
name(name), tag(name)
|
||||
{
|
||||
}
|
||||
StringTagMapping(const std::string& name) :
|
||||
name(name), tag(name)
|
||||
{
|
||||
}
|
||||
StringTagMapping(const char* name, const char* tag) :
|
||||
name(name), tag(tag)
|
||||
{
|
||||
}
|
||||
StringTagMapping(const std::string& name, const std::string& tag) :
|
||||
name(name), tag(tag)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<StringTagMapping> StringTagMappingTable;
|
||||
|
||||
#define STRINGTAGMAPPINGFUNCS_HELPER(tbl, name, index, tag) \
|
||||
inline int name##index (const char * tag) \
|
||||
{ \
|
||||
return DataHelpers::getStringTagMappingIndex(tbl, tag); \
|
||||
} \
|
||||
\
|
||||
inline std::string name##tag (unsigned int index) \
|
||||
{ \
|
||||
return DataHelpers::getStringTagMappingTag(tbl, index); \
|
||||
}
|
||||
|
||||
#define STRINGTAGMAPPINGFUNCS(tbl, name) STRINGTAGMAPPINGFUNCS_HELPER(tbl, get##name, Index, Tag)
|
||||
|
||||
class FieldRange
|
||||
{
|
||||
@@ -65,5 +105,6 @@ namespace DataHelpers
|
||||
QString boolToString(const bool value, const BoolFormat format);
|
||||
QString getElementName(const QString & prefix, const unsigned int index, const char * name = 0, const bool padding = false);
|
||||
QString timeToString(const int value, const unsigned int mask);
|
||||
|
||||
int getStringTagMappingIndex(const StringTagMappingTable& lut, const char * tag);
|
||||
std::string getStringTagMappingTag(const StringTagMappingTable& lut, unsigned int index);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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 "edgetxinterface.h"
|
||||
|
||||
#include "yaml_ops.h"
|
||||
#include "yaml_generalsettings.h"
|
||||
#include "yaml_modeldata.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
static YAML::Node loadYamlFromByteArray(const QByteArray& data)
|
||||
{
|
||||
// TODO: use real streaming to avoid memory copies
|
||||
std::istringstream data_istream(data.toStdString());
|
||||
return YAML::Load(data_istream);
|
||||
}
|
||||
|
||||
static void writeYamlToByteArray(const YAML::Node& node, QByteArray& data)
|
||||
{
|
||||
// TODO: use real streaming to avoid memory copies
|
||||
std::stringstream data_ostream;
|
||||
data_ostream << node;
|
||||
data = QByteArray::fromStdString(data_ostream.str());
|
||||
|
||||
qDebug() << "Saving YAML:";
|
||||
qDebug() << data_ostream.str().c_str();
|
||||
}
|
||||
|
||||
bool loadModelsListFromYaml(std::vector<CategoryData>& categories,
|
||||
EtxModelfiles& modelFiles,
|
||||
const QByteArray& data)
|
||||
{
|
||||
if (data.size() == 0)
|
||||
return true;
|
||||
|
||||
try {
|
||||
YAML::Node node = loadYamlFromByteArray(data);
|
||||
if (!node.IsSequence()) return false;
|
||||
|
||||
int modelIdx = 0;
|
||||
for (const auto& cat : node) {
|
||||
|
||||
if (!cat.IsMap()) continue;
|
||||
|
||||
for (const auto& cat_map : cat) {
|
||||
categories.push_back(cat_map.first.Scalar().c_str());
|
||||
|
||||
const auto& models = cat_map.second;
|
||||
if (!models.IsSequence()) continue;
|
||||
|
||||
for (const auto& model : models) {
|
||||
std::string filename, name;
|
||||
model["filename"] >> filename;
|
||||
model["name"] >> name;
|
||||
modelFiles.push_back(
|
||||
{filename, name, (int)categories.size() - 1, modelIdx++});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const std::runtime_error& e) {
|
||||
qDebug() << "YAML::ParserException: " << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loadModelFromYaml(ModelData& model, const QByteArray& data)
|
||||
{
|
||||
YAML::Node node = loadYamlFromByteArray(data);
|
||||
node >> model;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loadRadioSettingsFromYaml(GeneralSettings& settings, const QByteArray& data)
|
||||
{
|
||||
YAML::Node node = loadYamlFromByteArray(data);
|
||||
node >> settings;
|
||||
if (settings.version < CPN_CURRENT_SETTINGS_VERSION) {
|
||||
qDebug() << "Older version of settings detected:" << settings.version;
|
||||
}
|
||||
else if (settings.version > CPN_CURRENT_SETTINGS_VERSION) {
|
||||
qDebug() << "Newer version of settings detected:" << settings.version;
|
||||
QMessageBox::critical(NULL, CPN_STR_APP_NAME, QCoreApplication::translate("EdgeTXInterface", "Companion does not support settings version %1!").arg(settings.version));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// 'modelFiles' should be ordered by Category index to avoid
|
||||
// turning the sequence into a map.
|
||||
//
|
||||
bool writeModelsListToYaml(const std::vector<CategoryData>& categories,
|
||||
const EtxModelfiles& modelFiles,
|
||||
QByteArray& data)
|
||||
{
|
||||
YAML::Node node;
|
||||
for (const auto& modelFile: modelFiles) {
|
||||
|
||||
YAML::Node cat_attrs;
|
||||
cat_attrs["filename"] = modelFile.filename;
|
||||
cat_attrs["name"] = modelFile.name;
|
||||
|
||||
if (modelFile.category >= (int)categories.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string cat_name = categories[modelFile.category].name;
|
||||
node[modelFile.category][cat_name].push_back(cat_attrs);
|
||||
}
|
||||
|
||||
writeYamlToByteArray(node, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool writeModelToYaml(const ModelData& model, QByteArray& data)
|
||||
{
|
||||
YAML::Node node;
|
||||
node = model;
|
||||
|
||||
writeYamlToByteArray(node, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool writeRadioSettingsToYaml(const GeneralSettings& settings, QByteArray& data)
|
||||
{
|
||||
YAML::Node node;
|
||||
node = settings;
|
||||
|
||||
writeYamlToByteArray(node, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string patchFilenameToYaml(const std::string& str)
|
||||
{
|
||||
constexpr const char MODELS_EXT[] = ".bin";
|
||||
constexpr const char YAML_EXT[] = ".yml";
|
||||
constexpr unsigned bin_len = sizeof(MODELS_EXT) - 1;
|
||||
|
||||
// patch file extension
|
||||
auto const dot_pos = str.find_last_of('.');
|
||||
if ((dot_pos != std::string::npos) && (str.substr(dot_pos) == MODELS_EXT)) {
|
||||
std::string tmp = str;
|
||||
return tmp.replace(dot_pos, bin_len, YAML_EXT);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "radiodata.h"
|
||||
#include <QByteArray>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
constexpr unsigned int CPN_CURRENT_SETTINGS_VERSION = { 221 };
|
||||
|
||||
struct EtxModelMetadata {
|
||||
std::string filename;
|
||||
std::string name;
|
||||
int category;
|
||||
int modelIdx;
|
||||
};
|
||||
|
||||
typedef std::list<EtxModelMetadata> EtxModelfiles;
|
||||
|
||||
bool loadModelsListFromYaml(std::vector<CategoryData>& categories,
|
||||
EtxModelfiles& modelFiles,
|
||||
const QByteArray& data);
|
||||
|
||||
bool loadModelFromYaml(ModelData& model, const QByteArray& data);
|
||||
bool loadRadioSettingsFromYaml(GeneralSettings& settings, const QByteArray& data);
|
||||
|
||||
bool writeModelsListToYaml(const std::vector<CategoryData>& categories,
|
||||
const EtxModelfiles& modelFiles,
|
||||
QByteArray& data);
|
||||
|
||||
bool writeModelToYaml(const ModelData& model, QByteArray& data);
|
||||
bool writeRadioSettingsToYaml(const GeneralSettings& settings, QByteArray& data);
|
||||
|
||||
std::string patchFilenameToYaml(const std::string& str);
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#include "yaml_calibdata.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
YamlCalibData::YamlCalibData() { memset(calib, 0, sizeof(calib)); }
|
||||
|
||||
YamlCalibData::YamlCalibData(const int* calibMid, const int* calibSpanNeg,
|
||||
const int* calibSpanPos)
|
||||
{
|
||||
for (int i = 0; i < CPN_MAX_ANALOGS; i++) {
|
||||
calib[i].mid = calibMid[i];
|
||||
calib[i].spanNeg = calibSpanNeg[i];
|
||||
calib[i].spanPos = calibSpanPos[i];
|
||||
}
|
||||
}
|
||||
|
||||
void YamlCalibData::copy(int* calibMid, int* calibSpanNeg,
|
||||
int* calibSpanPos) const
|
||||
{
|
||||
for (int i = 0; i < CPN_MAX_ANALOGS; i++) {
|
||||
calibMid[i] = calib[i].mid;
|
||||
calibSpanNeg[i] = calib[i].spanNeg;
|
||||
calibSpanPos[i] = calib[i].spanPos;
|
||||
}
|
||||
}
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
|
||||
Node convert<CalibData>::encode(const CalibData& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["mid"] = rhs.mid;
|
||||
node["spanNeg"] = rhs.spanNeg;
|
||||
node["spanPos"] = rhs.spanPos;
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<CalibData>::decode(const Node& node, CalibData& rhs)
|
||||
{
|
||||
if (!node.IsMap()) return false;
|
||||
node["mid"] >> rhs.mid;
|
||||
node["spanNeg"] >> rhs.spanNeg;
|
||||
node["spanPos"] >> rhs.spanPos;
|
||||
return true;
|
||||
}
|
||||
|
||||
Node convert<YamlCalibData>::encode(const YamlCalibData& rhs)
|
||||
{
|
||||
Node node;
|
||||
int idx = 0;
|
||||
const auto* calibIdxLut = getCurrentFirmware()->getAnalogIndexNamesLookupTable();
|
||||
for (const auto& kv : *calibIdxLut) {
|
||||
node[kv.tag] = rhs.calib[idx++];
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<YamlCalibData>::decode(const Node& node, YamlCalibData& rhs)
|
||||
{
|
||||
if (!node.IsMap()) return false;
|
||||
|
||||
for (const auto& kv : node) {
|
||||
std::string tag;
|
||||
kv.first >> tag;
|
||||
int idx = getCurrentFirmware()->getAnalogInputIndex(tag.c_str());
|
||||
if (idx >= 0) {
|
||||
kv.second >> rhs.calib[idx];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "generalsettings.h"
|
||||
|
||||
struct CalibData {
|
||||
int16_t mid;
|
||||
int16_t spanNeg;
|
||||
int16_t spanPos;
|
||||
};
|
||||
|
||||
struct YamlCalibData {
|
||||
CalibData calib[CPN_MAX_ANALOGS];
|
||||
|
||||
YamlCalibData();
|
||||
YamlCalibData(const int* calibMid, const int* calibSpanNeg, const int* calibSpanPos);
|
||||
void copy(int* calibMid, int* calibSpanNeg, int* calibSpanPos) const;
|
||||
};
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<CalibData> {
|
||||
static Node encode(const CalibData& rhs);
|
||||
static bool decode(const Node& node, CalibData& rhs);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct convert<YamlCalibData> {
|
||||
static Node encode(const YamlCalibData& rhs);
|
||||
static bool decode(const Node& node, YamlCalibData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 "yaml_curvedata.h"
|
||||
|
||||
// CurveHeader curves[MAX_CURVES];
|
||||
// int8_t points[MAX_CURVE_POINTS];
|
||||
|
||||
void YamlReadCurvePoints(const YAML::Node& node, CurveData* curves)
|
||||
{
|
||||
int pidx = 0;
|
||||
for (int i = 0; i < CPN_MAX_CURVES; i++) {
|
||||
CurveData& curve = curves[i];
|
||||
for (int j = 0; j < curve.count; j++) {
|
||||
std::string pidx_str = std::to_string(pidx++);
|
||||
if (node[pidx_str]) {
|
||||
int y = 0;
|
||||
node[pidx_str]["val"] >> y;
|
||||
curve.points[j].y = (int8_t)y;
|
||||
}
|
||||
}
|
||||
if (curve.type == CurveData::CURVE_TYPE_CUSTOM) {
|
||||
// Custom curve: X points are trailing Y points
|
||||
curve.points[0].x = -100;
|
||||
for (int k = 1; k < curve.count - 1; k++) {
|
||||
std::string pidx_str = std::to_string(pidx++);
|
||||
if (node[pidx_str]) {
|
||||
int x = 0;
|
||||
node[pidx_str]["val"] >> x;
|
||||
curve.points[k].x = (int8_t)x;
|
||||
}
|
||||
}
|
||||
curve.points[curve.count - 1].x = +100;
|
||||
} else {
|
||||
// Standard curve: X points are generated
|
||||
for (int k = 0; k < curve.count; k++) {
|
||||
curve.points[k].x = -100 + (200 * k) / (curve.count - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void YamlWriteCurvePoints(YAML::Node& node, const CurveData* curves)
|
||||
{
|
||||
int pidx = 0;
|
||||
for (int i = 0; i < CPN_MAX_CURVES; i++) {
|
||||
|
||||
//TODO: assert max number of points
|
||||
// and raise exception
|
||||
|
||||
const CurveData& curve = curves[i];
|
||||
if (!curve.isEmpty()) {
|
||||
for (int k = 0; k < curve.count; k++) {
|
||||
node[std::to_string(pidx++)]["val"] = (int)curve.points[k].y;
|
||||
}
|
||||
if (curve.type == CurveData::CURVE_TYPE_CUSTOM) {
|
||||
for (int k = 1; k < curve.count - 1; k++) {
|
||||
node[std::to_string(pidx++)]["val"] = (int)curve.points[k].x;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pidx += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
Node convert<CurveData>::encode(const CurveData& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["type"] = (int)rhs.type;
|
||||
node["smooth"] = (int)rhs.smooth;
|
||||
node["points"] = rhs.count - 5;
|
||||
node["name"] = rhs.name;
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<CurveData>::decode(const Node& node, CurveData& rhs)
|
||||
{
|
||||
int curve_type = 0;
|
||||
node["type"] >> curve_type;
|
||||
rhs.type = (CurveData::CurveType)curve_type;
|
||||
node["smooth"] >> rhs.smooth;
|
||||
node["points"] >> ioffset_int(rhs.count, -5);
|
||||
node["name"] >> rhs.name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "curvedata.h"
|
||||
|
||||
void YamlReadCurvePoints(const YAML::Node& node, CurveData* curves);
|
||||
void YamlWriteCurvePoints(YAML::Node& node, const CurveData* curves);
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<CurveData> {
|
||||
static Node encode(const CurveData& rhs);
|
||||
static bool decode(const Node& node, CurveData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* 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 "yaml_customfunctiondata.h"
|
||||
#include "yaml_rawswitch.h"
|
||||
#include "yaml_rawsource.h"
|
||||
|
||||
static bool fnHasEnable(AssignFunc fn)
|
||||
{
|
||||
return (fn <= FuncInstantTrim)
|
||||
|| (fn >= FuncReset && fn <= FuncSetTimerLast)
|
||||
|| (fn >= FuncAdjustGV1 && fn <= FuncBindExternalModule)
|
||||
|| (fn == FuncVolume);
|
||||
}
|
||||
|
||||
static bool fnHasRepeat(AssignFunc fn)
|
||||
{
|
||||
return (fn == FuncPlayPrompt)
|
||||
|| (fn == FuncPlayValue)
|
||||
|| (fn == FuncPlayHaptic)
|
||||
|| (fn == FuncPlaySound);
|
||||
}
|
||||
|
||||
static const YamlLookupTable customFnLut = {
|
||||
{ FuncOverrideCH1, "OVERRIDE_CHANNEL" },
|
||||
{ FuncTrainer, "TRAINER" },
|
||||
{ FuncInstantTrim, "INSTANT_TRIM" },
|
||||
{ FuncReset, "RESET" },
|
||||
{ FuncSetTimer1, "SET_TIMER" },
|
||||
{ FuncAdjustGV1, "ADJUST_GVAR" },
|
||||
{ FuncVolume, "VOLUME" },
|
||||
{ FuncSetFailsafe, "SET_FAILSAFE" },
|
||||
{ FuncRangeCheckInternalModule, "RANGECHECK" },
|
||||
{ FuncBindInternalModule, "BIND" },
|
||||
{ FuncPlaySound, "PLAY_SOUND" },
|
||||
{ FuncPlayPrompt, "PLAY_TRACK" },
|
||||
{ FuncPlayValue, "PLAY_VALUE" },
|
||||
{ FuncPlayScript, "PLAY_SCRIPT" },
|
||||
{ FuncBackgroundMusic, "BACKGND_MUSIC" },
|
||||
{ FuncBackgroundMusicPause, "BACKGND_MUSIC_PAUSE" },
|
||||
{ FuncVario, "VARIO" },
|
||||
{ FuncPlayHaptic, "HAPTIC" },
|
||||
{ FuncLogs, "LOGS" },
|
||||
{ FuncBacklight, "BACKLIGHT" },
|
||||
{ FuncScreenshot, "SCREENSHOT" },
|
||||
{ FuncRacingMode, "RACING_MODE" },
|
||||
{ FuncDisableTouch, "DISABLE_TOUCH" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable trainerLut = {
|
||||
{ 0, "sticks" },
|
||||
{ 1, "Rud" },
|
||||
{ 2, "Ele" },
|
||||
{ 3, "Thr" },
|
||||
{ 4, "Ail" },
|
||||
{ 5, "chans" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable soundLut = {
|
||||
{ 0, "Bp1" },
|
||||
{ 1, "Bp2" },
|
||||
{ 2, "Bp3" },
|
||||
{ 3, "Wrn1" },
|
||||
{ 4, "Wrn2" },
|
||||
{ 5, "Chee" },
|
||||
{ 6, "Rata" },
|
||||
{ 7, "Tick" },
|
||||
{ 8, "Sirn" },
|
||||
{ 9, "Ring" },
|
||||
{ 10, "SciF" },
|
||||
{ 11, "Robt" },
|
||||
{ 12, "Chrp" },
|
||||
{ 13, "Tada" },
|
||||
{ 14, "Crck" },
|
||||
{ 15, "Alrm" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable resetLut = {
|
||||
{ 0, "Tmr1" },
|
||||
{ 1, "Tmr2" },
|
||||
{ 2, "Tmr3" },
|
||||
{ 3, "All" },
|
||||
{ 4, "Tele" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable gvarModeLut = {
|
||||
{ FUNC_ADJUST_GVAR_CONSTANT, "Cst" },
|
||||
{ FUNC_ADJUST_GVAR_SOURCE, "Src" },
|
||||
{ FUNC_ADJUST_GVAR_GVAR, "GVar" },
|
||||
{ FUNC_ADJUST_GVAR_INCDEC, "IncDec" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable moduleLut = {
|
||||
{ 0, "Int" },
|
||||
{ 1, "Ext" },
|
||||
};
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
Node convert<CustomFunctionData>::encode(const CustomFunctionData& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["swtch"] = rhs.swtch;
|
||||
|
||||
int fn = rhs.func;
|
||||
int p1 = 0;
|
||||
if(fn >= FuncOverrideCH1 && fn <= FuncOverrideCHLast) {
|
||||
p1 = fn - (int)FuncOverrideCH1;
|
||||
fn = (int)FuncOverrideCH1;
|
||||
} else if (fn >= FuncTrainer && fn <= FuncTrainerChannels) {
|
||||
p1 = fn - (int)FuncTrainer;
|
||||
fn = (int)FuncTrainer;
|
||||
} else if (fn >= FuncSetTimer1 && fn <= FuncSetTimerLast) {
|
||||
p1 = fn - (int)FuncSetTimer1;
|
||||
fn = (int)FuncSetTimer1;
|
||||
} else if (fn >= FuncAdjustGV1 && fn <= FuncAdjustGVLast) {
|
||||
p1 = fn - (int)FuncAdjustGV1;
|
||||
fn = (int)FuncAdjustGV1;
|
||||
} else if (fn >= FuncRangeCheckInternalModule && fn <= FuncRangeCheckExternalModule) {
|
||||
p1 = fn - (int)FuncRangeCheckInternalModule;
|
||||
fn = (int)FuncRangeCheckInternalModule;
|
||||
} else if (fn >= FuncBindInternalModule && fn <= FuncBindExternalModule) {
|
||||
p1 = fn - (int)FuncBindInternalModule;
|
||||
fn = (int)FuncBindInternalModule;
|
||||
}
|
||||
node["func"] = LookupValue(customFnLut, fn);
|
||||
|
||||
bool add_comma = true;
|
||||
std::string def;
|
||||
switch(fn) {
|
||||
case FuncOverrideCH1:
|
||||
def += std::to_string(p1);
|
||||
def += ",";
|
||||
def += std::to_string(rhs.param);
|
||||
break;
|
||||
case FuncTrainer:
|
||||
def += LookupValue(trainerLut, p1);
|
||||
break;
|
||||
case FuncPlaySound:
|
||||
def += LookupValue(soundLut, rhs.param);
|
||||
break;
|
||||
case FuncPlayPrompt:
|
||||
case FuncPlayScript:
|
||||
case FuncBackgroundMusic:
|
||||
def += std::string(rhs.paramarm);
|
||||
break;
|
||||
case FuncReset:
|
||||
def += LookupValue(resetLut, rhs.param);
|
||||
if (def.empty()) {
|
||||
def += std::to_string(rhs.param - resetLut.size());
|
||||
}
|
||||
break;
|
||||
case FuncSetTimer1: {
|
||||
def += LookupValue(resetLut, p1);
|
||||
def += ",";
|
||||
def += std::to_string(rhs.param);
|
||||
} break;
|
||||
case FuncPlayValue:
|
||||
case FuncVolume:
|
||||
case FuncBacklight: {
|
||||
def += YamlRawSourceEncode(RawSource(rhs.param));
|
||||
} break;
|
||||
case FuncAdjustGV1: {
|
||||
// + GV #
|
||||
def += std::to_string(p1);
|
||||
def += ",";
|
||||
def += LookupValue(gvarModeLut, rhs.adjustMode);
|
||||
def += ",";
|
||||
|
||||
switch(rhs.adjustMode) {
|
||||
case FUNC_ADJUST_GVAR_CONSTANT:
|
||||
case FUNC_ADJUST_GVAR_INCDEC:
|
||||
def += std::to_string(rhs.param);
|
||||
break;
|
||||
case FUNC_ADJUST_GVAR_GVAR:
|
||||
case FUNC_ADJUST_GVAR_SOURCE: {
|
||||
def += YamlRawSourceEncode(RawSource(rhs.param));
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
case FuncRangeCheckInternalModule:
|
||||
case FuncBindInternalModule: {
|
||||
def += LookupValue(moduleLut, p1);
|
||||
} break;
|
||||
case FuncLogs:
|
||||
def += std::to_string(rhs.param);
|
||||
break;
|
||||
default:
|
||||
add_comma = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fnHasEnable(rhs.func)) {
|
||||
if (add_comma) {
|
||||
def += ",";
|
||||
}
|
||||
def += std::to_string((int)rhs.enabled);
|
||||
} else if(fnHasRepeat(rhs.func)) {
|
||||
if (add_comma) {
|
||||
def += ",";
|
||||
}
|
||||
if (rhs.repeatParam == 0) {
|
||||
def += "1x";
|
||||
} else if (rhs.repeatParam == -1) {
|
||||
def += "!1x";
|
||||
} else {
|
||||
def += std::to_string(rhs.repeatParam);
|
||||
}
|
||||
}
|
||||
|
||||
if (!def.empty()) {
|
||||
node["def"] = def;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<CustomFunctionData>::decode(const Node& node,
|
||||
CustomFunctionData& rhs)
|
||||
{
|
||||
node["swtch"] >> rhs.swtch;
|
||||
|
||||
int func = 0;
|
||||
node["func"] >> customFnLut >> func;
|
||||
rhs.func = (AssignFunc)func;
|
||||
|
||||
std::string def_str;
|
||||
node["def"] >> def_str;
|
||||
std::stringstream def(def_str);
|
||||
|
||||
switch(rhs.func) {
|
||||
case FuncOverrideCH1: {
|
||||
int ch=0;
|
||||
def >> ch;
|
||||
rhs.func = (AssignFunc)((int)rhs.func + ch);
|
||||
def.ignore();
|
||||
def >> rhs.param;
|
||||
} break;
|
||||
case FuncTrainer: {
|
||||
std::string value_str;
|
||||
getline(def, value_str, ',');
|
||||
int value=0;
|
||||
Node(value_str) >> trainerLut >> value;
|
||||
rhs.func = (AssignFunc)((int)rhs.func + value);
|
||||
} break;
|
||||
case FuncPlaySound: {
|
||||
std::string snd;
|
||||
getline(def, snd, ',');
|
||||
Node(snd) >> soundLut >> rhs.param;
|
||||
} break;
|
||||
case FuncPlayPrompt:
|
||||
case FuncPlayScript:
|
||||
case FuncBackgroundMusic: {
|
||||
std::string file_str;
|
||||
getline(def, file_str, ',');
|
||||
strncpy(rhs.paramarm, file_str.c_str(), sizeof(rhs.paramarm)-1);
|
||||
} break;
|
||||
case FuncReset: {
|
||||
std::string rst_str;
|
||||
getline(def, rst_str, ',');
|
||||
try {
|
||||
rhs.param = std::stoi(rst_str);
|
||||
rhs.param += resetLut.size();
|
||||
break;
|
||||
} catch(...) {}
|
||||
Node(rst_str.c_str()) >> resetLut >> rhs.param;
|
||||
} break;
|
||||
case FuncSetTimer1: {
|
||||
// + timer #
|
||||
std::string tmr_str;
|
||||
getline(def, tmr_str, ',');
|
||||
int tmr = 0;
|
||||
Node(tmr_str) >> resetLut >> tmr;
|
||||
rhs.func = (AssignFunc)((int)rhs.func + tmr);
|
||||
def >> rhs.param;
|
||||
} break;
|
||||
case FuncPlayValue:
|
||||
case FuncVolume:
|
||||
case FuncBacklight: {
|
||||
std::string src_str;
|
||||
getline(def, src_str, ',');
|
||||
rhs.param = YamlRawSourceDecode(src_str).toValue();
|
||||
} break;
|
||||
case FuncAdjustGV1: {
|
||||
// + GV #
|
||||
int gvar_idx=0;
|
||||
def >> gvar_idx;
|
||||
rhs.func = (AssignFunc)((int)rhs.func + gvar_idx);
|
||||
def.ignore();
|
||||
|
||||
std::string mode;
|
||||
getline(def, mode, ',');
|
||||
Node(mode) >> gvarModeLut >> rhs.adjustMode;
|
||||
switch(rhs.adjustMode) {
|
||||
case FUNC_ADJUST_GVAR_CONSTANT:
|
||||
case FUNC_ADJUST_GVAR_INCDEC:
|
||||
def >> rhs.param;
|
||||
break;
|
||||
case FUNC_ADJUST_GVAR_GVAR:
|
||||
case FUNC_ADJUST_GVAR_SOURCE: {
|
||||
std::string src_str;
|
||||
getline(def, src_str, ',');
|
||||
RawSource src;
|
||||
Node(src_str) >> src;
|
||||
rhs.param = src.toValue();
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
case FuncRangeCheckInternalModule:
|
||||
case FuncBindInternalModule: {
|
||||
// DANGEROUS_FUNCTIONS...
|
||||
// + module # ???
|
||||
std::string mod;
|
||||
getline(def, mod, ',');
|
||||
int module=0;
|
||||
Node(mod) >> moduleLut >> module;
|
||||
rhs.func = (AssignFunc)((int)rhs.func + module);
|
||||
} break;
|
||||
case FuncLogs: {
|
||||
int param = 0;
|
||||
def >> param;
|
||||
rhs.param = param;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (fnHasEnable(rhs.func)) {
|
||||
int en = 0;
|
||||
def >> en;
|
||||
rhs.enabled = en;
|
||||
} else if(fnHasRepeat(rhs.func)) {
|
||||
std::string repeat;
|
||||
getline(def, repeat);
|
||||
if (repeat == "1x") {
|
||||
rhs.repeatParam = 0;
|
||||
} else if (repeat == "!1x") {
|
||||
rhs.repeatParam = -1;
|
||||
} else {
|
||||
try {
|
||||
rhs.repeatParam = std::stoi(repeat);
|
||||
} catch(...) {}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "customfunctiondata.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<CustomFunctionData> {
|
||||
static Node encode(const CustomFunctionData& rhs);
|
||||
static bool decode(const Node& node, CustomFunctionData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "yaml_expodata.h"
|
||||
#include "yaml_mixdata.h"
|
||||
#include "yaml_rawswitch.h"
|
||||
#include "yaml_rawsource.h"
|
||||
#include "curvereference.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
Node convert<ExpoData>::encode(const ExpoData& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["srcRaw"] = rhs.srcRaw;
|
||||
node["scale"] = rhs.scale;
|
||||
node["mode"] = rhs.mode; // InputMode
|
||||
node["chn"] = rhs.chn;
|
||||
node["swtch"] = rhs.swtch;
|
||||
node["flightModes"] = YamlWriteFlightModes(rhs.flightModes);
|
||||
node["weight"] = YamlWriteMixWeight(rhs.weight);
|
||||
node["offset"] = rhs.offset; // YamlWriteMixWeight
|
||||
node["curve"] = rhs.curve;
|
||||
node["carryTrim"] = rhs.carryTrim;
|
||||
node["name"] = rhs.name;
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<ExpoData>::decode(const Node& node, ExpoData& rhs)
|
||||
{
|
||||
node["srcRaw"] >> rhs.srcRaw;
|
||||
node["scale"] >> rhs.scale;
|
||||
node["mode"] >> rhs.mode; // InputMode
|
||||
node["chn"] >> rhs.chn;
|
||||
node["swtch"] >> rhs.swtch;
|
||||
if (node["flightModes"]) {
|
||||
rhs.flightModes = YamlReadFlightModes(node["flightModes"]);
|
||||
}
|
||||
if (node["weight"]) {
|
||||
rhs.weight = YamlReadMixWeight(node["weight"]);
|
||||
}
|
||||
if (node["offset"]) {
|
||||
rhs.offset = YamlReadMixWeight(node["offset"]);
|
||||
}
|
||||
node["curve"] >> rhs.curve;
|
||||
node["carryTrim"] >> rhs.carryTrim;
|
||||
node["name"] >> rhs.name;
|
||||
return true;
|
||||
}
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "input_data.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<ExpoData> {
|
||||
static Node encode(const ExpoData& rhs);
|
||||
static bool decode(const Node& node, ExpoData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* 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 "yaml_generalsettings.h"
|
||||
#include "yaml_customfunctiondata.h"
|
||||
#include "yaml_trainerdata.h"
|
||||
#include "yaml_calibdata.h"
|
||||
#include "yaml_switchconfig.h"
|
||||
#include "yaml_moduledata.h"
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "edgetxinterface.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
const YamlLookupTable beeperModeLut = {
|
||||
{ GeneralSettings::BEEPER_QUIET, "mode_quiet" },
|
||||
{ GeneralSettings::BEEPER_ALARMS_ONLY, "mode_alarms" },
|
||||
{ GeneralSettings::BEEPER_NOKEYS, "mode_nokeys" },
|
||||
{ GeneralSettings::BEEPER_ALL, "mode_all" },
|
||||
};
|
||||
|
||||
enum BacklightMode {
|
||||
e_backlight_mode_off = 0,
|
||||
e_backlight_mode_keys = 1,
|
||||
e_backlight_mode_sticks = 2,
|
||||
e_backlight_mode_all = e_backlight_mode_keys+e_backlight_mode_sticks,
|
||||
e_backlight_mode_on
|
||||
};
|
||||
|
||||
const YamlLookupTable backlightModeLut = {
|
||||
{ e_backlight_mode_off, "backlight_mode_off" },
|
||||
{ e_backlight_mode_keys, "backlight_mode_keys" },
|
||||
{ e_backlight_mode_sticks, "backlight_mode_sticks" },
|
||||
{ e_backlight_mode_all, "backlight_mode_all" },
|
||||
{ e_backlight_mode_on, "backlight_mode_on" },
|
||||
};
|
||||
|
||||
const YamlLookupTable bluetoothModeLut = {
|
||||
{ GeneralSettings::BLUETOOTH_MODE_OFF, "OFF" },
|
||||
{ GeneralSettings::BLUETOOTH_MODE_TELEMETRY, "TELEMETRY" },
|
||||
{ GeneralSettings::BLUETOOTH_MODE_TRAINER, "TRAINER" },
|
||||
};
|
||||
|
||||
const YamlLookupTable uartModeLut = {
|
||||
{ GeneralSettings::AUX_SERIAL_OFF, "MODE_NONE" },
|
||||
{ GeneralSettings::AUX_SERIAL_TELE_MIRROR, "MODE_TELEMETRY_MIRROR" },
|
||||
{ GeneralSettings::AUX_SERIAL_TELE_IN, "MODE_TELEMETRY" },
|
||||
{ GeneralSettings::AUX_SERIAL_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
|
||||
{ GeneralSettings::AUX_SERIAL_LUA, "MODE_LUA" },
|
||||
};
|
||||
|
||||
const YamlLookupTable antennaModeLut = {
|
||||
{ GeneralSettings::ANTENNA_MODE_INTERNAL, "MODE_INTERNAL" },
|
||||
{ GeneralSettings::ANTENNA_MODE_ASK, "MODE_ASK" },
|
||||
{ GeneralSettings::ANTENNA_MODE_PER_MODEL, "MODE_PER_MODEL" },
|
||||
{ GeneralSettings::ANTENNA_MODE_EXTERNAL, "MODE_EXTERNAL" },
|
||||
{ GeneralSettings::ANTENNA_MODE_INTERNAL_EXTERNAL, "MODE_INTERNAL_EXTERNAL" },
|
||||
};
|
||||
|
||||
const YamlLookupTable internalModuleLut = {
|
||||
{ MODULE_TYPE_NONE, "TYPE_NONE" },
|
||||
{ MODULE_TYPE_PPM, "TYPE_PPM" },
|
||||
{ MODULE_TYPE_XJT_PXX1, "TYPE_XJT_PXX1" },
|
||||
{ MODULE_TYPE_ISRM_PXX2, "TYPE_ISRM_PXX2" },
|
||||
{ MODULE_TYPE_DSM2, "TYPE_DSM2" },
|
||||
{ MODULE_TYPE_CROSSFIRE, "TYPE_CROSSFIRE" },
|
||||
{ MODULE_TYPE_MULTIMODULE, "TYPE_MULTIMODULE" },
|
||||
{ MODULE_TYPE_R9M_PXX1, "TYPE_R9M_PXX1" },
|
||||
{ MODULE_TYPE_R9M_PXX2, "TYPE_R9M_PXX2" },
|
||||
{ MODULE_TYPE_R9M_LITE_PXX1, "TYPE_R9M_LITE_PXX1" },
|
||||
{ MODULE_TYPE_R9M_LITE_PXX2, "TYPE_R9M_LITE_PXX2" },
|
||||
{ MODULE_TYPE_GHOST, "TYPE_GHOST" },
|
||||
{ MODULE_TYPE_R9M_LITE_PRO_PXX2, "TYPE_R9M_LITE_PRO_PXX2" },
|
||||
{ MODULE_TYPE_SBUS, "TYPE_SBUS" },
|
||||
{ MODULE_TYPE_XJT_LITE_PXX2, "TYPE_XJT_LITE_PXX2" },
|
||||
{ MODULE_TYPE_FLYSKY, "TYPE_FLYSKY" },
|
||||
};
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
|
||||
ENUM_CONVERTER(GeneralSettings::BeeperMode, beeperModeLut);
|
||||
|
||||
Node convert<GeneralSettings>::encode(const GeneralSettings& rhs)
|
||||
{
|
||||
Node node;
|
||||
|
||||
std::string board = getCurrentFirmware()->getFlavour().toStdString();
|
||||
node["board"] = board;
|
||||
|
||||
node["version"] = CPN_CURRENT_SETTINGS_VERSION;
|
||||
|
||||
YamlCalibData calib(rhs.calibMid, rhs.calibSpanNeg, rhs.calibSpanPos);
|
||||
node["calib"] = calib;
|
||||
|
||||
node["currModel"] = rhs.currModelIndex;
|
||||
node["currModelFilename"] = patchFilenameToYaml(rhs.currModelFilename);
|
||||
node["contrast"] = rhs.contrast;
|
||||
node["vBatWarn"] = rhs.vBatWarn;
|
||||
node["txVoltageCalibration"] = rhs.txVoltageCalibration;
|
||||
|
||||
node["vBatMin"] = rhs.vBatMin + 90;
|
||||
node["vBatMax"] = rhs.vBatMax + 120;
|
||||
|
||||
node["backlightMode"] = backlightModeLut << std::abs(rhs.backlightMode);
|
||||
node["trainer"] = rhs.trainer;
|
||||
node["view"] = rhs.view;
|
||||
node["fai"] = (int)rhs.fai;
|
||||
node["disableMemoryWarning"] = (int)rhs.disableMemoryWarning;
|
||||
node["beepMode"] = rhs.beeperMode;
|
||||
node["disableAlarmWarning"] = (int)rhs.disableAlarmWarning;
|
||||
node["disableRssiPoweroffAlarm"] = (int)rhs.disableRssiPoweroffAlarm;
|
||||
node["USBMode"] = rhs.usbMode;
|
||||
node["jackMode"] = rhs.jackMode;
|
||||
node["hapticMode"] = rhs.hapticMode;
|
||||
node["stickMode"] = rhs.stickMode;
|
||||
node["timezone"] = rhs.timezone;
|
||||
node["adjustRTC"] = (int)rhs.adjustRTC;
|
||||
node["inactivityTimer"] = rhs.inactivityTimer;
|
||||
node["telemetryBaudrate"] = rhs.telemetryBaudrate; // TODO: conversion???
|
||||
node["internalModule"] = LookupValue(internalModuleLut, rhs.internalModule);
|
||||
node["splashMode"] = rhs.splashMode; // TODO: B&W only
|
||||
node["lightAutoOff"] = rhs.backlightDelay;
|
||||
node["templateSetup"] = rhs.templateSetup;
|
||||
node["hapticLength"] = rhs.hapticLength + 2;
|
||||
node["speakerPitch"] = rhs.speakerPitch * 15;
|
||||
node["hapticStrength"] = rhs.hapticStrength + 2;
|
||||
node["beepLength"] = rhs.beeperLength + 2;
|
||||
node["gpsFormat"] = rhs.gpsFormat;
|
||||
node["speakerVolume"] = rhs.speakerVolume + 12;
|
||||
node["backlightBright"] = rhs.backlightBright;
|
||||
node["switchesDelay"] = rhs.switchesDelay;
|
||||
node["globalTimer"] = rhs.globalTimer;
|
||||
node["bluetoothName"] = rhs.bluetoothName;
|
||||
node["bluetoothBaudrate"] = rhs.bluetoothBaudrate;
|
||||
node["bluetoothMode"] = bluetoothModeLut << rhs.bluetoothMode;
|
||||
node["countryCode"] = rhs.countryCode;
|
||||
node["jitterFilter"] = (int)rhs.jitterFilter;
|
||||
node["disableRtcWarning"] = (int)rhs.rtcCheckDisable; // TODO: verify
|
||||
node["keysBacklight"] = (int)rhs.keysBacklight;
|
||||
node["imperial"] = rhs.imperial;
|
||||
node["ttsLanguage"] = rhs.ttsLanguage;
|
||||
node["beepVolume"] = rhs.beepVolume + 2;
|
||||
node["wavVolume"] = rhs.wavVolume + 2;
|
||||
node["varioVolume"] = rhs.varioVolume + 2;
|
||||
node["varioPitch"] = rhs.varioPitch * 10;
|
||||
node["varioRange"] = rhs.varioRange * 15;
|
||||
node["varioRepeat"] = rhs.varioRepeat;
|
||||
node["backgroundVolume"] = rhs.backgroundVolume + 2;
|
||||
node["auxSerialMode"] = uartModeLut << rhs.auxSerialMode;
|
||||
node["aux2SerialMode"] = uartModeLut << rhs.aux2SerialMode;
|
||||
node["antennaMode"] = antennaModeLut << rhs.antennaMode;
|
||||
node["backlightColor"] = rhs.backlightColor;
|
||||
|
||||
for (int i = 0; i < CPN_MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
const CustomFunctionData& fn = rhs.customFn[i];
|
||||
if (!fn.isEmpty()) {
|
||||
node["customFn"][std::to_string(i)] = fn;
|
||||
}
|
||||
}
|
||||
|
||||
Node sticksConfig;
|
||||
sticksConfig = YamlStickConfig(rhs.stickName);
|
||||
if (sticksConfig && sticksConfig.IsMap()) {
|
||||
node["sticksConfig"] = sticksConfig;
|
||||
}
|
||||
|
||||
Node switchConfig;
|
||||
switchConfig = YamlSwitchConfig(rhs.switchName, rhs.switchConfig);
|
||||
if (switchConfig && switchConfig.IsMap()) {
|
||||
node["switchConfig"] = switchConfig;
|
||||
}
|
||||
|
||||
Node potsConfig;
|
||||
potsConfig = YamlPotConfig(rhs.potName, rhs.potConfig);
|
||||
if (potsConfig && potsConfig.IsMap()) {
|
||||
node["potsConfig"] = potsConfig;
|
||||
}
|
||||
|
||||
Node slidersConfig;
|
||||
slidersConfig = YamlSliderConfig(rhs.sliderName, rhs.sliderConfig);
|
||||
if (slidersConfig && slidersConfig.IsMap()) {
|
||||
node["slidersConfig"] = slidersConfig;
|
||||
}
|
||||
|
||||
// Color lcd theme settings are not used in EdgeTx
|
||||
// RadioTheme::ThemeData themeData;
|
||||
|
||||
node["ownerRegistrationID"] = rhs.registrationId;
|
||||
|
||||
// Gyro (for now only xlites)
|
||||
node["gyroMax"] = rhs.gyroMax;
|
||||
node["gyroOffset"] = rhs.gyroOffset;
|
||||
|
||||
// OneBit sampling (X9D only?)
|
||||
node["uartSampleMode"] = rhs.uartSampleMode;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<GeneralSettings>::decode(const Node& node, GeneralSettings& rhs)
|
||||
{
|
||||
if (!node.IsMap()) return false;
|
||||
|
||||
// for (const auto& n : node) {
|
||||
// qDebug() << QString::fromStdString(n.first.Scalar());
|
||||
// }
|
||||
|
||||
node["version"] >> rhs.version;
|
||||
|
||||
// Decoding uses profile firmare therefore all conversions are performed on the fly
|
||||
// So set board to firmware board
|
||||
// However we should alert users that conversions may have occured
|
||||
// If conversion should rename file with _converted suffix as done for bin
|
||||
// Need to pass back messages and flags like converted so they can be handled in a more suitable section
|
||||
|
||||
rhs.variant = Board::BOARD_UNKNOWN;
|
||||
|
||||
std::string flavour;
|
||||
node["board"] >> flavour;
|
||||
|
||||
auto fw = getCurrentFirmware();
|
||||
auto msfw = Firmware::getFirmwareForFlavour(QString(flavour.c_str()));
|
||||
|
||||
if (flavour.empty()) {
|
||||
qDebug() << "Warning: Settings file does not contain board flavour! Default firmware board will be used";
|
||||
flavour = msfw->getFlavour().toStdString();
|
||||
}
|
||||
|
||||
qDebug() << "Settings version:" << rhs.version << "File flavour:" << flavour.c_str() << "Firmware flavour:" << fw->getFlavour();
|
||||
|
||||
if (fw->getFlavour().toStdString() != flavour) {
|
||||
QString prmpt = QCoreApplication::translate("YamlGeneralSettings", "File board (%1) does not match current profile board (%2), models and settings will be converted where possible.\n\nDo you wish to continue?").arg(Boards::getBoardName(msfw->getBoard())).arg(Boards::getBoardName(fw->getBoard()));
|
||||
|
||||
if (QMessageBox::question(NULL, CPN_STR_APP_NAME, prmpt, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) != QMessageBox::Yes) {
|
||||
// TODO: this triggers an error in the calling code so we need a graceful way to handle
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rhs.variant = fw->getBoard();
|
||||
|
||||
YamlCalibData calib;
|
||||
node["calib"] >> calib;
|
||||
calib.copy(rhs.calibMid, rhs.calibSpanNeg, rhs.calibSpanPos);
|
||||
|
||||
node["currModel"] >> rhs.currModelIndex;
|
||||
node["currModelFilename"] >> rhs.currModelFilename;
|
||||
node["contrast"] >> rhs.contrast;
|
||||
node["vBatWarn"] >> rhs.vBatWarn;
|
||||
node["txVoltageCalibration"] >> rhs.txVoltageCalibration;
|
||||
|
||||
node["vBatMin"] >> ioffset_int(rhs.vBatMin, 90);
|
||||
node["vBatMax"] >> ioffset_int(rhs.vBatMax, 120);
|
||||
|
||||
node["backlightMode"] >> backlightModeLut >> rhs.backlightMode;
|
||||
node["trainer"] >> rhs.trainer;
|
||||
node["view"] >> rhs.view;
|
||||
node["fai"] >> rhs.fai;
|
||||
node["disableMemoryWarning"] >> rhs.disableMemoryWarning;
|
||||
node["beepMode"] >> rhs.beeperMode;
|
||||
node["disableAlarmWarning"] >> rhs.disableAlarmWarning;
|
||||
node["disableRssiPoweroffAlarm"] >> rhs.disableRssiPoweroffAlarm;
|
||||
node["USBMode"] >> rhs.usbMode;
|
||||
node["jackMode"] >> rhs.jackMode;
|
||||
node["hapticMode"] >> rhs.hapticMode;
|
||||
node["stickMode"] >> rhs.stickMode;
|
||||
node["timezone"] >> rhs.timezone;
|
||||
node["adjustRTC"] >> rhs.adjustRTC;
|
||||
node["inactivityTimer"] >> rhs.inactivityTimer;
|
||||
node["telemetryBaudrate"] >> rhs.telemetryBaudrate; // TODO: conversion???
|
||||
|
||||
if (node["internalModule"]) {
|
||||
node["internalModule"] >> internalModuleLut >> rhs.internalModule;
|
||||
} else {
|
||||
rhs.internalModule = Boards::getDefaultInternalModules(fw->getBoard());
|
||||
}
|
||||
|
||||
node["splashMode"] >> rhs.splashMode; // TODO: B&W only
|
||||
node["lightAutoOff"] >> rhs.backlightDelay;
|
||||
node["templateSetup"] >> rhs.templateSetup;
|
||||
node["hapticLength"] >> ioffset_int(rhs.hapticLength, 2);
|
||||
node["speakerPitch"] >> ifactor<unsigned int>(rhs.speakerPitch, 15);
|
||||
node["hapticStrength"] >> ioffset_int(rhs.hapticStrength, 2);
|
||||
node["beepLength"] >> ioffset_int(rhs.beeperLength, 2);
|
||||
node["gpsFormat"] >> rhs.gpsFormat;
|
||||
node["speakerVolume"] >> ioffset_int(rhs.speakerVolume, 12);
|
||||
node["backlightBright"] >> rhs.backlightBright;
|
||||
node["switchesDelay"] >> rhs.switchesDelay;
|
||||
node["globalTimer"] >> rhs.globalTimer;
|
||||
node["bluetoothName"] >> rhs.bluetoothName;
|
||||
node["bluetoothBaudrate"] >> rhs.bluetoothBaudrate;
|
||||
node["bluetoothMode"] >> bluetoothModeLut >> rhs.bluetoothMode;
|
||||
node["countryCode"] >> rhs.countryCode;
|
||||
node["jitterFilter"] >> rhs.jitterFilter;
|
||||
node["disableRtcWarning"] >> rhs.rtcCheckDisable; // TODO: verify
|
||||
node["keysBacklight"] >> rhs.keysBacklight;
|
||||
node["imperial"] >> rhs.imperial;
|
||||
node["ttsLanguage"] >> rhs.ttsLanguage;
|
||||
node["beepVolume"] >> ioffset_int(rhs.beepVolume, 2);
|
||||
node["wavVolume"] >> ioffset_int(rhs.wavVolume, 2);
|
||||
node["varioVolume"] >> ioffset_int(rhs.varioVolume, 2);
|
||||
node["varioPitch"] >> ifactor<int>(rhs.varioPitch, 10);
|
||||
node["varioRange"] >> ifactor<int>(rhs.varioRange, 15);
|
||||
node["varioRepeat"] >> rhs.varioRepeat;
|
||||
node["backgroundVolume"] >> ioffset_int(rhs.backgroundVolume, 2);
|
||||
node["auxSerialMode"] >> uartModeLut >> rhs.auxSerialMode;
|
||||
node["aux2SerialMode"] >> uartModeLut >> rhs.aux2SerialMode;
|
||||
node["antennaMode"] >> antennaModeLut >> rhs.antennaMode;
|
||||
node["backlightColor"] >> rhs.backlightColor;
|
||||
node["customFn"] >> rhs.customFn;
|
||||
|
||||
YamlStickConfig stickConfig;
|
||||
node["sticksConfig"] >> stickConfig;
|
||||
stickConfig.copy(rhs.stickName);
|
||||
|
||||
YamlSwitchConfig switchConfig;
|
||||
node["switchConfig"] >> switchConfig;
|
||||
switchConfig.copy(rhs.switchName, rhs.switchConfig);
|
||||
|
||||
YamlPotConfig potsConfig;
|
||||
node["potsConfig"] >> potsConfig;
|
||||
potsConfig.copy(rhs.potName, rhs.potConfig);
|
||||
|
||||
YamlSliderConfig slidersConfig;
|
||||
node["slidersConfig"] >> slidersConfig;
|
||||
slidersConfig.copy(rhs.sliderName, rhs.sliderConfig);
|
||||
|
||||
// Color lcd theme settings are not used in EdgeTx
|
||||
// RadioTheme::ThemeData themeData;
|
||||
|
||||
node["ownerRegistrationID"] >> rhs.registrationId;
|
||||
|
||||
// Gyro (for now only xlites)
|
||||
node["gyroMax"] >> rhs.gyroMax;
|
||||
node["gyroOffset"] >> rhs.gyroOffset;
|
||||
|
||||
// OneBit sampling (X9D only?)
|
||||
node["uartSampleMode"] >> rhs.uartSampleMode;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "generalsettings.h"
|
||||
|
||||
namespace YAML {
|
||||
|
||||
template<>
|
||||
struct convert<GeneralSettings> {
|
||||
|
||||
static Node encode(const GeneralSettings& rhs);
|
||||
static bool decode(const Node& node, GeneralSettings& rhs);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "yaml_logicalswitchdata.h"
|
||||
#include "yaml_rawswitch.h"
|
||||
#include "yaml_rawsource.h"
|
||||
|
||||
static const YamlLookupTable funcLut = {
|
||||
{LS_FN_OFF, "FUNC_NONE"},
|
||||
{LS_FN_VEQUAL, "FUNC_VEQUAL"},
|
||||
{LS_FN_VALMOSTEQUAL, "FUNC_VALMOSTEQUAL"},
|
||||
{LS_FN_VPOS, "FUNC_VPOS"},
|
||||
{LS_FN_VNEG, "FUNC_VNEG"},
|
||||
{LS_FN_APOS, "FUNC_APOS"},
|
||||
{LS_FN_ANEG, "FUNC_ANEG"},
|
||||
{LS_FN_AND, "FUNC_AND"},
|
||||
{LS_FN_OR, "FUNC_OR"},
|
||||
{LS_FN_XOR, "FUNC_XOR"},
|
||||
{LS_FN_EDGE, "FUNC_EDGE"},
|
||||
{LS_FN_EQUAL, "FUNC_EQUAL"},
|
||||
{LS_FN_GREATER, "FUNC_GREATER"},
|
||||
{LS_FN_LESS, "FUNC_LESS"},
|
||||
{LS_FN_DPOS, "FUNC_DIFFEGREATER"},
|
||||
{LS_FN_DAPOS, "FUNC_ADIFFEGREATER"},
|
||||
{LS_FN_TIMER, "FUNC_TIMER"},
|
||||
{LS_FN_STICKY, "FUNC_STICKY"},
|
||||
};
|
||||
|
||||
static int timerValue2lsw(uint32_t t)
|
||||
{
|
||||
if (t < 20) {
|
||||
return t - 129;
|
||||
} else if (600) {
|
||||
return t / 5 - 113;
|
||||
} else {
|
||||
return t / 10 - 53;
|
||||
}
|
||||
}
|
||||
// val = [-129,-110] => [0,19] (step 1)
|
||||
// val = [-109,6] => [20,595] (step 5)
|
||||
// val = [7,122] => [600,1750] (step 10)
|
||||
//
|
||||
static int lswTimerValue(int val)
|
||||
{
|
||||
return (val < -109 ? 129+val : (val < 7 ? (113+val)*5 : (53+val)*10));
|
||||
}
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
Node convert<LogicalSwitchData>::encode(const LogicalSwitchData& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["func"] = funcLut << rhs.func;
|
||||
|
||||
std::string def;
|
||||
|
||||
switch (rhs.getFunctionFamily()) {
|
||||
case LS_FAMILY_VBOOL:
|
||||
case LS_FAMILY_STICKY: {
|
||||
def += YamlRawSwitchEncode(RawSwitch(rhs.val1));
|
||||
def += ",";
|
||||
def += YamlRawSwitchEncode(RawSwitch(rhs.val2));
|
||||
} break;
|
||||
|
||||
case LS_FAMILY_EDGE: {
|
||||
def += YamlRawSwitchEncode(RawSwitch(rhs.val1));
|
||||
def += ",";
|
||||
def += std::to_string(lswTimerValue(rhs.val2));
|
||||
def += ",";
|
||||
def += std::to_string(lswTimerValue(rhs.val3));
|
||||
} break;
|
||||
|
||||
case LS_FAMILY_VCOMP: {
|
||||
def += YamlRawSourceEncode(RawSource(rhs.val1));
|
||||
def += ",";
|
||||
def += YamlRawSourceEncode(RawSource(rhs.val2));
|
||||
} break;
|
||||
|
||||
case LS_FAMILY_TIMER: {
|
||||
def += std::to_string(lswTimerValue(rhs.val1));
|
||||
def += ",";
|
||||
def += std::to_string(lswTimerValue(rhs.val2));
|
||||
} break;
|
||||
|
||||
default: {
|
||||
def += YamlRawSourceEncode(RawSource(rhs.val1));
|
||||
def += ",";
|
||||
def += std::to_string(rhs.val2);
|
||||
} break;
|
||||
}
|
||||
|
||||
node["def"] = def;
|
||||
node["delay"] = rhs.delay;
|
||||
node["duration"] = rhs.duration;
|
||||
node["andsw"] = YamlRawSwitchEncode(RawSwitch(rhs.andsw));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<LogicalSwitchData>::decode(const Node& node,
|
||||
LogicalSwitchData& rhs)
|
||||
{
|
||||
node["func"] >> funcLut >> rhs.func;
|
||||
|
||||
std::string def_str;
|
||||
node["def"] >> def_str;
|
||||
std::stringstream def(def_str);
|
||||
|
||||
switch (rhs.getFunctionFamily()) {
|
||||
case LS_FAMILY_VBOOL:
|
||||
case LS_FAMILY_STICKY: {
|
||||
std::string sw_str;
|
||||
getline(def, sw_str, ',');
|
||||
rhs.val1 = YamlRawSwitchDecode(sw_str).toValue();
|
||||
getline(def, sw_str);
|
||||
rhs.val2 = YamlRawSwitchDecode(sw_str).toValue();
|
||||
} break;
|
||||
|
||||
case LS_FAMILY_EDGE: {
|
||||
std::string sw_str;
|
||||
getline(def, sw_str, ',');
|
||||
rhs.val1 = YamlRawSwitchDecode(sw_str).toValue();
|
||||
int v2=0, v3=0;
|
||||
def >> v2;
|
||||
rhs.val2 = timerValue2lsw(v2);
|
||||
def.ignore();
|
||||
if (def.peek() == '<') {
|
||||
rhs.val3 = -1;
|
||||
} else if (def.peek() == '-') {
|
||||
rhs.val3 = 0;
|
||||
} else {
|
||||
def >> v3;
|
||||
rhs.val3 = timerValue2lsw(v3);
|
||||
}
|
||||
} break;
|
||||
|
||||
case LS_FAMILY_VCOMP: {
|
||||
std::string src_str;
|
||||
getline(def, src_str, ',');
|
||||
rhs.val1 = YamlRawSourceDecode(src_str).toValue();
|
||||
getline(def, src_str);
|
||||
rhs.val2 = YamlRawSourceDecode(src_str).toValue();
|
||||
} break;
|
||||
|
||||
case LS_FAMILY_TIMER: {
|
||||
int v1=0, v2=0;
|
||||
def >> v1;
|
||||
rhs.val1 = timerValue2lsw(v1);
|
||||
def.ignore();
|
||||
def >> v2;
|
||||
rhs.val2 = timerValue2lsw(v2);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
std::string src_str;
|
||||
getline(def, src_str, ',');
|
||||
rhs.val1 = YamlRawSourceDecode(src_str).toValue();
|
||||
def >> rhs.val2;
|
||||
} break;
|
||||
}
|
||||
|
||||
node["delay"] >> rhs.delay;
|
||||
node["duration"] >> rhs.duration;
|
||||
|
||||
RawSwitch andsw;
|
||||
node["andsw"] >> andsw;
|
||||
rhs.andsw = andsw.toValue();
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "logicalswitchdata.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<LogicalSwitchData> {
|
||||
static Node encode(const LogicalSwitchData& rhs);
|
||||
static bool decode(const Node& node, LogicalSwitchData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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 "yaml_mixdata.h"
|
||||
#include "yaml_rawswitch.h"
|
||||
#include "yaml_rawsource.h"
|
||||
#include "curvereference.h"
|
||||
|
||||
static const YamlLookupTable mixMultiplexLut = {
|
||||
{ MLTPX_ADD, "ADD" },
|
||||
{ MLTPX_MUL, "MUL" },
|
||||
{ MLTPX_REP, "REPL" },
|
||||
};
|
||||
|
||||
#define GVAR_SMALL 128
|
||||
#define CPN_GV1 1024
|
||||
|
||||
int32_t YamlReadMixWeight(const YAML::Node& node)
|
||||
{
|
||||
std::string val = node.as<std::string>();
|
||||
if ((val.size() >= 4)
|
||||
&& (val[0] == '-')
|
||||
&& (val[1] == 'G')
|
||||
&& (val[2] == 'V')
|
||||
&& (val[3] >= '1')
|
||||
&& (val[3] <= '9')) {
|
||||
|
||||
return -10000 - std::stoi(val.substr(3));
|
||||
}
|
||||
|
||||
if ((val.size() >= 3)
|
||||
&& (val[0] == 'G')
|
||||
&& (val[1] == 'V')
|
||||
&& (val[2] >= '1')
|
||||
&& (val[2] <= '9')) {
|
||||
|
||||
return 10000 + std::stoi(val.substr(2));
|
||||
}
|
||||
|
||||
try {
|
||||
return std::stoi(val);
|
||||
} catch(...) {
|
||||
throw YAML::TypedBadConversion<int>(node.Mark());
|
||||
}
|
||||
}
|
||||
|
||||
std::string YamlWriteMixWeight(int32_t sval)
|
||||
{
|
||||
if (sval < -10000) {
|
||||
int n = -sval - 10000;
|
||||
return std::string("-GV") + std::to_string(n);
|
||||
} else if (sval > 10000) {
|
||||
int n = sval - 10000;
|
||||
return std::string("GV") + std::to_string(n);
|
||||
}
|
||||
|
||||
return std::to_string(sval);
|
||||
}
|
||||
|
||||
uint32_t YamlReadFlightModes(const YAML::Node& node)
|
||||
{
|
||||
std::string fm_str = node.as<std::string>();
|
||||
uint32_t bits = 0;
|
||||
uint32_t mask = 1;
|
||||
|
||||
for (uint32_t i = 0; i < fm_str.size(); i++) {
|
||||
if (fm_str[i] == '1') bits |= mask;
|
||||
mask <<= 1;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
std::string YamlWriteFlightModes(uint32_t val)
|
||||
{
|
||||
std::string fm_str;
|
||||
// TODO: constant for number of flight modes
|
||||
for (int i=0; i<9; i++) {
|
||||
uint32_t bit = (val >> i) & 1;
|
||||
fm_str += bit ? "1" : "0";
|
||||
}
|
||||
return fm_str;
|
||||
}
|
||||
|
||||
static const YamlLookupTable dummy = {};
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
ENUM_CONVERTER(MltpxValue, mixMultiplexLut);
|
||||
|
||||
Node convert<CurveReference>::encode(const CurveReference& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["type"] = (int)rhs.type;
|
||||
node["value"] = YamlWriteMixWeight(rhs.value);
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<CurveReference>::decode(const Node& node, CurveReference& rhs)
|
||||
{
|
||||
// no symbolic value defined in radio
|
||||
int type = 0;
|
||||
node["type"] >> type;
|
||||
rhs.type = (CurveReference::CurveRefType)type;
|
||||
if (node["value"]) {
|
||||
rhs.value = YamlReadMixWeight(node["value"]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Node convert<MixData>::encode(const MixData& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["destCh"] = rhs.destCh - 1;
|
||||
node["srcRaw"] = rhs.srcRaw;
|
||||
node["weight"] = YamlWriteMixWeight(rhs.weight);
|
||||
node["swtch"] = rhs.swtch;
|
||||
node["curve"] = rhs.curve;
|
||||
node["delayUp"] = rhs.delayUp;
|
||||
node["delayDown"] = rhs.delayDown;
|
||||
node["speedUp"] = rhs.speedUp;
|
||||
node["speedDown"] = rhs.speedDown;
|
||||
node["carryTrim"] = rhs.carryTrim;
|
||||
node["mltpx"] = rhs.mltpx;
|
||||
node["mixWarn"] = rhs.mixWarn;
|
||||
node["flightModes"] = YamlWriteFlightModes(rhs.flightModes);
|
||||
node["offset"] = YamlWriteMixWeight(rhs.sOffset);
|
||||
node["name"] = rhs.name;
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<MixData>::decode(const Node& node, MixData& rhs)
|
||||
{
|
||||
node["destCh"] >> ioffset_int((int&)rhs.destCh, -1);
|
||||
node["srcRaw"] >> rhs.srcRaw;
|
||||
if (node["weight"]) {
|
||||
rhs.weight = YamlReadMixWeight(node["weight"]);
|
||||
}
|
||||
node["swtch"] >> rhs.swtch;
|
||||
node["curve"] >> rhs.curve;
|
||||
node["delayUp"] >> rhs.delayUp;
|
||||
node["delayDown"] >> rhs.delayDown;
|
||||
node["speedUp"] >> rhs.speedUp;
|
||||
node["speedDown"] >> rhs.speedDown;
|
||||
node["carryTrim"] >> rhs.carryTrim;
|
||||
node["mltpx"] >> rhs.mltpx;
|
||||
node["mixWarn"] >> rhs.mixWarn;
|
||||
if (node["flightModes"]) {
|
||||
rhs.flightModes = YamlReadFlightModes(node["flightModes"]);
|
||||
}
|
||||
if (node["offset"]) {
|
||||
rhs.sOffset = YamlReadMixWeight(node["offset"]);
|
||||
}
|
||||
node["name"] >> rhs.name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "yaml_ops.h"
|
||||
#include "mixdata.h"
|
||||
|
||||
int32_t YamlReadMixWeight(const YAML::Node& node);
|
||||
std::string YamlWriteMixWeight(int32_t sval);
|
||||
|
||||
uint32_t YamlReadFlightModes(const YAML::Node& node);
|
||||
std::string YamlWriteFlightModes(uint32_t val);
|
||||
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<CurveReference> {
|
||||
static Node encode(const CurveReference& rhs);
|
||||
static bool decode(const Node& node, CurveReference& rhs);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct convert<MixData> {
|
||||
static Node encode(const MixData& rhs);
|
||||
static bool decode(const Node& node, MixData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "modeldata.h"
|
||||
|
||||
namespace YAML {
|
||||
|
||||
template <>
|
||||
struct convert<TimerData> {
|
||||
static Node encode(const TimerData& rhs);
|
||||
static bool decode(const Node& node, TimerData& rhs);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct convert<FlightModeData> {
|
||||
static bool decode(const Node& node, FlightModeData& rhs);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct convert<ModelData> {
|
||||
static Node encode(const ModelData& rhs);
|
||||
static bool decode(const Node& node, ModelData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* 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 "yaml_moduledata.h"
|
||||
#include "moduledata.h"
|
||||
#include "rawsource.h"
|
||||
|
||||
// type: TYPE_MULTIMODULE
|
||||
// subType: 15,2
|
||||
// channelsStart: 0
|
||||
// channelsCount: 12
|
||||
// failsafeMode: NOT_SET
|
||||
// mod:
|
||||
// multi:
|
||||
// disableTelemetry: 0
|
||||
// disableMapping: 0
|
||||
// autoBindMode: 0
|
||||
// lowPowerMode: 0
|
||||
// optionValue: 0
|
||||
// receiverTelemetryOff: 0
|
||||
// receiverHigherChannels: 0
|
||||
|
||||
static const YamlLookupTable protocolLut = {
|
||||
{ PULSES_OFF, "TYPE_NONE" },
|
||||
{ PULSES_PPM, "TYPE_PPM" },
|
||||
{ PULSES_PXX_XJT_X16, "TYPE_XJT_PXX1" },
|
||||
{ PULSES_ACCESS_ISRM, "TYPE_ISRM_PXX2" },
|
||||
{ PULSES_LP45, "TYPE_DSM2" },
|
||||
{ PULSES_CROSSFIRE, "TYPE_CROSSFIRE" },
|
||||
{ PULSES_MULTIMODULE, "TYPE_MULTIMODULE" },
|
||||
{ PULSES_PXX_R9M, "TYPE_R9M_PXX1" },
|
||||
{ PULSES_ACCESS_R9M, "TYPE_R9M_PXX2" },
|
||||
{ PULSES_PXX_R9M_LITE, "TYPE_R9M_LITE_PXX1" },
|
||||
{ PULSES_ACCESS_R9M_LITE, "TYPE_R9M_LITE_PXX2" },
|
||||
{ PULSES_GHOST, "TYPE_GHOST" },
|
||||
{ PULSES_ACCESS_R9M_LITE_PRO, "TYPE_R9M_LITE_PRO_PXX2" },
|
||||
{ PULSES_SBUS, "TYPE_SBUS" },
|
||||
{ PULSES_XJT_LITE_X16, "TYPE_XJT_LITE_PXX2" },
|
||||
{ PULSES_AFHDS3, "TYPE_FLYSKY" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable xjtLut = {
|
||||
{ 0, "D16" },
|
||||
{ 1, "D8" },
|
||||
{ 2, "LR12" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable isrmLut = {
|
||||
{ 0, "ACCESS" },
|
||||
{ 1, "D16" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable r9mLut = {
|
||||
{ MODULE_SUBTYPE_R9M_FCC, "FCC" },
|
||||
{ MODULE_SUBTYPE_R9M_EU, "EU" },
|
||||
{ MODULE_SUBTYPE_R9M_EUPLUS, "EUPLUS" },
|
||||
{ MODULE_SUBTYPE_R9M_AUPLUS, "AUPLUS" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable dsmLut = {
|
||||
{ 0, "LP45" },
|
||||
{ 1, "DSM2" },
|
||||
{ 3, "DSMX" },
|
||||
};
|
||||
|
||||
static const YamlLookupTable failsafeLut = {
|
||||
{ FAILSAFE_NOT_SET, "NOT_SET" },
|
||||
{ FAILSAFE_HOLD, "HOLD" },
|
||||
{ FAILSAFE_CUSTOM, "CUSTOM" },
|
||||
{ FAILSAFE_NOPULSES, "NOPULSES" },
|
||||
{ FAILSAFE_RECEIVER, "RECEIVER" },
|
||||
};
|
||||
|
||||
enum MMRFrskySubtypes {
|
||||
MM_RF_FRSKY_SUBTYPE_D16,
|
||||
MM_RF_FRSKY_SUBTYPE_D8,
|
||||
MM_RF_FRSKY_SUBTYPE_D16_8CH,
|
||||
MM_RF_FRSKY_SUBTYPE_V8,
|
||||
MM_RF_FRSKY_SUBTYPE_D16_LBT,
|
||||
MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH,
|
||||
MM_RF_FRSKY_SUBTYPE_D8_CLONED,
|
||||
MM_RF_FRSKY_SUBTYPE_D16_CLONED
|
||||
};
|
||||
|
||||
// from radio/src/pulses/multi.cpp
|
||||
static void convertMultiProtocolToEtx(int *protocol, int *subprotocol)
|
||||
{
|
||||
if (*protocol == 3 && *subprotocol == 0) {
|
||||
*protocol = MODULE_SUBTYPE_MULTI_FRSKY + 1;
|
||||
*subprotocol = MM_RF_FRSKY_SUBTYPE_D8;
|
||||
return;
|
||||
}
|
||||
|
||||
if (*protocol == 3 && *subprotocol == 1) {
|
||||
*protocol = MODULE_SUBTYPE_MULTI_FRSKY + 1;
|
||||
*subprotocol = MM_RF_FRSKY_SUBTYPE_D8_CLONED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (*protocol == 25) {
|
||||
*protocol = MODULE_SUBTYPE_MULTI_FRSKY + 1;
|
||||
*subprotocol = MM_RF_FRSKY_SUBTYPE_V8;
|
||||
return;
|
||||
}
|
||||
|
||||
if (*protocol == 15) {
|
||||
*protocol = MODULE_SUBTYPE_MULTI_FRSKY + 1;
|
||||
|
||||
if (*subprotocol == 0)
|
||||
*subprotocol = MM_RF_FRSKY_SUBTYPE_D16;
|
||||
else if (*subprotocol == 1)
|
||||
*subprotocol = MM_RF_FRSKY_SUBTYPE_D16_8CH;
|
||||
else if (*subprotocol == 2)
|
||||
*subprotocol = MM_RF_FRSKY_SUBTYPE_D16_LBT;
|
||||
else if (*subprotocol == 3)
|
||||
*subprotocol = MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH;
|
||||
else if (*subprotocol == 4)
|
||||
*subprotocol = MM_RF_FRSKY_SUBTYPE_D16_CLONED;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (*protocol >= 25)
|
||||
*protocol -= 1;
|
||||
|
||||
if (*protocol >= 16)
|
||||
*protocol -= 1;
|
||||
}
|
||||
|
||||
void convertEtxProtocolToMulti(int *protocol, int *subprotocol)
|
||||
{
|
||||
// Special treatment for the FrSky entry...
|
||||
if (*protocol == MODULE_SUBTYPE_MULTI_FRSKY + 1) {
|
||||
if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D8) {
|
||||
//D8
|
||||
*protocol = 3;
|
||||
*subprotocol = 0;
|
||||
}
|
||||
else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D8_CLONED) {
|
||||
//D8
|
||||
*protocol = 3;
|
||||
*subprotocol = 1;
|
||||
}
|
||||
else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_V8) {
|
||||
//V8
|
||||
*protocol = 25;
|
||||
*subprotocol = 0;
|
||||
}
|
||||
else {
|
||||
*protocol = 15;
|
||||
if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16_8CH)
|
||||
*subprotocol = 1;
|
||||
else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16)
|
||||
*subprotocol = 0; // D16
|
||||
else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16_LBT)
|
||||
*subprotocol = 2;
|
||||
else if (*subprotocol == MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH)
|
||||
*subprotocol = 3;
|
||||
else
|
||||
*subprotocol = 4; // D16_CLONED
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 15 for Multimodule is FrskyX or D16 which we map as a protocol of 3 (FrSky)
|
||||
// all protos > frskyx are therefore also off by one
|
||||
if (*protocol >= 15)
|
||||
*protocol += 1;
|
||||
// 25 is again a FrSky *protocol (FrskyV) so shift again
|
||||
if (*protocol >= 25)
|
||||
*protocol += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int exportPpmDelay(int delay) { return (delay - 300) / 50; }
|
||||
static int importPpmDelay(int delay) { return 300 + 50 * delay; }
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
Node convert<ModuleData>::encode(const ModuleData& rhs)
|
||||
{
|
||||
Node node;
|
||||
int protocol = rhs.protocol;
|
||||
int subtype = rhs.subType;
|
||||
if (rhs.protocol >= PULSES_LP45 && rhs.protocol <= PULSES_DSMX) {
|
||||
protocol = PULSES_LP45;
|
||||
subtype = rhs.protocol - PULSES_LP45;
|
||||
} else if (rhs.protocol == PULSES_ACCST_ISRM_D16 || rhs.protocol == PULSES_ACCESS_ISRM) {
|
||||
protocol = PULSES_ACCESS_ISRM;
|
||||
subtype = rhs.protocol - PULSES_ACCESS_ISRM;
|
||||
} else if (rhs.protocol >= PULSES_PXX_XJT_X16 && rhs.protocol <= PULSES_PXX_XJT_LR12) {
|
||||
protocol = PULSES_PXX_XJT_X16;
|
||||
subtype = rhs.protocol - PULSES_PXX_XJT_X16;
|
||||
} else if (rhs.protocol >= PULSES_XJT_LITE_X16 && rhs.protocol <= PULSES_XJT_LITE_LR12) {
|
||||
protocol = PULSES_XJT_LITE_X16;
|
||||
subtype = rhs.protocol - PULSES_XJT_LITE_X16;
|
||||
}
|
||||
node["type"] = LookupValue(protocolLut, protocol);
|
||||
|
||||
switch (protocol) {
|
||||
case PULSES_PXX_XJT_X16:
|
||||
case PULSES_XJT_LITE_X16:
|
||||
node["subType"] = LookupValue(xjtLut, subtype);
|
||||
break;
|
||||
case PULSES_ACCESS_ISRM:
|
||||
node["subType"] = LookupValue(isrmLut, subtype);
|
||||
break;
|
||||
case PULSES_PXX_R9M:
|
||||
case PULSES_PXX_R9M_LITE:
|
||||
node["subType"] = LookupValue(r9mLut, subtype);
|
||||
break;
|
||||
case PULSES_LP45:
|
||||
node["subType"] = LookupValue(dsmLut, subtype);
|
||||
break;
|
||||
case PULSES_MULTIMODULE: {
|
||||
int rfProtocol = rhs.multi.rfProtocol + 1;
|
||||
int subType = rhs.subType;
|
||||
convertEtxProtocolToMulti(&rfProtocol, &subType);
|
||||
std::string st_str = std::to_string(rfProtocol);
|
||||
st_str += ",";
|
||||
st_str += std::to_string(subType);
|
||||
node["subType"] = st_str;
|
||||
} break;
|
||||
}
|
||||
|
||||
node["channelsStart"] = rhs.channelsStart;
|
||||
node["channelsCount"] = rhs.channelsCount;
|
||||
node["failsafeMode"] = LookupValue(failsafeLut, rhs.failsafeMode);
|
||||
|
||||
Node mod;
|
||||
switch (protocol) {
|
||||
case PULSES_PXX_XJT_X16:
|
||||
case PULSES_PXX_R9M:
|
||||
case PULSES_PXX_R9M_LITE: {
|
||||
Node pxx;
|
||||
pxx["power"] = rhs.pxx.power;
|
||||
// pxx["receiverTelemetryOff"] = rhs.pxx.receiverTelemetryOff;
|
||||
// pxx["receiverHigherChannels"] = rhs.pxx.receiverHigherChannels;
|
||||
pxx["antennaMode"] = rhs.pxx.antennaMode;
|
||||
mod["pxx"] = pxx;
|
||||
} break;
|
||||
case PULSES_ACCESS_ISRM:
|
||||
case PULSES_ACCESS_R9M:
|
||||
case PULSES_ACCESS_R9M_LITE:
|
||||
case PULSES_ACCESS_R9M_LITE_PRO:
|
||||
case PULSES_XJT_LITE_X16: {
|
||||
Node pxx2;
|
||||
pxx2["receivers"] = rhs.access.receivers;
|
||||
pxx2["racingMode"] = rhs.access.racingMode;
|
||||
for (int i=0; i<(int)rhs.access.receivers; i++) {
|
||||
pxx2["receiverName"][std::to_string(i)] = rhs.access.receiverName[i];
|
||||
}
|
||||
mod["pxx2"] = pxx2;
|
||||
} break;
|
||||
case PULSES_MULTIMODULE: {
|
||||
Node multi;;
|
||||
multi["disableTelemetry"] = (int)rhs.multi.disableTelemetry;
|
||||
multi["disableMapping"] = (int)rhs.multi.disableMapping;
|
||||
multi["autoBindMode"] = (int)rhs.multi.autoBindMode;
|
||||
multi["lowPowerMode"] = (int)rhs.multi.lowPowerMode;
|
||||
multi["optionValue"] = rhs.multi.optionValue;
|
||||
// multi["receiverTelemetryOff"] = (int)rhs.pxx.receiverTelemetryOff;
|
||||
// multi["receiverHigherChannels"] = (int)rhs.pxx.receiverHigherChannels;
|
||||
mod["multi"] = multi;
|
||||
} break;
|
||||
case PULSES_SBUS: {
|
||||
Node sbus;
|
||||
sbus["refreshRate"] = rhs.ppm.frameLength;
|
||||
mod["sbus"] = sbus;
|
||||
} break;
|
||||
// TODO: afhds3, flysky
|
||||
default: {
|
||||
Node ppm;
|
||||
ppm["delay"] = exportPpmDelay(rhs.ppm.delay);
|
||||
ppm["pulsePol"] = (int)rhs.ppm.pulsePol;
|
||||
ppm["outputType"] = (int)rhs.ppm.outputType;
|
||||
ppm["frameLength"] = rhs.ppm.frameLength;
|
||||
mod["ppm"] = ppm;
|
||||
} break;
|
||||
}
|
||||
if (mod && mod.IsMap())
|
||||
node["mod"] = mod;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<ModuleData>::decode(const Node& node, ModuleData& rhs)
|
||||
{
|
||||
node["type"] >> protocolLut >> rhs.protocol;
|
||||
|
||||
Node subType;
|
||||
node["subType"] >> subType;
|
||||
|
||||
switch (rhs.protocol) {
|
||||
case PULSES_PXX_XJT_X16:
|
||||
case PULSES_XJT_LITE_X16: {
|
||||
int subProto = 0;
|
||||
subType >> xjtLut >> subProto;
|
||||
rhs.protocol += subProto;
|
||||
} break;
|
||||
case PULSES_ACCESS_ISRM: {
|
||||
int subProto = 0;
|
||||
subType >> isrmLut >> subProto;
|
||||
rhs.protocol += subProto;
|
||||
} break;
|
||||
case PULSES_PXX_R9M:
|
||||
case PULSES_PXX_R9M_LITE: {
|
||||
subType >> r9mLut >> rhs.subType;
|
||||
} break;
|
||||
case PULSES_LP45: {
|
||||
int subProto = 0;
|
||||
subType >> dsmLut >> subProto;
|
||||
rhs.protocol += subProto;
|
||||
} break;
|
||||
case PULSES_MULTIMODULE: {
|
||||
std::string st_str;
|
||||
subType >> st_str;
|
||||
if (!st_str.empty()) {
|
||||
size_t pos = 0;
|
||||
try {
|
||||
int rfProtocol = std::stoi(st_str, &pos);
|
||||
st_str = st_str.substr(pos + 1);
|
||||
int rfSubType = std::stoi(st_str);
|
||||
convertMultiProtocolToEtx(&rfProtocol, &rfSubType);
|
||||
if (rfProtocol > 0) {
|
||||
rhs.multi.rfProtocol = rfProtocol - 1;
|
||||
rhs.subType = rfSubType;
|
||||
}
|
||||
} catch(...) {}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
node["channelsStart"] >> rhs.channelsStart;
|
||||
node["channelsCount"] >> rhs.channelsCount;
|
||||
node["failsafeMode"] >> failsafeLut >> rhs.failsafeMode;
|
||||
|
||||
if (node["mod"]) {
|
||||
const Node& mod = node["mod"];
|
||||
if (mod["ppm"]) {
|
||||
const Node& ppm = mod["ppm"];
|
||||
ppm["delay"] >> rhs.ppm.delay;
|
||||
rhs.ppm.delay = importPpmDelay(rhs.ppm.delay);
|
||||
ppm["pulsePol"] >> rhs.ppm.pulsePol;
|
||||
ppm["outputType"] >> rhs.ppm.outputType;
|
||||
ppm["frameLength"] >> rhs.ppm.frameLength;
|
||||
} else if (mod["multi"]) {
|
||||
Node multi = mod["multi"];
|
||||
multi["disableTelemetry"] >> rhs.multi.disableTelemetry;
|
||||
multi["disableMapping"] >> rhs.multi.disableMapping;
|
||||
multi["autoBindMode"] >> rhs.multi.autoBindMode;
|
||||
multi["lowPowerMode"] >> rhs.multi.lowPowerMode;
|
||||
multi["optionValue"] >> rhs.multi.optionValue;
|
||||
// multi["receiverTelemetryOff"] >> rhs.pxx.receiverTelemetryOff;
|
||||
// multi["receiverHigherChannels"] >> rhs.pxx.receiverHigherChannels;
|
||||
} else if (mod["pxx"]) {
|
||||
Node pxx = mod["pxx"];
|
||||
pxx["power"] >> rhs.pxx.power;
|
||||
// pxx["receiverTelemetryOff"] >> rhs.pxx.receiverTelemetryOff;
|
||||
// pxx["receiverHigherChannels"] >> rhs.pxx.receiverHigherChannels;
|
||||
pxx["antennaMode"] >> rhs.pxx.antennaMode;
|
||||
} else if (mod["sbus"]) {
|
||||
mod["sbus"]["refreshRate"] >> rhs.ppm.frameLength;
|
||||
} else if (mod["pxx2"]) {
|
||||
Node pxx2 = mod["pxx2"];
|
||||
pxx2["receivers"] >> rhs.access.receivers;
|
||||
pxx2["racingMode"] >> rhs.access.racingMode;
|
||||
for (const auto& rx : pxx2["receiverName"]) {
|
||||
rx >> rhs.access.receiverName;
|
||||
}
|
||||
} else if (mod["flysky"]) {
|
||||
//TODO
|
||||
} else if (mod["afhds3"]) {
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "moduledata.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<ModuleData> {
|
||||
static Node encode(const ModuleData& rhs);
|
||||
static bool decode(const Node& node, ModuleData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
|
||||
YAML::Node operator >> (const YAML::Node& node, const YamlLookupTable& lut)
|
||||
{
|
||||
if (node && node.IsScalar()) {
|
||||
std::string str = node.as<std::string>();
|
||||
const auto& it =
|
||||
find_if(lut.begin(), lut.end(), [=](const YamlLookupTableElmt& elmt) {
|
||||
if (elmt.second == str) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (it != lut.end()) {
|
||||
return YAML::Node(it->first);
|
||||
}
|
||||
return YAML::Node();
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void operator >> (const YAML::Node& node, const ioffset_int& value)
|
||||
{
|
||||
if (node && node.IsScalar()) {
|
||||
value.assign(node.as<int>());
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void operator >> (const YAML::Node& node, bool& value)
|
||||
{
|
||||
if (node && node.IsScalar()) {
|
||||
value = node.as<int>();
|
||||
}
|
||||
}
|
||||
|
||||
namespace YAML {
|
||||
|
||||
std::string LookupValue(const YamlLookupTable& lut, const int& value)
|
||||
{
|
||||
const auto& it =
|
||||
find_if(lut.begin(), lut.end(), [=](const YamlLookupTableElmt& elmt) {
|
||||
if (elmt.first == value) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (it != lut.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
Node operator << (const YamlLookupTable& lut, const int& value)
|
||||
{
|
||||
std::string str = LookupValue(lut, value);
|
||||
if (!str.empty()) {
|
||||
return Node(str);
|
||||
}
|
||||
return Node();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
#include <algorithm>
|
||||
#include <QString>
|
||||
|
||||
typedef std::pair<int, std::string> YamlLookupTableElmt;
|
||||
typedef std::vector<YamlLookupTableElmt> YamlLookupTable;
|
||||
|
||||
class ioffset_int {
|
||||
|
||||
public:
|
||||
ioffset_int(int& val, int offset)
|
||||
: value(val), offset(offset)
|
||||
{}
|
||||
|
||||
void assign(int newValue) const {
|
||||
value = newValue - offset;
|
||||
}
|
||||
|
||||
private:
|
||||
int& value;
|
||||
int offset;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ifactor {
|
||||
|
||||
public:
|
||||
ifactor(T& val, int factor)
|
||||
: value(val), factor(factor)
|
||||
{}
|
||||
|
||||
void assign(T newValue) const {
|
||||
value = newValue / factor;
|
||||
}
|
||||
|
||||
private:
|
||||
T& value;
|
||||
T factor;
|
||||
};
|
||||
|
||||
YAML::Node operator >> (const YAML::Node& node, const YamlLookupTable& lut);
|
||||
void operator >> (const YAML::Node& node, const ioffset_int& value);
|
||||
|
||||
template<typename T>
|
||||
void operator >> (const YAML::Node& node, const ifactor<T>& value)
|
||||
{
|
||||
if (node && node.IsScalar()) {
|
||||
value.assign(node.as<T>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator >> (const YAML::Node& node, T& value)
|
||||
{
|
||||
if (node && !node.IsNull()) {
|
||||
value = node.as<T>();
|
||||
}
|
||||
}
|
||||
|
||||
// type specialisation
|
||||
template <> void operator >> (const YAML::Node& node, bool& value);
|
||||
|
||||
template <size_t N>
|
||||
void operator >> (const YAML::Node& node, char (&value)[N])
|
||||
{
|
||||
if (node && node.IsScalar()) {
|
||||
auto str = node.as<std::string>();
|
||||
str.copy(value, N-1);
|
||||
value[std::min(str.size(), N-1)] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
void operator>>(const YAML::Node& node, T (&value)[N])
|
||||
{
|
||||
if (!node) return;
|
||||
if (node.IsMap()) {
|
||||
for (const auto& elmt : node) {
|
||||
int idx = -1;
|
||||
try {
|
||||
idx = std::stoi(elmt.first.Scalar());
|
||||
} catch (...) {
|
||||
}
|
||||
if (idx < 0 || idx >= (int)N) continue;
|
||||
|
||||
if (elmt.second.IsMap() && (elmt.second.size() == 1) &&
|
||||
elmt.second["val"]) {
|
||||
elmt.second["val"] >> value[idx];
|
||||
} else {
|
||||
elmt.second >> value[idx];
|
||||
}
|
||||
}
|
||||
} else if (node.IsSequence()) {
|
||||
int idx = 0;
|
||||
for (const auto& elmt : node) {
|
||||
elmt >> value[idx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace YAML {
|
||||
|
||||
std::string LookupValue(const YamlLookupTable& lut, const int& value);
|
||||
Node operator << (const YamlLookupTable& lut, const int& value);
|
||||
|
||||
template <typename T, size_t N>
|
||||
Node encode_array(const T (&rhs)[N])
|
||||
{
|
||||
Node node;
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
Node elmt;
|
||||
elmt = rhs[i];
|
||||
node.push_back(elmt);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct convert_enum
|
||||
{
|
||||
static YAML::Node encode(const YamlLookupTable& lut, const T& rhs)
|
||||
{
|
||||
return lut << rhs;
|
||||
}
|
||||
static bool decode(const YAML::Node& node, const YamlLookupTable& lut, T& rhs)
|
||||
{
|
||||
if (node) {
|
||||
YAML::Node conv = node >> lut;
|
||||
if (conv.IsScalar()) {
|
||||
rhs = (T)conv.as<int>();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define ENUM_CONVERTER(enum_type, lut) \
|
||||
template <> \
|
||||
struct convert<enum_type> { \
|
||||
static YAML::Node encode(const enum_type& rhs) \
|
||||
{ \
|
||||
return convert_enum<enum_type>::encode(lut,rhs); \
|
||||
} \
|
||||
static bool decode(const YAML::Node& node, enum_type& rhs) \
|
||||
{ \
|
||||
return convert_enum<enum_type>::decode(node, lut, rhs); \
|
||||
} \
|
||||
}
|
||||
@@ -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 "yaml_rawsource.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
std::string YamlRawSourceEncode(const RawSource& rhs)
|
||||
{
|
||||
std::string src_str;
|
||||
switch (rhs.type) {
|
||||
case SOURCE_TYPE_VIRTUAL_INPUT:
|
||||
src_str += "I" + std::to_string(rhs.index);
|
||||
break;
|
||||
case SOURCE_TYPE_LUA_OUTPUT:
|
||||
src_str += "lua(";
|
||||
src_str += std::to_string(rhs.index / 16);
|
||||
src_str += ",";
|
||||
src_str += std::to_string(rhs.index % 16);
|
||||
src_str += ")";
|
||||
break;
|
||||
case SOURCE_TYPE_STICK:
|
||||
src_str = getCurrentFirmware()->getAnalogInputTag(rhs.index);
|
||||
break;
|
||||
case SOURCE_TYPE_TRIM:
|
||||
src_str = getCurrentFirmware()->getTrimSourcesTag(rhs.index);
|
||||
break;
|
||||
case SOURCE_TYPE_MAX:
|
||||
src_str += "MAX";
|
||||
break;
|
||||
case SOURCE_TYPE_SWITCH:
|
||||
src_str += "S";
|
||||
src_str += (rhs.index + 'A');
|
||||
break;
|
||||
case SOURCE_TYPE_CUSTOM_SWITCH:
|
||||
src_str += "ls(";
|
||||
src_str += std::to_string(rhs.index);
|
||||
src_str += ")";
|
||||
break;
|
||||
case SOURCE_TYPE_CYC:
|
||||
src_str = getCurrentFirmware()->getRawSourceCyclicTag(rhs.index);
|
||||
break;
|
||||
case SOURCE_TYPE_PPM:
|
||||
src_str += "tr(";
|
||||
src_str += std::to_string(rhs.index);
|
||||
src_str += ")";
|
||||
break;
|
||||
case SOURCE_TYPE_CH:
|
||||
src_str += "ch(";
|
||||
src_str += std::to_string(rhs.index);
|
||||
src_str += ")";
|
||||
break;
|
||||
case SOURCE_TYPE_GVAR:
|
||||
src_str += "gv(";
|
||||
src_str += std::to_string(rhs.index);
|
||||
src_str += ")";
|
||||
break;
|
||||
case SOURCE_TYPE_SPECIAL:
|
||||
src_str = getCurrentFirmware()->getRawSourceSpecialTypesTag(rhs.index);
|
||||
break;
|
||||
case SOURCE_TYPE_TELEMETRY:
|
||||
src_str = "tele(";
|
||||
switch (rhs.index % 3) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
src_str += '-';
|
||||
break;
|
||||
case 2:
|
||||
src_str += '+';
|
||||
break;
|
||||
}
|
||||
src_str += std::to_string(rhs.index / 3);
|
||||
src_str += ")";
|
||||
break;
|
||||
default:
|
||||
src_str = "NONE";
|
||||
break;
|
||||
}
|
||||
return src_str;
|
||||
}
|
||||
|
||||
RawSource YamlRawSourceDecode(const std::string& src_str)
|
||||
{
|
||||
RawSource rhs;
|
||||
const char* val = src_str.data();
|
||||
size_t val_len = src_str.size();
|
||||
|
||||
if (val_len > 1 && val[0] == 'I'
|
||||
&& (val[1] >= '0') && (val[1] <= '9')) {
|
||||
|
||||
int idx = std::stoi(src_str.substr(1));
|
||||
if (idx < CPN_MAX_INPUTS) {
|
||||
rhs = RawSource(SOURCE_TYPE_VIRTUAL_INPUT, idx);
|
||||
}
|
||||
} else if (val_len >= 2
|
||||
&& val[0] == 'S'
|
||||
&& val[1] >= 'A'
|
||||
&& val[1] <= 'Z') {
|
||||
|
||||
int idx = val[1] - 'A';
|
||||
if (idx < CPN_MAX_SWITCHES)
|
||||
rhs = RawSource(SOURCE_TYPE_SWITCH, idx);
|
||||
|
||||
} else if (val_len > 4 &&
|
||||
val[0] == 'l' &&
|
||||
val[1] == 'u' &&
|
||||
val[2] == 'a' &&
|
||||
val[3] == '(') {
|
||||
|
||||
std::stringstream src(src_str.substr(4));
|
||||
int script = 0, output = 0; // TODO: check rename outputs to inputs???
|
||||
src >> script;
|
||||
src.ignore();
|
||||
src >> output;
|
||||
if (script < CPN_MAX_SCRIPTS && output < CPN_MAX_SCRIPT_INPUTS)
|
||||
rhs = RawSource(SOURCE_TYPE_LUA_OUTPUT, script * 16 + output);
|
||||
|
||||
} else if (val_len > 3 &&
|
||||
val[0] == 'l' &&
|
||||
val[1] == 's' &&
|
||||
val[2] == '(') {
|
||||
|
||||
std::stringstream src(src_str.substr(3));
|
||||
int ls = 0;
|
||||
src >> ls;
|
||||
if (ls < CPN_MAX_LOGICAL_SWITCHES)
|
||||
rhs = RawSource(SOURCE_TYPE_CUSTOM_SWITCH, ls);
|
||||
|
||||
} else if (val_len > 3 &&
|
||||
val[0] == 't' &&
|
||||
val[1] == 'r' &&
|
||||
val[2] == '(') {
|
||||
|
||||
std::stringstream src(src_str.substr(3));
|
||||
int tr = 0;
|
||||
src >> tr;
|
||||
if (tr < getCurrentFirmware()->getCapability(TrainerInputs))
|
||||
rhs = RawSource(SOURCE_TYPE_PPM, tr);
|
||||
|
||||
} else if (val_len > 3 &&
|
||||
val[0] == 'c' &&
|
||||
val[1] == 'h' &&
|
||||
val[2] == '(') {
|
||||
|
||||
std::stringstream src(src_str.substr(3));
|
||||
int ch = 0;
|
||||
src >> ch;
|
||||
if (ch < CPN_MAX_CHNOUT)
|
||||
rhs = RawSource(SOURCE_TYPE_CH, ch);
|
||||
|
||||
} else if (val_len > 3 &&
|
||||
val[0] == 'g' &&
|
||||
val[1] == 'v' &&
|
||||
val[2] == '(') {
|
||||
|
||||
std::stringstream src(src_str.substr(3));
|
||||
int gv = 0;
|
||||
src >> gv;
|
||||
if (gv < CPN_MAX_GVARS)
|
||||
rhs = RawSource(SOURCE_TYPE_GVAR, gv);
|
||||
|
||||
} else if (val_len > 5 &&
|
||||
val[0] == 't' &&
|
||||
val[1] == 'e' &&
|
||||
val[2] == 'l' &&
|
||||
val[3] == 'e' &&
|
||||
val[4] == '(') {
|
||||
|
||||
std::stringstream src(src_str.substr(5));
|
||||
|
||||
// parse sign
|
||||
uint8_t sign = 0;
|
||||
char c = src.peek();
|
||||
if (c == '-') {
|
||||
sign = 1;
|
||||
src.ignore();
|
||||
} else if (c == '+') {
|
||||
sign = 2;
|
||||
src.ignore();
|
||||
}
|
||||
|
||||
int sensor = 0;
|
||||
src >> sensor;
|
||||
if (sensor < CPN_MAX_SENSORS)
|
||||
rhs = RawSource(SOURCE_TYPE_TELEMETRY, sensor * 3 + sign);
|
||||
|
||||
} else {
|
||||
|
||||
YAML::Node node(src_str);
|
||||
std::string ana_str;
|
||||
node >> ana_str;
|
||||
int ana_idx = getCurrentFirmware()->getAnalogInputIndex(ana_str.c_str());
|
||||
if (ana_idx >= 0) {
|
||||
rhs.type = SOURCE_TYPE_STICK;
|
||||
rhs.index = ana_idx;
|
||||
}
|
||||
|
||||
int trm_idx = getCurrentFirmware()->getTrimSourcesIndex(src_str.c_str());
|
||||
if (trm_idx >= 0) {
|
||||
rhs.type = SOURCE_TYPE_TRIM;
|
||||
rhs.index = trm_idx;
|
||||
}
|
||||
|
||||
int cyc_idx = getCurrentFirmware()->getRawSourceCyclicIndex(src_str.c_str());
|
||||
if (cyc_idx >= 0) {
|
||||
rhs.type = SOURCE_TYPE_CYC;
|
||||
rhs.index = cyc_idx;
|
||||
}
|
||||
|
||||
int sp_idx = getCurrentFirmware()->getRawSourceSpecialTypesIndex(src_str.c_str());
|
||||
if (sp_idx >= 0) {
|
||||
rhs.type = SOURCE_TYPE_SPECIAL;
|
||||
rhs.index = sp_idx;
|
||||
}
|
||||
|
||||
if (node.IsScalar() && node.as<std::string>() == "MAX") {
|
||||
rhs.type = SOURCE_TYPE_MAX;
|
||||
rhs.index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rhs;
|
||||
}
|
||||
|
||||
namespace YAML {
|
||||
Node convert<RawSource>::encode(const RawSource& rhs)
|
||||
{
|
||||
return Node(YamlRawSourceEncode(rhs));
|
||||
}
|
||||
|
||||
bool convert<RawSource>::decode(const Node& node, RawSource& rhs)
|
||||
{
|
||||
std::string src_str = node.Scalar();
|
||||
rhs = YamlRawSourceDecode(src_str);
|
||||
return true;
|
||||
}
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "rawsource.h"
|
||||
|
||||
std::string YamlRawSourceEncode(const RawSource& rhs);
|
||||
RawSource YamlRawSourceDecode(const std::string& src_str);
|
||||
|
||||
namespace YAML {
|
||||
template <>
|
||||
struct convert<RawSource> {
|
||||
static Node encode(const RawSource& rhs);
|
||||
static bool decode(const Node& node, RawSource& rhs);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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 "yaml_rawswitch.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
std::string YamlRawSwitchEncode(const RawSwitch& rhs)
|
||||
{
|
||||
std::string sw_str;
|
||||
int32_t sval = rhs.index;
|
||||
if (rhs.index < 0) {
|
||||
sval = -sval;
|
||||
sw_str += "!";
|
||||
}
|
||||
|
||||
int multiposcnt = Boards::getCapability(getCurrentBoard(), Board::MultiposPotsPositions);
|
||||
|
||||
switch (rhs.type) {
|
||||
case SWITCH_TYPE_SWITCH:
|
||||
sw_str += getCurrentFirmware()->getSwitchesTag((sval - 1) / 3);
|
||||
sw_str += std::to_string((sval - 1) % 3);
|
||||
break;
|
||||
|
||||
case SWITCH_TYPE_VIRTUAL:
|
||||
sw_str += "L";
|
||||
sw_str += std::to_string(sval);
|
||||
break;
|
||||
|
||||
case SWITCH_TYPE_MULTIPOS_POT:
|
||||
sw_str += "6P";
|
||||
sw_str += std::to_string(sval / multiposcnt);
|
||||
sw_str += std::to_string(sval % multiposcnt);
|
||||
break;
|
||||
|
||||
case SWITCH_TYPE_TRIM:
|
||||
sw_str += getCurrentFirmware()->getTrimSwitchesTag(sval);
|
||||
break;
|
||||
|
||||
case SWITCH_TYPE_FLIGHT_MODE:
|
||||
sw_str += "FM";
|
||||
sw_str += std::to_string(sval - 1);
|
||||
break;
|
||||
|
||||
case SWITCH_TYPE_SENSOR:
|
||||
sw_str += "T";
|
||||
sw_str += std::to_string(sval + 1);
|
||||
break;
|
||||
|
||||
case SWITCH_TYPE_TIMER_MODE:
|
||||
// TODO: check as it appears to be depreciated as not in RawSwitch data model and not in radio yaml export
|
||||
break;
|
||||
|
||||
default:
|
||||
sw_str += getCurrentFirmware()->getRawSwitchTypesTag(rhs.type);
|
||||
break;
|
||||
}
|
||||
return sw_str;
|
||||
}
|
||||
|
||||
RawSwitch YamlRawSwitchDecode(const std::string& sw_str)
|
||||
{
|
||||
RawSwitch rhs; // constructor sets to SWITCH_TYPE_NONE
|
||||
const char* val = sw_str.data();
|
||||
size_t val_len = sw_str.size();
|
||||
std::string sw_str_tmp = sw_str;
|
||||
|
||||
// yaml-cpp does not escape this
|
||||
if (val_len > 0 && val[0] == '\\') {
|
||||
val++; val_len--;
|
||||
sw_str_tmp = sw_str_tmp.substr(1);
|
||||
}
|
||||
|
||||
bool neg = false;
|
||||
if (val_len > 0 && val[0] == '!') {
|
||||
neg = true;
|
||||
val++;
|
||||
val_len--;
|
||||
sw_str_tmp = sw_str_tmp.substr(1);
|
||||
}
|
||||
|
||||
int multiposcnt = Boards::getCapability(getCurrentBoard(), Board::MultiposPotsPositions);
|
||||
|
||||
// TODO: validate all expected numeric chars are numeric not just first
|
||||
|
||||
if (val_len >= 2 && val[0] == 'L' && (val[1] >= '0' && val[1] <= '9')) {
|
||||
|
||||
int sw_idx = std::stoi(sw_str_tmp.substr(1, val_len - 1));
|
||||
if (sw_idx < CPN_MAX_LOGICAL_SWITCHES) {
|
||||
rhs = RawSwitch(SWITCH_TYPE_VIRTUAL, sw_idx);
|
||||
}
|
||||
|
||||
} else if (val_len > 3 && val[0] == '6' && val[1] == 'P' &&
|
||||
(val[2] >= '0' && val[2] <= '9') &&
|
||||
(val[3] >= '0' && val[3] < (multiposcnt + '0'))) {
|
||||
|
||||
rhs = RawSwitch(SWITCH_TYPE_MULTIPOS_POT,
|
||||
(val[2] - '0') * multiposcnt + (val[3] - '0'));
|
||||
|
||||
} else if (val_len == 3 && val[0] == 'F' && val[1] == 'M' &&
|
||||
(val[2] >= '0' && val[2] <= '9')) {
|
||||
|
||||
rhs = RawSwitch(SWITCH_TYPE_FLIGHT_MODE, val[2] - '0' + 1);
|
||||
|
||||
} else if (val_len >= 2 && val[0] == 'T' &&
|
||||
(val[1] >= '0' && val[1] <= '9')) {
|
||||
|
||||
// starts at T1
|
||||
int sensor_idx = std::stoi(sw_str_tmp.substr(1, val_len - 1));
|
||||
if ((sensor_idx > 0) && (sensor_idx < CPN_MAX_SENSORS)) {
|
||||
rhs = RawSwitch(SWITCH_TYPE_SENSOR, sensor_idx - 1);
|
||||
}
|
||||
|
||||
} else if (sw_str_tmp.substr(0, 4) == std::string("Trim")) {
|
||||
|
||||
int tsw_idx = getCurrentFirmware()->getTrimSwitchesIndex(sw_str_tmp.c_str());
|
||||
if (tsw_idx >= 0) {
|
||||
rhs.type = SWITCH_TYPE_TRIM;
|
||||
rhs.index = tsw_idx;
|
||||
}
|
||||
|
||||
} else if (val_len >= 3 && val[0] == 'S' &&
|
||||
(val[1] >= 'A' && val[1] <= 'Z') &&
|
||||
(val[2] >= '0' && val[2] <= '2')) {
|
||||
|
||||
int sw_idx = getCurrentFirmware()->getSwitchesIndex(sw_str_tmp.substr(0, 2).c_str());
|
||||
if (sw_idx >= 0) {
|
||||
rhs.type = SWITCH_TYPE_SWITCH;
|
||||
rhs.index = sw_idx * 3 + (val[2] - '0' + 1);
|
||||
}
|
||||
|
||||
// TODO: SWITCH_TYPE_TIMER_MODE
|
||||
// check as it appears to be depreciated as not in RawSwitch data model and not in radio yaml export
|
||||
|
||||
} else {
|
||||
// types which do not use index
|
||||
int sw_type = getCurrentFirmware()->getRawSwitchTypesIndex(sw_str_tmp.c_str());
|
||||
if (sw_type >= 0) {
|
||||
rhs.type = (RawSwitchType)sw_type;
|
||||
rhs.index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
rhs.index = -rhs.index;
|
||||
}
|
||||
return rhs;
|
||||
}
|
||||
|
||||
namespace YAML {
|
||||
|
||||
Node convert<RawSwitch>::encode(const RawSwitch& rhs)
|
||||
{
|
||||
return Node(YamlRawSwitchEncode(rhs));
|
||||
}
|
||||
|
||||
bool convert<RawSwitch>::decode(const Node& node, RawSwitch& rhs)
|
||||
{
|
||||
rhs = YamlRawSwitchDecode(node.Scalar());
|
||||
return true;
|
||||
}
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "yaml_ops.h"
|
||||
#include "rawswitch.h"
|
||||
|
||||
std::string YamlRawSwitchEncode(const RawSwitch& rhs);
|
||||
RawSwitch YamlRawSwitchDecode(const std::string& sw_str);
|
||||
|
||||
namespace YAML {
|
||||
|
||||
template <>
|
||||
struct convert<RawSwitch> {
|
||||
static Node encode(const RawSwitch& rhs);
|
||||
static bool decode(const Node& node, RawSwitch& rhs);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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 "yaml_screendata.h"
|
||||
#include "yaml_rawsource.h"
|
||||
#include "yaml_ops.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
static const YamlLookupTable zoneOptionValueEnum = {
|
||||
{ZOV_Unsigned, "Unsigned"}, {ZOV_Signed, "Signed"}, {ZOV_Bool, "Bool"},
|
||||
{ZOV_String, "String"}, {ZOV_Source, "Source"}, {ZOV_Color, "Color"},
|
||||
};
|
||||
|
||||
std::string color_to_hex( unsigned int i )
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << "0x"
|
||||
<< std::setfill ('0') << std::setw(6)
|
||||
<< std::hex << i;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
ENUM_CONVERTER(ZoneOptionValueEnum, zoneOptionValueEnum);
|
||||
|
||||
Node convert<ZoneOptionValueTyped>::encode(const ZoneOptionValueTyped& rhs)
|
||||
{
|
||||
Node node, value;
|
||||
node["type"] = rhs.type;
|
||||
|
||||
switch (rhs.type) {
|
||||
case ZOV_Unsigned:
|
||||
value["unsignedValue"] = rhs.value.unsignedValue;
|
||||
break;
|
||||
case ZOV_Signed:
|
||||
value["signedValue"] = rhs.value.signedValue;
|
||||
break;
|
||||
case ZOV_Bool:
|
||||
value["boolValue"] = rhs.value.boolValue;
|
||||
break;
|
||||
case ZOV_Source:
|
||||
value["source"] = rhs.value.sourceValue;
|
||||
break;
|
||||
case ZOV_Color:
|
||||
value["color"] = color_to_hex(rhs.value.colorValue);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
node["value"] = value;
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<ZoneOptionValueTyped>::decode(const Node& node,
|
||||
ZoneOptionValueTyped& rhs)
|
||||
{
|
||||
node["type"] >> rhs.type;
|
||||
if (node["value"]) {
|
||||
Node value = node["value"];
|
||||
if (value.IsMap()) {
|
||||
value["unsignedValue"] >> rhs.value.unsignedValue;
|
||||
value["signedValue"] >> rhs.value.signedValue;
|
||||
value["boolValue"] >> rhs.value.boolValue;
|
||||
value["stringValue"] >> rhs.value.stringValue;
|
||||
value["source"] >> rhs.value.sourceValue;
|
||||
value["color"] >> rhs.value.colorValue;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct convert<WidgetPersistentData> {
|
||||
static Node encode(const WidgetPersistentData& rhs)
|
||||
{
|
||||
Node node;
|
||||
for (int i=0; i<MAX_WIDGET_OPTIONS; i++) {
|
||||
if (!rhs.options[i].isEmpty()) {
|
||||
Node options;
|
||||
options = rhs.options[i];
|
||||
if (options && options.IsMap()) {
|
||||
node["options"][std::to_string(i)] = options;
|
||||
}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, WidgetPersistentData& rhs)
|
||||
{
|
||||
node["options"] >> rhs.options;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Node convert<ZonePersistentData>::encode(const ZonePersistentData& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["widgetName"] = rhs.widgetName;
|
||||
node["widgetData"] = rhs.widgetData;
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<ZonePersistentData>::decode(const Node& node, ZonePersistentData& rhs)
|
||||
{
|
||||
node["widgetName"] >> rhs.widgetName;
|
||||
node["widgetData"] >> rhs.widgetData;
|
||||
return true;
|
||||
}
|
||||
|
||||
Node convert<ScreenData>::encode(const ScreenData& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["LayoutId"] = rhs.layoutId;
|
||||
node["layoutData"] = rhs.layoutPersistentData;
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<ScreenData>::decode(const Node& node, ScreenData& rhs)
|
||||
{
|
||||
node["LayoutId"] >> rhs.layoutId;
|
||||
node["layoutData"] >> rhs.layoutPersistentData;
|
||||
return true;
|
||||
}
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "customisation_data.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<ZonePersistentData> {
|
||||
static Node encode(const ZonePersistentData& rhs);
|
||||
static bool decode(const Node& node, ZonePersistentData& rhs);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct convert<ZoneOptionValueTyped> {
|
||||
static Node encode(const ZoneOptionValueTyped& rhs);
|
||||
static bool decode(const Node& node, ZoneOptionValueTyped& rhs);
|
||||
};
|
||||
|
||||
template <int N, int O>
|
||||
struct convert<WidgetsContainerPersistentData<N,O> > {
|
||||
typedef WidgetsContainerPersistentData<N,O> PersistentData;
|
||||
static Node encode(const PersistentData& rhs)
|
||||
{
|
||||
Node node;
|
||||
for (int i=0; i<N; i++) {
|
||||
if (strlen(rhs.zones[i].widgetName) > 0) {
|
||||
node["zones"][std::to_string(i)] = rhs.zones[i];
|
||||
}
|
||||
}
|
||||
for(int i=0; i<O; i++) {
|
||||
if (!rhs.options[i].isEmpty()) {
|
||||
node["options"][std::to_string(i)] = rhs.options[i];
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, PersistentData& rhs)
|
||||
{
|
||||
node["zones"] >> rhs.zones;
|
||||
node["options"] >> rhs.options;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef RadioLayout::CustomScreenData ScreenData;
|
||||
|
||||
template <>
|
||||
struct convert<ScreenData> {
|
||||
static Node encode(const ScreenData& rhs);
|
||||
static bool decode(const Node& node, ScreenData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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 "yaml_sensordata.h"
|
||||
|
||||
static const YamlLookupTable sensorType = {
|
||||
{SensorData::TELEM_TYPE_CUSTOM, "TYPE_CUSTOM"},
|
||||
{SensorData::TELEM_TYPE_CALCULATED, "TYPE_CALCULATED"},
|
||||
};
|
||||
|
||||
static const YamlLookupTable sensorFormula = {
|
||||
{SensorData::TELEM_FORMULA_ADD, "FORMULA_ADD"},
|
||||
{SensorData::TELEM_FORMULA_AVERAGE, "FORMULA_AVERAGE"},
|
||||
{SensorData::TELEM_FORMULA_MIN, "FORMULA_MIN"},
|
||||
{SensorData::TELEM_FORMULA_MAX, "FORMULA_MAX"},
|
||||
{SensorData::TELEM_FORMULA_MULTIPLY, "FORMULA_MULTIPLY"},
|
||||
{SensorData::TELEM_FORMULA_TOTALIZE, "FORMULA_TOTALIZE"},
|
||||
{SensorData::TELEM_FORMULA_CELL, "FORMULA_CELL"},
|
||||
{SensorData::TELEM_FORMULA_CONSUMPTION, "FORMULA_CONSUMPTION"},
|
||||
{SensorData::TELEM_FORMULA_DIST, "FORMULA_DIST"},
|
||||
};
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
Node convert<SensorData>::encode(const SensorData& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["type"] = LookupValue(sensorType, rhs.type);
|
||||
|
||||
Node cfg;
|
||||
if (rhs.type == SensorData::TELEM_TYPE_CUSTOM) {
|
||||
node["id1"]["id"] = rhs.id;
|
||||
node["subid"] = rhs.subid;
|
||||
|
||||
unsigned int instance = rhs.instance;
|
||||
if (instance != 0) {
|
||||
instance =
|
||||
((instance - 1) & 0x1F) | (rhs.rxIdx << 5) | (rhs.moduleIdx << 7);
|
||||
}
|
||||
node["id2"]["instance"] = instance;
|
||||
cfg["custom"]["ratio"] = rhs.ratio;
|
||||
cfg["custom"]["offset"] = rhs.offset;
|
||||
} else {
|
||||
if (rhs.persistent) {
|
||||
node["persistent"] = 1;
|
||||
node["id1"]["persistentValue"] = rhs.persistentValue;
|
||||
}
|
||||
|
||||
node["id2"]["formula"] = LookupValue(sensorFormula, rhs.formula);
|
||||
|
||||
switch (rhs.formula) {
|
||||
case SensorData::TELEM_FORMULA_CELL:
|
||||
cfg["cell"]["source"] = rhs.source;
|
||||
cfg["cell"]["index"] = rhs.index;
|
||||
break;
|
||||
case SensorData::TELEM_FORMULA_ADD:
|
||||
case SensorData::TELEM_FORMULA_AVERAGE:
|
||||
case SensorData::TELEM_FORMULA_MULTIPLY:
|
||||
case SensorData::TELEM_FORMULA_MIN:
|
||||
case SensorData::TELEM_FORMULA_MAX: {
|
||||
Node sources;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (rhs.sources[i]) {
|
||||
sources[std::to_string(i)]["val"] = rhs.sources[i];
|
||||
}
|
||||
}
|
||||
cfg["calc"]["sources"] = sources;
|
||||
} break;
|
||||
case SensorData::TELEM_FORMULA_DIST:
|
||||
if (rhs.gps) {
|
||||
cfg["dist"]["gps"] = rhs.gps;
|
||||
}
|
||||
if (rhs.alt) {
|
||||
cfg["dist"]["alt"] = rhs.alt;
|
||||
}
|
||||
break;
|
||||
case SensorData::TELEM_FORMULA_CONSUMPTION:
|
||||
case SensorData::TELEM_FORMULA_TOTALIZE:
|
||||
cfg["consumption"]["source"] = rhs.amps;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
node["label"] = rhs.label;
|
||||
node["unit"] = rhs.unit;
|
||||
node["prec"] = rhs.prec;
|
||||
node["autoOffset"] = (int)rhs.autoOffset;
|
||||
node["filter"] = (int)rhs.filter;
|
||||
node["logs"] = (int)rhs.logs;
|
||||
node["persistent"] = (int)rhs.persistent;
|
||||
node["onlyPositive"] = (int)rhs.onlyPositive;
|
||||
|
||||
if (cfg && cfg.IsMap()) {
|
||||
node["cfg"] = cfg;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<SensorData>::decode(const Node& node, SensorData& rhs)
|
||||
{
|
||||
node["type"] >> sensorType >> rhs.type;
|
||||
if (node["id1"]) {
|
||||
Node id1 = node["id1"];
|
||||
id1["id"] >> rhs.id;
|
||||
id1["persistentValue"] >> rhs.persistentValue;
|
||||
}
|
||||
node["subid"] >> rhs.subid;
|
||||
if (node["id2"]) {
|
||||
Node id2 = node["id2"];
|
||||
id2["instance"] >> rhs.instance;
|
||||
id2["formula"] >> sensorFormula >> rhs.formula;
|
||||
}
|
||||
|
||||
if (rhs.type == SensorData::TELEM_TYPE_CUSTOM) {
|
||||
rhs.rxIdx = (rhs.instance >> 5) & 0x03; // 2 bits Rx idx
|
||||
rhs.moduleIdx = (rhs.instance >> 7) & 0x1; // 1 bit module idx
|
||||
rhs.instance = (rhs.instance & 0x1F) + 1; // 5 bits instance
|
||||
}
|
||||
|
||||
node["label"] >> rhs.label;
|
||||
node["unit"] >> rhs.unit;
|
||||
node["prec"] >> rhs.prec;
|
||||
node["autoOffset"] >> rhs.autoOffset;
|
||||
node["filter"] >> rhs.filter;
|
||||
node["logs"] >> rhs.logs;
|
||||
node["persistent"] >> rhs.persistent;
|
||||
node["onlyPositive"] >> rhs.onlyPositive;
|
||||
|
||||
if (node["cfg"]) {
|
||||
Node cfg = node["cfg"];
|
||||
if (cfg.IsMap()) {
|
||||
if (cfg["custom"]) {
|
||||
Node custom = cfg["custom"];
|
||||
if (custom.IsMap()) {
|
||||
custom["ratio"] >> rhs.ratio;
|
||||
custom["offset"] >> rhs.offset;
|
||||
}
|
||||
} else if (cfg["cell"]) {
|
||||
Node cell = cfg["cell"];
|
||||
if (cell.IsMap()) {
|
||||
cell["source"] >> rhs.source;
|
||||
cell["index"] >> rhs.index;
|
||||
}
|
||||
} else if (cfg["calc"]) {
|
||||
Node calc = cfg["calc"];
|
||||
if (calc.IsMap()) {
|
||||
calc["sources"] >> rhs.sources;
|
||||
}
|
||||
} else if (cfg["consumption"]) {
|
||||
Node consumption = cfg["consumption"];
|
||||
if (consumption.IsMap()) {
|
||||
consumption["source"] >> rhs.amps;
|
||||
}
|
||||
} else if (cfg["dist"]) {
|
||||
Node dist = cfg["dist"];
|
||||
if (dist.IsMap()) {
|
||||
dist["gps"] >> rhs.gps;
|
||||
dist["alt"] >> rhs.alt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "sensordata.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<SensorData> {
|
||||
static Node encode(const SensorData& rhs);
|
||||
static bool decode(const Node& node, SensorData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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 "yaml_switchconfig.h"
|
||||
|
||||
#include "boards.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
const YamlLookupTable switchConfigLut = {
|
||||
{Board::SWITCH_NOT_AVAILABLE, "none"},
|
||||
{Board::SWITCH_TOGGLE, "toggle"},
|
||||
{Board::SWITCH_2POS, "2pos"},
|
||||
{Board::SWITCH_3POS, "3pos"},
|
||||
};
|
||||
|
||||
|
||||
const YamlLookupTable potConfigLut = {
|
||||
{Board::POT_NONE, "none"},
|
||||
{Board::POT_WITH_DETENT, "with_detent"},
|
||||
{Board::POT_MULTIPOS_SWITCH, "multipos_switch"},
|
||||
{Board::POT_WITHOUT_DETENT, "without_detent"},
|
||||
};
|
||||
|
||||
const YamlLookupTable slidersLut = {
|
||||
{0, "LS"},
|
||||
{1, "RS"},
|
||||
};
|
||||
|
||||
const YamlLookupTable sliderConfigLut = {
|
||||
{Board::SLIDER_NONE, "none"},
|
||||
{Board::SLIDER_WITH_DETENT, "with_detent"},
|
||||
};
|
||||
|
||||
int YamlStickLookup::name2idx(const std::string& name)
|
||||
{
|
||||
try {
|
||||
int idx = std::stoi(name);
|
||||
if (idx < 4) {
|
||||
return idx;
|
||||
}
|
||||
} catch(...) {}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string YamlStickLookup::idx2name(unsigned int idx)
|
||||
{
|
||||
if (idx < 4) {
|
||||
return std::to_string(idx);
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
int YamlSwitchLookup::name2idx(const std::string& name)
|
||||
{
|
||||
auto fw = getCurrentFirmware();
|
||||
int idx = fw->getSwitchesIndex(name.c_str());
|
||||
if (idx < 0) return -1;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
std::string YamlSwitchLookup::idx2name(unsigned int idx)
|
||||
{
|
||||
auto fw = getCurrentFirmware();
|
||||
unsigned int switches = Boards::getCapability(fw->getBoard(), Board::Switches);
|
||||
if (idx >= switches) return std::string();
|
||||
|
||||
return fw->getSwitchesTag(idx);
|
||||
}
|
||||
|
||||
int YamlPotLookup::name2idx(const std::string& name)
|
||||
{
|
||||
auto fw = getCurrentFirmware();
|
||||
int idx = fw->getAnalogInputIndex(name.c_str());
|
||||
if (idx < 0) return idx;
|
||||
|
||||
int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks);
|
||||
if (idx < sticks) return -1;
|
||||
idx -= sticks;
|
||||
|
||||
int pots = Boards::getCapability(fw->getBoard(), Board::Pots);
|
||||
if (idx >= pots) return -1;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
std::string YamlPotLookup::idx2name(unsigned int idx)
|
||||
{
|
||||
auto fw = getCurrentFirmware();
|
||||
unsigned int pots = Boards::getCapability(fw->getBoard(), Board::Pots);
|
||||
if (idx >= pots) return std::string();
|
||||
|
||||
unsigned int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks);
|
||||
return fw->getAnalogInputTag(idx + sticks);
|
||||
}
|
||||
|
||||
int YamlSliderLookup::name2idx(const std::string& name)
|
||||
{
|
||||
auto fw = getCurrentFirmware();
|
||||
int idx = fw->getAnalogInputIndex(name.c_str());
|
||||
if (idx < 0) return idx;
|
||||
|
||||
int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks);
|
||||
if (idx < sticks) return -1;
|
||||
idx -= sticks;
|
||||
|
||||
int pots = Boards::getCapability(fw->getBoard(), Board::Pots);
|
||||
if (idx < pots) return -1;
|
||||
idx -= pots;
|
||||
|
||||
int sliders = Boards::getCapability(fw->getBoard(), Board::Sliders);
|
||||
if (idx >= sliders) return -1;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
std::string YamlSliderLookup::idx2name(unsigned int idx)
|
||||
{
|
||||
auto fw = getCurrentFirmware();
|
||||
unsigned int sliders = Boards::getCapability(fw->getBoard(), Board::Sliders);
|
||||
if (idx >= sliders) return std::string();
|
||||
|
||||
unsigned int sticks = Boards::getCapability(fw->getBoard(), Board::Sticks);
|
||||
unsigned int pots = Boards::getCapability(fw->getBoard(), Board::Pots);
|
||||
return fw->getAnalogInputTag(idx + pots + sticks);
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "yaml_ops.h"
|
||||
#include "generalsettings.h"
|
||||
#include <string.h>
|
||||
|
||||
struct YamlStickLookup {
|
||||
static int name2idx(const std::string& name);
|
||||
static std::string idx2name(unsigned int idx);
|
||||
};
|
||||
|
||||
template <unsigned int N, class name_lookup>
|
||||
struct YamlNameConfig {
|
||||
char name[N][HARDWARE_NAME_LEN + 1];
|
||||
|
||||
YamlNameConfig() { memset(name, 0, sizeof(name)); }
|
||||
|
||||
YamlNameConfig(const char in_names[N][HARDWARE_NAME_LEN + 1])
|
||||
{
|
||||
memcpy(name, in_names, sizeof(name));
|
||||
}
|
||||
|
||||
void copy(char out_names[N][HARDWARE_NAME_LEN + 1])
|
||||
{
|
||||
memcpy(out_names, name, sizeof(name));
|
||||
}
|
||||
};
|
||||
|
||||
typedef YamlNameConfig<CPN_MAX_SWITCHES, YamlStickLookup> YamlStickConfig;
|
||||
|
||||
template <unsigned int N, class name_lookup, const YamlLookupTable& cfg_lut>
|
||||
struct YamlKnobConfig : public YamlNameConfig<N, name_lookup> {
|
||||
unsigned int config[N];
|
||||
|
||||
YamlKnobConfig() { memset(config, 0, sizeof(config)); }
|
||||
|
||||
YamlKnobConfig(const char in_names[N][HARDWARE_NAME_LEN + 1],
|
||||
const unsigned int in_configs[N]) :
|
||||
YamlNameConfig<N, name_lookup>(in_names)
|
||||
{
|
||||
memcpy(config, in_configs, sizeof(config));
|
||||
}
|
||||
|
||||
void copy(char out_names[N][HARDWARE_NAME_LEN + 1],
|
||||
unsigned int out_configs[N])
|
||||
{
|
||||
YamlNameConfig<N, name_lookup>::copy(out_names);
|
||||
memcpy(out_configs, config, sizeof(config));
|
||||
}
|
||||
};
|
||||
|
||||
// SA:
|
||||
// type: 3pos
|
||||
// name:
|
||||
struct YamlSwitchLookup {
|
||||
static int name2idx(const std::string& name);
|
||||
static std::string idx2name(unsigned int idx);
|
||||
};
|
||||
extern const YamlLookupTable switchConfigLut;
|
||||
typedef YamlKnobConfig<CPN_MAX_SWITCHES, YamlSwitchLookup, switchConfigLut>
|
||||
YamlSwitchConfig;
|
||||
|
||||
// S1:
|
||||
// type: with_detent
|
||||
// name:
|
||||
struct YamlPotLookup {
|
||||
static int name2idx(const std::string& name);
|
||||
static std::string idx2name(unsigned int idx);
|
||||
};
|
||||
extern const YamlLookupTable potConfigLut;
|
||||
typedef YamlKnobConfig<CPN_MAX_POTS, YamlPotLookup, potConfigLut> YamlPotConfig;
|
||||
|
||||
// S1:
|
||||
// type: with_detent
|
||||
// name:
|
||||
struct YamlSliderLookup {
|
||||
static int name2idx(const std::string& name);
|
||||
static std::string idx2name(unsigned int idx);
|
||||
};
|
||||
extern const YamlLookupTable sliderConfigLut;
|
||||
typedef YamlKnobConfig<CPN_MAX_SLIDERS, YamlSliderLookup, sliderConfigLut>
|
||||
YamlSliderConfig;
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <unsigned int N, class name_lookup>
|
||||
struct convert<YamlNameConfig<N, name_lookup> > {
|
||||
static Node encode(const YamlNameConfig<N, name_lookup>& rhs)
|
||||
{
|
||||
Node node;
|
||||
for (unsigned int i=0; i<N; i++) {
|
||||
std::string name = name_lookup::idx2name(i);
|
||||
if (!name.empty() && rhs.name[i][0]) {
|
||||
node[name]["name"] = rhs.name[i];
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
static bool decode(const Node& node, YamlNameConfig<N, name_lookup>& rhs)
|
||||
{
|
||||
if (!node.IsMap()) return false;
|
||||
int idx = 0;
|
||||
for (const auto& kv : node) {
|
||||
idx = name_lookup::name2idx(kv.first.Scalar());
|
||||
if (idx >= 0) {
|
||||
kv.second["name"] >> rhs.name[idx];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned int N, class name_lookup, const YamlLookupTable& cfg_lut>
|
||||
struct convert<YamlKnobConfig<N, name_lookup, cfg_lut> > {
|
||||
static Node encode(const YamlKnobConfig<N, name_lookup, cfg_lut>& rhs)
|
||||
{
|
||||
Node node;
|
||||
for (unsigned int i=0; i<N; i++) {
|
||||
std::string name = name_lookup::idx2name(i);
|
||||
if (!name.empty() && (rhs.config[i] || rhs.name[i][0])) {
|
||||
node[name]["type"] = cfg_lut << rhs.config[i];
|
||||
node[name]["name"] = rhs.name[i];
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
static bool decode(const Node& node,
|
||||
YamlKnobConfig<N, name_lookup, cfg_lut>& rhs)
|
||||
{
|
||||
if (!node.IsMap()) return false;
|
||||
int idx = 0;
|
||||
for (const auto& kv : node) {
|
||||
idx = name_lookup::name2idx(kv.first.Scalar());
|
||||
if (idx >= 0) {
|
||||
kv.second["type"] >> cfg_lut >> rhs.config[idx];
|
||||
kv.second["name"] >> rhs.name[idx];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 "yaml_trainerdata.h"
|
||||
#include "generalsettings.h"
|
||||
|
||||
const YamlLookupTable trainerMixMode = {
|
||||
{TrainerMix::TRN_MIX_MODE_OFF, "OFF"},
|
||||
{TrainerMix::TRN_MIX_MODE_ADD, "ADD"},
|
||||
{TrainerMix::TRN_MIX_MODE_SUBST, "REPL"},
|
||||
};
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
|
||||
Node convert<TrainerMix>::encode(const TrainerMix& rhs)
|
||||
{
|
||||
Node node;
|
||||
node["srcChn"] = rhs.src;
|
||||
node["mode"] = trainerMixMode << rhs.mode;
|
||||
node["studWeight"] = rhs.weight;
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<TrainerMix>::decode(const Node& node, TrainerMix& rhs)
|
||||
{
|
||||
node["srcChn"] >> rhs.src;
|
||||
node["mode"] >> trainerMixMode >> rhs.mode;
|
||||
node["studWeight"] >> rhs.weight;
|
||||
return true;
|
||||
}
|
||||
|
||||
Node convert<TrainerData>::encode(const TrainerData& rhs)
|
||||
{
|
||||
Node node;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
node["calib"][std::to_string(i)]["val"] = rhs.calib[i];
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
node["mix"][std::to_string(i)] = rhs.mix[i];
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
bool convert<TrainerData>::decode(const Node& node, TrainerData& rhs)
|
||||
{
|
||||
if (node["calib"]) {
|
||||
const Node& calib = node["calib"];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
calib[std::to_string(i)]["val"] >> rhs.calib[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (node["mix"]) {
|
||||
const Node& mix = node["mix"];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mix[std::to_string(i)] >> rhs.mix[i];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 "yaml_ops.h"
|
||||
#include "generalsettings.h"
|
||||
|
||||
extern const YamlLookupTable trainerMixMode;
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
struct convert<TrainerMix> {
|
||||
static Node encode(const TrainerMix& rhs);
|
||||
static bool decode(const Node& node, TrainerMix& rhs);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct convert<TrainerData> {
|
||||
static Node encode(const TrainerData& rhs);
|
||||
static bool decode(const Node& node, TrainerData& rhs);
|
||||
};
|
||||
} // namespace YAML
|
||||
@@ -178,3 +178,9 @@ void Firmware::addOptionsGroup(const OptionsGroup & options)
|
||||
{
|
||||
this->opts.append(options);
|
||||
}
|
||||
|
||||
QString Firmware::getFlavour()
|
||||
{
|
||||
QStringList strl = id.split("-");
|
||||
return strl.count() >= 2 ? strl.at(1) : QString();
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "radiodata.h"
|
||||
#include "../../radio/src/definitions.h"
|
||||
#include "simulatorinterface.h"
|
||||
#include "datahelpers.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QStringList>
|
||||
@@ -33,6 +34,7 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
const uint8_t modn12x3[4][4]= {
|
||||
{1, 2, 3, 4},
|
||||
@@ -163,7 +165,9 @@ enum Capability {
|
||||
HasADCJitterFilter,
|
||||
HasTelemetryBaudrate,
|
||||
TopBarZones,
|
||||
FunctionSwitches
|
||||
FunctionSwitches,
|
||||
HasModelsList,
|
||||
HasFlySkyGimbals
|
||||
};
|
||||
|
||||
class EEPROMInterface
|
||||
@@ -258,6 +262,8 @@ enum EepromLoadErrors {
|
||||
NUM_ERRORS
|
||||
};
|
||||
|
||||
constexpr char FIRMWARE_ID_PREFIX[] = { "edgetx-" };
|
||||
|
||||
class Firmware
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Firmware)
|
||||
@@ -285,8 +291,16 @@ class Firmware
|
||||
board(board),
|
||||
variantBase(0),
|
||||
base(base),
|
||||
eepromInterface(nullptr)
|
||||
{ }
|
||||
eepromInterface(nullptr),
|
||||
analogInputNamesLookupTable(Boards::getAnalogNamesLookupTable(board)),
|
||||
switchesLookupTable(Boards::getSwitchesLookupTable(board)),
|
||||
trimSwitchesLookupTable(Boards::getTrimSwitchesLookupTable(board)),
|
||||
trimSourcesLookupTable(Boards::getTrimSourcesLookupTable(board)),
|
||||
rawSwitchTypesLookupTable(RawSwitch::getRawSwitchTypesLookupTable()),
|
||||
rawSourceSpecialTypesLookupTable(RawSource::getSpecialTypesLookupTable()),
|
||||
rawSourceCyclicLookupTable(RawSource::getCyclicLookupTable())
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Firmware() { }
|
||||
|
||||
@@ -393,6 +407,26 @@ class Firmware
|
||||
currentVariant = value;
|
||||
}
|
||||
|
||||
QString getFlavour();
|
||||
|
||||
static Firmware * getFirmwareForFlavour(const QString & flavour)
|
||||
{
|
||||
return getFirmwareForId(FIRMWARE_ID_PREFIX + flavour);
|
||||
}
|
||||
|
||||
const StringTagMappingTable* getAnalogIndexNamesLookupTable()
|
||||
{
|
||||
return &analogInputNamesLookupTable;
|
||||
}
|
||||
|
||||
STRINGTAGMAPPINGFUNCS(analogInputNamesLookupTable, AnalogInput);
|
||||
STRINGTAGMAPPINGFUNCS(switchesLookupTable, Switches);
|
||||
STRINGTAGMAPPINGFUNCS(trimSwitchesLookupTable, TrimSwitches);
|
||||
STRINGTAGMAPPINGFUNCS(trimSourcesLookupTable, TrimSources);
|
||||
STRINGTAGMAPPINGFUNCS(rawSwitchTypesLookupTable, RawSwitchTypes);
|
||||
STRINGTAGMAPPINGFUNCS(rawSourceSpecialTypesLookupTable, RawSourceSpecialTypes);
|
||||
STRINGTAGMAPPINGFUNCS(rawSourceCyclicLookupTable, RawSourceCyclic);
|
||||
|
||||
protected:
|
||||
QString id;
|
||||
QString name;
|
||||
@@ -400,6 +434,16 @@ class Firmware
|
||||
unsigned int variantBase;
|
||||
Firmware * base;
|
||||
EEPROMInterface * eepromInterface;
|
||||
|
||||
// used by YAML encode and decode
|
||||
const StringTagMappingTable analogInputNamesLookupTable;
|
||||
const StringTagMappingTable switchesLookupTable;
|
||||
const StringTagMappingTable trimSwitchesLookupTable;
|
||||
const StringTagMappingTable trimSourcesLookupTable;
|
||||
const StringTagMappingTable rawSwitchTypesLookupTable;
|
||||
const StringTagMappingTable rawSourceSpecialTypesLookupTable;
|
||||
const StringTagMappingTable rawSourceCyclicLookupTable;
|
||||
|
||||
QList<const char *> languages;
|
||||
//QList<const char *> ttslanguages;
|
||||
OptionsList opts;
|
||||
@@ -407,6 +451,7 @@ class Firmware
|
||||
static QVector<Firmware *> registeredFirmwares;
|
||||
static Firmware * defaultVariant;
|
||||
static Firmware * currentVariant;
|
||||
|
||||
};
|
||||
|
||||
inline Firmware * getCurrentFirmware()
|
||||
|
||||
@@ -54,14 +54,18 @@ bool GeneralSettings::switchSourceAllowedTaranis(int index) const
|
||||
|
||||
bool GeneralSettings::isPotAvailable(int index) const
|
||||
{
|
||||
if (index < 0 || index > Boards::getCapability(getCurrentBoard(), Board::Pots))
|
||||
int numPots = Boards::getCapability(getCurrentBoard(), Board::Pots);
|
||||
if (getCurrentFirmware()->getCapability(HasFlySkyGimbals))
|
||||
numPots -= 2;
|
||||
|
||||
if (index < 0 || index >= numPots)
|
||||
return false;
|
||||
return potConfig[index] != Board::POT_NONE;
|
||||
}
|
||||
|
||||
bool GeneralSettings::isSliderAvailable(int index) const
|
||||
{
|
||||
if (index < 0 || index > Boards::getCapability(getCurrentBoard(), Board::Sliders))
|
||||
if (index < 0 || index >= Boards::getCapability(getCurrentBoard(), Board::Sliders))
|
||||
return false;
|
||||
return sliderConfig[index] != Board::SLIDER_NONE;
|
||||
}
|
||||
@@ -241,6 +245,8 @@ GeneralSettings::GeneralSettings()
|
||||
}
|
||||
}
|
||||
|
||||
internalModule = g.profile[g.sessionId()].defaultInternalModule();
|
||||
|
||||
const char * themeName = IS_FLYSKY_NV14(board) ? "FlySky" : "EdgeTX";
|
||||
RadioTheme::init(themeName, themeData);
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@ class GeneralSettings {
|
||||
int vBatMin;
|
||||
int vBatMax;
|
||||
int backlightMode;
|
||||
unsigned int internalModule; // Introducted in EdgeTX 2.6 yaml only
|
||||
TrainerData trainer;
|
||||
unsigned int view; // main screen view // TODO enum
|
||||
bool disableThrottleWarning;
|
||||
@@ -231,8 +232,8 @@ class GeneralSettings {
|
||||
char switchName[CPN_MAX_SWITCHES][HARDWARE_NAME_LEN + 1];
|
||||
unsigned int switchConfig[CPN_MAX_SWITCHES];
|
||||
char stickName[CPN_MAX_STICKS][HARDWARE_NAME_LEN + 1];
|
||||
char potName[CPN_MAX_KNOBS][HARDWARE_NAME_LEN + 1];
|
||||
unsigned int potConfig[CPN_MAX_KNOBS];
|
||||
char potName[CPN_MAX_POTS][HARDWARE_NAME_LEN + 1];
|
||||
unsigned int potConfig[CPN_MAX_POTS];
|
||||
char sliderName[CPN_MAX_SLIDERS][HARDWARE_NAME_LEN + 1];
|
||||
unsigned int sliderConfig[CPN_MAX_SLIDERS];
|
||||
|
||||
|
||||
@@ -63,8 +63,6 @@ class RSSIAlarmData {
|
||||
}
|
||||
};
|
||||
|
||||
#define CPN_MAX_SCRIPTS 9
|
||||
#define CPN_MAX_SCRIPT_INPUTS 10
|
||||
class ScriptData {
|
||||
public:
|
||||
ScriptData() { clear(); }
|
||||
@@ -145,8 +143,8 @@ class ModelData {
|
||||
unsigned int switchWarningEnable;
|
||||
unsigned int thrTrimSwitch;
|
||||
unsigned int potsWarningMode;
|
||||
bool potsWarnEnabled[CPN_MAX_POTS];
|
||||
int potsWarnPosition[CPN_MAX_POTS];
|
||||
bool potsWarnEnabled[CPN_MAX_POTS + CPN_MAX_SLIDERS];
|
||||
int potsWarnPosition[CPN_MAX_POTS + CPN_MAX_SLIDERS];
|
||||
bool displayChecklist;
|
||||
|
||||
GVarData gvarData[CPN_MAX_GVARS];
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
#include "multiprotocols.h"
|
||||
#include "afhds3.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "compounditemmodels.h"
|
||||
#include "generalsettings.h"
|
||||
|
||||
#include <QPair>
|
||||
#include <QVector>
|
||||
|
||||
void ModuleData::convert(RadioDataConversionState & cstate)
|
||||
{
|
||||
@@ -149,7 +154,7 @@ QString ModuleData::indexToString(int index, Firmware * fw)
|
||||
}
|
||||
|
||||
// static
|
||||
QString ModuleData::protocolToString(unsigned protocol)
|
||||
QString ModuleData::protocolToString(unsigned int protocol)
|
||||
{
|
||||
static const char * strings[] = {
|
||||
"OFF",
|
||||
@@ -159,8 +164,8 @@ QString ModuleData::protocolToString(unsigned protocol)
|
||||
"LP45", "DSM2", "DSMX",
|
||||
"PPM16", "PPMsim",
|
||||
"FrSky XJT (D16)", "FrSky XJT (D8)", "FrSky XJT (LR12)", "FrSky DJT",
|
||||
"TBS Crossfire",
|
||||
"DIY Multiprotocol Module",
|
||||
"Crossfire",
|
||||
"Multi",
|
||||
"FrSky R9M",
|
||||
"FrSky R9M Lite",
|
||||
"FrSky R9M Lite Pro",
|
||||
@@ -171,7 +176,7 @@ QString ModuleData::protocolToString(unsigned protocol)
|
||||
"FrSky ACCESS R9M Lite Pro",
|
||||
"FrSky XJT lite (D16)", "FrSky XJT lite (D8)", "FrSky XJT lite (LR12)",
|
||||
"AFHDS3",
|
||||
"ImmersionRC Ghost"
|
||||
"Ghost"
|
||||
};
|
||||
|
||||
return CHECK_IN_ARRAY(strings, protocol);
|
||||
@@ -262,3 +267,232 @@ int ModuleData::getMaxChannelCount()
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
|
||||
/*
|
||||
If Companion did not combine the /radio/src/datastructs type and sub-type fields
|
||||
this would be so much cleaner and, modules and protocols generally easier to maintain
|
||||
Another case for refactoring ModuleData as a whole!
|
||||
*/
|
||||
|
||||
// static
|
||||
int ModuleData::getTypeFromProtocol(unsigned int protocol)
|
||||
{
|
||||
// must be kept in sync with opentxeeprom.h ProtocolsConversionTable
|
||||
|
||||
const QVector<QPair<int, int>>ProtocolTypeTable = {
|
||||
|
||||
{ PULSES_OFF, MODULE_TYPE_NONE },
|
||||
{ PULSES_PPM, MODULE_TYPE_PPM },
|
||||
|
||||
{ PULSES_PXX_XJT_X16, MODULE_TYPE_XJT_PXX1 },
|
||||
{ PULSES_PXX_XJT_D8, MODULE_TYPE_XJT_PXX1 },
|
||||
{ PULSES_PXX_XJT_LR12, MODULE_TYPE_XJT_PXX1 },
|
||||
|
||||
{ PULSES_ACCESS_ISRM, MODULE_TYPE_ISRM_PXX2 },
|
||||
{ PULSES_ACCST_ISRM_D16, MODULE_TYPE_ISRM_PXX2 },
|
||||
|
||||
{ PULSES_LP45, MODULE_TYPE_DSM2 },
|
||||
{ PULSES_DSM2, MODULE_TYPE_DSM2 },
|
||||
{ PULSES_DSMX, MODULE_TYPE_DSM2 },
|
||||
|
||||
{ PULSES_CROSSFIRE, MODULE_TYPE_CROSSFIRE },
|
||||
{ PULSES_MULTIMODULE, MODULE_TYPE_MULTIMODULE },
|
||||
{ PULSES_PXX_R9M, MODULE_TYPE_R9M_PXX1 },
|
||||
{ PULSES_ACCESS_R9M, MODULE_TYPE_R9M_PXX2 },
|
||||
{ PULSES_PXX_R9M_LITE, MODULE_TYPE_R9M_LITE_PXX1 },
|
||||
{ PULSES_ACCESS_R9M_LITE, MODULE_TYPE_R9M_LITE_PXX2 },
|
||||
{ PULSES_GHOST, MODULE_TYPE_GHOST },
|
||||
{ PULSES_ACCESS_R9M_LITE_PRO, MODULE_TYPE_R9M_LITE_PRO_PXX2 },
|
||||
{ PULSES_SBUS, MODULE_TYPE_SBUS },
|
||||
|
||||
{ PULSES_XJT_LITE_X16, MODULE_TYPE_XJT_LITE_PXX2 },
|
||||
{ PULSES_XJT_LITE_D8, MODULE_TYPE_XJT_LITE_PXX2 },
|
||||
{ PULSES_XJT_LITE_LR12, MODULE_TYPE_XJT_LITE_PXX2 },
|
||||
|
||||
{ PULSES_AFHDS3, MODULE_TYPE_FLYSKY }
|
||||
};
|
||||
|
||||
QPair<int, int>elmt;
|
||||
|
||||
foreach (elmt, ProtocolTypeTable) {
|
||||
if (elmt.first == (int)protocol)
|
||||
return elmt.second;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// static
|
||||
int ModuleData::getSubTypeFromProtocol(unsigned int protocol)
|
||||
{
|
||||
if (protocol == PULSES_ACCST_ISRM_D16 || protocol == PULSES_ACCESS_ISRM)
|
||||
return protocol - PULSES_ACCESS_ISRM;
|
||||
else if (protocol >= PULSES_PXX_XJT_X16 && protocol <= PULSES_PXX_XJT_LR12)
|
||||
return protocol - PULSES_PXX_XJT_X16;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static
|
||||
QString ModuleData::typeToString(int type)
|
||||
{
|
||||
static const char * strings[] = {
|
||||
"OFF",
|
||||
"PPM",
|
||||
"XJT",
|
||||
"ISRM",
|
||||
"DSM2",
|
||||
"CRSF",
|
||||
"MULTI",
|
||||
"R9M",
|
||||
"R9M ACCESS",
|
||||
"R9MLite",
|
||||
"R9ML ACCESS",
|
||||
"GHST",
|
||||
"R9MLP ACCESS",
|
||||
"SBUS",
|
||||
"XJT Lite",
|
||||
"FLYSKY"
|
||||
};
|
||||
|
||||
return CHECK_IN_ARRAY(strings, type);
|
||||
}
|
||||
|
||||
AbstractStaticItemModel * ModuleData::internalModuleItemModel(int board)
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName("moduledata.internalmodule");
|
||||
|
||||
auto modules = Boards::getSupportedInternalModules(board == Board::BOARD_UNKNOWN ? getCurrentBoard() : (Board::Type)board);
|
||||
for(auto mod : modules) {
|
||||
mdl->appendToItemList(typeToString(mod), mod);
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
// static
|
||||
bool ModuleData::isProtocolAvailable(int moduleidx, unsigned int protocol, GeneralSettings & settings)
|
||||
{
|
||||
if (protocol == PULSES_OFF)
|
||||
return true;
|
||||
|
||||
Firmware *fw = getCurrentFirmware();
|
||||
Board::Type board = fw->getBoard();
|
||||
|
||||
if (moduleidx == 0 && Boards::getCapability(board, Board::HasInternalModuleSupport))
|
||||
return (int)settings.internalModule == getTypeFromProtocol(protocol);
|
||||
|
||||
QString id = fw->getId();
|
||||
|
||||
if (IS_HORUS_OR_TARANIS(board)) {
|
||||
switch (moduleidx) {
|
||||
case 1:
|
||||
switch (protocol) {
|
||||
case PULSES_OFF:
|
||||
case PULSES_PPM:
|
||||
return true;
|
||||
case PULSES_PXX_XJT_X16:
|
||||
case PULSES_PXX_XJT_D8:
|
||||
case PULSES_PXX_XJT_LR12:
|
||||
return !(IS_TARANIS_XLITES(board) || IS_TARANIS_X9LITE(board));
|
||||
case PULSES_PXX_R9M:
|
||||
case PULSES_LP45:
|
||||
case PULSES_DSM2:
|
||||
case PULSES_DSMX:
|
||||
case PULSES_SBUS:
|
||||
case PULSES_MULTIMODULE:
|
||||
case PULSES_CROSSFIRE:
|
||||
case PULSES_AFHDS3:
|
||||
case PULSES_GHOST:
|
||||
return true;
|
||||
case PULSES_ACCESS_R9M:
|
||||
return IS_ACCESS_RADIO(board, id) || (IS_FAMILY_HORUS_OR_T16(board) && id.contains("externalaccessmod"));
|
||||
case PULSES_PXX_R9M_LITE:
|
||||
case PULSES_ACCESS_R9M_LITE:
|
||||
case PULSES_ACCESS_R9M_LITE_PRO:
|
||||
case PULSES_XJT_LITE_X16:
|
||||
case PULSES_XJT_LITE_D8:
|
||||
case PULSES_XJT_LITE_LR12:
|
||||
return (IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || IS_JUMPER_TLITE(board));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
case -1:
|
||||
switch (protocol) {
|
||||
case PULSES_PPM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (IS_SKY9X(board)) {
|
||||
switch (moduleidx) {
|
||||
case 0:
|
||||
switch (protocol) {
|
||||
case PULSES_PPM:
|
||||
case PULSES_PXX_XJT_X16:
|
||||
case PULSES_PXX_XJT_D8:
|
||||
case PULSES_PXX_XJT_LR12:
|
||||
case PULSES_PXX_R9M:
|
||||
case PULSES_LP45:
|
||||
case PULSES_DSM2:
|
||||
case PULSES_DSMX:
|
||||
case PULSES_SBUS:
|
||||
case PULSES_MULTIMODULE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (protocol) {
|
||||
case PULSES_PPM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (protocol) {
|
||||
case PULSES_PPM:
|
||||
case PULSES_DSMX:
|
||||
case PULSES_LP45:
|
||||
case PULSES_DSM2:
|
||||
// case PULSES_PXX_DJT: // Unavailable for now
|
||||
case PULSES_PPM16:
|
||||
case PULSES_PPMSIM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // to avoid compiler warning
|
||||
}
|
||||
|
||||
// static
|
||||
AbstractStaticItemModel * ModuleData::protocolItemModel(GeneralSettings & settings)
|
||||
{
|
||||
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
|
||||
mdl->setName("moduledata.protocol");
|
||||
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
for (unsigned int j = 0; j < PULSES_PROTOCOL_LAST; j++) {
|
||||
mdl->appendToItemList(protocolToString(j), j, isProtocolAvailable(i, j, settings), 0, i + 1/*flag cannot be 0*/);
|
||||
}
|
||||
}
|
||||
|
||||
mdl->loadItemList();
|
||||
return mdl;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MODULEDATA_H
|
||||
#define MODULEDATA_H
|
||||
#pragma once
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
@@ -27,6 +26,30 @@
|
||||
|
||||
class Firmware;
|
||||
class RadioDataConversionState;
|
||||
class AbstractStaticItemModel;
|
||||
class GeneralSettings;
|
||||
|
||||
// from radio/src/pulses/module_constants.h
|
||||
enum ModuleType {
|
||||
MODULE_TYPE_NONE = 0,
|
||||
MODULE_TYPE_PPM,
|
||||
MODULE_TYPE_XJT_PXX1,
|
||||
MODULE_TYPE_ISRM_PXX2,
|
||||
MODULE_TYPE_DSM2,
|
||||
MODULE_TYPE_CROSSFIRE,
|
||||
MODULE_TYPE_MULTIMODULE,
|
||||
MODULE_TYPE_R9M_PXX1, // R9M
|
||||
MODULE_TYPE_R9M_PXX2, // R9M ACCESS
|
||||
MODULE_TYPE_R9M_LITE_PXX1, //R9MLite
|
||||
MODULE_TYPE_R9M_LITE_PXX2, //R9MLP
|
||||
MODULE_TYPE_GHOST, // Replaces MODULE_TYPE_R9M_LITE_PRO_PXX1 which doesn't exist
|
||||
MODULE_TYPE_R9M_LITE_PRO_PXX2,
|
||||
MODULE_TYPE_SBUS,
|
||||
MODULE_TYPE_XJT_LITE_PXX2,
|
||||
MODULE_TYPE_FLYSKY, //no more protocols possible because of 4 bits value
|
||||
MODULE_TYPE_COUNT,
|
||||
MODULE_TYPE_MAX = MODULE_TYPE_COUNT - 1
|
||||
};
|
||||
|
||||
enum PulsesProtocol {
|
||||
PULSES_OFF,
|
||||
@@ -219,10 +242,14 @@ class ModuleData {
|
||||
QString subTypeToString(int type = -1) const;
|
||||
QString powerValueToString(Firmware * fw) const;
|
||||
static QString indexToString(int index, Firmware * fw);
|
||||
static QString protocolToString(unsigned protocol);
|
||||
static QString protocolToString(unsigned int protocol);
|
||||
static QStringList powerValueStrings(enum PulsesProtocol protocol, int subType, Firmware * fw);
|
||||
bool hasFailsafes(Firmware * fw) const;
|
||||
int getMaxChannelCount();
|
||||
static int getTypeFromProtocol(unsigned int protocol);
|
||||
static int getSubTypeFromProtocol(unsigned int protocol);
|
||||
static QString typeToString(int type);
|
||||
static AbstractStaticItemModel * internalModuleItemModel(int board = -1);
|
||||
static bool isProtocolAvailable(int moduleidx, unsigned int protocol, GeneralSettings & settings);
|
||||
static AbstractStaticItemModel * protocolItemModel(GeneralSettings & settings);
|
||||
};
|
||||
|
||||
#endif // MODULEDATA_H
|
||||
|
||||
@@ -79,6 +79,8 @@ inline int MAX_POTS(Board::Type board, int version)
|
||||
{
|
||||
if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board))
|
||||
return 3;
|
||||
if (version <= 220 && (IS_HORUS_X10(board) || IS_FAMILY_T16(board)))
|
||||
return 5;
|
||||
if (IS_FAMILY_T12(board))
|
||||
return 2;
|
||||
return Boards::getCapability(board, Board::Pots);
|
||||
@@ -95,7 +97,7 @@ inline int MAX_POTS_STORAGE(Board::Type board, int version)
|
||||
{
|
||||
if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board))
|
||||
return 3;
|
||||
if (version >= 219 && IS_FAMILY_HORUS_OR_T16(board))
|
||||
if (version <= 220 && IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board))
|
||||
return 5;
|
||||
if (IS_FAMILY_T12(board))
|
||||
return 2;
|
||||
@@ -105,6 +107,8 @@ inline int MAX_POTS_STORAGE(Board::Type board, int version)
|
||||
inline int MAX_POTS_SOURCES(Board::Type board, int version)
|
||||
{
|
||||
if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board))
|
||||
return 3;
|
||||
if (version <= 220 && (IS_HORUS_X10(board) || IS_FAMILY_T16(board)))
|
||||
return 5;
|
||||
if (IS_FAMILY_T12(board))
|
||||
return 2;
|
||||
@@ -115,6 +119,8 @@ inline int MAX_XPOTS(Board::Type board, int version)
|
||||
{
|
||||
if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board))
|
||||
return 3;
|
||||
if (version <= 220 && (IS_HORUS_X10(board) || IS_FAMILY_T16(board)))
|
||||
return 5;
|
||||
if (IS_FAMILY_T12(board))
|
||||
return 2;
|
||||
return Boards::getCapability(board, Board::MultiposPots);
|
||||
@@ -180,6 +186,7 @@ inline int MAX_MOUSE_ANALOG_SOURCES(Board::Type board, int version)
|
||||
#define NUM_PPM_INPUTS(board, version) 16
|
||||
#define ROTENC_COUNT(board, version) ((IS_STM32(board) && version >= 218) ? 0 : 1)
|
||||
#define MAX_AUX_TRIMS(board) ((IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board)) ? 2 : 0)
|
||||
#define MAX_SOURCE_TYPE_SPECIAL(board, version) SOURCE_TYPE_SPECIAL_COUNT
|
||||
|
||||
inline int switchIndex(int i, Board::Type board, unsigned int version)
|
||||
{
|
||||
@@ -340,6 +347,8 @@ class SourcesConversionTable: public ConversionTable {
|
||||
int offset = 0;
|
||||
if (version <= 218 && IS_HORUS_X10(board) && i >= CPN_MAX_STICKS + MAX_POTS_STORAGE(board, version))
|
||||
offset += 2;
|
||||
if (version <= 220 && (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) && i >= CPN_MAX_STICKS + MAX_POTS_STORAGE(board, version))
|
||||
offset += 2;
|
||||
|
||||
addConversion(RawSource(SOURCE_TYPE_STICK, i + offset), val++);
|
||||
}
|
||||
@@ -376,12 +385,8 @@ class SourcesConversionTable: public ConversionTable {
|
||||
if (!(flags & FLAG_NOTELEMETRY)) {
|
||||
for (int i=0; i<MAX_GVARS(board, version); i++)
|
||||
addConversion(RawSource(SOURCE_TYPE_GVAR, i), val++);
|
||||
addConversion(RawSource(SOURCE_TYPE_SPECIAL, 0), val++); // BATT
|
||||
addConversion(RawSource(SOURCE_TYPE_SPECIAL, 1), val++); // TIME
|
||||
val += 5;
|
||||
addConversion(RawSource(SOURCE_TYPE_SPECIAL, 2), val++); // Timer1
|
||||
addConversion(RawSource(SOURCE_TYPE_SPECIAL, 3), val++); // Timer2
|
||||
addConversion(RawSource(SOURCE_TYPE_SPECIAL, 4), val++); // Timer3
|
||||
for (int i=0; i<MAX_SOURCE_TYPE_SPECIAL(board, version); i++)
|
||||
addConversion(RawSource(SOURCE_TYPE_SPECIAL, i), val++);
|
||||
for (int i=0; i<MAX_TELEMETRY_SENSORS(board, version)*3; ++i) {
|
||||
addConversion(RawSource(SOURCE_TYPE_TELEMETRY, i), val++);
|
||||
}
|
||||
@@ -1275,10 +1280,6 @@ class CurvesField: public TransformedField {
|
||||
curve->points[j].x = *cur++;
|
||||
curve->points[curve->count-1].x = +100;
|
||||
}
|
||||
else {
|
||||
for (int j=0; j<curve->count; j++)
|
||||
curve->points[j].x = -100 + (200*i) / (curve->count-1);
|
||||
}
|
||||
qCDebug(eepromImport) << QString("imported curve: %3 points").arg(curve->count);
|
||||
}
|
||||
}
|
||||
@@ -2947,6 +2948,9 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
|
||||
if (version <= 218 && IS_HORUS_X10(board) && (i == CPN_MAX_STICKS + 3)) {
|
||||
input += 2;
|
||||
}
|
||||
if (version <= 220 && IS_FAMILY_HORUS_OR_T16(board) && (i == CPN_MAX_STICKS + 5)) { // make room for EXT3 and EXT4
|
||||
input += 2;
|
||||
}
|
||||
internalField.Append(new SignedField<16>(this, generalData.calibMid[input]));
|
||||
internalField.Append(new SignedField<16>(this, generalData.calibSpanNeg[input]));
|
||||
internalField.Append(new SignedField<16>(this, generalData.calibSpanPos[input]));
|
||||
|
||||
@@ -59,59 +59,59 @@ const char * OpenTxEepromInterface::getName()
|
||||
{
|
||||
switch (board) {
|
||||
case BOARD_JUMPER_T12:
|
||||
return "OpenTX for Jumper T12";
|
||||
return "EdgeTX for Jumper T12";
|
||||
case BOARD_JUMPER_TLITE:
|
||||
return "OpenTX for Jumper T-Lite";
|
||||
return "EdgeTX for Jumper T-Lite";
|
||||
case BOARD_JUMPER_TPRO:
|
||||
return "OpenTX for Jumper T-Pro";
|
||||
return "EdgeTX for Jumper T-Pro";
|
||||
case BOARD_JUMPER_T16:
|
||||
return "OpenTX for Jumper T16";
|
||||
return "EdgeTX for Jumper T16";
|
||||
case BOARD_JUMPER_T18:
|
||||
return "OpenTX for Jumper T18";
|
||||
return "EdgeTX for Jumper T18";
|
||||
case BOARD_RADIOMASTER_TX16S:
|
||||
return "OpenTX for Radiomaster TX16S";
|
||||
return "EdgeTX for Radiomaster TX16S";
|
||||
case BOARD_RADIOMASTER_TX12:
|
||||
return "OpenTX for Radiomaster TX12";
|
||||
return "EdgeTX for Radiomaster TX12";
|
||||
case BOARD_RADIOMASTER_ZORRO:
|
||||
return "OpenTX for Radiomaster Zorro";
|
||||
return "EdgeTX for Radiomaster Zorro";
|
||||
case BOARD_RADIOMASTER_T8:
|
||||
return "OpenTX for Radiomaster T8";
|
||||
return "EdgeTX for Radiomaster T8";
|
||||
case BOARD_TARANIS_X9D:
|
||||
return "OpenTX for FrSky Taranis X9D";
|
||||
return "EdgeTX for FrSky Taranis X9D";
|
||||
case BOARD_TARANIS_X9DP:
|
||||
return "OpenTX for FrSky Taranis X9D+";
|
||||
return "EdgeTX for FrSky Taranis X9D+";
|
||||
case BOARD_TARANIS_X9DP_2019:
|
||||
return "OpenTX for FrSky Taranis X9D+ 2019";
|
||||
return "EdgeTX for FrSky Taranis X9D+ 2019";
|
||||
case BOARD_TARANIS_X9E:
|
||||
return "OpenTX for FrSky Taranis X9E";
|
||||
return "EdgeTX for FrSky Taranis X9E";
|
||||
case BOARD_TARANIS_X7:
|
||||
return "OpenTX for FrSky Taranis X7";
|
||||
return "EdgeTX for FrSky Taranis X7";
|
||||
case BOARD_TARANIS_X7_ACCESS:
|
||||
return "OpenTX for FrSky Taranis X7 Access";
|
||||
return "EdgeTX for FrSky Taranis X7 Access";
|
||||
case BOARD_TARANIS_X9LITES:
|
||||
return "OpenTX for FrSky Taranis X9-Lite S";
|
||||
return "EdgeTX for FrSky Taranis X9-Lite S";
|
||||
case BOARD_TARANIS_X9LITE:
|
||||
return "OpenTX for FrSky Taranis X9-Lite";
|
||||
return "EdgeTX for FrSky Taranis X9-Lite";
|
||||
case BOARD_TARANIS_XLITE:
|
||||
return "OpenTX for FrSky Taranis X-Lite";
|
||||
return "EdgeTX for FrSky Taranis X-Lite";
|
||||
case BOARD_TARANIS_XLITES:
|
||||
return "OpenTX for FrSky Taranis X-Lite S/Pro";
|
||||
return "EdgeTX for FrSky Taranis X-Lite S/Pro";
|
||||
case BOARD_SKY9X:
|
||||
return "OpenTX for Sky9x board / 9X";
|
||||
return "EdgeTX for Sky9x board / 9X";
|
||||
case BOARD_9XRPRO:
|
||||
return "OpenTX for 9XR-PRO";
|
||||
return "EdgeTX for 9XR-PRO";
|
||||
case BOARD_AR9X:
|
||||
return "OpenTX for ar9x board / 9X";
|
||||
return "EdgeTX for ar9x board / 9X";
|
||||
case BOARD_HORUS_X12S:
|
||||
return "OpenTX for FrSky Horus";
|
||||
return "EdgeTX for FrSky Horus";
|
||||
case BOARD_X10:
|
||||
return "OpenTX for FrSky X10";
|
||||
return "EdgeTX for FrSky X10";
|
||||
case BOARD_X10_EXPRESS:
|
||||
return "OpenTX for FrSky X10 Express";
|
||||
return "EdgeTX for FrSky X10 Express";
|
||||
case BOARD_FLYSKY_NV14:
|
||||
return "OpenTX for FlySky NV14";
|
||||
return "EdgeTX for FlySky NV14";
|
||||
default:
|
||||
return "OpenTX for an unknown board";
|
||||
return "Board is unknown to EdgeTX";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t *
|
||||
errors.set(HAS_WARNINGS);
|
||||
}
|
||||
else if (version_error == NOT_OPENTX) {
|
||||
dbg << " not open9x";
|
||||
dbg << " not OpenTX";
|
||||
errors.set(version_error);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
@@ -286,7 +286,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t *
|
||||
|
||||
uint8_t OpenTxEepromInterface::getLastDataVersion(Board::Type board)
|
||||
{
|
||||
return 220;
|
||||
return 220; // Note: this is the last bin format before the switch to YAML introduced in Companion version 2.6
|
||||
}
|
||||
|
||||
void OpenTxEepromInterface::showErrors(const QString & title, const QStringList & errors)
|
||||
@@ -752,14 +752,17 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
case HasAntennaChoice:
|
||||
return ((IS_FAMILY_HORUS_OR_T16(board) && board != Board::BOARD_X10_EXPRESS) || (IS_TARANIS_XLITE(board) && !IS_TARANIS_XLITES(board))) ? true : false;
|
||||
case HasADCJitterFilter:
|
||||
return IS_HORUS_OR_TARANIS(board) ? true : false;
|
||||
return IS_HORUS_OR_TARANIS(board);
|
||||
case HasTelemetryBaudrate:
|
||||
return IS_HORUS_OR_TARANIS(board) ? true : false;
|
||||
return IS_HORUS_OR_TARANIS(board);
|
||||
case TopBarZones:
|
||||
return getCapability(LcdWidth) > getCapability(LcdHeight) ? 4 : 2;
|
||||
case FunctionSwitches:
|
||||
return IS_JUMPER_TPRO(board) ? 6 : 0;
|
||||
|
||||
case HasModelsList:
|
||||
return IS_FAMILY_HORUS_OR_T16(board);
|
||||
case HasFlySkyGimbals:
|
||||
return (IS_RADIOMASTER_TX16S(board) && id.contains("flyskygimbals"));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -981,6 +984,13 @@ EepromLoadErrors OpenTxEepromInterface::checkVersion(unsigned int version)
|
||||
// ALL: TimerData countdownStart invert value
|
||||
// ALL: convert more fields from zchar to normal string
|
||||
// COLORLCD: change CustomScreenData and TopBarPersistentData
|
||||
return OLD_VERSION;
|
||||
|
||||
case 221:
|
||||
// ALL: YAML storage
|
||||
// X10PCB: add pots EXT3 and EXT4 (conversion required as shifts slider settings in multiple fields)
|
||||
// RM TX16S: add Flysky gimbals firmware build option and repurpose EXT3 and EXT4 if selected
|
||||
// ??: add source TX GPS
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1270,25 +1280,28 @@ void addOpenTxArm9xOptions(OpenTxFirmware * firmware, bool dblkeys = true)
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
}
|
||||
|
||||
// TODO: refactoring OpenTxFirmware constructor - need to check if used elsewhere and how
|
||||
#define FIRMWAREID(flavour) std::string(FIRMWARE_ID_PREFIX).append(flavour).c_str()
|
||||
|
||||
void registerOpenTxFirmwares()
|
||||
{
|
||||
OpenTxFirmware * firmware;
|
||||
|
||||
/* FrSky Taranis X9D+ board */
|
||||
firmware = new OpenTxFirmware("opentx-x9d+", Firmware::tr("FrSky Taranis X9D+"), BOARD_TARANIS_X9DP);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x9d+"), Firmware::tr("FrSky Taranis X9D+"), BOARD_TARANIS_X9DP);
|
||||
firmware->addOption("noras", Firmware::tr("Disable RAS (SWR)"));
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3);
|
||||
|
||||
/* FrSky Taranis X9D+ 2019 board */
|
||||
firmware = new OpenTxFirmware("opentx-x9d+2019", Firmware::tr("FrSky Taranis X9D+ 2019"), BOARD_TARANIS_X9DP_2019);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x9d+2019"), Firmware::tr("FrSky Taranis X9D+ 2019"), BOARD_TARANIS_X9DP_2019);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* FrSky Taranis X9D board */
|
||||
firmware = new OpenTxFirmware("opentx-x9d", Firmware::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x9d"), Firmware::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D);
|
||||
firmware->addOption("noras", Firmware::tr("Disable RAS (SWR)"));
|
||||
firmware->addOption("haptic", Firmware::tr("Haptic module installed"));
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
@@ -1296,7 +1309,7 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3);
|
||||
|
||||
/* FrSky Taranis X9E board */
|
||||
firmware = new OpenTxFirmware("opentx-x9e", Firmware::tr("FrSky Taranis X9E"), BOARD_TARANIS_X9E);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x9e"), Firmware::tr("FrSky Taranis X9E"), BOARD_TARANIS_X9E);
|
||||
firmware->addOption("shutdownconfirm", Firmware::tr("Confirmation before radio shutdown"));
|
||||
firmware->addOption("horussticks", Firmware::tr("Horus gimbals installed (Hall sensors)"));
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
@@ -1304,44 +1317,44 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, EU + FLEX);
|
||||
|
||||
/* FrSky X9-Lite board */
|
||||
firmware = new OpenTxFirmware("opentx-x9lite", Firmware::tr("FrSky Taranis X9-Lite"), BOARD_TARANIS_X9LITE);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x9lite"), Firmware::tr("FrSky Taranis X9-Lite"), BOARD_TARANIS_X9LITE);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* FrSky X9-LiteS board */
|
||||
firmware = new OpenTxFirmware("opentx-x9lites", Firmware::tr("FrSky Taranis X9-Lite S"), BOARD_TARANIS_X9LITES);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x9lites"), Firmware::tr("FrSky Taranis X9-Lite S"), BOARD_TARANIS_X9LITES);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* FrSky X7 board */
|
||||
firmware = new OpenTxFirmware("opentx-x7", Firmware::tr("FrSky Taranis X7 / X7S"), BOARD_TARANIS_X7);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x7"), Firmware::tr("FrSky Taranis X7 / X7S"), BOARD_TARANIS_X7);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, EU + FLEX);
|
||||
|
||||
/* FrSky X7 Access board */
|
||||
firmware = new OpenTxFirmware("opentx-x7access", Firmware::tr("FrSky Taranis X7 / X7S Access"), BOARD_TARANIS_X7_ACCESS);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x7access"), Firmware::tr("FrSky Taranis X7 / X7S Access"), BOARD_TARANIS_X7_ACCESS);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* FrSky X-Lite S/PRO board */
|
||||
firmware = new OpenTxFirmware("opentx-xlites", Firmware::tr("FrSky Taranis X-Lite S/PRO"), BOARD_TARANIS_XLITES);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("xlites"), Firmware::tr("FrSky Taranis X-Lite S/PRO"), BOARD_TARANIS_XLITES);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* FrSky X-Lite board */
|
||||
firmware = new OpenTxFirmware("opentx-xlite", Firmware::tr("FrSky Taranis X-Lite"), BOARD_TARANIS_XLITE);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("xlite"), Firmware::tr("FrSky Taranis X-Lite"), BOARD_TARANIS_XLITE);
|
||||
// firmware->addOption("stdr9m", Firmware::tr("Use JR-sized R9M module"));
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, EU + FLEX);
|
||||
|
||||
/* FrSky X10 board */
|
||||
firmware = new OpenTxFirmware("opentx-x10", Firmware::tr("FrSky Horus X10 / X10S"), BOARD_X10);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x10"), Firmware::tr("FrSky Horus X10 / X10S"), BOARD_X10);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("internalaccess", Firmware::tr("Support for ACCESS internal module replacement"));
|
||||
firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS"));
|
||||
@@ -1349,13 +1362,13 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, EU + FLEX);
|
||||
|
||||
/* FrSky X10 Express board */
|
||||
firmware = new OpenTxFirmware("opentx-x10express", Firmware::tr("FrSky Horus X10 Express / X10S Express"), BOARD_X10_EXPRESS);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x10express"), Firmware::tr("FrSky Horus X10 Express / X10S Express"), BOARD_X10_EXPRESS);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* FrSky X12 (Horus) board */
|
||||
firmware = new OpenTxFirmware("opentx-x12s", Firmware::tr("FrSky Horus X12S"), BOARD_HORUS_X12S);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("x12s"), Firmware::tr("FrSky Horus X12S"), BOARD_HORUS_X12S);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("internalaccess", Firmware::tr("Support for ACCESS internal module replacement"));
|
||||
firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS"));
|
||||
@@ -1364,7 +1377,7 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, EU + FLEX);
|
||||
|
||||
/* Jumper T12 board */
|
||||
firmware = new OpenTxFirmware("opentx-t12", QCoreApplication::translate("Firmware", "Jumper T12 / T12 Pro"), BOARD_JUMPER_T12);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("t12"), QCoreApplication::translate("Firmware", "Jumper T12 / T12 Pro"), BOARD_JUMPER_T12);
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
|
||||
@@ -1375,7 +1388,7 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* Jumper T-Lite board */
|
||||
firmware = new OpenTxFirmware("opentx-tlite", QCoreApplication::translate("Firmware", "Jumper T-Lite"), BOARD_JUMPER_TLITE);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("tlite"), QCoreApplication::translate("Firmware", "Jumper T-Lite"), BOARD_JUMPER_TLITE);
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
|
||||
@@ -1385,7 +1398,7 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* Jumper T-Pro board */
|
||||
firmware = new OpenTxFirmware("opentx-tpro", QCoreApplication::translate("Firmware", "Jumper T-Pro"), BOARD_JUMPER_TPRO);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("tpro"), QCoreApplication::translate("Firmware", "Jumper T-Pro"), BOARD_JUMPER_TPRO);
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
|
||||
@@ -1395,7 +1408,7 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* Jumper T16 board */
|
||||
firmware = new OpenTxFirmware("opentx-t16", Firmware::tr("Jumper T16 / T16+ / T16 Pro"), BOARD_JUMPER_T16);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("t16"), Firmware::tr("Jumper T16 / T16+ / T16 Pro"), BOARD_JUMPER_T16);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module"));
|
||||
firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module"));
|
||||
@@ -1404,7 +1417,7 @@ void registerOpenTxFirmwares()
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* Radiomaster TX12 board */
|
||||
firmware = new OpenTxFirmware("opentx-tx12", QCoreApplication::translate("Firmware", "Radiomaster TX12"), BOARD_RADIOMASTER_TX12);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("tx12"), QCoreApplication::translate("Firmware", "Radiomaster TX12"), BOARD_RADIOMASTER_TX12);
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
|
||||
@@ -1414,7 +1427,7 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* Radiomaster Zorro board */
|
||||
firmware = new OpenTxFirmware("opentx-zorro", QCoreApplication::translate("Firmware", "Radiomaster Zorro"), Board::BOARD_RADIOMASTER_ZORRO);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("zorro"), QCoreApplication::translate("Firmware", "Radiomaster Zorro"), Board::BOARD_RADIOMASTER_ZORRO);
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
|
||||
@@ -1425,7 +1438,7 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
|
||||
|
||||
/* Radiomaster T8 board */
|
||||
firmware = new OpenTxFirmware("opentx-t8", QCoreApplication::translate("Firmware", "Radiomaster T8"), BOARD_RADIOMASTER_T8);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("t8"), QCoreApplication::translate("Firmware", "Radiomaster T8"), BOARD_RADIOMASTER_T8);
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
|
||||
@@ -1436,17 +1449,18 @@ void registerOpenTxFirmwares()
|
||||
firmware->addOption("bindkey", Firmware::tr("Allow bind using bind key"));
|
||||
|
||||
/* Radiomaster TX16S board */
|
||||
firmware = new OpenTxFirmware("opentx-tx16s", Firmware::tr("Radiomaster TX16S / SE / Hall / Masterfire"), BOARD_RADIOMASTER_TX16S);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("tx16s"), Firmware::tr("Radiomaster TX16S / SE / Hall / Masterfire"), BOARD_RADIOMASTER_TX16S);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
static const Firmware::Option opt_bt("bluetooth", Firmware::tr("Support for bluetooth module"));
|
||||
static const Firmware::Option opt_internal_gps("internalgps", Firmware::tr("Support internal GPS"));
|
||||
firmware->addOptionsGroup({opt_bt, opt_internal_gps});
|
||||
firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS"));
|
||||
firmware->addOption("flyskygimbals", Firmware::tr("Support hardware mod: FlySky Paladin EV Gimbals"));
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* Jumper T18 board */
|
||||
firmware = new OpenTxFirmware("opentx-t18", Firmware::tr("Jumper T18"), BOARD_JUMPER_T18);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("t18"), Firmware::tr("Jumper T18"), BOARD_JUMPER_T18);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module"));
|
||||
firmware->addOption("externalaccessmod", Firmware::tr("Support hardware mod: R9M ACCESS"));
|
||||
@@ -1454,30 +1468,30 @@ void registerOpenTxFirmwares()
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
|
||||
/* FlySky NV14 board */
|
||||
firmware = new OpenTxFirmware("opentx-nv14", QCoreApplication::translate("Firmware", "FlySky NV14"), BOARD_FLYSKY_NV14);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("nv14"), QCoreApplication::translate("Firmware", "FlySky NV14"), BOARD_FLYSKY_NV14);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module"));
|
||||
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* 9XR-Pro */
|
||||
firmware = new OpenTxFirmware("opentx-9xrpro", Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("9xrpro"), Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO);
|
||||
addOpenTxArm9xOptions(firmware, false);
|
||||
registerOpenTxFirmware(firmware, true);
|
||||
|
||||
/* ar9x board */
|
||||
firmware = new OpenTxFirmware("opentx-ar9x", Firmware::tr("9X with AR9X board"), BOARD_AR9X);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("ar9x"), Firmware::tr("9X with AR9X board"), BOARD_AR9X);
|
||||
addOpenTxArm9xOptions(firmware, true);
|
||||
//firmware->addOption("rtc", Firmware::tr("Optional RTC added"));
|
||||
//firmware->addOption("volume", Firmware::tr("i2c volume control added"));
|
||||
registerOpenTxFirmware(firmware, true);
|
||||
|
||||
/* Sky9x board */
|
||||
firmware = new OpenTxFirmware("opentx-sky9x", Firmware::tr("9X with Sky9x board"), BOARD_SKY9X);
|
||||
firmware = new OpenTxFirmware(FIRMWAREID("sky9x"), Firmware::tr("9X with Sky9x board"), BOARD_SKY9X);
|
||||
addOpenTxArm9xOptions(firmware);
|
||||
registerOpenTxFirmware(firmware, true);
|
||||
|
||||
Firmware::setDefaultVariant(Firmware::getFirmwareForId("opentx-tx16s"));
|
||||
Firmware::setDefaultVariant(Firmware::getFirmwareForFlavour("tx16s"));
|
||||
Firmware::setCurrentVariant(Firmware::getDefaultVariant());
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@ void RadioData::fixModelFilename(unsigned int index)
|
||||
{
|
||||
ModelData & model = models[index];
|
||||
QString filename(model.filename);
|
||||
bool ok = filename.endsWith(".bin");
|
||||
const bool hasSDCard = Boards::getCapability(getCurrentFirmware()->getBoard(), Board::HasSDCard);
|
||||
bool ok = hasSDCard ? filename.endsWith(".yml") : filename.endsWith(".bin");
|
||||
if (ok) {
|
||||
if (filename.startsWith("model") && filename.mid(5, filename.length()-9).toInt() > 0) {
|
||||
ok = false;
|
||||
@@ -54,7 +55,7 @@ void RadioData::fixModelFilename(unsigned int index)
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
sprintf(model.filename, "model%d.bin", index+1);
|
||||
sprintf(model.filename, "model%d.%s", index + 1, hasSDCard ? "yml" : "bin");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,11 +69,12 @@ void RadioData::fixModelFilenames()
|
||||
|
||||
QString RadioData::getNextModelFilename()
|
||||
{
|
||||
const bool hasSDCard = Boards::getCapability(getCurrentFirmware()->getBoard(), Board::HasSDCard);
|
||||
char filename[sizeof(ModelData::filename)];
|
||||
int index = 0;
|
||||
bool found = true;
|
||||
while (found) {
|
||||
sprintf(filename, "model%d.bin", ++index);
|
||||
sprintf(filename, "model%d.%s", ++index, hasSDCard ? "yml" : "bin");
|
||||
found = false;
|
||||
for (unsigned int i=0; i<models.size(); i++) {
|
||||
if (strcmp(filename, models[i].filename) == 0) {
|
||||
|
||||
@@ -12,7 +12,8 @@ class RadioDataConversionState;
|
||||
class CategoryData {
|
||||
public:
|
||||
CategoryData(const char * name) {
|
||||
strncpy(this->name, name, sizeof(CategoryData::name));
|
||||
memset(this->name, 0, sizeof(CategoryData::name));
|
||||
strncpy(this->name, name, sizeof(CategoryData::name)-1);
|
||||
}
|
||||
char name[15+1];
|
||||
};
|
||||
|
||||
@@ -96,6 +96,10 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
result.max = 24 * 60 * result.step - 60; // 23:59:00 with 1-minute resolution
|
||||
result.unit = tr("s");
|
||||
}
|
||||
else if (index == 2) { //GPS
|
||||
result.max = 30000;
|
||||
result.min = -result.max;
|
||||
}
|
||||
else { // Timers 1 - 3
|
||||
result.step = 1;
|
||||
result.max = 9 * 60 * 60 - 1; // 8:59:59 (to match firmware)
|
||||
@@ -137,7 +141,7 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con
|
||||
};
|
||||
|
||||
static const QString special[] = {
|
||||
tr("Batt"), tr("Time"), tr("Timer1"), tr("Timer2"), tr("Timer3"),
|
||||
tr("Batt"), tr("Time"), tr("GPS"), tr("Reserved1"), tr("Reserved2"), tr("Reserved3"), tr("Reserved4")
|
||||
};
|
||||
|
||||
static const QString rotary[] = { tr("REa"), tr("REb") };
|
||||
@@ -208,11 +212,11 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con
|
||||
return LimitData().nameToString(index);
|
||||
|
||||
case SOURCE_TYPE_SPECIAL:
|
||||
if (index >= SOURCE_TYPE_SPECIAL_TIMER1_IDX && index <= SOURCE_TYPE_SPECIAL_TIMER1_IDX + CPN_MAX_TIMERS - 1) {
|
||||
if (index >= SOURCE_TYPE_SPECIAL_FIRST_TIMER && index <= SOURCE_TYPE_SPECIAL_LAST_TIMER) {
|
||||
if (model)
|
||||
result = model->timers[index - SOURCE_TYPE_SPECIAL_TIMER1_IDX].nameToString(index - SOURCE_TYPE_SPECIAL_TIMER1_IDX);
|
||||
result = model->timers[index - SOURCE_TYPE_SPECIAL_FIRST_TIMER].nameToString(index - SOURCE_TYPE_SPECIAL_FIRST_TIMER);
|
||||
else
|
||||
result = TimerData().nameToString(index - SOURCE_TYPE_SPECIAL_TIMER1_IDX);
|
||||
result = TimerData().nameToString(index - SOURCE_TYPE_SPECIAL_FIRST_TIMER);
|
||||
}
|
||||
else
|
||||
result = CHECK_IN_ARRAY(special, index);
|
||||
@@ -289,7 +293,7 @@ bool RawSource::isSlider(int * sliderIndex, Board::Type board) const
|
||||
|
||||
bool RawSource::isTimeBased(Board::Type board) const
|
||||
{
|
||||
return (type == SOURCE_TYPE_SPECIAL && index > 0);
|
||||
return (type == SOURCE_TYPE_SPECIAL && index >= SOURCE_TYPE_SPECIAL_FIRST_TIMER && index <= SOURCE_TYPE_SPECIAL_LAST_TIMER);
|
||||
}
|
||||
|
||||
bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings * const gs, Board::Type board) const
|
||||
@@ -305,6 +309,9 @@ bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings
|
||||
if (type == SOURCE_TYPE_SWITCH && index >= b.getCapability(Board::Switches))
|
||||
return false;
|
||||
|
||||
if (type == SOURCE_TYPE_SPECIAL && index >= SOURCE_TYPE_SPECIAL_FIRST_RESERVED && index <= SOURCE_TYPE_SPECIAL_LAST_RESERVED)
|
||||
return false;
|
||||
|
||||
if (model) {
|
||||
if (type == SOURCE_TYPE_VIRTUAL_INPUT && !model->isInputValid(index))
|
||||
return false;
|
||||
@@ -411,3 +418,38 @@ QStringList RawSource::getSwitchList(Boards board) const
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// static
|
||||
StringTagMappingTable RawSource::getSpecialTypesLookupTable()
|
||||
{
|
||||
StringTagMappingTable tbl;
|
||||
|
||||
tbl.insert(tbl.end(), {
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_TX_BATT), "TX_VOLTAGE"},
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_TX_TIME), "TX_TIME"},
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_TX_GPS), "TX_GPS"},
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_RESERVED1), "RESERVED1"},
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_RESERVED2), "RESERVED2"},
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_RESERVED3), "RESERVED3"},
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_RESERVED4), "RESERVED4"},
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_TIMER1), "TIMER1"},
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_TIMER2), "TIMER2"},
|
||||
{std::to_string(SOURCE_TYPE_SPECIAL_TIMER3), "TIMER3"},
|
||||
});
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
// static
|
||||
StringTagMappingTable RawSource::getCyclicLookupTable()
|
||||
{
|
||||
StringTagMappingTable tbl;
|
||||
|
||||
tbl.insert(tbl.end(), {
|
||||
{"0", "CYC1"},
|
||||
{"1", "CYC2"},
|
||||
{"2", "CYC3"},
|
||||
});
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
#include "datahelpers.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
@@ -178,8 +179,25 @@ enum RawSourceType {
|
||||
MAX_SOURCE_TYPE
|
||||
};
|
||||
|
||||
enum RawSourceTypeSpecial {
|
||||
SOURCE_TYPE_SPECIAL_TX_BATT,
|
||||
SOURCE_TYPE_SPECIAL_TX_TIME,
|
||||
SOURCE_TYPE_SPECIAL_TX_GPS,
|
||||
SOURCE_TYPE_SPECIAL_FIRST_RESERVED,
|
||||
SOURCE_TYPE_SPECIAL_RESERVED1 = SOURCE_TYPE_SPECIAL_FIRST_RESERVED,
|
||||
SOURCE_TYPE_SPECIAL_RESERVED2,
|
||||
SOURCE_TYPE_SPECIAL_RESERVED3,
|
||||
SOURCE_TYPE_SPECIAL_RESERVED4,
|
||||
SOURCE_TYPE_SPECIAL_LAST_RESERVED = SOURCE_TYPE_SPECIAL_RESERVED4,
|
||||
SOURCE_TYPE_SPECIAL_FIRST_TIMER,
|
||||
SOURCE_TYPE_SPECIAL_TIMER1 = SOURCE_TYPE_SPECIAL_FIRST_TIMER,
|
||||
SOURCE_TYPE_SPECIAL_TIMER2,
|
||||
SOURCE_TYPE_SPECIAL_TIMER3,
|
||||
SOURCE_TYPE_SPECIAL_LAST_TIMER = SOURCE_TYPE_SPECIAL_TIMER3,
|
||||
SOURCE_TYPE_SPECIAL_COUNT
|
||||
};
|
||||
|
||||
constexpr int SOURCE_TYPE_STICK_THR_IDX { 3 }; // TODO is there a function to determine index?
|
||||
constexpr int SOURCE_TYPE_SPECIAL_TIMER1_IDX { 2 }; // TODO temp const until Timers own source type
|
||||
|
||||
class RawSourceRange
|
||||
{
|
||||
@@ -257,6 +275,8 @@ class RawSource {
|
||||
void clear() { type = SOURCE_TYPE_NONE; index = 0; }
|
||||
QStringList getStickList(Boards board) const;
|
||||
QStringList getSwitchList(Boards board) const;
|
||||
static StringTagMappingTable getSpecialTypesLookupTable();
|
||||
static StringTagMappingTable getCyclicLookupTable();
|
||||
|
||||
bool operator == ( const RawSource & other) const {
|
||||
return (this->type == other.type) && (this->index == other.index);
|
||||
|
||||
@@ -241,3 +241,28 @@ QStringList RawSwitch::getSwitchList(Boards board) const
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// static
|
||||
StringTagMappingTable RawSwitch::getRawSwitchTypesLookupTable()
|
||||
{
|
||||
StringTagMappingTable tbl;
|
||||
|
||||
tbl.insert(tbl.end(), {
|
||||
{std::to_string(SWITCH_TYPE_NONE), "NONE"},
|
||||
{std::to_string(SWITCH_TYPE_SWITCH), "Sxn"},
|
||||
{std::to_string(SWITCH_TYPE_VIRTUAL), "Ln"},
|
||||
{std::to_string(SWITCH_TYPE_MULTIPOS_POT), "6Pn"},
|
||||
{std::to_string(SWITCH_TYPE_TRIM), "Trim"},
|
||||
{std::to_string(SWITCH_TYPE_ROTARY_ENCODER), "RE"},
|
||||
{std::to_string(SWITCH_TYPE_ON), "ON"},
|
||||
{std::to_string(SWITCH_TYPE_OFF), "OFF"},
|
||||
{std::to_string(SWITCH_TYPE_ONE), "ONE"},
|
||||
{std::to_string(SWITCH_TYPE_FLIGHT_MODE), "FMn"},
|
||||
{std::to_string(SWITCH_TYPE_TIMER_MODE), "Timer"},
|
||||
{std::to_string(SWITCH_TYPE_TELEMETRY), "TELEMETRY_STREAMING"},
|
||||
{std::to_string(SWITCH_TYPE_SENSOR), "Tnn"},
|
||||
{std::to_string(SWITCH_TYPE_ACT), "RADIO_ACTIVITY"},
|
||||
});
|
||||
|
||||
return tbl;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "boards.h"
|
||||
#include "constants.h"
|
||||
#include "datahelpers.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
@@ -89,6 +90,7 @@ class RawSwitch {
|
||||
bool isSet() const { return type != SWITCH_TYPE_NONE || index != 0; }
|
||||
void clear() { type = SWITCH_TYPE_NONE; index = 0; }
|
||||
QStringList getSwitchList(Boards board) const;
|
||||
static StringTagMappingTable getRawSwitchTypesLookupTable();
|
||||
|
||||
bool operator== ( const RawSwitch& other) const {
|
||||
return (this->type == other.type) && (this->index == other.index);
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
constexpr int CPN_MAX_SENSORS { 60 };
|
||||
constexpr int SENSOR_LABEL_LEN { 4 };
|
||||
|
||||
constexpr int SENSOR_ISCONFIGURABLE { 1 << 1 };
|
||||
|
||||
@@ -65,7 +65,7 @@ void FrSkyData::clear()
|
||||
fasOffset = 0;
|
||||
for (int i=0; i<4; i++)
|
||||
screens[i].clear();
|
||||
varioSource = 2/*VARIO*/;
|
||||
varioSource = 0;
|
||||
blades = 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,12 @@ void TimerData::clear()
|
||||
swtch = RawSwitch(SWITCH_TYPE_NONE);
|
||||
}
|
||||
|
||||
bool TimerData::isEmpty()
|
||||
bool TimerData::isEmpty() const
|
||||
{
|
||||
return (swtch == RawSwitch(SWITCH_TYPE_NONE, 0) && mode == TIMERMODE_OFF && name[0] == '\0' && minuteBeep == 0 && countdownBeep == COUNTDOWNBEEP_SILENT && val == 0 && persistent == 0 /*&& pvalue == 0*/);
|
||||
return (swtch == RawSwitch(SWITCH_TYPE_NONE, 0) && mode == TIMERMODE_OFF &&
|
||||
name[0] == '\0' && minuteBeep == 0 &&
|
||||
countdownBeep == COUNTDOWNBEEP_SILENT && val == 0 &&
|
||||
persistent == 0 /*&& pvalue == 0*/);
|
||||
}
|
||||
|
||||
bool TimerData::isModeOff()
|
||||
|
||||
@@ -88,7 +88,7 @@ class TimerData {
|
||||
|
||||
void convert(RadioDataConversionState & cstate);
|
||||
void clear();
|
||||
bool isEmpty();
|
||||
bool isEmpty() const;
|
||||
bool isModeOff();
|
||||
QString nameToString(int index) const;
|
||||
QString countdownBeepToString() const;
|
||||
|
||||
@@ -266,7 +266,7 @@ void FlashEEpromDialog::on_burnButton_clicked()
|
||||
backupFilename = generateProcessUniqueTempFileName("eeprom.bin");
|
||||
}
|
||||
if (!backupFilename.isEmpty()) {
|
||||
if (!readEeprom(backupFilename, progressDialog.progress())) {
|
||||
if (!readSettings(backupFilename, progressDialog.progress())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -297,7 +297,7 @@ void FlashEEpromDialog::on_burnButton_clicked()
|
||||
}
|
||||
|
||||
// and write...
|
||||
bool result = writeEeprom(filename, progressDialog.progress());
|
||||
bool result = writeSettings(filename, progressDialog.progress());
|
||||
if (!result && !progressDialog.isEmpty()) {
|
||||
progressDialog.exec();
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ void FlashFirmwareDialog::startFlash(const QString &filename)
|
||||
backupPath=g.backupDir();
|
||||
}
|
||||
backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
|
||||
result = readEeprom(backupFilename, progressDialog.progress());
|
||||
result = readSettings(backupFilename, progressDialog.progress());
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
@@ -322,14 +322,14 @@ void FlashFirmwareDialog::startFlash(const QString &filename)
|
||||
QMessageBox::warning(this, tr("Conversion failed"), tr("Cannot convert Models and Settings for use with this firmware, original data will be used"));
|
||||
restoreFilename = backupFilename;
|
||||
}
|
||||
if (!writeEeprom(restoreFilename, progressDialog.progress())) {
|
||||
if (!writeSettings(restoreFilename, progressDialog.progress())) {
|
||||
QMessageBox::warning(this, tr("Restore failed"), tr("Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1").arg(backupFilename));
|
||||
}
|
||||
}
|
||||
|
||||
progressDialog.progress()->setInfo(tr("Flashing done"));
|
||||
}
|
||||
|
||||
|
||||
progressDialog.exec();
|
||||
|
||||
if (isTempFileName(filename)) {
|
||||
|
||||
@@ -25,15 +25,22 @@
|
||||
CalibrationPanel::CalibrationPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
GeneralPanel(parent, generalSettings, firmware)
|
||||
{
|
||||
int rows = Boards::getCapability(getCurrentBoard(), Board::MaxAnalogs);
|
||||
Board::Type board = getCurrentBoard();
|
||||
int rows = Boards::getCapability(board, Board::MaxAnalogs);
|
||||
|
||||
QStringList headerLabels;
|
||||
headerLabels << "" << tr("Negative span") << tr("Mid value") << tr("Positive span");
|
||||
|
||||
TableLayout * tableLayout = new TableLayout(this, rows, headerLabels);
|
||||
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int i = 0, row = 0; i < rows; i++) {
|
||||
int col = 0;
|
||||
if (firmware->getCapability(HasFlySkyGimbals) &&
|
||||
i >= (Boards::getCapability(board, Board::Sticks) + 5) &&
|
||||
i < (Boards::getCapability(board, Board::Sticks) + 7))
|
||||
continue;
|
||||
|
||||
row++;
|
||||
QLabel * label = new QLabel(this);
|
||||
label->setText(firmware->getAnalogInputName(i));
|
||||
tableLayout->addWidget(i, col++, label);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
constexpr char FIM_SWITCHTYPE2POS[] {"Switch Type 2 Pos"};
|
||||
constexpr char FIM_SWITCHTYPE3POS[] {"Switch Type 3 Pos"};
|
||||
constexpr char FIM_INTERNALMODULES[] {"Internal Modules"};
|
||||
|
||||
HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels):
|
||||
GeneralPanel(parent, generalSettings, firmware),
|
||||
@@ -52,6 +53,9 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
|
||||
int auxmodelid = editorItemModels->registerItemModel(GeneralSettings::auxSerialModeItemModel());
|
||||
int baudmodelid = editorItemModels->registerItemModel(GeneralSettings::telemetryBaudrateItemModel());
|
||||
|
||||
id = editorItemModels->registerItemModel(ModuleData::internalModuleItemModel());
|
||||
tabFilteredModels->registerItemModel(new FilteredItemModel(editorItemModels->getItemModel(id)), FIM_INTERNALMODULES);
|
||||
|
||||
grid = new QGridLayout(this);
|
||||
int count;
|
||||
int row = 0;
|
||||
@@ -64,7 +68,8 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
|
||||
}
|
||||
|
||||
count = Boards::getCapability(board, Board::Pots);
|
||||
if (count) {
|
||||
count -= firmware->getCapability(HasFlySkyGimbals) ? 2 : 0;
|
||||
if (count > 0) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
addPot(i, row);
|
||||
}
|
||||
@@ -126,6 +131,26 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
|
||||
addParams(row, antennaMode);
|
||||
}
|
||||
|
||||
if (Boards::getCapability(board, Board::HasInternalModuleSupport)) {
|
||||
addLabel(tr("Internal module"), row, 0);
|
||||
AutoComboBox *internalModule = new AutoComboBox(this);
|
||||
internalModule->setModel(tabFilteredModels->getItemModel(FIM_INTERNALMODULES));
|
||||
internalModule->setField(generalSettings.internalModule, this);
|
||||
addParams(row, internalModule);
|
||||
connect(internalModule, &AutoComboBox::currentDataChanged, this, [=] () {
|
||||
QMessageBox::warning(this, CPN_STR_APP_NAME,
|
||||
tr("ALERT: Check each model's internal module protocol to ensure it is compatible!"));
|
||||
});
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HasTelemetryBaudrate)) {
|
||||
addLabel(tr("Maximum Baud"), row, 0);
|
||||
AutoComboBox *maxBaudRate = new AutoComboBox(this);
|
||||
maxBaudRate->setModel(editorItemModels->getItemModel(baudmodelid));
|
||||
maxBaudRate->setField(generalSettings.telemetryBaudrate, this);
|
||||
addParams(row, maxBaudRate);
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HasAuxSerialMode)) {
|
||||
QString lbl = "Serial Port";
|
||||
if (IS_RADIOMASTER_TX16S(board))
|
||||
@@ -162,14 +187,6 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
|
||||
addParams(row, sportPower);
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HasTelemetryBaudrate)) {
|
||||
addLabel(tr("Maximum Baud"), row, 0);
|
||||
AutoComboBox *maxBaudRate = new AutoComboBox(this);
|
||||
maxBaudRate->setModel(editorItemModels->getItemModel(baudmodelid));
|
||||
maxBaudRate->setField(generalSettings.telemetryBaudrate, this);
|
||||
addParams(row, maxBaudRate);
|
||||
}
|
||||
|
||||
if (firmware->getCapability(HastxCurrentCalibration)) {
|
||||
addLabel(tr("Current Offset"), row, 0);
|
||||
AutoSpinBox *txCurrentCalibration = new AutoSpinBox(this);
|
||||
|
||||
@@ -157,7 +157,7 @@ MainWindow::MainWindow():
|
||||
if (!str.isEmpty()) {
|
||||
int fileType = getStorageType(str);
|
||||
|
||||
if (fileType==STORAGE_TYPE_EEPE || fileType==STORAGE_TYPE_EEPM || fileType==STORAGE_TYPE_BIN || fileType==STORAGE_TYPE_OTX) {
|
||||
if (fileType==STORAGE_TYPE_EEPE || fileType==STORAGE_TYPE_EEPM || fileType==STORAGE_TYPE_BIN || fileType==STORAGE_TYPE_ETX) {
|
||||
MdiChild * child = createMdiChild();
|
||||
if (child->loadFile(str)) {
|
||||
if (!(printing && model >= 0 && (getCurrentFirmware()->getCapability(Models) == 0 || model<getCurrentFirmware()->getCapability(Models)) && !printfilename.isEmpty())) {
|
||||
@@ -897,24 +897,24 @@ void MainWindow::customizeSplash()
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::writeEeprom()
|
||||
void MainWindow::writeSettings()
|
||||
{
|
||||
if (activeMdiChild())
|
||||
activeMdiChild()->writeEeprom();
|
||||
activeMdiChild()->writeSettings();
|
||||
}
|
||||
|
||||
void MainWindow::readEeprom()
|
||||
void MainWindow::readSettings()
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
QString tempFile;
|
||||
if (IS_FAMILY_HORUS_OR_T16(board))
|
||||
tempFile = generateProcessUniqueTempFileName("temp.otx");
|
||||
if (Boards::getCapability(board, Board::HasSDCard))
|
||||
tempFile = generateProcessUniqueTempFileName("temp.etx");
|
||||
else
|
||||
tempFile = generateProcessUniqueTempFileName("temp.bin");
|
||||
|
||||
qDebug() << "MainWindow::readEeprom(): using temp file: " << tempFile;
|
||||
qDebug() << "Reading models and settings into temp file: " << tempFile;
|
||||
|
||||
if (readEepromFromRadio(tempFile)) {
|
||||
if (readSettingsFromRadio(tempFile)) {
|
||||
MdiChild * child = createMdiChild();
|
||||
child->newFile(false);
|
||||
child->loadFile(tempFile, false);
|
||||
@@ -933,10 +933,10 @@ bool MainWindow::readFirmwareFromRadio(const QString & filename)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MainWindow::readEepromFromRadio(const QString & filename)
|
||||
bool MainWindow::readSettingsFromRadio(const QString & filename)
|
||||
{
|
||||
ProgressDialog progressDialog(this, tr("Read Models and Settings from Radio"), CompanionIcon("read_eeprom.png"));
|
||||
bool result = ::readEeprom(filename, progressDialog.progress());
|
||||
bool result = ::readSettings(filename, progressDialog.progress());
|
||||
if (!result) {
|
||||
if (!progressDialog.isEmpty()) {
|
||||
progressDialog.exec();
|
||||
@@ -974,7 +974,7 @@ void MainWindow::readBackup()
|
||||
}
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save Radio Backup to File"), g.eepromDir(), EXTERNAL_EEPROM_FILES_FILTER);
|
||||
if (!fileName.isEmpty()) {
|
||||
if (!readEepromFromRadio(fileName))
|
||||
if (!readSettingsFromRadio(fileName))
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1045,8 +1045,8 @@ void MainWindow::updateMenus()
|
||||
saveAsAct->setEnabled(activeChild);
|
||||
closeAct->setEnabled(activeChild);
|
||||
compareAct->setEnabled(activeChild);
|
||||
writeEepromAct->setEnabled(activeChild);
|
||||
readEepromAct->setEnabled(true);
|
||||
writeSettingsAct->setEnabled(activeChild);
|
||||
readSettingsAct->setEnabled(true);
|
||||
if (IS_FAMILY_HORUS_OR_T16(getCurrentBoard())) {
|
||||
writeBUToRadioAct->setEnabled(false);
|
||||
readBUToFileAct->setEnabled(false);
|
||||
@@ -1199,8 +1199,8 @@ void MainWindow::retranslateUi(bool showMsg)
|
||||
trAct(sdsyncAct, tr("Synchronize SD"), tr("SD card synchronization"));
|
||||
|
||||
trAct(openDocURLAct, tr("Manuals and other Documents"), tr("Open the EdgeTX document page in a web browser"));
|
||||
trAct(writeEepromAct, tr("Write Models and Settings To Radio"), tr("Write Models and Settings to Radio"));
|
||||
trAct(readEepromAct, tr("Read Models and Settings From Radio"), tr("Read Models and Settings from Radio"));
|
||||
trAct(writeSettingsAct, tr("Write Models and Settings To Radio"), tr("Write Models and Settings to Radio"));
|
||||
trAct(readSettingsAct, tr("Read Models and Settings From Radio"), tr("Read Models and Settings from Radio"));
|
||||
trAct(burnConfigAct, tr("Configure Communications..."), tr("Configure software for communicating with the Radio"));
|
||||
trAct(writeBUToRadioAct, tr("Write Backup to Radio"), tr("Write Backup from file to Radio"));
|
||||
trAct(readBUToFileAct, tr("Backup Radio to File"), tr("Save a complete backup file of all settings and model data in the Radio"));
|
||||
@@ -1256,8 +1256,8 @@ void MainWindow::createActions()
|
||||
burnListAct = addAct("list.png", SLOT(burnList()));
|
||||
readFlashAct = addAct("read_flash.png", SLOT(readFlash()));
|
||||
writeFlashAct = addAct("write_flash.png", SLOT(writeFlash()));
|
||||
writeEepromAct = addAct("write_eeprom.png", SLOT(writeEeprom()));
|
||||
readEepromAct = addAct("read_eeprom.png", SLOT(readEeprom()));
|
||||
writeSettingsAct = addAct("write_eeprom.png", SLOT(writeSettings()));
|
||||
readSettingsAct = addAct("read_eeprom.png", SLOT(readSettings()));
|
||||
burnConfigAct = addAct("configure.png", SLOT(burnConfig()));
|
||||
|
||||
writeBUToRadioAct = addAct("write_eeprom_file.png", SLOT(writeBackup()));
|
||||
@@ -1347,8 +1347,8 @@ void MainWindow::createMenus()
|
||||
settingsMenu->addAction(importSettingsAct);
|
||||
|
||||
burnMenu = menuBar()->addMenu("");
|
||||
burnMenu->addAction(writeEepromAct);
|
||||
burnMenu->addAction(readEepromAct);
|
||||
burnMenu->addAction(writeSettingsAct);
|
||||
burnMenu->addAction(readSettingsAct);
|
||||
burnMenu->addSeparator();
|
||||
burnMenu->addAction(writeBUToRadioAct);
|
||||
burnMenu->addAction(readBUToFileAct);
|
||||
@@ -1435,8 +1435,8 @@ void MainWindow::createToolBars()
|
||||
burnToolBar = new QToolBar(this);
|
||||
addToolBar( Qt::LeftToolBarArea, burnToolBar );
|
||||
burnToolBar->setObjectName("Write");
|
||||
burnToolBar->addAction(writeEepromAct);
|
||||
burnToolBar->addAction(readEepromAct);
|
||||
burnToolBar->addAction(writeSettingsAct);
|
||||
burnToolBar->addAction(readSettingsAct);
|
||||
burnToolBar->addSeparator();
|
||||
burnToolBar->addAction(writeBUToRadioAct);
|
||||
burnToolBar->addAction(readBUToFileAct);
|
||||
@@ -1626,9 +1626,11 @@ int MainWindow::newProfile(bool loadProfile)
|
||||
if (i == MAX_PROFILES) //Failed to find free slot
|
||||
return -1;
|
||||
|
||||
Firmware *newfw = Firmware::getDefaultVariant();
|
||||
g.profile[i].init();
|
||||
g.profile[i].name(tr("New Radio"));
|
||||
g.profile[i].fwType(Firmware::getDefaultVariant()->getId());
|
||||
g.profile[i].name("New Radio");
|
||||
g.profile[i].fwType(newfw->getId());
|
||||
g.profile[i].defaultInternalModule(Boards::getDefaultInternalModules(newfw->getBoard()));
|
||||
|
||||
if (loadProfile) {
|
||||
if (loadProfileId(i))
|
||||
|
||||
@@ -103,8 +103,8 @@ class MainWindow : public QMainWindow
|
||||
bool loadProfileId(const unsigned pid);
|
||||
void loadProfile();
|
||||
void logFile();
|
||||
void writeEeprom();
|
||||
void readEeprom();
|
||||
void writeSettings();
|
||||
void readSettings();
|
||||
void writeFlash(QString fileToFlash="");
|
||||
void readFlash();
|
||||
void writeBackup();
|
||||
@@ -156,7 +156,7 @@ class MainWindow : public QMainWindow
|
||||
QMdiSubWindow * findMdiChild(const QString & fileName);
|
||||
bool anyChildrenDirty();
|
||||
|
||||
bool readEepromFromRadio(const QString & filename);
|
||||
bool readSettingsFromRadio(const QString & filename);
|
||||
bool readFirmwareFromRadio(const QString & filename);
|
||||
|
||||
bool checkProfileRadioExists(int profId);
|
||||
@@ -203,8 +203,8 @@ class MainWindow : public QMainWindow
|
||||
QAction *changelogAct;
|
||||
QAction *compareAct;
|
||||
QAction *editSplashAct;
|
||||
QAction *writeEepromAct;
|
||||
QAction *readEepromAct;
|
||||
QAction *writeSettingsAct;
|
||||
QAction *readSettingsAct;
|
||||
QAction *burnConfigAct;
|
||||
QAction *burnListAct;
|
||||
QAction *writeFlashAct;
|
||||
|
||||
@@ -1320,7 +1320,7 @@ void MdiChild::newFile(bool createDefaults)
|
||||
{
|
||||
static int sequenceNumber = 1;
|
||||
isUntitled = true;
|
||||
curFile = QString("document%1.otx").arg(sequenceNumber++);
|
||||
curFile = QString("document%1.etx").arg(sequenceNumber++);
|
||||
updateTitle();
|
||||
|
||||
if (createDefaults && firmware->getCapability(Capability::HasModelCategories)) {
|
||||
@@ -1345,6 +1345,7 @@ bool MdiChild::loadFile(const QString & filename, bool resetCurrentFile)
|
||||
setCurrentFile(filename);
|
||||
}
|
||||
|
||||
// For etx files this will never be true as any conversion occurs when parsing file
|
||||
if (!Boards::isBoardCompatible(storage.getBoard(), getCurrentBoard())) {
|
||||
if (!convertStorage(storage.getBoard(), getCurrentBoard(), true))
|
||||
return false;
|
||||
@@ -1360,7 +1361,7 @@ bool MdiChild::loadFile(const QString & filename, bool resetCurrentFile)
|
||||
bool MdiChild::save()
|
||||
{
|
||||
QFileInfo fi(curFile);
|
||||
if (isUntitled || !fi.isWritable()) {
|
||||
if (isUntitled || !fi.isWritable() || fi.suffix().toLower() != "etx") {
|
||||
return saveAs(true);
|
||||
}
|
||||
else {
|
||||
@@ -1375,7 +1376,7 @@ bool MdiChild::saveAs(bool isNew)
|
||||
#ifdef __APPLE__
|
||||
QString filter;
|
||||
#else
|
||||
QString filter(OTX_FILES_FILTER % YML_FILES_FILTER);
|
||||
QString filter(ETX_FILES_FILTER % YML_FILES_FILTER);
|
||||
#endif
|
||||
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), g.eepromDir() + "/" + fi.fileName(), filter);
|
||||
@@ -1455,7 +1456,7 @@ void MdiChild::setCurrentFile(const QString & fileName)
|
||||
|
||||
void MdiChild::forceNewFilename(const QString & suffix, const QString & ext)
|
||||
{
|
||||
curFile.replace(QRegExp("\\.(eepe|bin|hex|otx)$"), suffix + "." + ext);
|
||||
curFile.replace(QRegExp("\\.(eepe|bin|hex|otx|etx)$"), suffix + "." + ext);
|
||||
}
|
||||
|
||||
bool MdiChild::convertStorage(Board::Type from, Board::Type to, bool newFile)
|
||||
@@ -1528,7 +1529,7 @@ int MdiChild::askQuestion(const QString & msg, QMessageBox::StandardButtons butt
|
||||
return QMessageBox::question(this, CPN_STR_APP_NAME, msg, buttons, defaultButton);
|
||||
}
|
||||
|
||||
void MdiChild::writeEeprom() // write to Tx
|
||||
void MdiChild::writeSettings() // write to Tx
|
||||
{
|
||||
if (g.confirmWriteModelsAndSettings()) {
|
||||
QMessageBox msgbox;
|
||||
@@ -1547,19 +1548,21 @@ void MdiChild::writeEeprom() // write to Tx
|
||||
}
|
||||
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_FAMILY_HORUS_OR_T16(board)) {
|
||||
|
||||
if (Boards::getCapability(board, Board::HasSDCard)) {
|
||||
QString radioPath = findMassstoragePath("RADIO", true);
|
||||
qDebug() << "Searching for SD card, found" << radioPath;
|
||||
if (radioPath.isEmpty()) {
|
||||
qDebug() << "MdiChild::writeEeprom(): Horus radio not found";
|
||||
qDebug() << "Radio SD card not found";
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Unable to find radio SD card!"));
|
||||
return;
|
||||
}
|
||||
if (saveFile(radioPath, false)) {
|
||||
emit newStatusMessage(tr("Models and Settings written"), 2000);
|
||||
QMessageBox::information(this, CPN_STR_TTL_INFO, tr("Saved models and settings to radio"));
|
||||
}
|
||||
else {
|
||||
qDebug() << "MdiChild::writeEeprom(): saveFile error";
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Error saving models and settings to radio!"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -87,7 +87,7 @@ class MdiChild : public QWidget
|
||||
bool saveAs(bool isNew=false);
|
||||
bool saveFile(const QString & fileName, bool setCurrent=true);
|
||||
void closeFile(bool force = false);
|
||||
void writeEeprom();
|
||||
void writeSettings();
|
||||
void print(int model=-1, const QString & filename="");
|
||||
void onFirmwareChanged();
|
||||
|
||||
@@ -179,7 +179,7 @@ class MdiChild : public QWidget
|
||||
|
||||
bool maybeSave();
|
||||
void setCurrentFile(const QString & fileName);
|
||||
void forceNewFilename(const QString & suffix = "", const QString & ext = "otx");
|
||||
void forceNewFilename(const QString & suffix = "", const QString & ext = "etx");
|
||||
bool convertStorage(Board::Type from, Board::Type to, bool newFile = false);
|
||||
void showWarning(const QString & msg);
|
||||
int askQuestion(const QString & msg, QMessageBox::StandardButtons buttons = (QMessageBox::Yes | QMessageBox::No), QMessageBox::StandardButton defaultButton = QMessageBox::No);
|
||||
|
||||
@@ -106,11 +106,12 @@ ModelEdit::ModelEdit(QWidget * parent, RadioData & radioData, int modelId, Firmw
|
||||
s1.report("Telemetry");
|
||||
}
|
||||
|
||||
if (Boards::getCapability(firmware->getBoard(), Board::HasColorLcd)) {
|
||||
// temporary hide
|
||||
/*if (Boards::getCapability(firmware->getBoard(), Board::HasColorLcd)) {
|
||||
addTab(new ColorCustomScreensPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Custom Screens"));
|
||||
s1.report("ColorLcd Custom Screens");
|
||||
}
|
||||
else if (firmware->getCapability(TelemetryCustomScreens)) {
|
||||
else */if (firmware->getCapability(TelemetryCustomScreens)) {
|
||||
addTab(new TelemetryCustomScreensPanel(this, model, generalSettings, firmware, sharedItemModels), tr("Custom Screens"));
|
||||
s1.report("Telemetry Custom Screens");
|
||||
}
|
||||
|
||||
@@ -237,14 +237,12 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
|
||||
ui->trainerMode->hide();
|
||||
}
|
||||
|
||||
// The protocols available on this board
|
||||
for (unsigned int i = 0; i < PULSES_PROTOCOL_LAST; i++) {
|
||||
if (firmware->isAvailable((PulsesProtocol) i, moduleIdx)) {
|
||||
ui->protocol->addItem(ModuleData::protocolToString(i), i);
|
||||
if (i == module.protocol)
|
||||
ui->protocol->setCurrentIndex(ui->protocol->count() - 1);
|
||||
}
|
||||
if (panelFilteredItemModels && moduleIdx >= 0) {
|
||||
int id = panelFilteredItemModels->registerItemModel(new FilteredItemModel(ModuleData::protocolItemModel(generalSettings), moduleIdx + 1/*flag cannot be 0*/), QString("Module Protocol %1").arg(moduleIdx));
|
||||
ui->protocol->setModel(panelFilteredItemModels->getItemModel(id));
|
||||
ui->protocol->setField(module.protocol, this);
|
||||
}
|
||||
|
||||
for (int i = 0; i <= MODULE_SUBTYPE_MULTI_LAST; i++) {
|
||||
if (i == MODULE_SUBTYPE_MULTI_SCANNER)
|
||||
continue;
|
||||
@@ -266,7 +264,7 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
|
||||
|
||||
update();
|
||||
|
||||
connect(ui->protocol, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ModulePanel::onProtocolChanged);
|
||||
connect(ui->protocol, &AutoComboBox::currentDataChanged, this, &ModulePanel::onProtocolChanged);
|
||||
connect(ui->multiSubType, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ModulePanel::onSubTypeChanged);
|
||||
connect(ui->multiProtocol, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ModulePanel::onMultiProtocolChanged);
|
||||
connect(this, &ModulePanel::channelsRangeChanged, this, &ModulePanel::setupFailsafes);
|
||||
@@ -662,8 +660,7 @@ void ModulePanel::update()
|
||||
|
||||
void ModulePanel::onProtocolChanged(int index)
|
||||
{
|
||||
if (!lock && module.protocol != ui->protocol->itemData(index).toUInt()) {
|
||||
module.protocol = ui->protocol->itemData(index).toInt();
|
||||
if (!lock) {
|
||||
module.channelsCount = module.getMaxChannelCount();
|
||||
update();
|
||||
emit updateItemModels();
|
||||
@@ -1171,6 +1168,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
|
||||
panelItemModels->registerItemModel(TimerData::countdownBeepItemModel());
|
||||
panelItemModels->registerItemModel(TimerData::countdownStartItemModel());
|
||||
panelItemModels->registerItemModel(TimerData::persistentItemModel());
|
||||
panelItemModels->registerItemModel(TimerData::modeItemModel());
|
||||
panelFilteredModels->registerItemModel(new FilteredItemModel(ModelData::trainerModeItemModel(generalSettings, firmware)), FIM_TRAINERMODE);
|
||||
|
||||
Board::Type board = firmware->getBoard();
|
||||
@@ -1320,6 +1318,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
|
||||
Board::SwitchInfo switchInfo = Boards::getSwitchInfo(board, i);
|
||||
switchInfo.config = Board::SwitchType(generalSettings.switchConfig[i]);
|
||||
if (switchInfo.config == Board::SWITCH_NOT_AVAILABLE || switchInfo.config == Board::SWITCH_TOGGLE) {
|
||||
model.switchWarningEnable |= (1 << i);
|
||||
continue;
|
||||
}
|
||||
RawSource src(RawSourceType::SOURCE_TYPE_SWITCH, i);
|
||||
@@ -1389,7 +1388,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
|
||||
// ui->functionSwitchesLayout->hide();
|
||||
|
||||
for (int i = firmware->getCapability(NumFirstUsableModule); i < firmware->getCapability(NumModules); i++) {
|
||||
modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i);
|
||||
modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i, panelFilteredModels);
|
||||
ui->modulesLayout->addWidget(modules[i]);
|
||||
connect(modules[i], &ModulePanel::modified, this, &SetupPanel::modified);
|
||||
connect(modules[i], &ModulePanel::updateItemModels, this, &SetupPanel::onModuleUpdateItemModels);
|
||||
|
||||
@@ -805,7 +805,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="protocol">
|
||||
<widget class="AutoComboBox" name="protocol">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
||||
@@ -651,7 +651,7 @@ void TreeModel::refresh()
|
||||
EEPROMInterface * eepromInterface = getCurrentEEpromInterface();
|
||||
Board::Type board = eepromInterface->getBoard();
|
||||
TreeItem * defaultCategoryItem = NULL;
|
||||
bool hasEepromSizeData = (IS_FAMILY_HORUS_OR_T16(board) ? false : true);
|
||||
bool hasEepromSizeData = false; // not necessary with move to YAML storage for all boards TODO: remove unused code
|
||||
|
||||
if (hasEepromSizeData) {
|
||||
availableEEpromSize = Boards::getEEpromSize(board) - 64; // let's consider fat
|
||||
@@ -753,7 +753,7 @@ bool TreeModel::isModelIdUnique(unsigned modelIdx, unsigned module, unsigned pro
|
||||
int cnt = 0;
|
||||
if (protocol== PULSES_PXX_XJT_D8)
|
||||
return true;
|
||||
|
||||
|
||||
for (auto const& model: radioData->models) {
|
||||
if (!model.isEmpty()) {
|
||||
const ModuleData& moduleData = model.moduleData[module];
|
||||
|
||||
@@ -175,7 +175,7 @@ bool writeFirmware(const QString & filename, ProgressWidget * progress)
|
||||
return flashProcess.run();
|
||||
}
|
||||
|
||||
bool readEeprom(const QString & filename, ProgressWidget * progress)
|
||||
bool readSettings(const QString & filename, ProgressWidget * progress)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
|
||||
@@ -186,64 +186,84 @@ bool readEeprom(const QString & filename, ProgressWidget * progress)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IS_FAMILY_HORUS_OR_T16(board)) {
|
||||
QString radioPath = findMassstoragePath("RADIO", true);
|
||||
qDebug() << "Searching for SD card, found" << radioPath;
|
||||
if (radioPath.isEmpty()) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR,
|
||||
QCoreApplication::translate("RadioInterface", "Unable to find radio SD card!"));
|
||||
return false;
|
||||
}
|
||||
RadioData radioData;
|
||||
Storage inputStorage(radioPath);
|
||||
if (!inputStorage.load(radioData)) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, inputStorage.error());
|
||||
return false;
|
||||
}
|
||||
Storage outputStorage(filename);
|
||||
if (!outputStorage.write(radioData)) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, outputStorage.error());
|
||||
return false;
|
||||
}
|
||||
if (Boards::getCapability(board, Board::HasSDCard))
|
||||
return readSettingsSDCard(filename, progress);
|
||||
else
|
||||
return readSettingsEeprom(filename, progress);
|
||||
}
|
||||
|
||||
if (getCurrentBoard() == Board::BOARD_JUMPER_T16 && inputStorage.getBoard() == Board::BOARD_X10) {
|
||||
if (displayT16ImportWarning() == false)
|
||||
return false;
|
||||
}
|
||||
bool readSettingsSDCard(const QString & filename, ProgressWidget * progress)
|
||||
{
|
||||
QString radioPath = findMassstoragePath("RADIO", true);
|
||||
qDebug() << "Searching for SD card, found" << radioPath;
|
||||
if (radioPath.isEmpty()) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR,
|
||||
QCoreApplication::translate("RadioInterface", "Unable to find radio SD card!"));
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
QString path = findMassstoragePath("EEPROM.BIN");
|
||||
if (path.isEmpty()) {
|
||||
// On previous OpenTX we called the EEPROM file "TARANIS.BIN" :(
|
||||
path = findMassstoragePath("TARANIS.BIN");
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
// Mike's bootloader calls the EEPROM file "ERSKY9X.BIN" :(
|
||||
path = findMassstoragePath("ERSKY9X.BIN");
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
RadioNotFoundDialog dialog(progress);
|
||||
dialog.exec();
|
||||
|
||||
// if radio.yml it is a converted radio
|
||||
// if radio.bin unconverted pre 2.6
|
||||
// if neither then unconverted eeprom or empty
|
||||
if (!QFile::exists(radioPath % "/RADIO/radio.yml") && !QFile::exists(radioPath % "/RADIO/radio.bin"))
|
||||
return readSettingsEeprom(filename, progress);
|
||||
|
||||
RadioData radioData;
|
||||
Storage inputStorage(radioPath);
|
||||
if (!inputStorage.load(radioData)) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, QCoreApplication::translate("RadioInterface", "Failed to read Models and Settings from") % radioPath);
|
||||
return false;
|
||||
}
|
||||
Storage outputStorage(filename);
|
||||
if (!outputStorage.write(radioData)) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, QCoreApplication::translate("RadioInterface", "Failed to write Models and Setting file") % filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getCurrentBoard() == Board::BOARD_JUMPER_T16 && inputStorage.getBoard() == Board::BOARD_X10) {
|
||||
if (displayT16ImportWarning() == false)
|
||||
return false;
|
||||
}
|
||||
CopyProcess copyProcess(path, filename, progress);
|
||||
if (!copyProcess.run()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return QFileInfo(filename).exists();
|
||||
}
|
||||
|
||||
|
||||
if (!IS_STM32(board)) {
|
||||
FlashProcess flashProcess(getRadioInterfaceCmd(), getReadEEpromCmd(filename), progress);
|
||||
if (!flashProcess.run()) {
|
||||
return false;
|
||||
}
|
||||
bool readSettingsEeprom(const QString & filename, ProgressWidget * progress)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
|
||||
QString path = findMassstoragePath("EEPROM.BIN");
|
||||
if (path.isEmpty()) {
|
||||
// On previous OpenTX we called the EEPROM file "TARANIS.BIN" :(
|
||||
path = findMassstoragePath("TARANIS.BIN");
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
// Mike's bootloader calls the EEPROM file "ERSKY9X.BIN" :(
|
||||
path = findMassstoragePath("ERSKY9X.BIN");
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
RadioNotFoundDialog dialog(progress);
|
||||
dialog.exec();
|
||||
return false;
|
||||
}
|
||||
CopyProcess copyProcess(path, filename, progress);
|
||||
if (!copyProcess.run()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!IS_STM32(board)) {
|
||||
FlashProcess flashProcess(getRadioInterfaceCmd(), getReadEEpromCmd(filename), progress);
|
||||
if (!flashProcess.run()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return QFileInfo(filename).exists();
|
||||
}
|
||||
|
||||
bool writeEeprom(const QString & filename, ProgressWidget * progress)
|
||||
bool writeSettings(const QString & filename, ProgressWidget * progress)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
|
||||
@@ -272,94 +292,29 @@ bool writeEeprom(const QString & filename, ProgressWidget * progress)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
|
||||
#if defined WIN32 || !defined __GNUC__
|
||||
#include <windows.h>
|
||||
bool isRemovableMedia(const QString & vol)
|
||||
{
|
||||
char szDosDeviceName[MAX_PATH];
|
||||
QString volume = vol;
|
||||
UINT driveType = GetDriveType(volume.replace("/", "\\").toLatin1());
|
||||
if (driveType != DRIVE_REMOVABLE)
|
||||
return false;
|
||||
QueryDosDevice(volume.replace("/", "").toLatin1(), szDosDeviceName, MAX_PATH);
|
||||
if (strstr(szDosDeviceName, "\\Floppy") != NULL) { // it's a floppy
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
#include "mountlist.h"
|
||||
#endif // defined WIN32 || !defined __GNUC__
|
||||
#endif // (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
|
||||
|
||||
QString findMassstoragePath(const QString & filename, bool onlyPath)
|
||||
{
|
||||
QString temppath;
|
||||
QString eepromfile;
|
||||
QString probefile;
|
||||
bool found = false;
|
||||
|
||||
QRegularExpression fstypeRe("^(v?fat|msdos)", QRegularExpression::CaseInsensitiveOption); // Linux: "vfat"; macOS: "msdos"; Win: "FAT32"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
||||
|
||||
foreach(const QStorageInfo & si, QStorageInfo::mountedVolumes()) {
|
||||
//qDebug() << si.rootPath() << si.name() << si.device() << si.displayName() << si.fileSystemType() << si.isReady();
|
||||
if (!si.isReady() || !QString(si.fileSystemType()).contains(fstypeRe))
|
||||
continue;
|
||||
temppath = si.rootPath();
|
||||
eepromfile = temppath % "/" % filename;
|
||||
qDebug() << "Searching for" << eepromfile;
|
||||
if (QFile::exists(eepromfile)) {
|
||||
probefile = temppath % "/" % filename;
|
||||
qDebug() << "Searching for" << probefile;
|
||||
if (QFile::exists(probefile)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif defined WIN32 || !defined __GNUC__
|
||||
static QStringList blacklist;
|
||||
foreach(const QFileInfo & drive, QDir::drives()) {
|
||||
temppath = drive.absolutePath();
|
||||
if (blacklist.contains(temppath))
|
||||
continue;
|
||||
if (!isRemovableMedia(temppath)) {
|
||||
blacklist.append(temppath);
|
||||
continue;
|
||||
}
|
||||
WCHAR szVolumeName[256] ;
|
||||
WCHAR szFileSystemName[256];
|
||||
DWORD dwSerialNumber = 0;
|
||||
DWORD dwMaxFileNameLength=256;
|
||||
DWORD dwFileSystemFlags=0;
|
||||
if (!GetVolumeInformationW( (WCHAR *) drive.absolutePath().utf16(),szVolumeName,256,&dwSerialNumber,&dwMaxFileNameLength,&dwFileSystemFlags,szFileSystemName,256))
|
||||
continue;
|
||||
eepromfile = temppath % "/" % filename;
|
||||
qDebug() << "Searching for" << eepromfile;
|
||||
if (QFile::exists(eepromfile)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
const static QStringList blacklist = QStringList() << "/" << "/net" << "/proc" << "/run";
|
||||
QStringList drives;
|
||||
struct mount_entry *entry;
|
||||
struct mount_entry *firstEntry;
|
||||
firstEntry = entry = read_file_system_list(true);
|
||||
while (entry != NULL) {
|
||||
temppath = entry->me_mountdir;
|
||||
if (!drives.contains(entry->me_devname) && !blacklist.contains(temppath) && QString(entry->me_type).contains(fstypeRe)) {
|
||||
drives.append(entry->me_devname);
|
||||
eepromfile = temppath % "/" % filename;
|
||||
qDebug() << "Searching for" << eepromfile;
|
||||
if (QFile::exists(eepromfile)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
entry = entry->me_next;
|
||||
}
|
||||
free_file_system_list(firstEntry);
|
||||
#endif
|
||||
|
||||
if (found)
|
||||
return onlyPath ? temppath : eepromfile;
|
||||
return onlyPath ? temppath : probefile;
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,9 @@ QStringList getWriteFirmwareArgs(const QString &filename);
|
||||
|
||||
bool readFirmware(const QString &filename, ProgressWidget *progress);
|
||||
bool writeFirmware(const QString &filename, ProgressWidget *progress);
|
||||
bool readEeprom(const QString &filename, ProgressWidget *progress);
|
||||
bool writeEeprom(const QString &filename, ProgressWidget *progress);
|
||||
bool readSettings(const QString &filename, ProgressWidget *progress);
|
||||
bool readSettingsSDCard(const QString &filename, ProgressWidget *progress);
|
||||
bool readSettingsEeprom(const QString &filename, ProgressWidget *progress);
|
||||
bool writeSettings(const QString &filename, ProgressWidget *progress);
|
||||
|
||||
#endif // _RADIOINTERFACE_H_
|
||||
|
||||
@@ -103,7 +103,7 @@ void joystickDialog::populateSourceCombo(QComboBox * cb)
|
||||
for (i=0; i < Board::STICK_AXIS_COUNT; ++i) {
|
||||
cb->addItem(Boards::getAxisName(i) % tr(" Stick"), i);
|
||||
}
|
||||
for (; i < Board::STICK_AXIS_COUNT + CPN_MAX_POTS; ++i) {
|
||||
for (; i < Board::STICK_AXIS_COUNT + CPN_MAX_POTS + CPN_MAX_SLIDERS; ++i) {
|
||||
cb->addItem(tr("Knob/Slider %1").arg(i - Board::STICK_AXIS_COUNT + 1), i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ QString SimulatorStartupDialog::radioEepromFileName(const QString & firmwareId,
|
||||
if (pos > 0)
|
||||
radioId = radioId.mid(pos+1);
|
||||
if (usesCategorizedStorage(radioId))
|
||||
ext = "otx";
|
||||
ext = "etx";
|
||||
|
||||
eepromFileName = QString("eeprom-%1.%2").arg(radioId, ext);
|
||||
eepromFileName = QDir(folder).filePath(eepromFileName.toLatin1());
|
||||
|
||||
@@ -249,9 +249,9 @@ bool SimulatorWidget::setStartupData(const QByteArray & dataSource, bool fromFil
|
||||
error = store.error();
|
||||
}
|
||||
else {
|
||||
if (fileName.endsWith(".otx", Qt::CaseInsensitive)) {
|
||||
// no radios can work with .otx files directly, so we load contents into either
|
||||
// a temporary folder (Horus) or local data array (other radios) which we'll save back to .otx upon exit
|
||||
if (fileName.endsWith(".etx", Qt::CaseInsensitive)) {
|
||||
// no radios can work with .etx files directly, so we load contents into either
|
||||
// a temporary folder (Horus) or local data array (other radios) which we'll save back to .etx upon exit
|
||||
if ((ret = setRadioData(&simuData))) {
|
||||
startupFromFile = false;
|
||||
return true;
|
||||
@@ -294,17 +294,20 @@ bool SimulatorWidget::setRadioData(RadioData * radioData)
|
||||
|
||||
saveTempRadioData = (flags & SIMULATOR_FLAGS_STANDALONE);
|
||||
|
||||
if (IS_FAMILY_HORUS_OR_T16(m_board))
|
||||
// All radios use SD card data path from 2.6.0 on
|
||||
bool hasSdCard = Boards::getCapability(m_board, Board::HasSDCard);
|
||||
if (hasSdCard)
|
||||
ret = useTempDataPath(true);
|
||||
|
||||
if (ret) {
|
||||
if (radioDataPath.isEmpty()) {
|
||||
if (!hasSdCard) {
|
||||
startupData.fill(0, Boards::getEEpromSize(m_board));
|
||||
if (firmware->getEEpromInterface()->save((uint8_t *)startupData.data(), *radioData, 0, firmware->getCapability(SimulatorVariant)) <= 0) {
|
||||
if (firmware->getEEpromInterface()->save(
|
||||
(uint8_t *)startupData.data(), *radioData, 0,
|
||||
firmware->getCapability(SimulatorVariant)) <= 0) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ret = saveRadioData(radioData, radioDataPath);
|
||||
}
|
||||
}
|
||||
@@ -365,7 +368,7 @@ bool SimulatorWidget::useTempDataPath(bool deleteOnClose)
|
||||
if (deleteTempRadioData)
|
||||
deleteTempData();
|
||||
|
||||
QTemporaryDir tmpDir(QDir::tempPath() + "/otx-XXXXXX");
|
||||
QTemporaryDir tmpDir(QDir::tempPath() + "/etx-XXXXXX");
|
||||
if (tmpDir.isValid()) {
|
||||
setDataPath(tmpDir.path());
|
||||
tmpDir.setAutoRemove(false);
|
||||
@@ -379,7 +382,7 @@ bool SimulatorWidget::useTempDataPath(bool deleteOnClose)
|
||||
}
|
||||
}
|
||||
|
||||
// This will save radio data from temporary folder structure back into an .otx file, eg. for Horus.
|
||||
// This will save radio data from temporary folder structure back into an .etx file, eg. for Horus.
|
||||
bool SimulatorWidget::saveTempData()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
@@ -127,7 +127,7 @@ CommandLineParseResult cliOptions(SimulatorOptions * simOptions, int * profileId
|
||||
QApplication::translate("SimulatorMain", "type"));
|
||||
|
||||
cliOptions.addPositionalArgument(QApplication::translate("SimulatorMain", "data-source"),
|
||||
QApplication::translate("SimulatorMain", "Radio data (.bin/.eeprom/.otx) image file to use OR data folder path (for Horus-style radios).\n"
|
||||
QApplication::translate("SimulatorMain", "Radio data (.bin/.eeprom/.etx) image file to use OR data folder path (for Horus-style radios).\n"
|
||||
"NOTE: any existing EEPROM data incompatible with the selected radio type may be overwritten!"),
|
||||
QApplication::translate("SimulatorMain", "[data-source]"));
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ set(storage_NAMES
|
||||
hexeeprom
|
||||
categorized
|
||||
sdcard
|
||||
etx
|
||||
otx
|
||||
yaml
|
||||
)
|
||||
|
||||
@@ -409,16 +409,10 @@ QMap<int, QString> AppData::getActiveProfiles() const
|
||||
void AppData::convertSettings(QSettings & settings)
|
||||
{
|
||||
quint32 savedVer = settings.value(SETTINGS_VERSION_KEY, 0).toUInt();
|
||||
#if (VERSION_NUMBER < QT_VERSION_CHECK(2, 3, 0))
|
||||
// convert old 2.2.x version marker; TODO: remove once v2.3 is established (because we'll always convert and clean 2.2.x settings anyway)
|
||||
if (savedVer == 220)
|
||||
savedVer = 0x2020000;
|
||||
#endif
|
||||
|
||||
if (savedVer == CPN_SETTINGS_VERSION)
|
||||
return;
|
||||
if (savedVer > CPN_SETTINGS_VERSION) {
|
||||
qWarning().noquote() << "Saved settings version is newer than current, skippig conversions. Saved:" << fmtHex(savedVer) << "Current:" << fmtHex(CPN_SETTINGS_VERSION);
|
||||
qWarning().noquote() << "Saved settings version is newer than current, skipping conversions. Saved:" << fmtHex(savedVer) << "Current:" << fmtHex(CPN_SETTINGS_VERSION);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -432,29 +426,24 @@ void AppData::convertSettings(QSettings & settings)
|
||||
<< " from v" << fmtHex(savedVer) << " (" << fmtHex(savedMajMin) << ") to v"
|
||||
<< fmtHex(CPN_SETTINGS_VERSION) << " (" << fmtHex(currMajMin) << "). Removing unused: " << removeUnused;
|
||||
|
||||
if (settings.contains("useWizard")) {
|
||||
if (!settings.contains(newModelAction_key()))
|
||||
settings.setValue(newModelAction_key(), (settings.value("useWizard").toBool() ? MODEL_ACT_WIZARD : MODEL_ACT_EDITOR));
|
||||
if (removeUnused)
|
||||
settings.remove("useWizard");
|
||||
}
|
||||
|
||||
// meaning of warningId changed during v2.2 development but value of "7" indicates old setting, removing it will restore defaults
|
||||
if (savedMajMin < 0x203 && settings.contains("warningId") && settings.value("warningId").toInt() == 7)
|
||||
settings.remove("warningId");
|
||||
|
||||
// Convert joystick settings to new style of key names
|
||||
static const QString jsCalBasePath = QStringLiteral("JsCalibration/%1");
|
||||
if (settings.contains(jsCalBasePath.arg("stick0_axe"))) {
|
||||
const QStringList vars({"axe", "inv", "max", "med", "min"});
|
||||
for (int i=0; i < MAX_JOYSTICKS; ++i) {
|
||||
for (const QString & var : vars) {
|
||||
const QString oldPath = jsCalBasePath.arg(QString("stick%1_%2").arg(i).arg(var)); // old format "/stick#_var"
|
||||
const QVariant val = settings.value(oldPath);
|
||||
if (val.isValid())
|
||||
settings.setValue(jsCalBasePath.arg(QString("%1/stick_%2").arg(i).arg(var)), val); // new format "/#/stick_var"
|
||||
if (removeUnused)
|
||||
settings.remove(oldPath);
|
||||
// firmwares renamed from opentx-* to edgetx-* at 2.6
|
||||
if (savedMajMin <= 0x207) { // Note: change merged post 2.6 rc 1 and version bumped to 2.7 the Nightly users also require upgrade
|
||||
qInfo().noquote() << "Converting profiles";
|
||||
static const QString profileFwTypePath = QStringLiteral("Profiles/profile%1/fwType");
|
||||
for (int i = 0; i < MAX_PROFILES; i++) {
|
||||
if (settings.contains(profileFwTypePath.arg(i))) {
|
||||
const QVariant oldValue = settings.value(profileFwTypePath.arg(i));
|
||||
if (oldValue.isValid()) {
|
||||
const QString oldval = settings.value(profileFwTypePath.arg(i)).toString();
|
||||
QString newval = oldval;
|
||||
newval.replace("opentx-", "edgetx-");
|
||||
if (oldval != newval) {
|
||||
settings.setValue(profileFwTypePath.arg(i), newval);
|
||||
qInfo().noquote().nospace() << "Converted entry " << profileFwTypePath.arg(i)
|
||||
<< " from (" << oldval << ")"
|
||||
<< " to (" << newval << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -481,7 +470,8 @@ void AppData::clearUnusedSettings(QSettings & settings)
|
||||
|
||||
bool AppData::findPreviousVersionSettings(QString * version) const
|
||||
{
|
||||
static const QStringList versList({QStringLiteral("2.2"), QStringLiteral("2.1"), QStringLiteral("2.0")});
|
||||
// TODO need a more dynamic method since ETX moves so quickly
|
||||
static const QStringList versList({QStringLiteral("2.6"), QStringLiteral("2.5"), QStringLiteral("2.4")});
|
||||
|
||||
for (const QString &ver : versList) {
|
||||
const QString prod("Companion " % ver);
|
||||
@@ -498,30 +488,15 @@ bool AppData::findPreviousVersionSettings(QString * version) const
|
||||
}
|
||||
}
|
||||
|
||||
QSettings settings(COMPANY, "OpenTX Companion");
|
||||
if (settings.contains(SETTINGS_VERSION_KEY)) {
|
||||
*version = QStringLiteral("1.x");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
settings.clear();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppData::importSettings(const QString & fromVersion)
|
||||
{
|
||||
QString fromProduct;
|
||||
QString fromProduct = PRODUCT_NO_VERS % " " % fromVersion;
|
||||
//qDebug() << "From Product:" << fromProduct;
|
||||
upgradeFromVersion.clear();
|
||||
|
||||
if (fromVersion.startsWith("2."))
|
||||
fromProduct = "Companion " % fromVersion;
|
||||
else if (fromVersion == "1.x")
|
||||
fromProduct = "OpenTX Companion";
|
||||
else
|
||||
return false;
|
||||
|
||||
upgradeFromVersion = fromVersion;
|
||||
|
||||
QSettings fromSettings(COMPANY, fromProduct);
|
||||
@@ -535,8 +510,10 @@ bool AppData::importSettings(QSettings * fromSettings)
|
||||
|
||||
// Create temporary settings because we may modify them before import.
|
||||
QSettings tempSettings(COMPANY, PRODUCT % "_import");
|
||||
for (const QString & key : fromSettings->allKeys())
|
||||
for (const QString & key : fromSettings->allKeys()) {
|
||||
tempSettings.setValue(key, fromSettings->value(key));
|
||||
//qInfo().noquote() << "Import key(" << key << ") value(" << fromSettings->value(key) << ")";
|
||||
}
|
||||
|
||||
// convert settings first to simplify import process
|
||||
convertSettings(tempSettings);
|
||||
|
||||
@@ -38,20 +38,21 @@
|
||||
#include <QSettings>
|
||||
#include <QStandardPaths>
|
||||
|
||||
//! CPN_SETTINGS_REVISION is used to track settings changes independently of OpenTX version. It should be reset to zero whenever settings are migrated to new COMPANY or PRODUCT.
|
||||
//! CPN_SETTINGS_REVISION is used to track settings changes independently of EdgeTX version. It should be reset to zero whenever settings are migrated to new COMPANY or PRODUCT.
|
||||
//! \note !! Increment this value if properties are removed or refactored. It will trigger a conversion/cleanup of any stored settings. \sa AppData::convertSettings()
|
||||
#define CPN_SETTINGS_REVISION 0
|
||||
#define CPN_SETTINGS_REVISION 1 // Note: bumped to ensure 2.7 Nightly version users also get upgraded
|
||||
|
||||
//! CPN_SETTINGS_VERSION is used for settings data version tracking.
|
||||
#define CPN_SETTINGS_VERSION ((VERSION_NUMBER << 8) | CPN_SETTINGS_REVISION)
|
||||
|
||||
#define COMPANY QStringLiteral("EdgeTX")
|
||||
#define COMPANY_DOMAIN QStringLiteral("edgetx.org")
|
||||
#define PRODUCT_NO_VERS QStringLiteral("Companion")
|
||||
#define PRODUCT QStringLiteral("Companion " QT_STRINGIFY(VERSION_MAJOR) "." QT_STRINGIFY(VERSION_MINOR))
|
||||
#define APP_COMPANION QStringLiteral("EdgeTX Companion")
|
||||
#define APP_SIMULATOR QStringLiteral("EdgeTX Simulator")
|
||||
|
||||
//! Default location for OpenTX-related user documents (settigns, logs, etc)
|
||||
//! Default location for EdgeTX-related user documents (settigns, logs, etc)
|
||||
#define CPN_DOCUMENTS_LOCATION QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) % "/" % COMPANY
|
||||
//! Location for settings backup files. TODO: make option or remember last location.
|
||||
#define CPN_SETTINGS_BACKUP_DIR CPN_DOCUMENTS_LOCATION % "/backup"
|
||||
@@ -379,6 +380,7 @@ class Profile: public CompStoreObj
|
||||
PROPERTYSTR(sdPath)
|
||||
PROPERTYSTR(pBackupDir)
|
||||
|
||||
PROPERTY (int, defaultInternalModule, 0)
|
||||
PROPERTY4(int, channelOrder, "default_channel_order", 0)
|
||||
PROPERTY4(int, defaultMode, "default_mode", 1)
|
||||
PROPERTY (int, volumeGain, 10)
|
||||
|
||||
@@ -20,8 +20,49 @@
|
||||
|
||||
#include "categorized.h"
|
||||
#include "firmwares/opentx/opentxinterface.h"
|
||||
#include "firmwares/edgetx/edgetxinterface.h"
|
||||
#include "miniz.c" // Can only be included once!
|
||||
|
||||
#include <regex>
|
||||
|
||||
bool CategorizedStorageFormat::load(RadioData & radioData)
|
||||
{
|
||||
StorageType st = getStorageType(filename);
|
||||
if (st == STORAGE_TYPE_UNKNOWN) {
|
||||
st = probeFormat();
|
||||
}
|
||||
if (st == STORAGE_TYPE_ETX || st == STORAGE_TYPE_YML) {
|
||||
return loadYaml(radioData);
|
||||
} else {
|
||||
return loadBin(radioData);
|
||||
}
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::write(const RadioData & radioData)
|
||||
{
|
||||
StorageType st = getStorageType(filename);
|
||||
if (st == STORAGE_TYPE_UNKNOWN) {
|
||||
st = probeFormat();
|
||||
}
|
||||
if (st == STORAGE_TYPE_ETX || st == STORAGE_TYPE_YML ||
|
||||
st == STORAGE_TYPE_UNKNOWN) {
|
||||
return writeYaml(radioData);
|
||||
} else {
|
||||
return writeBin(radioData);
|
||||
}
|
||||
}
|
||||
|
||||
StorageType CategorizedStorageFormat::probeFormat()
|
||||
{
|
||||
if (QFile(filename + "/RADIO/radio.yml").exists()) // converted
|
||||
return getStorageType("radio.yml");
|
||||
else if (QFile(filename + "/RADIO/radio.bin").exists()) // unconverted
|
||||
return getStorageType("radio.bin");
|
||||
else
|
||||
return getStorageType(filename);
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::loadBin(RadioData & radioData)
|
||||
{
|
||||
QByteArray radioSettingsBuffer;
|
||||
if (!loadFile(radioSettingsBuffer, "RADIO/radio.bin")) {
|
||||
@@ -113,7 +154,7 @@ bool CategorizedStorageFormat::load(RadioData & radioData)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::write(const RadioData & radioData)
|
||||
bool CategorizedStorageFormat::writeBin(const RadioData & radioData)
|
||||
{
|
||||
QByteArray modelsList; // models.txt
|
||||
QByteArray radioSettingsData; // radio.bin
|
||||
@@ -145,7 +186,7 @@ bool CategorizedStorageFormat::write(const RadioData & radioData)
|
||||
if (!getCurrentFirmware()->getCapability(HasModelCategories)) {
|
||||
// Use format with model number and file name. This is needed because
|
||||
// radios without category support can have unused model slots
|
||||
modelsList.append(QString("%1 %2\n").arg(m).arg(model.filename));
|
||||
modelsList.append(QString("%1 %2\n").arg(m).arg(model.filename).toLocal8Bit());
|
||||
} else {
|
||||
sortedModels[model.category].push_back(QString("%1\n").arg(model.filename));
|
||||
}
|
||||
@@ -153,10 +194,12 @@ bool CategorizedStorageFormat::write(const RadioData & radioData)
|
||||
|
||||
if (getCurrentFirmware()->getCapability(HasModelCategories)) {
|
||||
for (size_t c=0; c<numCategories; c++) {
|
||||
modelsList.append(QString().sprintf("[%s]\n", radioData.categories[c].name));
|
||||
modelsList.append(QString()
|
||||
.sprintf("[%s]\n", radioData.categories[c].name)
|
||||
.toLocal8Bit());
|
||||
numModels = sortedModels[c].size();
|
||||
for (size_t m=0; m<numModels; m++) {
|
||||
modelsList.append(sortedModels[c][m]);
|
||||
modelsList.append(sortedModels[c][m].toLocal8Bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,3 +210,157 @@ bool CategorizedStorageFormat::write(const RadioData & radioData)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::loadYaml(RadioData & radioData)
|
||||
{
|
||||
if (getStorageType(filename) == STORAGE_TYPE_UNKNOWN && probeFormat() == STORAGE_TYPE_ETX) {
|
||||
if (!QFile(filename + "/" + "RADIO/radio.yml").exists())
|
||||
qDebug() << tr("Can't find %1/RADIO/radio.yml").arg(filename);
|
||||
else
|
||||
qDebug() << tr("Found %1/RADIO/radio.yml").arg(filename);
|
||||
|
||||
if (!QFile(filename + "/" + "MODELS/models.yml").exists())
|
||||
qDebug() << tr("Can't find %1/MODELS/models.yml").arg(filename);
|
||||
else
|
||||
qDebug() << tr("Found %1/MODELS/models.yml").arg(filename);
|
||||
}
|
||||
else {
|
||||
if (!QFile(filename).exists())
|
||||
qDebug() << tr("Can't find %1").arg(filename);
|
||||
else
|
||||
qDebug() << tr("Found %1").arg(filename);
|
||||
}
|
||||
|
||||
QByteArray radioSettingsBuffer;
|
||||
if (!loadFile(radioSettingsBuffer, "RADIO/radio.yml")) {
|
||||
setError(tr("Can't extract RADIO/radio.yml"));
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!loadRadioSettingsFromYaml(radioData.generalSettings, radioSettingsBuffer)) {
|
||||
setError(tr("Can't load RADIO/radio.yml"));
|
||||
return false;
|
||||
}
|
||||
} catch(const std::runtime_error& e) {
|
||||
setError(tr("Can't load RADIO/radio.yml") + ":\n" + QString(e.what()));
|
||||
return false;
|
||||
}
|
||||
|
||||
board = (Board::Type)radioData.generalSettings.variant;
|
||||
|
||||
// get models
|
||||
EtxModelfiles modelFiles;
|
||||
|
||||
QByteArray modelslistBuffer;
|
||||
if (loadFile(modelslistBuffer, "MODELS/models.yml")) {
|
||||
if (!loadModelsListFromYaml(radioData.categories, modelFiles, modelslistBuffer)) {
|
||||
setError(tr("Can't load MODELS/models.yml"));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// fetch "MODELS/modelXX.yml"
|
||||
std::list<std::string> filelist;
|
||||
if (!getFileList(filelist)) {
|
||||
setError(tr("Can't list files"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::regex yml_regex("MODELS/(model([0-9]+)\\.yml)");
|
||||
for(const auto& f : filelist) {
|
||||
std::smatch match;
|
||||
if (std::regex_match(f, match, yml_regex)) {
|
||||
if (match.size() == 3) {
|
||||
std::ssub_match modelFile = match[1];
|
||||
std::ssub_match modelIdx = match[2];
|
||||
modelFiles.push_back({ modelFile.str(), "", 0, std::stoi(modelIdx.str()) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
radioData.models.resize(modelFiles.size());
|
||||
for (const auto& mc : modelFiles) {
|
||||
qDebug() << "Filename: " << mc.filename.c_str() << " / Category: " << mc.category;
|
||||
|
||||
QByteArray modelBuffer;
|
||||
QString filename = "MODELS/" + QString::fromStdString(mc.filename);
|
||||
if (!loadFile(modelBuffer, filename)) {
|
||||
setError(tr("Can't extract ") + filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Please note:
|
||||
// ModelData() use memset to clear everything to 0
|
||||
//
|
||||
auto& model = radioData.models[mc.modelIdx];
|
||||
|
||||
try {
|
||||
if (!loadModelFromYaml(model,modelBuffer)) {
|
||||
setError(tr("Can't load ") + filename);
|
||||
return false;
|
||||
}
|
||||
} catch(const std::runtime_error& e) {
|
||||
setError(tr("Can't load ") + filename + ":\n" + QString(e.what()));
|
||||
return false;
|
||||
}
|
||||
|
||||
model.category = mc.category;
|
||||
model.modelIndex = mc.modelIdx;
|
||||
strncpy(model.filename, mc.filename.c_str(), sizeof(model.filename)-1);
|
||||
|
||||
model.used = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CategorizedStorageFormat::writeYaml(const RadioData & radioData)
|
||||
{
|
||||
QByteArray radioSettingsBuffer;
|
||||
if (!writeRadioSettingsToYaml(radioData.generalSettings, radioSettingsBuffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!writeFile(radioSettingsBuffer, "RADIO/radio.yml")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasCategories = getCurrentFirmware()->getCapability(HasModelCategories);
|
||||
|
||||
EtxModelfiles modelFiles;
|
||||
for (const auto& model : radioData.models) {
|
||||
|
||||
if (model.isEmpty())
|
||||
continue;
|
||||
|
||||
QString modelFilename;
|
||||
if (hasCategories) {
|
||||
std::string ymlFilename = patchFilenameToYaml(model.filename);
|
||||
modelFilename =
|
||||
QString("MODELS/%1").arg(QString::fromStdString(ymlFilename));
|
||||
modelFiles.push_back(
|
||||
{ymlFilename, std::string(model.name), model.category});
|
||||
} else {
|
||||
modelFilename = QString("MODELS/model%1.yml")
|
||||
.arg(model.modelIndex, 2, 10, QLatin1Char('0'));
|
||||
}
|
||||
|
||||
QByteArray modelData;
|
||||
writeModelToYaml(model, modelData);
|
||||
if (!writeFile(modelData, modelFilename)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasCategories) {
|
||||
// TODO: sort 'modelFiles' by category index
|
||||
QByteArray modelslistBuffer;
|
||||
if (!writeModelsListToYaml(radioData.categories, modelFiles, modelslistBuffer)
|
||||
|| !writeFile(modelslistBuffer, "MODELS/models.yml")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "storage.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
class CategorizedStorageFormat : public StorageFormat
|
||||
{
|
||||
@@ -41,6 +43,14 @@ class CategorizedStorageFormat : public StorageFormat
|
||||
protected:
|
||||
virtual bool loadFile(QByteArray & fileData, const QString & fileName) = 0;
|
||||
virtual bool writeFile(const QByteArray & fileData, const QString & fileName) = 0;
|
||||
virtual bool getFileList(std::list<std::string>& filelist) = 0;
|
||||
|
||||
virtual bool loadBin(RadioData & radioData);
|
||||
virtual bool writeBin(const RadioData & radioData);
|
||||
virtual bool loadYaml(RadioData & radioData);
|
||||
virtual bool writeYaml(const RadioData & radioData);
|
||||
|
||||
StorageType probeFormat();
|
||||
};
|
||||
|
||||
#endif // _CATEGORIZED_H_
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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 "etx.h"
|
||||
#include <QFile>
|
||||
|
||||
#define MZ_ALLOCATION_SIZE (32*1024)
|
||||
|
||||
bool EtxFormat::load(RadioData & radioData)
|
||||
{
|
||||
QFile file(filename);
|
||||
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
setError(tr("Error opening file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray archiveContents = file.readAll();
|
||||
|
||||
qDebug() << "File" << filename << "read, size:" << archiveContents.size();
|
||||
|
||||
// open zip file
|
||||
memset(&zip_archive, 0, sizeof(zip_archive));
|
||||
if (!mz_zip_reader_init_mem(&zip_archive, archiveContents.data(), archiveContents.size(), 0)) {
|
||||
qDebug() << tr("Error opening EdgeTX archive %1").arg(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = CategorizedStorageFormat::load(radioData);
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool EtxFormat::write(const RadioData & radioData)
|
||||
{
|
||||
qDebug() << "Saving to archive" << filename;
|
||||
|
||||
memset(&zip_archive, 0, sizeof(zip_archive));
|
||||
if (!mz_zip_writer_init_heap(&zip_archive, 0, MZ_ALLOCATION_SIZE)) {
|
||||
setError(tr("Error initializing EdgeTX archive writer"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = CategorizedStorageFormat::write(radioData);
|
||||
if (result) {
|
||||
// finalize archive and get contents
|
||||
char * archiveContents;
|
||||
size_t archiveSize;
|
||||
if (mz_zip_writer_finalize_heap_archive(&zip_archive, (void **)&archiveContents, &archiveSize)) {
|
||||
qDebug() << "Archive size" << archiveSize;
|
||||
// write contents to file
|
||||
QFile file(filename);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
qint64 len = file.write(archiveContents, archiveSize);
|
||||
if (len != (qint64)archiveSize) {
|
||||
setError(tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
setError(tr("Error creating EdgeTX file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
setError(tr("Error creating EdgeTX archive"));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
mz_zip_writer_end(&zip_archive);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool EtxFormat::loadFile(QByteArray & filedata, const QString & filename)
|
||||
{
|
||||
size_t size;
|
||||
void * data = mz_zip_reader_extract_file_to_heap(&zip_archive, qPrintable(filename), &size, 0);
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << QString("Extracted file %1, size=%2").arg(filename).arg(size);
|
||||
filedata.clear();
|
||||
filedata.append((char *)data, size);
|
||||
mz_free(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EtxFormat::writeFile(const QByteArray & filedata, const QString & filename)
|
||||
{
|
||||
if (!mz_zip_writer_add_mem(&zip_archive, filename.toStdString().c_str(), filedata.data(), filedata.size(), MZ_DEFAULT_LEVEL)) {
|
||||
setError(tr("Error adding %1 to EdgeTX archive").arg(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EtxFormat::getFileList(std::list<std::string>& filelist)
|
||||
{
|
||||
int count = (int)mz_zip_reader_get_num_files(&zip_archive);
|
||||
if (count == 0) return false;
|
||||
|
||||
mz_zip_archive_file_stat file_stat;
|
||||
for (int i=0; i<count; i++) {
|
||||
if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) continue;
|
||||
if (mz_zip_reader_is_file_a_directory(&zip_archive, i)) continue;
|
||||
filelist.push_back(file_stat.m_filename);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 _ETX_H_
|
||||
#define _ETX_H_
|
||||
|
||||
#include "categorized.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
#define MINIZ_HEADER_FILE_ONLY
|
||||
#include "miniz.c"
|
||||
#undef MINIZ_HEADER_FILE_ONLY
|
||||
|
||||
class EtxFormat : public CategorizedStorageFormat
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(EtxFormat)
|
||||
|
||||
public:
|
||||
EtxFormat(const QString & filename):
|
||||
CategorizedStorageFormat(filename)
|
||||
{
|
||||
}
|
||||
|
||||
virtual QString name() { return "etx"; }
|
||||
virtual bool load(RadioData & radioData);
|
||||
virtual bool write(const RadioData & radioData);
|
||||
|
||||
protected:
|
||||
virtual bool loadFile(QByteArray & fileData, const QString & fileName);
|
||||
virtual bool writeFile(const QByteArray & fileData, const QString & fileName);
|
||||
virtual bool getFileList(std::list<std::string>& filelist);
|
||||
|
||||
mz_zip_archive zip_archive;
|
||||
};
|
||||
|
||||
#endif // _ETX_H_
|
||||
@@ -305,11 +305,11 @@ bool FirmwareInterface::seekSplash(QByteArray sps, QByteArray spe, int size)
|
||||
return false;
|
||||
}
|
||||
|
||||
#define OTX_SPS_9X "SPS\0\200\100"
|
||||
#define OTX_SPS_TARANIS "SPS\0\324\100"
|
||||
#define OTX_SPS_SIZE 6
|
||||
#define OTX_SPE "SPE"
|
||||
#define OTX_SPE_SIZE 4
|
||||
#define ETX_SPS_9X "SPS\0\200\100"
|
||||
#define ETX_SPS_TARANIS "SPS\0\324\100"
|
||||
#define ETX_SPS_SIZE 6
|
||||
#define ETX_SPE "SPE"
|
||||
#define ETX_SPE_SIZE 4
|
||||
|
||||
void FirmwareInterface::seekSplash()
|
||||
{
|
||||
@@ -342,11 +342,11 @@ void FirmwareInterface::seekSplash()
|
||||
return;
|
||||
}
|
||||
|
||||
if (seekSplash(QByteArray(OTX_SPS_9X, OTX_SPS_SIZE), QByteArray(OTX_SPE, OTX_SPE_SIZE), 1024)) {
|
||||
if (seekSplash(QByteArray(ETX_SPS_9X, ETX_SPS_SIZE), QByteArray(ETX_SPE, ETX_SPE_SIZE), 1024)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (seekSplash(QByteArray(OTX_SPS_TARANIS, OTX_SPS_SIZE), QByteArray(OTX_SPE, OTX_SPE_SIZE), RLE_SPLASH_MAX_SIZE)) {
|
||||
if (seekSplash(QByteArray(ETX_SPS_TARANIS, ETX_SPS_SIZE), QByteArray(ETX_SPE, ETX_SPE_SIZE), RLE_SPLASH_MAX_SIZE)) {
|
||||
splashWidth = SPLASHX9D_WIDTH;
|
||||
splashHeight = SPLASHX9D_HEIGHT;
|
||||
splash_format = QImage::Format_Indexed8;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
|
||||
#include "otx.h"
|
||||
#include "miniz.c"
|
||||
#include <QFile>
|
||||
|
||||
#define MZ_ALLOCATION_SIZE (32*1024)
|
||||
@@ -40,7 +39,7 @@ bool OtxFormat::load(RadioData & radioData)
|
||||
// open zip file
|
||||
memset(&zip_archive, 0, sizeof(zip_archive));
|
||||
if (!mz_zip_reader_init_mem(&zip_archive, archiveContents.data(), archiveContents.size(), 0)) {
|
||||
qDebug() << tr("Error opening OTX archive %1").arg(filename);
|
||||
qDebug() << tr("Error opening OpenTX archive %1").arg(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -55,7 +54,7 @@ bool OtxFormat::write(const RadioData & radioData)
|
||||
|
||||
memset(&zip_archive, 0, sizeof(zip_archive));
|
||||
if (!mz_zip_writer_init_heap(&zip_archive, 0, MZ_ALLOCATION_SIZE)) {
|
||||
setError(tr("Error initializing OTX archive writer"));
|
||||
setError(tr("Error initializing OpenTX archive writer"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -76,12 +75,12 @@ bool OtxFormat::write(const RadioData & radioData)
|
||||
}
|
||||
}
|
||||
else {
|
||||
setError(tr("Error creating OTX file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
setError(tr("Error creating OpenTX file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
setError(tr("Error creating OTX archive"));
|
||||
setError(tr("Error creating OpenTX archive"));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
@@ -108,7 +107,7 @@ bool OtxFormat::loadFile(QByteArray & filedata, const QString & filename)
|
||||
bool OtxFormat::writeFile(const QByteArray & filedata, const QString & filename)
|
||||
{
|
||||
if (!mz_zip_writer_add_mem(&zip_archive, filename.toStdString().c_str(), filedata.data(), filedata.size(), MZ_DEFAULT_LEVEL)) {
|
||||
setError(tr("Error adding %1 to OTX archive").arg(filename));
|
||||
setError(tr("Error adding %1 to OpenTX archive").arg(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ class OtxFormat : public CategorizedStorageFormat
|
||||
protected:
|
||||
virtual bool loadFile(QByteArray & fileData, const QString & fileName);
|
||||
virtual bool writeFile(const QByteArray & fileData, const QString & fileName);
|
||||
virtual bool getFileList(std::list<std::string>& filelist) { return false; }
|
||||
|
||||
mz_zip_archive zip_archive;
|
||||
};
|
||||
|
||||
@@ -57,8 +57,19 @@ bool SdcardFormat::writeFile(const QByteArray & data, const QString & filename)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdcardFormat::getFileList(std::list<std::string>& filelist)
|
||||
{
|
||||
QDir dir(filename);
|
||||
if (!dir.cd("MODELS")) return false;
|
||||
|
||||
QStringList ql = dir.entryList();
|
||||
for (const auto& str : ql) {
|
||||
filelist.push_back("MODELS/" + str.toStdString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdcardStorageFactory::probe(const QString & path)
|
||||
{
|
||||
return QDir(path).exists();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ class SdcardFormat : public CategorizedStorageFormat
|
||||
protected:
|
||||
virtual bool loadFile(QByteArray & fileData, const QString & fileName);
|
||||
virtual bool writeFile(const QByteArray & fileData, const QString & fileName);
|
||||
virtual bool getFileList(std::list<std::string>& filelist);
|
||||
};
|
||||
|
||||
class SdcardStorageFactory : public DefaultStorageFactory<SdcardFormat>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "bineeprom.h"
|
||||
#include "eepe.h"
|
||||
#include "otx.h"
|
||||
#include "etx.h"
|
||||
#include "sdcard.h"
|
||||
#include "yaml.h"
|
||||
#include "firmwareinterface.h"
|
||||
@@ -42,6 +43,8 @@ StorageType getStorageType(const QString & filename)
|
||||
return STORAGE_TYPE_XML;
|
||||
else if (suffix == "OTX")
|
||||
return STORAGE_TYPE_OTX;
|
||||
else if (suffix == "ETX")
|
||||
return STORAGE_TYPE_ETX;
|
||||
else if (suffix == "YML")
|
||||
return STORAGE_TYPE_YML;
|
||||
else
|
||||
@@ -64,6 +67,7 @@ void registerStorageFactories()
|
||||
registerStorageFactory(new DefaultStorageFactory<EepeFormat>("eepe"));
|
||||
registerStorageFactory(new DefaultStorageFactory<HexEepromFormat>("hex"));
|
||||
registerStorageFactory(new DefaultStorageFactory<OtxFormat>("otx"));
|
||||
registerStorageFactory(new DefaultStorageFactory<EtxFormat>("etx"));
|
||||
registerStorageFactory(new DefaultStorageFactory<YamlFormat>("yml"));
|
||||
registerStorageFactory(new SdcardStorageFactory());
|
||||
}
|
||||
@@ -84,17 +88,20 @@ bool Storage::load(RadioData & radioData)
|
||||
|
||||
bool ret = false;
|
||||
foreach(StorageFactory * factory, registeredStorageFactories) {
|
||||
StorageFormat * format = factory->instance(filename);
|
||||
if (format->load(radioData)) {
|
||||
board = format->getBoard();
|
||||
setWarning(format->warning());
|
||||
ret = true;
|
||||
break;
|
||||
if (factory->probe(filename)) {
|
||||
StorageFormat * format = factory->instance(filename);
|
||||
if (format->load(radioData)) {
|
||||
board = format->getBoard();
|
||||
setWarning(format->warning());
|
||||
ret = true;
|
||||
delete format;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
setError(format->error());
|
||||
}
|
||||
delete format;
|
||||
}
|
||||
else {
|
||||
setError(format->error());
|
||||
}
|
||||
delete format;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user