mirror of
https://github.com/opentx/opentx.git
synced 2025-07-13 11:29:51 +03:00
Merge from 2.3
This commit is contained in:
commit
4c484017a4
161 changed files with 3683 additions and 10306 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -4,5 +4,5 @@
|
|||
branch = master
|
||||
[submodule "libACCESS"]
|
||||
path = radio/src/thirdparty/libACCESS
|
||||
url = https://github.com/FrSky-OS/libACCESS.git
|
||||
url = https://github.com/FrSkyRC/libACCESS.git
|
||||
branch = master
|
||||
|
|
77
.travis.yml
77
.travis.yml
|
@ -1,65 +1,50 @@
|
|||
sudo: required
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-sdk-team/ppa'
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
update: true
|
||||
packages:
|
||||
- curl
|
||||
- libmpfr4
|
||||
- libmpc3
|
||||
- libfox-1.6-dev
|
||||
- libgtest-dev
|
||||
- clang-6.0
|
||||
- python3-pip
|
||||
|
||||
env:
|
||||
global:
|
||||
# - QT_BASE=53
|
||||
# - QT_BASE=54
|
||||
# - QT_BASE=55
|
||||
# - QT_BASE=56
|
||||
- QT_BASE=57
|
||||
# - GCC_ARM=/opt/gcc-arm-none-eabi/bin
|
||||
- PYTHONPATH=${PYTHONPATH}:/usr/lib/python3/dist-packages
|
||||
- GCC_ARM_VERSION=4_7-2013q3
|
||||
matrix:
|
||||
#
|
||||
# ALL will build every individual board & DEFAULT, sequentially.
|
||||
# DEFAULT is "make all" (including Companion & Simulator), with default settings
|
||||
#
|
||||
# - FLAVOR=ALL
|
||||
- FLAVOR=DEFAULT
|
||||
- FLAVOR=COMPANION
|
||||
- FLAVOR=ARM9X
|
||||
# - FLAVOR=AR9X
|
||||
# - FLAVOR=SKY9X
|
||||
# - FLAVOR=9XRPRO
|
||||
- FLAVOR=X9LITE
|
||||
- FLAVOR=X9LITES
|
||||
- FLAVOR=X7
|
||||
- FLAVOR=T12
|
||||
- FLAVOR=XLITE
|
||||
- FLAVOR=XLITES
|
||||
- FLAVOR=X9
|
||||
# - FLAVOR=X9D
|
||||
# - FLAVOR=X9D+
|
||||
# - FLAVOR=X9E
|
||||
- FLAVOR=T16
|
||||
- FLAVOR=HORUS
|
||||
# - FLAVOR=X10
|
||||
# - FLAVOR=X12Sr10
|
||||
# - FLAVOR=X12S
|
||||
- FLAVOR=COLORLCD
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository ppa:ubuntu-sdk-team/ppa --yes
|
||||
- sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded --yes
|
||||
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test --yes
|
||||
- if [ "$QT_BASE" = "53" ]; then sudo add-apt-repository ppa:beineri/opt-qt532-trusty -y; fi
|
||||
- if [ "$QT_BASE" = "54" ]; then sudo add-apt-repository ppa:beineri/opt-qt542-trusty -y; fi
|
||||
- if [ "$QT_BASE" = "55" ]; then sudo add-apt-repository ppa:beineri/opt-qt551-trusty -y; fi
|
||||
- if [ "$QT_BASE" = "56" ]; then sudo add-apt-repository ppa:beineri/opt-qt562-trusty -y; fi
|
||||
- if [ "$QT_BASE" = "57" ]; then sudo add-apt-repository ppa:beineri/opt-qt571-trusty -y; fi
|
||||
- sudo apt-get update -qq
|
||||
- pyenv uninstall -f 2.7.6 && pyenv install 3.5.4 && pyenv global 3.5.4
|
||||
- pip install pillow
|
||||
|
||||
install:
|
||||
- sudo apt-get --yes --force-yes install curl libmpfr4 libmpc3 libfox-1.6-dev libgtest-dev
|
||||
- sudo apt-get --yes --force-yes install gcc-arm-none-eabi
|
||||
# Trying to build with gcc-arm 4.7 isn't working because it can't find the compiler, despite adding to PATH (in commit-tests.sh) by defining GCC_ARM above
|
||||
# - wget --quiet https://launchpad.net/gcc-arm-embedded/4.7/4.7-2013-q3-update/+download/gcc-arm-none-eabi-4_7-2013q3-20130916-linux.tar.bz2
|
||||
# - tar xjf gcc-arm-none-eabi-4_7-2013q3-20130916-linux.tar.bz2
|
||||
# - mv gcc-arm-none-eabi-4_7-2013q3 /opt/gcc-arm-none-eabi
|
||||
- wget --quiet https://launchpad.net/gcc-arm-embedded/4.7/4.7-2013-q3-update/+download/gcc-arm-none-eabi-${GCC_ARM_VERSION}-20130916-linux.tar.bz2
|
||||
- tar xjf gcc-arm-none-eabi-${GCC_ARM_VERSION}-20130916-linux.tar.bz2
|
||||
- sudo mv gcc-arm-none-eabi-${GCC_ARM_VERSION} /opt/gcc-arm-none-eabi
|
||||
- sudo ln -s /opt/gcc-arm-none-eabi/bin/arm-none-eabi-gcc /usr/bin/arm-none-eabi-gcc
|
||||
- sudo ln -s /opt/gcc-arm-none-eabi/bin/arm-none-eabi-g++ /usr/bin/arm-none-eabi-g++
|
||||
- sudo ln -s /opt/gcc-arm-none-eabi/bin/arm-none-eabi-as /usr/bin/arm-none-eabi-as
|
||||
- sudo ln -s /opt/gcc-arm-none-eabi/bin/arm-none-eabi-objcopy /usr/bin/arm-none-eabi-objcopy
|
||||
- sudo ln -s /opt/gcc-arm-none-eabi/bin/arm-none-eabi-objdump /usr/bin/arm-none-eabi-objdump
|
||||
- sudo ln -s /opt/gcc-arm-none-eabi/bin/arm-none-eabi-size /usr/bin/arm-none-eabi-size
|
||||
- sudo apt-get install --yes --force-yes -qq qt${QT_BASE}base qt${QT_BASE}multimedia qt${QT_BASE}svg qt${QT_BASE}tools; source /opt/qt${QT_BASE}/bin/qt${QT_BASE}-env.sh
|
||||
- sudo ln -sf /usr/bin/python3 /usr/bin/python
|
||||
- python3 -m pip install pillow clang
|
||||
|
||||
script:
|
||||
- ./tools/commit-tests.sh
|
||||
|
|
|
@ -6,7 +6,7 @@ set(VERSION_REVISION "0")
|
|||
set(VERSION_SUFFIX $ENV{OPENTX_VERSION_SUFFIX})
|
||||
set(VERSION_FAMILY ${VERSION_MAJOR}.${VERSION_MINOR})
|
||||
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}${VERSION_SUFFIX})
|
||||
set(SDCARD_REVISION "0000")
|
||||
set(SDCARD_REVISION "0024")
|
||||
set(SDCARD_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}V${SDCARD_REVISION})
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
@ -235,15 +235,21 @@ add_custom_target(tests-radio
|
|||
|
||||
if(Qt5Core_FOUND AND NOT DISABLE_COMPANION)
|
||||
add_subdirectory(${COMPANION_SRC_DIRECTORY})
|
||||
add_custom_target(gtests DEPENDS gtests-radio gtests-companion)
|
||||
add_custom_target(tests-companion
|
||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/gtests-companion
|
||||
DEPENDS gtests-companion
|
||||
)
|
||||
add_custom_target(gtests
|
||||
DEPENDS gtests-radio gtests-companion
|
||||
)
|
||||
add_custom_target(tests
|
||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/gtests-radio && ${CMAKE_CURRENT_BINARY_DIR}/gtests-companion
|
||||
DEPENDS gtests
|
||||
DEPENDS tests-radio tests-companion
|
||||
)
|
||||
else()
|
||||
add_custom_target(gtests DEPENDS gtests-radio)
|
||||
add_custom_target(gtests
|
||||
DEPENDS gtests-radio
|
||||
)
|
||||
add_custom_target(tests
|
||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/gtests-radio
|
||||
DEPENDS gtests
|
||||
DEPENDS tests-radio
|
||||
)
|
||||
endif()
|
||||
|
|
28
CREDITS.txt
28
CREDITS.txt
|
@ -1633,3 +1633,31 @@ Siegfried Preißler
|
|||
Bernard Mohamedaly
|
||||
John North
|
||||
Thomas Wormsley
|
||||
Michael Schreiber
|
||||
DTg Privat
|
||||
Frédéric Devillard
|
||||
Lauland Bourg
|
||||
Jurij Peternel
|
||||
Murray King
|
||||
Horia Adrian Bucovanu
|
||||
Freddy Prousteau
|
||||
Wojciech Winiarski
|
||||
James A Davey
|
||||
James Donelson
|
||||
David Jolly
|
||||
Domingos S. Fonseca M.
|
||||
Kenneth Frehafer
|
||||
Christian Epple
|
||||
David Williams
|
||||
Michael Bernard
|
||||
Michael Wagner
|
||||
Carl Pennington
|
||||
LTR Consulting
|
||||
Norman Brisson
|
||||
Darko Perković
|
||||
Andreas Fischer
|
||||
Pablo Peinado Abad
|
||||
NthWave Web Works
|
||||
Simon Brenner
|
||||
Joseph Litko
|
||||
Bradley Murchie
|
||||
|
|
|
@ -85,6 +85,11 @@ void LimitData::clear()
|
|||
max = +1000;
|
||||
}
|
||||
|
||||
bool LimitData::isEmpty() const
|
||||
{
|
||||
return (min == -1000 && max == 1000 && !revert && !offset && !ppmCenter && !symetrical && name[0] == '\0');
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CurveData
|
||||
|
|
|
@ -111,6 +111,7 @@ class LimitData {
|
|||
QString revertToString() const;
|
||||
QString nameToString(int index) const;
|
||||
void clear();
|
||||
bool isEmpty() const;
|
||||
};
|
||||
|
||||
class CurvePoint {
|
||||
|
|
|
@ -123,6 +123,9 @@ enum TrainerMode {
|
|||
TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE,
|
||||
TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE,
|
||||
TRAINER_MODE_MASTER_BATTERY_COMPARTMENT,
|
||||
TRAINER_MODE_MASTER_BLUETOOTH,
|
||||
TRAINER_MODE_SLAVE_BLUETOOTH,
|
||||
TRAINER_MODE_MULTI
|
||||
};
|
||||
|
||||
class ModelData {
|
||||
|
|
|
@ -86,7 +86,7 @@ QString ModuleData::rfProtocolToString() const
|
|||
{
|
||||
switch (protocol) {
|
||||
case PULSES_MULTIMODULE:
|
||||
return Multiprotocols::protocolToString((int)multi.rfProtocol, multi.customProto);
|
||||
return Multiprotocols::protocolToString((int)multi.rfProtocol);
|
||||
|
||||
default:
|
||||
return CPN_STR_UNKNOWN_ITEM;
|
||||
|
@ -107,7 +107,7 @@ QString ModuleData::subTypeToString(int type) const
|
|||
|
||||
switch (protocol) {
|
||||
case PULSES_MULTIMODULE:
|
||||
return Multiprotocols::subTypeToString(multi.customProto ? MM_RF_CUSTOM_SELECTED : (int)multi.rfProtocol, (unsigned)type);
|
||||
return Multiprotocols::subTypeToString((int)multi.rfProtocol, (unsigned)type);
|
||||
|
||||
case PULSES_PXX_R9M:
|
||||
return CHECK_IN_ARRAY(strings, type);
|
||||
|
|
|
@ -164,9 +164,10 @@ class ModuleData {
|
|||
|
||||
struct Multi {
|
||||
unsigned int rfProtocol;
|
||||
bool disableTelemetry;
|
||||
bool disableMapping;
|
||||
bool autoBindMode;
|
||||
bool lowPowerMode;
|
||||
bool customProto;
|
||||
int optionValue;
|
||||
} multi;
|
||||
|
||||
|
|
|
@ -172,5 +172,8 @@ QString Multiprotocols::protocolToString(int protocol, bool custom)
|
|||
// static
|
||||
QString Multiprotocols::subTypeToString(int protocol, unsigned subType)
|
||||
{
|
||||
return tr(qPrintable(multiProtocols.getProtocol(protocol).subTypeStrings.value(subType, CPN_STR_UNKNOWN_ITEM)));
|
||||
if (protocol > MODULE_SUBTYPE_MULTI_LAST)
|
||||
return tr(qPrintable(QString::number(subType)));
|
||||
else
|
||||
return tr(qPrintable(multiProtocols.getProtocol(protocol).subTypeStrings.value(subType, CPN_STR_UNKNOWN_ITEM)));
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <vector>
|
||||
#include <QtCore>
|
||||
#include "moduledata.h"
|
||||
|
||||
#define MM_RF_CUSTOM_SELECTED 0xff
|
||||
|
||||
|
@ -48,7 +49,7 @@ class Multiprotocols
|
|||
|
||||
unsigned int numSubTypes() const
|
||||
{
|
||||
return (unsigned int) subTypeStrings.length();
|
||||
return protocol > MODULE_SUBTYPE_MULTI_LAST ? 8 : (unsigned int) subTypeStrings.length();
|
||||
}
|
||||
|
||||
int getOptionMin() const;
|
||||
|
|
|
@ -2037,9 +2037,10 @@ class ModuleUnionField: public UnionField<unsigned int> {
|
|||
rfProtExtra(0)
|
||||
{
|
||||
ModuleData::Multi& multi = module.multi;
|
||||
internalField.Append(new UnsignedField<2>(this, rfProtExtra));
|
||||
internalField.Append(new SpareBitsField<3>(this));
|
||||
internalField.Append(new BoolField<1>(this, multi.customProto));
|
||||
internalField.Append(new UnsignedField<3>(this, rfProtExtra));
|
||||
internalField.Append(new BoolField<1>(this, multi.disableTelemetry));
|
||||
internalField.Append(new BoolField<1>(this, multi.disableMapping));
|
||||
internalField.Append(new SpareBitsField<1>(this));
|
||||
internalField.Append(new BoolField<1>(this, multi.autoBindMode));
|
||||
internalField.Append(new BoolField<1>(this, multi.lowPowerMode));
|
||||
internalField.Append(new SignedField<8>(this, multi.optionValue));
|
||||
|
@ -2052,12 +2053,17 @@ class ModuleUnionField: public UnionField<unsigned int> {
|
|||
|
||||
void beforeExport() override
|
||||
{
|
||||
rfProtExtra = (module.multi.rfProtocol >> 4) & 0x03;
|
||||
if (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST)
|
||||
module.multi.rfProtocol += 3;
|
||||
rfProtExtra = (module.multi.rfProtocol & 0x70) >> 4;
|
||||
module.multi.rfProtocol &= 0x0f;
|
||||
}
|
||||
|
||||
void afterImport() override
|
||||
{
|
||||
module.multi.rfProtocol = (rfProtExtra & 0x3) << 4 | (module.rfProtocol & 0xf);
|
||||
module.multi.rfProtocol = (rfProtExtra << 4) + (module.rfProtocol & 0xf);
|
||||
if (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST)
|
||||
module.multi.rfProtocol -= 3;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -1222,7 +1222,6 @@ void registerOpenTxFirmwares()
|
|||
/* FrSky Taranis X9D+ 2019 board */
|
||||
firmware = new OpenTxFirmware("opentx-x9d+2019", Firmware::tr("FrSky Taranis X9D+ 2019"), BOARD_TARANIS_X9DP_2019);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
firmware->addOption("autoupdate", Firmware::tr("Support for auto update on boot"));
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky Taranis X9D board */
|
||||
|
@ -1243,13 +1242,11 @@ void registerOpenTxFirmwares()
|
|||
/* FrSky X9-Lite board */
|
||||
firmware = new OpenTxFirmware("opentx-x9lite", Firmware::tr("FrSky Taranis X9-Lite"), BOARD_TARANIS_X9LITE);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
firmware->addOption("autoupdate", Firmware::tr("Support for auto update on boot"));
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky X9-LiteS board */
|
||||
firmware = new OpenTxFirmware("opentx-x9lites", Firmware::tr("FrSky Taranis X9-Lite S"), BOARD_TARANIS_X9LITES);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
firmware->addOption("autoupdate", Firmware::tr("Support for auto update on boot"));
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky X7 board */
|
||||
|
@ -1260,7 +1257,6 @@ void registerOpenTxFirmwares()
|
|||
/* FrSky X-Lite S/PRO board */
|
||||
firmware = new OpenTxFirmware("opentx-xlites", Firmware::tr("FrSky Taranis X-Lite S/PRO"), BOARD_TARANIS_XLITES);
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
firmware->addOption("autoupdate", Firmware::tr("Support for auto update on boot"));
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky X-Lite board */
|
||||
|
@ -1276,9 +1272,8 @@ void registerOpenTxFirmwares()
|
|||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky X10 Express board */
|
||||
firmware = new OpenTxFirmware("opentx-x10express", Firmware::tr("FrSky Horus X10 / X10S Express"), BOARD_X10_EXPRESS);
|
||||
firmware = new OpenTxFirmware("opentx-x10express", Firmware::tr("FrSky Horus X10 Express / X10S Express"), BOARD_X10_EXPRESS);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("autoupdate", Firmware::tr("Support for auto update on boot"));
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* FrSky X12 (Horus) board */
|
||||
|
@ -1289,17 +1284,18 @@ void registerOpenTxFirmwares()
|
|||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* Jumper T12 board */
|
||||
firmware = new OpenTxFirmware("opentx-t12", QCoreApplication::translate("Firmware", "Jumper T12"), BOARD_JUMPER_T12);
|
||||
firmware = new OpenTxFirmware("opentx-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"));
|
||||
firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen"));
|
||||
firmware->addOption("flexr9m", Firmware::tr("Enable non certified R9M firmwares"));
|
||||
firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module"));
|
||||
addOpenTxFontOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* Jumper T16 board */
|
||||
firmware = new OpenTxFirmware("opentx-t16", Firmware::tr("Jumper T16 / T16+"), BOARD_JUMPER_T16);
|
||||
firmware = new OpenTxFirmware("opentx-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"));
|
||||
|
|
|
@ -40,6 +40,12 @@ void HardwarePanel::setupSwitchType(int index, QLabel * label, AutoLineEdit * na
|
|||
else if (index == 5) {
|
||||
label->setText("SH");
|
||||
}
|
||||
if (index == 6) {
|
||||
label->setText("SI");
|
||||
}
|
||||
else if (index == 7) {
|
||||
label->setText("SJ");
|
||||
}
|
||||
}
|
||||
if (IS_JUMPER_T12(board)) {
|
||||
if (index == 4) {
|
||||
|
@ -166,7 +172,7 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
|
|||
ui->txCurrentCalibrationLabel->hide();
|
||||
}
|
||||
|
||||
if (IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board)|| IS_TARANIS_X9E(board) || IS_HORUS(board) || IS_JUMPER_T12(board)) {
|
||||
if (IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board)|| IS_TARANIS_X9E(board) || IS_HORUS(board)) {
|
||||
ui->bluetoothMode->addItem(tr("OFF"), 0);
|
||||
if (IS_TARANIS_X9E(board)) {
|
||||
ui->bluetoothMode->addItem(tr("Enabled"), 1);
|
||||
|
|
|
@ -701,6 +701,10 @@ void MdiChild::updateTitle()
|
|||
if (availableEEpromSize >= 0) {
|
||||
title += QString(" - %1 ").arg(availableEEpromSize) + tr("free bytes");
|
||||
}
|
||||
QFileInfo fi(curFile);
|
||||
if (!isUntitled && !fi.isWritable()) {
|
||||
title += QString(" (%1)").arg(tr("read only"));
|
||||
}
|
||||
setWindowTitle(title);
|
||||
}
|
||||
|
||||
|
@ -1355,7 +1359,8 @@ bool MdiChild::loadFile(const QString & filename, bool resetCurrentFile)
|
|||
|
||||
bool MdiChild::save()
|
||||
{
|
||||
if (isUntitled) {
|
||||
QFileInfo fi(curFile);
|
||||
if (isUntitled || !fi.isWritable()) {
|
||||
return saveAs(true);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -101,6 +101,7 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
|
|||
{
|
||||
Stopwatch s1("Channels");
|
||||
|
||||
chnCapability = firmware->getCapability(Outputs);
|
||||
int channelNameMaxLen = firmware->getCapability(ChannelsName);
|
||||
|
||||
QStringList headerLabels;
|
||||
|
@ -115,11 +116,11 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
|
|||
headerLabels << tr("PPM Center");
|
||||
if (firmware->getCapability(SYMLimits))
|
||||
headerLabels << tr("Linear Subtrim");
|
||||
TableLayout *tableLayout = new TableLayout(this, firmware->getCapability(LogicalSwitches), headerLabels);
|
||||
TableLayout *tableLayout = new TableLayout(this, chnCapability, headerLabels);
|
||||
|
||||
s1.report("header");
|
||||
|
||||
for (int i=0; i<firmware->getCapability(Outputs); i++) {
|
||||
for (int i=0; i<chnCapability; i++) {
|
||||
int col = 0;
|
||||
|
||||
// Channel label
|
||||
|
@ -196,7 +197,7 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
|
|||
|
||||
disableMouseScrolling();
|
||||
tableLayout->resizeColumnsToContents();
|
||||
tableLayout->pushRowsUp(firmware->getCapability(Outputs)+1);
|
||||
tableLayout->pushRowsUp(chnCapability+1);
|
||||
s1.report("end");
|
||||
}
|
||||
|
||||
|
@ -279,7 +280,7 @@ void Channels::ppmcenterEdited()
|
|||
|
||||
void Channels::update()
|
||||
{
|
||||
for (int i=0; i<firmware->getCapability(Outputs); i++) {
|
||||
for (int i=0; i<chnCapability; i++) {
|
||||
updateLine(i);
|
||||
}
|
||||
}
|
||||
|
@ -315,8 +316,8 @@ void Channels::chnPaste()
|
|||
{
|
||||
const QClipboard *clipboard = QApplication::clipboard();
|
||||
const QMimeData *mimeData = clipboard->mimeData();
|
||||
if (mimeData->hasFormat("application/x-companion-chn")) {
|
||||
QByteArray chnData = mimeData->data("application/x-companion-chn");
|
||||
if (mimeData->hasFormat(MIMETYPE_CHN)) {
|
||||
QByteArray chnData = mimeData->data(MIMETYPE_CHN);
|
||||
LimitData *chn = &model->limitData[selectedChannel];
|
||||
memcpy(chn, chnData.constData(), sizeof(LimitData));
|
||||
updateLine(selectedChannel);
|
||||
|
@ -326,8 +327,17 @@ void Channels::chnPaste()
|
|||
|
||||
void Channels::chnDelete()
|
||||
{
|
||||
model->limitData[selectedChannel].clear();
|
||||
updateLine(selectedChannel);
|
||||
int maxidx = chnCapability - 1;
|
||||
for (int i=selectedChannel; i<maxidx; i++) {
|
||||
if (!model->limitData[i].isEmpty() || !model->limitData[i+1].isEmpty()) {
|
||||
LimitData *chn1 = &model->limitData[i];
|
||||
LimitData *chn2 = &model->limitData[i+1];
|
||||
memcpy(chn1, chn2, sizeof(LimitData));
|
||||
updateLine(i);
|
||||
}
|
||||
}
|
||||
model->limitData[maxidx].clear();
|
||||
updateLine(maxidx);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
|
@ -336,32 +346,93 @@ void Channels::chnCopy()
|
|||
QByteArray chnData;
|
||||
chnData.append((char*)&model->limitData[selectedChannel],sizeof(LimitData));
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData("application/x-companion-chn", chnData);
|
||||
mimeData->setData(MIMETYPE_CHN, chnData);
|
||||
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
|
||||
}
|
||||
|
||||
void Channels::chnCut()
|
||||
{
|
||||
chnCopy();
|
||||
chnDelete();
|
||||
chnClear();
|
||||
}
|
||||
|
||||
void Channels::chn_customContextMenuRequested(QPoint pos)
|
||||
{
|
||||
QLabel *label = (QLabel *)sender();
|
||||
selectedChannel = label->property("index").toInt();
|
||||
QLabel *label = (QLabel *)sender();
|
||||
selectedChannel = label->property("index").toInt();
|
||||
|
||||
QPoint globalPos = label->mapToGlobal(pos);
|
||||
QPoint globalPos = label->mapToGlobal(pos);
|
||||
|
||||
const QClipboard *clipboard = QApplication::clipboard();
|
||||
const QMimeData *mimeData = clipboard->mimeData();
|
||||
bool hasData = mimeData->hasFormat("application/x-companion-chn");
|
||||
const QClipboard *clipboard = QApplication::clipboard();
|
||||
const QMimeData *mimeData = clipboard->mimeData();
|
||||
bool hasData = mimeData->hasFormat(MIMETYPE_CHN);
|
||||
bool moveUpAllowed = (selectedChannel > 0);
|
||||
bool moveDownAllowed = (selectedChannel < (chnCapability - 1));
|
||||
bool insertAllowed = (selectedChannel < (chnCapability - 1)) && (model->limitData[chnCapability - 1].isEmpty());
|
||||
|
||||
QMenu contextMenu;
|
||||
contextMenu.addAction(CompanionIcon("copy.png"), tr("&Copy"),this,SLOT(chnCopy()));
|
||||
contextMenu.addAction(CompanionIcon("cut.png"), tr("&Cut"),this,SLOT(chnCut()));
|
||||
contextMenu.addAction(CompanionIcon("paste.png"), tr("&Paste"),this,SLOT(chnPaste()))->setEnabled(hasData);
|
||||
contextMenu.addAction(CompanionIcon("clear.png"), tr("&Delete"),this,SLOT(chnDelete()));
|
||||
QMenu contextMenu;
|
||||
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(chnCopy()));
|
||||
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(chnCut()));
|
||||
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(chnPaste()))->setEnabled(hasData);
|
||||
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(chnClear()));
|
||||
contextMenu.addSeparator();
|
||||
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"),this,SLOT(chnInsert()))->setEnabled(insertAllowed);
|
||||
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(chnDelete()));
|
||||
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(chnMoveUp()))->setEnabled(moveUpAllowed);
|
||||
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(chnMoveDown()))->setEnabled(moveDownAllowed);
|
||||
contextMenu.addSeparator();
|
||||
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(chnClearAll()));
|
||||
|
||||
contextMenu.exec(globalPos);
|
||||
contextMenu.exec(globalPos);
|
||||
}
|
||||
|
||||
void Channels::chnMoveUp()
|
||||
{
|
||||
swapChnData(selectedChannel, selectedChannel - 1);
|
||||
}
|
||||
|
||||
void Channels::chnMoveDown()
|
||||
{
|
||||
swapChnData(selectedChannel, selectedChannel + 1);
|
||||
}
|
||||
|
||||
void Channels::chnClear()
|
||||
{
|
||||
model->limitData[selectedChannel].clear();
|
||||
updateLine(selectedChannel);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void Channels::chnClearAll()
|
||||
{
|
||||
for (int i=0; i<chnCapability; i++) {
|
||||
model->limitData[i].clear();
|
||||
updateLine(i);
|
||||
}
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void Channels::chnInsert()
|
||||
{
|
||||
for (int i=(chnCapability - 1); i>selectedChannel; i--) {
|
||||
if (!model->limitData[i].isEmpty() || !model->limitData[i-1].isEmpty()) {
|
||||
memcpy(&model->limitData[i], &model->limitData[i-1], sizeof(LimitData));
|
||||
updateLine(i);
|
||||
}
|
||||
}
|
||||
chnClear();
|
||||
}
|
||||
|
||||
void Channels::swapChnData(int idx1, int idx2)
|
||||
{
|
||||
if ((idx1 != idx2) && (!model->limitData[idx1].isEmpty() || !model->limitData[idx2].isEmpty())) {
|
||||
LimitData chntmp = model->limitData[idx2];
|
||||
LimitData *chn1 = &model->limitData[idx1];
|
||||
LimitData *chn2 = &model->limitData[idx2];
|
||||
memcpy(chn2, chn1, sizeof(LimitData));
|
||||
memcpy(chn1, &chntmp, sizeof(LimitData));
|
||||
updateLine(idx1);
|
||||
updateLine(idx2);
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include <QtCore>
|
||||
|
||||
constexpr char MIMETYPE_CHN[] = "application/x-companion-chn";
|
||||
|
||||
class GVarGroup;
|
||||
|
||||
class LimitsGroup
|
||||
|
@ -70,9 +72,15 @@ class Channels : public ModelPanel
|
|||
void chnCopy();
|
||||
void chnPaste();
|
||||
void chnCut();
|
||||
void chnMoveUp();
|
||||
void chnMoveDown();
|
||||
void chnInsert();
|
||||
void chnClear();
|
||||
void chnClearAll();
|
||||
void chn_customContextMenuRequested(QPoint pos);
|
||||
|
||||
private:
|
||||
void swapChnData(int idx1, int idx2);
|
||||
QLineEdit *name[CPN_MAX_CHNOUT];
|
||||
LimitsGroup *chnOffset[CPN_MAX_CHNOUT];
|
||||
LimitsGroup *chnMin[CPN_MAX_CHNOUT];
|
||||
|
@ -82,6 +90,7 @@ class Channels : public ModelPanel
|
|||
QSpinBox *centerSB[CPN_MAX_CHNOUT];
|
||||
QCheckBox *symlimitsChk[CPN_MAX_CHNOUT];
|
||||
int selectedChannel;
|
||||
int chnCapability;
|
||||
};
|
||||
|
||||
#endif // _CHANNELS_H_
|
||||
|
|
|
@ -74,7 +74,7 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
|
|||
{
|
||||
Stopwatch s1("CustomFunctionsPanel - populate");
|
||||
lock = true;
|
||||
int num_fsw = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions);
|
||||
fswCapability = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions);
|
||||
|
||||
rawSwitchItemModel = new RawSwitchFilterItemModel(&generalSettings, model, model ? RawSwitch::SpecialFunctionsContext : RawSwitch::GlobalFunctionsContext, this);
|
||||
rawSrcAllItemModel = new RawSourceFilterItemModel(&generalSettings, model, this);
|
||||
|
@ -83,7 +83,7 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
|
|||
|
||||
if (!firmware->getCapability(VoicesAsNumbers)) {
|
||||
tracksSet = getFilesSet(getSoundsPath(generalSettings), QStringList() << "*.wav" << "*.WAV", firmware->getCapability(VoicesMaxLength));
|
||||
for (int i=0; i<num_fsw; i++) {
|
||||
for (int i=0; i<fswCapability; i++) {
|
||||
if (functions[i].func==FuncPlayPrompt || functions[i].func==FuncBackgroundMusic) {
|
||||
QString temp = functions[i].paramarm;
|
||||
if (!temp.isEmpty()) {
|
||||
|
@ -97,7 +97,7 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
|
|||
|
||||
if (IS_STM32(firmware->getBoard())) {
|
||||
scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/FUNCTIONS", QStringList() << "*.lua", firmware->getCapability(VoicesMaxLength));
|
||||
for (int i=0; i<num_fsw; i++) {
|
||||
for (int i=0; i<fswCapability; i++) {
|
||||
if (functions[i].func==FuncPlayScript) {
|
||||
QString temp = functions[i].paramarm;
|
||||
if (!temp.isEmpty()) {
|
||||
|
@ -113,9 +113,9 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
|
|||
|
||||
QStringList headerLabels;
|
||||
headerLabels << "#" << tr("Switch") << tr("Action") << tr("Parameters") << tr("Enable");
|
||||
TableLayout * tableLayout = new TableLayout(this, num_fsw, headerLabels);
|
||||
TableLayout * tableLayout = new TableLayout(this, fswCapability, headerLabels);
|
||||
|
||||
for (int i=0; i<num_fsw; i++) {
|
||||
for (int i=0; i<fswCapability; i++) {
|
||||
// The label
|
||||
QLabel * label = new QLabel(this);
|
||||
label->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
@ -244,7 +244,7 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
|
|||
tableLayout->resizeColumnsToContents();
|
||||
s1.report("resizeColumnsToContents");
|
||||
tableLayout->setColumnWidth(3, 300);
|
||||
tableLayout->pushRowsUp(num_fsw+1);
|
||||
tableLayout->pushRowsUp(fswCapability+1);
|
||||
s1.report("end");
|
||||
}
|
||||
|
||||
|
@ -579,7 +579,6 @@ void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified)
|
|||
widgetsMask |= CUSTOM_FUNCTION_ENABLE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fswtchFunc[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SHOW_FUNC);
|
||||
|
@ -603,8 +602,7 @@ void CustomFunctionsPanel::update()
|
|||
{
|
||||
updateDataModels();
|
||||
lock = true;
|
||||
int num_fsw = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions);
|
||||
for (int i=0; i<num_fsw; i++) {
|
||||
for (int i=0; i<fswCapability; i++) {
|
||||
refreshCustomFunction(i);
|
||||
}
|
||||
lock = false;
|
||||
|
@ -614,30 +612,28 @@ void CustomFunctionsPanel::fswPaste()
|
|||
{
|
||||
const QClipboard *clipboard = QApplication::clipboard();
|
||||
const QMimeData *mimeData = clipboard->mimeData();
|
||||
if (mimeData->hasFormat("application/x-companion-fsw")) {
|
||||
QByteArray fswData = mimeData->data("application/x-companion-fsw");
|
||||
if (mimeData->hasFormat(MIMETYPE_FSW)) {
|
||||
QByteArray fswData = mimeData->data(MIMETYPE_FSW);
|
||||
CustomFunctionData *fsw = &functions[selectedFunction];
|
||||
memcpy(fsw, fswData.constData(), sizeof(CustomFunctionData));
|
||||
lock = true;
|
||||
fswtchSwtch[selectedFunction]->setCurrentIndex(fswtchSwtch[selectedFunction]->findData(functions[selectedFunction].swtch.toValue()));
|
||||
fswtchFunc[selectedFunction]->setCurrentIndex(fswtchFunc[selectedFunction]->findData(functions[selectedFunction].func));
|
||||
populateGVmodeCB(fswtchGVmode[selectedFunction], functions[selectedFunction].adjustMode);
|
||||
populateFuncParamCB(fswtchParamT[selectedFunction], functions[selectedFunction].func, functions[selectedFunction].param, functions[selectedFunction].adjustMode);
|
||||
refreshCustomFunction(selectedFunction);
|
||||
lock = false;
|
||||
resetCBsAndRefresh(selectedFunction);
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::fswDelete()
|
||||
{
|
||||
functions[selectedFunction].clear();
|
||||
// TODO update switch and func
|
||||
lock = true;
|
||||
fswtchSwtch[selectedFunction]->setCurrentIndex(fswtchSwtch[selectedFunction]->findData(functions[selectedFunction].swtch.toValue()));
|
||||
fswtchFunc[selectedFunction]->setCurrentIndex(fswtchFunc[selectedFunction]->findData(functions[selectedFunction].func));
|
||||
refreshCustomFunction(selectedFunction);
|
||||
lock = false;
|
||||
int maxidx = fswCapability - 1;
|
||||
for (int i=selectedFunction; i<maxidx; i++) {
|
||||
if (!functions[i].isEmpty() || !functions[i+1].isEmpty()) {
|
||||
CustomFunctionData *fsw1 = &functions[i];
|
||||
CustomFunctionData *fsw2 = &functions[i+1];
|
||||
memcpy(fsw1, fsw2, sizeof(CustomFunctionData));
|
||||
resetCBsAndRefresh(i);
|
||||
}
|
||||
}
|
||||
functions[maxidx].clear();
|
||||
resetCBsAndRefresh(maxidx);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
|
@ -646,34 +642,44 @@ void CustomFunctionsPanel::fswCopy()
|
|||
QByteArray fswData;
|
||||
fswData.append((char*)&functions[selectedFunction], sizeof(CustomFunctionData));
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData("application/x-companion-fsw", fswData);
|
||||
mimeData->setData(MIMETYPE_FSW, fswData);
|
||||
QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::fswCut()
|
||||
{
|
||||
fswCopy();
|
||||
fswDelete();
|
||||
fswClear();
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::fsw_customContextMenuRequested(QPoint pos)
|
||||
{
|
||||
QLabel *label = (QLabel *)sender();
|
||||
selectedFunction = label->property("index").toInt();
|
||||
QLabel *label = (QLabel *)sender();
|
||||
selectedFunction = label->property("index").toInt();
|
||||
|
||||
QPoint globalPos = label->mapToGlobal(pos);
|
||||
QPoint globalPos = label->mapToGlobal(pos);
|
||||
|
||||
const QClipboard *clipboard = QApplication::clipboard();
|
||||
const QMimeData *mimeData = clipboard->mimeData();
|
||||
bool hasData = mimeData->hasFormat("application/x-companion-fsw");
|
||||
const QClipboard *clipboard = QApplication::clipboard();
|
||||
const QMimeData *mimeData = clipboard->mimeData();
|
||||
bool hasData = mimeData->hasFormat(MIMETYPE_FSW);
|
||||
bool moveUpAllowed = (selectedFunction > 0);
|
||||
bool moveDownAllowed = (selectedFunction < (fswCapability - 1));
|
||||
bool insertAllowed = (selectedFunction < (fswCapability - 1)) && (functions[fswCapability - 1].isEmpty());
|
||||
|
||||
QMenu contextMenu;
|
||||
contextMenu.addAction(CompanionIcon("copy.png"), tr("&Copy"),this,SLOT(fswCopy()));
|
||||
contextMenu.addAction(CompanionIcon("cut.png"), tr("&Cut"),this,SLOT(fswCut()));
|
||||
contextMenu.addAction(CompanionIcon("paste.png"), tr("&Paste"),this,SLOT(fswPaste()))->setEnabled(hasData);
|
||||
contextMenu.addAction(CompanionIcon("clear.png"), tr("&Delete"),this,SLOT(fswDelete()));
|
||||
QMenu contextMenu;
|
||||
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(fswCopy()));
|
||||
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(fswCut()));
|
||||
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(fswPaste()))->setEnabled(hasData);
|
||||
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(fswClear()));
|
||||
contextMenu.addSeparator();
|
||||
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"),this,SLOT(fswInsert()))->setEnabled(insertAllowed);
|
||||
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(fswDelete()));
|
||||
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(fswMoveUp()))->setEnabled(moveUpAllowed);
|
||||
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(fswMoveDown()))->setEnabled(moveDownAllowed);
|
||||
contextMenu.addSeparator();
|
||||
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(fswClearAll()));
|
||||
|
||||
contextMenu.exec(globalPos);
|
||||
contextMenu.exec(globalPos);
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::populateFuncCB(QComboBox *b, unsigned int value)
|
||||
|
@ -755,3 +761,65 @@ void CustomFunctionsPanel::populateFuncParamCB(QComboBox *b, uint function, unsi
|
|||
b->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::fswMoveUp()
|
||||
{
|
||||
swapFuncData(selectedFunction, selectedFunction - 1);
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::fswMoveDown()
|
||||
{
|
||||
swapFuncData(selectedFunction, selectedFunction + 1);
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::fswClear()
|
||||
{
|
||||
functions[selectedFunction].clear();
|
||||
resetCBsAndRefresh(selectedFunction);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::fswClearAll()
|
||||
{
|
||||
for (int i=0; i<fswCapability; i++) {
|
||||
functions[i].clear();
|
||||
resetCBsAndRefresh(i);
|
||||
}
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::fswInsert()
|
||||
{
|
||||
for (int i=(fswCapability - 1); i>selectedFunction; i--) {
|
||||
if (!functions[i].isEmpty() || !functions[i-1].isEmpty()) {
|
||||
memcpy(&functions[i], &functions[i-1], sizeof(CustomFunctionData));
|
||||
resetCBsAndRefresh(i);
|
||||
}
|
||||
}
|
||||
fswClear();
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::swapFuncData(int idx1, int idx2)
|
||||
{
|
||||
if ((idx1 != idx2) && (!functions[idx1].isEmpty() || !functions[idx2].isEmpty())) {
|
||||
CustomFunctionData fswtmp = functions[idx2];
|
||||
CustomFunctionData *fsw1 = &functions[idx1];
|
||||
CustomFunctionData *fsw2 = &functions[idx2];
|
||||
memcpy(fsw2, fsw1, sizeof(CustomFunctionData));
|
||||
memcpy(fsw1, &fswtmp, sizeof(CustomFunctionData));
|
||||
resetCBsAndRefresh(idx1);
|
||||
resetCBsAndRefresh(idx2);
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
void CustomFunctionsPanel::resetCBsAndRefresh(int idx)
|
||||
{
|
||||
lock = true;
|
||||
fswtchSwtch[idx]->setCurrentIndex(fswtchSwtch[idx]->findData(functions[idx].swtch.toValue()));
|
||||
fswtchFunc[idx]->setCurrentIndex(fswtchFunc[idx]->findData(functions[idx].func));
|
||||
fswtchGVmode[idx]->setCurrentIndex(functions[idx].adjustMode);
|
||||
populateFuncParamCB(fswtchParamT[idx], functions[idx].func, functions[idx].param, functions[idx].adjustMode);
|
||||
refreshCustomFunction(idx);
|
||||
lock = false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ class RawSourceFilterItemModel;
|
|||
class RawSwitchFilterItemModel;
|
||||
class TimerEdit;
|
||||
|
||||
constexpr char MIMETYPE_FSW[] = "application/x-companion-fsw";
|
||||
|
||||
class RepeatComboBox: public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -53,7 +55,7 @@ class CustomFunctionsPanel : public GenericPanel
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CustomFunctionsPanel(QWidget *parent, ModelData * mode, GeneralSettings & generalSettings, Firmware * firmware);
|
||||
CustomFunctionsPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware);
|
||||
~CustomFunctionsPanel();
|
||||
|
||||
virtual void update();
|
||||
|
@ -77,11 +79,18 @@ class CustomFunctionsPanel : public GenericPanel
|
|||
void fswCopy();
|
||||
void fswPaste();
|
||||
void fswCut();
|
||||
void fswMoveUp();
|
||||
void fswMoveDown();
|
||||
void fswInsert();
|
||||
void fswClear();
|
||||
void fswClearAll();
|
||||
|
||||
private:
|
||||
void populateFuncCB(QComboBox *b, unsigned int value);
|
||||
void populateGVmodeCB(QComboBox *b, unsigned int value);
|
||||
void populateFuncParamCB(QComboBox *b, uint function, unsigned int value, unsigned int adjustmode=0);
|
||||
void swapFuncData(int idx1, int idx2);
|
||||
void resetCBsAndRefresh(int idx);
|
||||
RawSwitchFilterItemModel * rawSwitchItemModel;
|
||||
RawSourceFilterItemModel * rawSrcAllItemModel;
|
||||
RawSourceFilterItemModel * rawSrcInputsItemModel;
|
||||
|
@ -105,6 +114,7 @@ class CustomFunctionsPanel : public GenericPanel
|
|||
QMediaPlayer * mediaPlayer;
|
||||
|
||||
int selectedFunction;
|
||||
int fswCapability;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -527,8 +527,8 @@ void LogicalSwitchesPanel::cswPaste()
|
|||
QByteArray cswData = mimeData->data("application/x-companion-csw");
|
||||
LogicalSwitchData *csw = &model->logicalSw[selectedSwitch];
|
||||
memcpy(csw, cswData.constData(), sizeof(LogicalSwitchData));
|
||||
update();
|
||||
emit modified();
|
||||
updateLine(selectedSwitch);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -195,13 +195,24 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
|
|||
|
||||
ui->label_module->setText(ModuleData::indexToString(moduleIdx, firmware));
|
||||
if (moduleIdx < 0) {
|
||||
if (IS_HORUS(firmware->getBoard())) {
|
||||
if (!IS_TARANIS(firmware->getBoard())) {
|
||||
ui->trainerMode->setItemData(TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE, 0, Qt::UserRole - 1);
|
||||
ui->trainerMode->setItemData(TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE, 0, Qt::UserRole - 1);
|
||||
}
|
||||
if (generalSettings.auxSerialMode != UART_MODE_SBUS_TRAINER) {
|
||||
ui->trainerMode->setItemData(TRAINER_MODE_MASTER_BATTERY_COMPARTMENT, 0, Qt::UserRole - 1);
|
||||
}
|
||||
else if (generalSettings.auxSerialMode != UART_MODE_SBUS_TRAINER) {
|
||||
ui->trainerMode->setItemData(TRAINER_MODE_MASTER_BATTERY_COMPARTMENT, 0, Qt::UserRole - 1);
|
||||
}
|
||||
|
||||
if (generalSettings.bluetoothMode != 2) {
|
||||
ui->trainerMode->setItemData(TRAINER_MODE_MASTER_BLUETOOTH, 0, Qt::UserRole - 1);
|
||||
ui->trainerMode->setItemData(TRAINER_MODE_SLAVE_BLUETOOTH, 0, Qt::UserRole - 1);
|
||||
}
|
||||
|
||||
if (!IS_JUMPER_T16(firmware->getBoard())) {
|
||||
ui->trainerMode->setItemData(TRAINER_MODE_MULTI, 0, Qt::UserRole - 1);
|
||||
}
|
||||
|
||||
ui->trainerMode->setCurrentIndex(model.trainerMode);
|
||||
if (!IS_HORUS_OR_TARANIS(firmware->getBoard())) {
|
||||
ui->label_trainerMode->hide();
|
||||
|
@ -227,6 +238,9 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
|
|||
continue;
|
||||
ui->multiProtocol->addItem(Multiprotocols::protocolToString(i), i);
|
||||
}
|
||||
for (int i=MODULE_SUBTYPE_MULTI_LAST + 1; i <= 124; i++) {
|
||||
ui->multiProtocol->addItem(QString::number(i + 3), i);
|
||||
}
|
||||
|
||||
ui->btnGrpValueType->setId(ui->optPercent, FAILSAFE_DISPLAY_PERCENT);
|
||||
ui->btnGrpValueType->setId(ui->optUs, FAILSAFE_DISPLAY_USEC);
|
||||
|
@ -269,7 +283,9 @@ bool ModulePanel::moduleHasFailsafes()
|
|||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_R9M ||
|
||||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_R9M_LITE ||
|
||||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_R9M_LITE_PRO ||
|
||||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_XJT_LITE_X16);
|
||||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_XJT_LITE_X16 ||
|
||||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_MULTIMODULE
|
||||
);
|
||||
}
|
||||
|
||||
void ModulePanel::setupFailsafes()
|
||||
|
@ -469,14 +485,14 @@ void ModulePanel::update()
|
|||
break;
|
||||
case PULSES_MULTIMODULE:
|
||||
mask |= MASK_CHANNELS_RANGE | MASK_RX_NUMBER | MASK_MULTIMODULE | MASK_SUBTYPES;
|
||||
max_rx_num = 15;
|
||||
max_rx_num = 63;
|
||||
if (module.multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2)
|
||||
mask |= MASK_CHANNELS_COUNT;
|
||||
else
|
||||
module.channelsCount = 16;
|
||||
if (pdef.optionsstr != nullptr)
|
||||
mask |= MASK_MULTIOPTION;
|
||||
if (pdef.hasFailsafe)
|
||||
if (pdef.hasFailsafe || (module.multi.rfProtocol == MODULE_SUBTYPE_MULTI_FRSKY && (module.subType == 0 || module.subType == 2 || module.subType > 3 )))
|
||||
mask |= MASK_FAILSAFES;
|
||||
break;
|
||||
case PULSES_OFF:
|
||||
|
@ -565,7 +581,7 @@ void ModulePanel::update()
|
|||
unsigned i = 0;
|
||||
switch(protocol){
|
||||
case PULSES_MULTIMODULE:
|
||||
numEntries = (module.multi.customProto ? 8 : pdef.numSubTypes());
|
||||
numEntries = (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST ? 8 : pdef.numSubTypes());
|
||||
break;
|
||||
case PULSES_PXX_R9M:
|
||||
if (firmware->getCapability(HasModuleR9MFlex))
|
||||
|
@ -587,11 +603,19 @@ void ModulePanel::update()
|
|||
ui->multiProtocol->setVisible(mask & MASK_MULTIMODULE);
|
||||
ui->label_option->setVisible(mask & MASK_MULTIOPTION);
|
||||
ui->optionValue->setVisible(mask & MASK_MULTIOPTION);
|
||||
ui->autoBind->setVisible(mask & MASK_MULTIMODULE);
|
||||
ui->disableTelem->setVisible(mask & MASK_MULTIMODULE);
|
||||
ui->disableChMap->setVisible(mask & MASK_MULTIMODULE);
|
||||
ui->lowPower->setVisible(mask & MASK_MULTIMODULE);
|
||||
ui->autoBind->setVisible(mask & MASK_MULTIMODULE);
|
||||
if (module.multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2)
|
||||
ui->autoBind->setText(tr("Autodetect Format"));
|
||||
else
|
||||
ui->autoBind->setText(tr("Bind on channel"));
|
||||
|
||||
if (mask & MASK_MULTIMODULE) {
|
||||
ui->multiProtocol->setCurrentIndex(ui->multiProtocol->findData(module.multi.rfProtocol));
|
||||
ui->disableTelem->setChecked(module.multi.disableTelemetry);
|
||||
ui->disableChMap->setChecked(module.multi.disableMapping);
|
||||
ui->autoBind->setChecked(module.multi.autoBindMode);
|
||||
ui->lowPower->setChecked(module.multi.lowPowerMode);
|
||||
}
|
||||
|
@ -763,7 +787,7 @@ void ModulePanel::onMultiProtocolChanged(int index)
|
|||
lock=true;
|
||||
module.multi.rfProtocol = (unsigned int)rfProtocol;
|
||||
unsigned int maxSubTypes = multiProtocols.getProtocol(index).numSubTypes();
|
||||
if (module.multi.customProto)
|
||||
if (rfProtocol > MODULE_SUBTYPE_MULTI_LAST)
|
||||
maxSubTypes=8;
|
||||
module.subType = std::min(module.subType, maxSubTypes -1);
|
||||
module.channelsCount = getMaxChannelCount();
|
||||
|
@ -793,10 +817,21 @@ void ModulePanel::onSubTypeChanged()
|
|||
}
|
||||
}
|
||||
|
||||
void ModulePanel::on_disableTelem_stateChanged(int state)
|
||||
{
|
||||
module.multi.disableTelemetry = (state == Qt::Checked);
|
||||
}
|
||||
|
||||
void ModulePanel::on_disableChMap_stateChanged(int state)
|
||||
{
|
||||
module.multi.disableMapping = (state == Qt::Checked);
|
||||
}
|
||||
|
||||
void ModulePanel::on_autoBind_stateChanged(int state)
|
||||
{
|
||||
module.multi.autoBindMode = (state == Qt::Checked);
|
||||
}
|
||||
|
||||
void ModulePanel::on_lowPower_stateChanged(int state)
|
||||
{
|
||||
module.multi.lowPowerMode = (state == Qt::Checked);
|
||||
|
|
|
@ -86,6 +86,8 @@ class ModulePanel : public ModelPanel
|
|||
void onMultiProtocolChanged(int index);
|
||||
void onSubTypeChanged();
|
||||
void on_autoBind_stateChanged(int state);
|
||||
void on_disableChMap_stateChanged(int state);
|
||||
void on_disableTelem_stateChanged(int state);
|
||||
void on_lowPower_stateChanged(int state);
|
||||
void on_r9mPower_currentIndexChanged(int index);
|
||||
void setChannelFailsafeValue(const int channel, const int value, quint8 updtSb = 0);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1075</width>
|
||||
<height>434</height>
|
||||
<height>438</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -417,7 +417,6 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="autoBind">
|
||||
<property name="text">
|
||||
<string>Bind on startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -935,9 +934,24 @@
|
|||
<string>Master/SBUS in battery compartment</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Master/Bluetooth</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Slave/Bluetooth</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Master/Multi</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<item row="11" column="0" colspan="2">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
|
@ -950,6 +964,20 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="disableTelem">
|
||||
<property name="text">
|
||||
<string>Disable Telemetry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="disableChMap">
|
||||
<property name="text">
|
||||
<string>Disable Ch. Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
|
|
|
@ -2417,7 +2417,7 @@ If you have a settings backup file, you may import that instead.</source>
|
|||
<message>
|
||||
<location filename="../modeledit/curves.cpp" line="156"/>
|
||||
<source>Popup menu available</source>
|
||||
<translation>Popoup-Menü verfügbar</translation>
|
||||
<translation>Popup-Menü verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modeledit/curves.cpp" line="209"/>
|
||||
|
@ -2482,7 +2482,7 @@ If you have a settings backup file, you may import that instead.</source>
|
|||
<message>
|
||||
<location filename="../modeledit/curves.cpp" line="458"/>
|
||||
<source>Not enough free points in EEPROM to store the curve.</source>
|
||||
<translation>Es sind nicht genügend freie Stützstellen im EEPROM vorhanden, um diese Kurve zu abzuspeichern.</translation>
|
||||
<translation>Es sind nicht genügend freie Stützpunkte im EEPROM vorhanden, um diese Kurve zu abzuspeichern.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1
radio/sdcard/.gitignore
vendored
Normal file
1
radio/sdcard/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*/opentx.sdcard.version
|
132
radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua
Normal file
132
radio/sdcard/horus/SCRIPTS/TOOLS/Graupner HoTT.lua
Normal file
|
@ -0,0 +1,132 @@
|
|||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for HoTT description
|
||||
-- To start operation:
|
||||
-- Write "HoTT" at address 0..3
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write 0xDF at address 5
|
||||
-- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters
|
||||
-- by 8 lines
|
||||
-- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page,
|
||||
-- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev
|
||||
-- Write at address 4 the value 0xFF will request the buffer to be cleared
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local function HoTT_Release()
|
||||
multiBuffer( 0, 0 )
|
||||
end
|
||||
|
||||
local function HoTT_Draw_LCD()
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local result
|
||||
local offset=0
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR)
|
||||
--Draw RX Menu
|
||||
if multiBuffer( 4 ) == 0xFF then
|
||||
lcd.drawText(10,50,"No HoTT telemetry...", BLINK)
|
||||
else
|
||||
for line = 0, 7, 1 do
|
||||
for i = 0, 21-1, 1 do
|
||||
value=multiBuffer( line*21+6+i )
|
||||
if value > 0x80 then
|
||||
value = value - 0x80
|
||||
lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS)
|
||||
else
|
||||
lcd.drawText(10+i*16,32+16*line,string.char(value))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
--Draw RX Menu on LCD_W=128
|
||||
if multiBuffer( 4 ) == 0xFF then
|
||||
lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE)
|
||||
else
|
||||
for line = 0, 7, 1 do
|
||||
for i = 0, 21-1, 1 do
|
||||
value=multiBuffer( line*21+6+i )
|
||||
if value > 0x80 then
|
||||
value = value - 0x80
|
||||
lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS)
|
||||
else
|
||||
lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function HoTT_Init()
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('H') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('H') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('T') )
|
||||
multiBuffer( 3, string.byte('T') )
|
||||
--Request init of the RX buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Request RX to send the config menu
|
||||
multiBuffer( 5, 0xDF )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function HoTT_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
HoTT_Release()
|
||||
return 2
|
||||
else
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event);
|
||||
multiBuffer( 5, 0xD7 )
|
||||
elseif event == EVT_VIRTUAL_NEXT_PAGE then
|
||||
multiBuffer( 5, 0xDE )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
multiBuffer( 5, 0xD9 )
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
multiBuffer( 5, 0xDD )
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
multiBuffer( 5, 0xDB )
|
||||
else
|
||||
multiBuffer( 5, 0xDF )
|
||||
end
|
||||
HoTT_Draw_LCD()
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=HoTT_Init, run=HoTT_Run }
|
132
radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua
Normal file
132
radio/sdcard/taranis-x7/SCRIPTS/TOOLS/Graupner HoTT.lua
Normal file
|
@ -0,0 +1,132 @@
|
|||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for HoTT description
|
||||
-- To start operation:
|
||||
-- Write "HoTT" at address 0..3
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write 0xDF at address 5
|
||||
-- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters
|
||||
-- by 8 lines
|
||||
-- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page,
|
||||
-- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev
|
||||
-- Write at address 4 the value 0xFF will request the buffer to be cleared
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local function HoTT_Release()
|
||||
multiBuffer( 0, 0 )
|
||||
end
|
||||
|
||||
local function HoTT_Draw_LCD()
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local result
|
||||
local offset=0
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR)
|
||||
--Draw RX Menu
|
||||
if multiBuffer( 4 ) == 0xFF then
|
||||
lcd.drawText(10,50,"No HoTT telemetry...", BLINK)
|
||||
else
|
||||
for line = 0, 7, 1 do
|
||||
for i = 0, 21-1, 1 do
|
||||
value=multiBuffer( line*21+6+i )
|
||||
if value > 0x80 then
|
||||
value = value - 0x80
|
||||
lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS)
|
||||
else
|
||||
lcd.drawText(10+i*16,32+16*line,string.char(value))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
--Draw RX Menu on LCD_W=128
|
||||
if multiBuffer( 4 ) == 0xFF then
|
||||
lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE)
|
||||
else
|
||||
for line = 0, 7, 1 do
|
||||
for i = 0, 21-1, 1 do
|
||||
value=multiBuffer( line*21+6+i )
|
||||
if value > 0x80 then
|
||||
value = value - 0x80
|
||||
lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS)
|
||||
else
|
||||
lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function HoTT_Init()
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('H') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('H') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('T') )
|
||||
multiBuffer( 3, string.byte('T') )
|
||||
--Request init of the RX buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Request RX to send the config menu
|
||||
multiBuffer( 5, 0xDF )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function HoTT_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
HoTT_Release()
|
||||
return 2
|
||||
else
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event);
|
||||
multiBuffer( 5, 0xD7 )
|
||||
elseif event == EVT_VIRTUAL_NEXT_PAGE then
|
||||
multiBuffer( 5, 0xDE )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
multiBuffer( 5, 0xD9 )
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
multiBuffer( 5, 0xDD )
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
multiBuffer( 5, 0xDB )
|
||||
else
|
||||
multiBuffer( 5, 0xDF )
|
||||
end
|
||||
HoTT_Draw_LCD()
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=HoTT_Init, run=HoTT_Run }
|
132
radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua
Normal file
132
radio/sdcard/taranis-x9/SCRIPTS/TOOLS/Graupner HoTT.lua
Normal file
|
@ -0,0 +1,132 @@
|
|||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html #
|
||||
---- # #
|
||||
---- # This program is free software; you can redistribute it and/or modify #
|
||||
---- # it under the terms of the GNU General Public License version 2 as #
|
||||
---- # published by the Free Software Foundation. #
|
||||
---- # #
|
||||
---- # This program is distributed in the hope that it will be useful #
|
||||
---- # but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
---- # GNU General Public License for more details. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
|
||||
--###############################################################################
|
||||
-- Multi buffer for HoTT description
|
||||
-- To start operation:
|
||||
-- Write "HoTT" at address 0..3
|
||||
-- Write 0xFF at address 4 will request the buffer to be cleared
|
||||
-- Write 0xDF at address 5
|
||||
-- Read buffer from address 6 access the RX text for 168 bytes, 21 caracters
|
||||
-- by 8 lines
|
||||
-- Write at address 5 sends an order to the RX: 0xDF=start, 0xD7=prev page,
|
||||
-- 0xDE=next page, 0xD9=enter, 0xDD=next or 0xDB=prev
|
||||
-- Write at address 4 the value 0xFF will request the buffer to be cleared
|
||||
-- !! Before exiting the script must write 0 at address 0 for normal operation !!
|
||||
--###############################################################################
|
||||
|
||||
local function HoTT_Release()
|
||||
multiBuffer( 0, 0 )
|
||||
end
|
||||
|
||||
local function HoTT_Draw_LCD()
|
||||
local i
|
||||
local value
|
||||
local line
|
||||
local result
|
||||
local offset=0
|
||||
|
||||
lcd.clear()
|
||||
|
||||
if LCD_W == 480 then
|
||||
--Draw title
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, "Graupner HoTT RX configuration", MENU_TITLE_COLOR)
|
||||
--Draw RX Menu
|
||||
if multiBuffer( 4 ) == 0xFF then
|
||||
lcd.drawText(10,50,"No HoTT telemetry...", BLINK)
|
||||
else
|
||||
for line = 0, 7, 1 do
|
||||
for i = 0, 21-1, 1 do
|
||||
value=multiBuffer( line*21+6+i )
|
||||
if value > 0x80 then
|
||||
value = value - 0x80
|
||||
lcd.drawText(10+i*16,32+16*line,string.char(value).." ",INVERS)
|
||||
else
|
||||
lcd.drawText(10+i*16,32+16*line,string.char(value))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
--Draw RX Menu on LCD_W=128
|
||||
if multiBuffer( 4 ) == 0xFF then
|
||||
lcd.drawText(2,17,"No HoTT telemetry...",SMLSIZE)
|
||||
else
|
||||
for line = 0, 7, 1 do
|
||||
for i = 0, 21-1, 1 do
|
||||
value=multiBuffer( line*21+6+i )
|
||||
if value > 0x80 then
|
||||
value = value - 0x80
|
||||
lcd.drawText(2+i*6,1+8*line,string.char(value).." ",SMLSIZE+INVERS)
|
||||
else
|
||||
lcd.drawText(2+i*6,1+8*line,string.char(value),SMLSIZE)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function HoTT_Init()
|
||||
--Set protocol to talk to
|
||||
multiBuffer( 0, string.byte('H') )
|
||||
--test if value has been written
|
||||
if multiBuffer( 0 ) ~= string.byte('H') then
|
||||
error("Not enough memory!")
|
||||
return 2
|
||||
end
|
||||
multiBuffer( 1, string.byte('o') )
|
||||
multiBuffer( 2, string.byte('T') )
|
||||
multiBuffer( 3, string.byte('T') )
|
||||
--Request init of the RX buffer
|
||||
multiBuffer( 4, 0xFF )
|
||||
--Request RX to send the config menu
|
||||
multiBuffer( 5, 0xDF )
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function HoTT_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
elseif event == EVT_VIRTUAL_EXIT then
|
||||
HoTT_Release()
|
||||
return 2
|
||||
else
|
||||
if event == EVT_VIRTUAL_PREV_PAGE then
|
||||
killEvents(event);
|
||||
multiBuffer( 5, 0xD7 )
|
||||
elseif event == EVT_VIRTUAL_NEXT_PAGE then
|
||||
multiBuffer( 5, 0xDE )
|
||||
elseif event == EVT_VIRTUAL_ENTER then
|
||||
multiBuffer( 5, 0xD9 )
|
||||
elseif event == EVT_VIRTUAL_NEXT then
|
||||
multiBuffer( 5, 0xDD )
|
||||
elseif event == EVT_VIRTUAL_PREV then
|
||||
multiBuffer( 5, 0xDB )
|
||||
else
|
||||
multiBuffer( 5, 0xDF )
|
||||
end
|
||||
HoTT_Draw_LCD()
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return { init=HoTT_Init, run=HoTT_Run }
|
|
@ -31,6 +31,7 @@ option(AUTOSWITCH "Automatic switch detection in menus" ON)
|
|||
option(SEMIHOSTING "Enable debugger semihosting" OFF)
|
||||
option(JITTER_MEASURE "Enable ADC jitter measurement" OFF)
|
||||
option(WATCHDOG "Enable hardware Watchdog" ON)
|
||||
option(ASTERISK "Enable asterisk icon (test only firmware)" OFF)
|
||||
if(SDL_FOUND)
|
||||
option(SIMU_AUDIO "Enable simulator audio." ON)
|
||||
endif()
|
||||
|
@ -72,7 +73,7 @@ set(GVARS_VARIANT 1)
|
|||
set(FRSKY_VARIANT 2)
|
||||
set(3POS_VARIANT 4)
|
||||
|
||||
set(RADIO_DEPENDENCIES radio_translations)
|
||||
set(RADIO_DEPENDENCIES firmware_translations)
|
||||
|
||||
set(FATFS_SRC
|
||||
${FATFS_DIR}/ff.c
|
||||
|
@ -168,9 +169,11 @@ include(storage/conversions/CMakeLists.txt)
|
|||
|
||||
add_subdirectory(lua)
|
||||
|
||||
if(RAMBACKUP)
|
||||
add_definitions(-DRAMBACKUP)
|
||||
set(SRC ${SRC} storage/rambackup.cpp storage/rlc.cpp)
|
||||
if(RTC_BACKUP_RAM)
|
||||
add_definitions(-DRTC_BACKUP_RAM)
|
||||
set(SRC ${SRC} storage/rlc.cpp)
|
||||
set(FIRMWARE_SRC ${FIRMWARE_SRC} storage/rtc_backup.cpp)
|
||||
set(GTEST_SRC ${GTEST_SRC} ${RADIO_SRC_DIRECTORY}/storage/rtc_backup.cpp)
|
||||
endif()
|
||||
|
||||
if(NOT LUA STREQUAL NO)
|
||||
|
@ -248,6 +251,10 @@ if(JITTER_MEASURE)
|
|||
add_definitions(-DJITTER_MEASURE)
|
||||
endif()
|
||||
|
||||
if(ASTERISK)
|
||||
add_definitions(-DASTERISK)
|
||||
endif()
|
||||
|
||||
if(WATCHDOG)
|
||||
add_definitions(-DWATCHDOG)
|
||||
endif()
|
||||
|
@ -523,7 +530,8 @@ if(NOT MSVC)
|
|||
|
||||
add_executable(firmware ${SRC} ${FIRMWARE_HEADERS})
|
||||
link_libraries(firmware -lstdc++)
|
||||
add_dependencies(firmware ${RADIO_DEPENDENCIES})
|
||||
add_dependencies(firmware ${RADIO_DEPENDENCIES} ${FIRMWARE_DEPENDENCIES})
|
||||
set_target_properties(firmware PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
add_custom_command(
|
||||
TARGET firmware POST_BUILD
|
||||
|
|
|
@ -180,7 +180,7 @@ void Bluetooth::processTrainerByte(uint8_t data)
|
|||
break;
|
||||
|
||||
case STATE_DATA_IN_FRAME:
|
||||
if (data == BYTESTUFF) {
|
||||
if (data == BYTE_STUFF) {
|
||||
dataState = STATE_DATA_XOR; // XOR next byte
|
||||
}
|
||||
else if (data == START_STOP) {
|
||||
|
@ -225,8 +225,8 @@ void Bluetooth::processTrainerByte(uint8_t data)
|
|||
void Bluetooth::pushByte(uint8_t byte)
|
||||
{
|
||||
crc ^= byte;
|
||||
if (byte == START_STOP || byte == BYTESTUFF) {
|
||||
buffer[bufferIndex++] = 0x7d;
|
||||
if (byte == START_STOP || byte == BYTE_STUFF) {
|
||||
buffer[bufferIndex++] = BYTE_STUFF;
|
||||
byte ^= STUFF_MASK;
|
||||
}
|
||||
buffer[bufferIndex++] = byte;
|
||||
|
@ -762,11 +762,11 @@ const char * Bluetooth::flashFirmware(const char * filename, ProgressHandler pro
|
|||
pausePulses();
|
||||
|
||||
bluetoothInit(BLUETOOTH_BOOTLOADER_BAUDRATE, true); // normal mode
|
||||
watchdogSuspend(1000);
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(1000);
|
||||
|
||||
bluetoothInit(BLUETOOTH_BOOTLOADER_BAUDRATE, false); // bootloader mode
|
||||
watchdogSuspend(1000);
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(1000);
|
||||
|
||||
const char * result = doFlashFirmware(filename, progressHandler);
|
||||
|
@ -785,7 +785,7 @@ const char * Bluetooth::flashFirmware(const char * filename, ProgressHandler pro
|
|||
progressHandler(getBasename(filename), STR_MODULE_RESET, 0, 0);
|
||||
|
||||
/* wait 1s off */
|
||||
watchdogSuspend(1000);
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(1000);
|
||||
|
||||
state = BLUETOOTH_STATE_OFF;
|
||||
|
|
|
@ -194,10 +194,8 @@ enum TrainerMode {
|
|||
TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE,
|
||||
TRAINER_MODE_MASTER_BATTERY_COMPARTMENT,
|
||||
#endif
|
||||
#if defined(BLUETOOTH)
|
||||
TRAINER_MODE_MASTER_BLUETOOTH,
|
||||
TRAINER_MODE_SLAVE_BLUETOOTH,
|
||||
#endif
|
||||
TRAINER_MODE_MULTI,
|
||||
};
|
||||
#elif defined(PCBSKY9X)
|
||||
|
@ -208,12 +206,10 @@ enum TrainerMode {
|
|||
};
|
||||
#endif
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
#if defined(RADIO_T16)
|
||||
#define TRAINER_MODE_MAX() TRAINER_MODE_MULTI
|
||||
#elif defined(BLUETOOTH)
|
||||
#define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE_BLUETOOTH
|
||||
#elif defined(RADIO_T16)
|
||||
#define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE
|
||||
#elif defined(PCBX7) || defined(PCBXLITE)
|
||||
#define TRAINER_MODE_MAX() TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
|
||||
#else
|
||||
|
@ -269,6 +265,7 @@ enum TelemetryProtocol
|
|||
PROTOCOL_TELEMETRY_SPEKTRUM,
|
||||
PROTOCOL_TELEMETRY_FLYSKY_IBUS,
|
||||
PROTOCOL_TELEMETRY_HITEC,
|
||||
PROTOCOL_TELEMETRY_HOTT,
|
||||
PROTOCOL_TELEMETRY_MULTIMODULE,
|
||||
PROTOCOL_TELEMETRY_LAST=PROTOCOL_TELEMETRY_MULTIMODULE,
|
||||
PROTOCOL_TELEMETRY_LUA
|
||||
|
|
|
@ -421,6 +421,7 @@ PACK(struct TrainerModuleData {
|
|||
|
||||
// Only used in case switch and if statements as "virtual" protocol
|
||||
#define MM_RF_CUSTOM_SELECTED 0xff
|
||||
#define MULTI_MAX_PROTOCOLS 127 // rfProtocol:4 + rfProtocolExtra:3
|
||||
PACK(struct ModuleData {
|
||||
uint8_t type:4 ENUM(ModuleType);
|
||||
// TODO some refactoring is needed, rfProtocol is only used by DSM2 and MULTI, it could be merged with subType
|
||||
|
@ -440,8 +441,9 @@ PACK(struct ModuleData {
|
|||
int8_t frameLength;
|
||||
} ppm);
|
||||
NOBACKUP(struct {
|
||||
uint8_t rfProtocolExtra:2;
|
||||
uint8_t spare1:3 SKIP;
|
||||
uint8_t rfProtocolExtra:3;
|
||||
uint8_t disableTelemetry:1;
|
||||
uint8_t disableMapping:1;
|
||||
uint8_t customProto:1;
|
||||
uint8_t autoBindMode:1;
|
||||
uint8_t lowPowerMode:1;
|
||||
|
@ -475,15 +477,13 @@ PACK(struct ModuleData {
|
|||
} NAME(mod) FUNC(select_mod_type);
|
||||
|
||||
// Helper functions to set both of the rfProto protocol at the same time
|
||||
NOBACKUP(inline uint8_t getMultiProtocol(bool returnCustom) {
|
||||
if (returnCustom && multi.customProto)
|
||||
return MM_RF_CUSTOM_SELECTED;
|
||||
NOBACKUP(inline uint8_t getMultiProtocol() {
|
||||
return ((uint8_t) (rfProtocol & 0x0f)) + (multi.rfProtocolExtra << 4);
|
||||
})
|
||||
|
||||
NOBACKUP(inline void setMultiProtocol(uint8_t proto) {
|
||||
rfProtocol = (uint8_t) (proto & 0x0f);
|
||||
multi.rfProtocolExtra = (proto & 0x30) >> 4;
|
||||
multi.rfProtocolExtra = (proto & 0x70) >> 4;
|
||||
})
|
||||
});
|
||||
|
||||
|
|
|
@ -169,14 +169,14 @@ void evalFunctions(const CustomFunctionData * functions, CustomFunctionsContext
|
|||
if (param == 0)
|
||||
newActiveFunctions |= 0x0F;
|
||||
else if (param <= NUM_STICKS)
|
||||
newActiveFunctions |= (1 << (param-1));
|
||||
newActiveFunctions |= (1 << (param - 1));
|
||||
else if (param == NUM_STICKS + 1)
|
||||
newActiveFunctions |= (1 << FUNCTION_TRAINER_CHANNELS);
|
||||
newActiveFunctions |= (1u << FUNCTION_TRAINER_CHANNELS);
|
||||
break;
|
||||
}
|
||||
|
||||
case FUNC_INSTANT_TRIM:
|
||||
newActiveFunctions |= (1 << FUNCTION_INSTANT_TRIM);
|
||||
newActiveFunctions |= (1u << FUNCTION_INSTANT_TRIM);
|
||||
if (!isFunctionActive(FUNCTION_INSTANT_TRIM)) {
|
||||
#if defined(COLORLCD)
|
||||
#warning IS_INSTANT_TRIM_ALLOWED() is always false
|
||||
|
|
|
@ -864,6 +864,44 @@ void drawDate(coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags att)
|
|||
}
|
||||
}
|
||||
|
||||
void drawTimerWithMode(coord_t x, coord_t y, uint8_t index, LcdFlags att)
|
||||
{
|
||||
const TimerData &timer = g_model.timers[index];
|
||||
|
||||
if (timer.mode) {
|
||||
const TimerState &timerState = timersStates[index];
|
||||
const uint8_t negative = (timerState.val < 0 ? BLINK | INVERS : 0);
|
||||
if (timerState.val < 60 * 60) { // display MM:SS
|
||||
div_t qr = div((int) abs(timerState.val), 60);
|
||||
lcdDrawNumber(x - 5, y, qr.rem, att | LEADING0 | negative, 2);
|
||||
lcdDrawText(lcdLastLeftPos, y, ":", att | BLINK | negative);
|
||||
lcdDrawNumber(lcdLastLeftPos, y, qr.quot, att | negative);
|
||||
if (negative)
|
||||
lcdDrawText(lcdLastLeftPos, y, "-", att | negative);
|
||||
}
|
||||
else if (timerState.val < (99 * 60 * 60) + (59 * 60)) { // display HHhMM
|
||||
div_t qr = div((int) (abs(timerState.val) / 60), 60);
|
||||
lcdDrawNumber(x - 5, y, qr.rem, att | LEADING0, 2);
|
||||
lcdDrawText(lcdLastLeftPos, y, "h", att);
|
||||
lcdDrawNumber(lcdLastLeftPos, y, qr.quot, att);
|
||||
if (negative)
|
||||
lcdDrawText(lcdLastLeftPos, y, "-", att);
|
||||
}
|
||||
else { //display HHHH for crazy large persistent timers
|
||||
lcdDrawText(x - 5, y, "h", att);
|
||||
lcdDrawNumber(lcdLastLeftPos, y, timerState.val / 3600, att);
|
||||
}
|
||||
uint8_t xLabel = (negative ? x - 56 : x - 49);
|
||||
uint8_t len = zlen(timer.name, LEN_TIMER_NAME);
|
||||
if (len > 0) {
|
||||
lcdDrawSizedText(xLabel, y + FH, timer.name, len, RIGHT | ZCHAR);
|
||||
}
|
||||
else {
|
||||
drawTimerMode(xLabel, y + FH, timer.mode, RIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawTelemScreenDate(coord_t x, coord_t y, source_t sensor, LcdFlags att)
|
||||
{
|
||||
y+=3;
|
||||
|
|
|
@ -107,6 +107,7 @@ void lcdDrawSizedText(coord_t x, coord_t y, const char * s, unsigned char len, L
|
|||
void lcdDrawText(coord_t x, coord_t y, const char * s);
|
||||
void lcdDrawSizedText(coord_t x, coord_t y, const char * s, unsigned char len);
|
||||
void lcdDrawTextAlignedLeft(coord_t y, const char * s);
|
||||
void drawTimerWithMode(coord_t x, coord_t y, uint8_t index, LcdFlags att);
|
||||
|
||||
#define lcdDrawTextAlignedCenter(y, s) lcdDrawText((LCD_W-sizeof(s)*FW+FW+1)/2, y, s)
|
||||
|
||||
|
@ -178,6 +179,7 @@ uint8_t * lcdLoadBitmap(uint8_t * dest, const char * filename, uint8_t width, ui
|
|||
#define BLINK_ON_PHASE (0)
|
||||
#else
|
||||
#define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6))
|
||||
#define SLOW_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<7))
|
||||
#endif
|
||||
|
||||
inline pixel_t getPixel(uint8_t x, uint8_t y)
|
||||
|
|
|
@ -378,7 +378,7 @@ void drawOffsetBar(uint8_t x, uint8_t y, MixData * md)
|
|||
|
||||
void menuModelMixOne(event_t event)
|
||||
{
|
||||
title(STR_MIXER);
|
||||
title(STR_MIXES);
|
||||
MixData * md2 = mixAddress(s_currIdx) ;
|
||||
putsChn(lcdLastRightPos+1*FW, 0, md2->destCh+1,0);
|
||||
|
||||
|
@ -731,10 +731,10 @@ void menuModelExpoMix(uint8_t expo, event_t event)
|
|||
break;
|
||||
}
|
||||
|
||||
lcdDrawNumber(FW*max(sizeof(TR_MENUINPUTS), sizeof(TR_MIXER))+FW+FW/2, 0, getExpoMixCount(expo));
|
||||
lcdDrawText(FW*max(sizeof(TR_MENUINPUTS), sizeof(TR_MIXER))+FW+FW/2, 0, expo ? STR_MAX(MAX_EXPOS) : STR_MAX(MAX_MIXERS));
|
||||
lcdDrawNumber(FW*max(sizeof(TR_MENUINPUTS), sizeof(TR_MIXES))+FW+FW/2, 0, getExpoMixCount(expo));
|
||||
lcdDrawText(FW*max(sizeof(TR_MENUINPUTS), sizeof(TR_MIXES))+FW+FW/2, 0, expo ? STR_MAX(MAX_EXPOS) : STR_MAX(MAX_MIXERS));
|
||||
|
||||
SIMPLE_MENU(expo ? STR_MENUINPUTS : STR_MIXER, menuTabModel, expo ? MENU_MODEL_INPUTS : MENU_MODEL_MIXES, s_maxLines);
|
||||
SIMPLE_MENU(expo ? STR_MENUINPUTS : STR_MIXES, menuTabModel, expo ? MENU_MODEL_INPUTS : MENU_MODEL_MIXES, s_maxLines);
|
||||
|
||||
sub = menuVerticalPosition;
|
||||
s_currCh = 0;
|
||||
|
|
|
@ -86,9 +86,9 @@ void drawOffsetBar(uint8_t x, uint8_t y, MixData * md)
|
|||
void menuModelMixOne(event_t event)
|
||||
{
|
||||
MixData * md2 = mixAddress(s_currIdx) ;
|
||||
putsChn(PSIZE(TR_MIXER)*FW+FW, 0, md2->destCh+1,0);
|
||||
putsChn(PSIZE(TR_MIXES)*FW+FW, 0, md2->destCh+1,0);
|
||||
|
||||
SUBMENU(STR_MIXER, MIX_FIELD_COUNT, {0, 0, 0, 0, 0, 1, CASE_FLIGHT_MODES((MAX_FLIGHT_MODES-1) | NAVIGATION_LINE_BY_LINE) 0, 0 /*, ...*/});
|
||||
SUBMENU(STR_MIXES, MIX_FIELD_COUNT, {0, 0, 0, 0, 0, 1, CASE_FLIGHT_MODES((MAX_FLIGHT_MODES-1) | NAVIGATION_LINE_BY_LINE) 0, 0 /*, ...*/});
|
||||
|
||||
int8_t sub = menuVerticalPosition;
|
||||
int8_t editMode = s_editMode;
|
||||
|
|
|
@ -87,12 +87,24 @@ enum MenuModelSetupItems {
|
|||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE,
|
||||
#if defined(MULTIMODULE)
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS,
|
||||
#endif
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS,
|
||||
#if defined(MULTIMODULE)
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_TELEM,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_MAPPING,
|
||||
#endif
|
||||
#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_ANTENNA,
|
||||
#endif
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_POWER,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE,
|
||||
ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS,
|
||||
|
@ -106,20 +118,22 @@ enum MenuModelSetupItems {
|
|||
#if defined(MULTIMODULE)
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE,
|
||||
#endif
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER,
|
||||
#if defined(MULTIMODULE)
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS,
|
||||
#endif
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM,
|
||||
#if defined(PCBSKY9X) && defined(REVX)
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_OUTPUT_TYPE,
|
||||
#endif
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS,
|
||||
#if defined(MULTIMODULE)
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING,
|
||||
#endif
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_REGISTER_RANGE,
|
||||
|
@ -191,12 +205,12 @@ enum MenuModelSetupItems {
|
|||
#define OUTPUT_TYPE_ROW
|
||||
#endif
|
||||
|
||||
inline uint8_t EXTERNAL_MODULE_TYPE_ROW()
|
||||
inline uint8_t MODULE_TYPE_ROWS(int moduleIdx)
|
||||
{
|
||||
if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE))
|
||||
if (isModuleXJT(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx))
|
||||
return 1;
|
||||
#if defined(MULTIMODULE)
|
||||
else if (isModuleMultimodule(EXTERNAL_MODULE)) {
|
||||
else if (isModuleMultimodule(moduleIdx)) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
@ -204,6 +218,17 @@ inline uint8_t EXTERNAL_MODULE_TYPE_ROW()
|
|||
return 0;
|
||||
}
|
||||
|
||||
inline uint8_t MODULE_SUBTYPE_ROWS(int moduleIdx)
|
||||
{
|
||||
#if defined(MULTIMODULE)
|
||||
if (isModuleMultimodule(moduleIdx)) {
|
||||
return MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? 1 : HIDDEN_ROW;
|
||||
}
|
||||
#endif
|
||||
|
||||
return HIDDEN_ROW;
|
||||
}
|
||||
|
||||
#define POT_WARN_ROWS ((g_model.potsWarnMode) ? (uint8_t)(NUM_POTS+NUM_SLIDERS) : (uint8_t)0)
|
||||
#define TIMER_ROWS 1, 0, 1, 0, 0, 0
|
||||
|
||||
|
@ -280,17 +305,22 @@ void onBluetoothConnectMenu(const char * result)
|
|||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
#define INTERNAL_MODULE_ROWS \
|
||||
LABEL(InternalModule), \
|
||||
INTERNAL_MODULE_TYPE_ROWS, \
|
||||
MODULE_CHANNELS_ROWS(INTERNAL_MODULE), \
|
||||
IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(isModuleRxNumAvailable(INTERNAL_MODULE) ? (uint8_t)2 : (uint8_t)1)), \
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* RxNum */ \
|
||||
EXTERNAL_ANTENNA_ROW \
|
||||
IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), /* Failsafe */ \
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), /* Range check and Register buttons */ \
|
||||
IF_PXX2_MODULE(INTERNAL_MODULE, 0), /* Module options */ \
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 1 */ \
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 2 */ \
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 3 */
|
||||
MODULE_TYPE_ROWS(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE*/ \
|
||||
MULTIMODULE_SUBTYPE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE*/ \
|
||||
MULTIMODULE_STATUS_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS, ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS */ \
|
||||
MODULE_CHANNELS_ROWS(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS*/ \
|
||||
IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(IF_INTERNAL_MODULE_ON(isModuleRxNumAvailable(INTERNAL_MODULE) ? (uint8_t)2 : (uint8_t)1))), /* *ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE */\
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM*/ \
|
||||
MODULE_OPTION_ROW(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS */ \
|
||||
MULTIMODULE_MODULE_ROWS(INTERNAL_MODULE) /* ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND */ \
|
||||
EXTERNAL_ANTENNA_ROW /* ITEM_MODEL_SETUP_INTERNAL_MODULE_ANTENNA */ \
|
||||
MODULE_POWER_ROW(INTERNAL_MODULE), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_POWER */ \
|
||||
IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE */ \
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE */ \
|
||||
IF_PXX2_MODULE(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS*/ \
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1 */ \
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2 */ \
|
||||
IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_3 */
|
||||
#else
|
||||
#define INTERNAL_MODULE_ROWS
|
||||
#endif
|
||||
|
@ -330,13 +360,13 @@ void menuModelSetup(event_t event)
|
|||
INTERNAL_MODULE_ROWS
|
||||
|
||||
LABEL(ExternalModule),
|
||||
EXTERNAL_MODULE_TYPE_ROW(),
|
||||
MODULE_TYPE_ROWS(EXTERNAL_MODULE),
|
||||
MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE)
|
||||
MODULE_POWER_ROW(EXTERNAL_MODULE),
|
||||
MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE)
|
||||
MODULE_CHANNELS_ROWS(EXTERNAL_MODULE),
|
||||
IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), // line reused for PPM: PPM settings
|
||||
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum
|
||||
MODULE_POWER_ROW(EXTERNAL_MODULE),
|
||||
IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)),
|
||||
MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE)
|
||||
FAILSAFE_ROWS(EXTERNAL_MODULE),
|
||||
|
@ -371,19 +401,18 @@ void menuModelSetup(event_t event)
|
|||
NUM_STICKS+NUM_POTS+NUM_SLIDERS-1, // Center beeps
|
||||
0, // Global functions
|
||||
|
||||
LABEL(ExternalModule),
|
||||
EXTERNAL_MODULE_TYPE_ROW(),
|
||||
LABEL(ExternalModule),
|
||||
MODULE_TYPE_ROWS(EXTERNAL_MODULE),
|
||||
MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE)
|
||||
MODULE_POWER_ROW(EXTERNAL_MODULE),
|
||||
MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE)
|
||||
MODULE_CHANNELS_ROWS(EXTERNAL_MODULE),
|
||||
IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), // line reused for PPM: PPM settings
|
||||
OUTPUT_TYPE_ROW
|
||||
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum
|
||||
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum
|
||||
MODULE_POWER_ROW(EXTERNAL_MODULE),
|
||||
IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)),
|
||||
MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE)
|
||||
FAILSAFE_ROWS(EXTERNAL_MODULE),
|
||||
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons
|
||||
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons
|
||||
IF_PXX2_MODULE(EXTERNAL_MODULE, 0), // Module options
|
||||
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 1
|
||||
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // Receiver 2
|
||||
|
@ -429,6 +458,7 @@ void menuModelSetup(event_t event)
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS);
|
||||
LcdFlags attr = (sub == k ? blink : 0);
|
||||
|
||||
|
@ -800,6 +830,7 @@ void menuModelSetup(event_t event)
|
|||
lcdDrawTextAlignedLeft(y, STR_INTERNALRF);
|
||||
break;
|
||||
|
||||
#if !defined(INTERNAL_MODULE_MULTI)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE:
|
||||
{
|
||||
lcdDrawTextAlignedLeft(y, INDENT TR_MODE);
|
||||
|
@ -849,6 +880,7 @@ void menuModelSetup(event_t event)
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PCBSKY9X)
|
||||
case ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL:
|
||||
|
@ -860,101 +892,103 @@ void menuModelSetup(event_t event)
|
|||
lcdDrawTextAlignedLeft(y, STR_EXTERNALRF);
|
||||
break;
|
||||
|
||||
#if defined(INTERNAL_MODULE_MULTI)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE:
|
||||
lcdDrawTextAlignedLeft(y, INDENT TR_MODE);
|
||||
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_EXTERNAL_MODULE_PROTOCOLS, reusableBuffer.moduleSetup.newType, menuHorizontalPosition==0 ? attr : 0);
|
||||
if (isModuleXJT(EXTERNAL_MODULE))
|
||||
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_XJT_ACCST_RF_PROTOCOLS, 1+g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==1 ? attr : 0);
|
||||
else if (isModuleDSM2(EXTERNAL_MODULE))
|
||||
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_DSM_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, menuHorizontalPosition==1 ? attr : 0);
|
||||
else if (isModuleR9MNonAccess(EXTERNAL_MODULE))
|
||||
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_R9M_REGION, g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition==1 ? attr : 0));
|
||||
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_EXTERNAL_MODULE_PROTOCOLS, moduleIdx == EXTERNAL_MODULE ? reusableBuffer.moduleSetup.newType : g_model.moduleData[moduleIdx].type, menuHorizontalPosition==0 ? attr : 0);
|
||||
if (isModuleXJT(moduleIdx))
|
||||
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_XJT_ACCST_RF_PROTOCOLS, 1+g_model.moduleData[moduleIdx].subType, menuHorizontalPosition==1 ? attr : 0);
|
||||
else if (isModuleDSM2(moduleIdx))
|
||||
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_DSM_PROTOCOLS, g_model.moduleData[moduleIdx].rfProtocol, menuHorizontalPosition==1 ? attr : 0);
|
||||
else if (isModuleR9MNonAccess(moduleIdx))
|
||||
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_R9M_REGION, g_model.moduleData[moduleIdx].subType, (menuHorizontalPosition==1 ? attr : 0));
|
||||
#if defined(MULTIMODULE)
|
||||
else if (isModuleMultimodule(EXTERNAL_MODULE)) {
|
||||
int multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false);
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].multi.customProto)
|
||||
lcdDrawText(lcdNextPos + 3, y, STR_MULTI_CUSTOM, menuHorizontalPosition==1 ? attr : 0);
|
||||
else
|
||||
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_MULTI_PROTOCOLS, multi_rfProto, menuHorizontalPosition==1 ? attr : 0);
|
||||
else if (isModuleMultimodule(moduleIdx)) {
|
||||
int multi_rfProto = g_model.moduleData[moduleIdx].getMultiProtocol();
|
||||
lcdDrawMultiProtocolString(lcdNextPos + 3, y, moduleIdx, multi_rfProto, menuHorizontalPosition == 1 ? attr : 0);
|
||||
}
|
||||
#endif
|
||||
if (attr && menuHorizontalPosition == 0) {
|
||||
if (attr && menuHorizontalPosition == 0 && moduleIdx == EXTERNAL_MODULE) {
|
||||
if (s_editMode > 0) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].type = MODULE_TYPE_NONE;
|
||||
g_model.moduleData[moduleIdx].type = MODULE_TYPE_NONE;
|
||||
}
|
||||
else if (reusableBuffer.moduleSetup.newType != reusableBuffer.moduleSetup.previousType) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].type = reusableBuffer.moduleSetup.newType;
|
||||
g_model.moduleData[moduleIdx].type = reusableBuffer.moduleSetup.newType;
|
||||
reusableBuffer.moduleSetup.previousType = reusableBuffer.moduleSetup.newType;
|
||||
setModuleType(EXTERNAL_MODULE, g_model.moduleData[EXTERNAL_MODULE].type);
|
||||
setModuleType(moduleIdx, g_model.moduleData[moduleIdx].type);
|
||||
}
|
||||
else if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_NONE) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].type = reusableBuffer.moduleSetup.newType;
|
||||
else if (g_model.moduleData[moduleIdx].type == MODULE_TYPE_NONE) {
|
||||
g_model.moduleData[moduleIdx].type = reusableBuffer.moduleSetup.newType;
|
||||
}
|
||||
}
|
||||
if (attr) {
|
||||
if (s_editMode > 0) {
|
||||
switch (menuHorizontalPosition) {
|
||||
case 0:
|
||||
reusableBuffer.moduleSetup.newType = checkIncDec(event, reusableBuffer.moduleSetup.newType, MODULE_TYPE_NONE, MODULE_TYPE_MAX, EE_MODEL, isExternalModuleAvailable);
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
if (moduleIdx == INTERNAL_MODULE) {
|
||||
uint8_t moduleType = checkIncDec(event, g_model.moduleData[moduleIdx].type, MODULE_TYPE_NONE, MODULE_TYPE_MAX, EE_MODEL,
|
||||
isInternalModuleAvailable);
|
||||
if (checkIncDec_Ret) {
|
||||
setModuleType(moduleIdx, moduleType);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
reusableBuffer.moduleSetup.newType = checkIncDec(event, reusableBuffer.moduleSetup.newType, MODULE_TYPE_NONE, MODULE_TYPE_MAX, EE_MODEL,
|
||||
isExternalModuleAvailable);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (isModuleDSM2(EXTERNAL_MODULE)) {
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX);
|
||||
if (isModuleDSM2(moduleIdx)) {
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX);
|
||||
}
|
||||
else if (isModuleR9MNonAccess(EXTERNAL_MODULE)) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].subType = checkIncDec(event,
|
||||
g_model.moduleData[EXTERNAL_MODULE].subType,
|
||||
MODULE_SUBTYPE_R9M_FCC,
|
||||
MODULE_SUBTYPE_R9M_LAST,
|
||||
EE_MODEL,
|
||||
isR9MModeAvailable);
|
||||
else if (isModuleR9MNonAccess(moduleIdx)) {
|
||||
g_model.moduleData[moduleIdx].subType = checkIncDec(event,
|
||||
g_model.moduleData[moduleIdx].subType,
|
||||
MODULE_SUBTYPE_R9M_FCC,
|
||||
MODULE_SUBTYPE_R9M_LAST,
|
||||
EE_MODEL,
|
||||
isR9MModeAvailable);
|
||||
if (checkIncDec_Ret) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].pxx.power = 0;
|
||||
g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0;
|
||||
g_model.moduleData[EXTERNAL_MODULE].channelsCount = defaultModuleChannels_M8(EXTERNAL_MODULE);
|
||||
g_model.moduleData[moduleIdx].pxx.power = 0;
|
||||
g_model.moduleData[moduleIdx].channelsStart = 0;
|
||||
g_model.moduleData[moduleIdx].channelsCount = defaultModuleChannels_M8(moduleIdx);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
else if (isModuleMultimodule(EXTERNAL_MODULE)) {
|
||||
int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].multi.customProto == 1 ? MODULE_SUBTYPE_MULTI_CUSTOM : g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false);
|
||||
CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MODULE_SUBTYPE_MULTI_LAST, isMultiProtocolSelectable);
|
||||
else if (isModuleMultimodule(moduleIdx)) {
|
||||
int multiRfProto = g_model.moduleData[moduleIdx].getMultiProtocol();
|
||||
CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MULTI_MAX_PROTOCOLS, isMultiProtocolSelectable);
|
||||
if (checkIncDec_Ret) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.customProto = (multiRfProto == MODULE_SUBTYPE_MULTI_CUSTOM);
|
||||
if (!g_model.moduleData[EXTERNAL_MODULE].multi.customProto)
|
||||
g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(multiRfProto);
|
||||
g_model.moduleData[EXTERNAL_MODULE].subType = 0;
|
||||
// Sensible default for DSM2 (same as for ppm): 7ch@22ms + Autodetect settings enabled
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = 1;
|
||||
}
|
||||
else {
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = 0;
|
||||
}
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.optionValue = 0;
|
||||
g_model.moduleData[moduleIdx].setMultiProtocol(multiRfProto);
|
||||
g_model.moduleData[moduleIdx].subType = 0;
|
||||
resetMultiProtocolsOptions(moduleIdx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, MODULE_SUBTYPE_PXX1_LAST);
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, 0, MODULE_SUBTYPE_PXX1_LAST);
|
||||
}
|
||||
|
||||
if (checkIncDec_Ret) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0;
|
||||
g_model.moduleData[EXTERNAL_MODULE].channelsCount = defaultModuleChannels_M8(EXTERNAL_MODULE);
|
||||
g_model.moduleData[moduleIdx].channelsStart = 0;
|
||||
g_model.moduleData[moduleIdx].channelsCount = defaultModuleChannels_M8(moduleIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if POPUP_LEVEL > 1
|
||||
else if (old_editMode > 0) {
|
||||
if (isModuleR9MNonAccess(EXTERNAL_MODULE)) {
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].subType > MODULE_SUBTYPE_R9M_EU) {
|
||||
if (isModuleR9MNonAccess(moduleIdx)) {
|
||||
if (g_model.moduleData[moduleIdx].subType > MODULE_SUBTYPE_R9M_EU) {
|
||||
POPUP_WARNING(STR_MODULE_PROTOCOL_FLEX_WARN_LINE1);
|
||||
SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0);
|
||||
}
|
||||
#if POPUP_LEVEL >= 3
|
||||
else if (g_model.moduleData[EXTERNAL_MODULE].subType == MODULE_SUBTYPE_R9M_EU) {
|
||||
else if (g_model.moduleData[moduleIdx].subType == MODULE_SUBTYPE_R9M_EU) {
|
||||
POPUP_WARNING(STR_MODULE_PROTOCOL_EU_WARN_LINE1);
|
||||
SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0);
|
||||
}
|
||||
|
@ -970,32 +1004,22 @@ void menuModelSetup(event_t event)
|
|||
break;
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_SUBTYPE:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE:
|
||||
{
|
||||
lcdDrawTextAlignedLeft(y, STR_SUBTYPE);
|
||||
uint8_t multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true);
|
||||
const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_rfProto);
|
||||
|
||||
if (multi_rfProto == MM_RF_CUSTOM_SELECTED) {
|
||||
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false), (menuHorizontalPosition == 0 ? attr : 0), 2);
|
||||
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN + 3 * FW, y, g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition == 1 ? attr : 0), 2);
|
||||
}
|
||||
else {
|
||||
if (pdef->subTypeString != nullptr)
|
||||
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, pdef->subTypeString, g_model.moduleData[EXTERNAL_MODULE].subType, attr);
|
||||
}
|
||||
lcdDrawMultiSubProtocolString(MODEL_SETUP_2ND_COLUMN, y, moduleIdx, g_model.moduleData[moduleIdx].subType, attr);
|
||||
if (attr && s_editMode > 0) {
|
||||
switch (menuHorizontalPosition) {
|
||||
case 0:
|
||||
if (multi_rfProto == MM_RF_CUSTOM_SELECTED)
|
||||
g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false), 0, 63, EE_MODEL));
|
||||
else if (pdef->maxSubtype > 0)
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, pdef->maxSubtype);
|
||||
break;
|
||||
case 1:
|
||||
// Custom protocol, third column is subtype
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, 7);
|
||||
case 0:{
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, 0, getMaxMultiSubtype(moduleIdx));
|
||||
if (checkIncDec_Ret) {
|
||||
resetMultiProtocolsOptions(moduleIdx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1100,7 +1124,6 @@ void menuModelSetup(event_t event)
|
|||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS:
|
||||
{
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
ModuleData & moduleData = g_model.moduleData[moduleIdx];
|
||||
lcdDrawTextAlignedLeft(y, STR_CHANNELRANGE);
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_CH, menuHorizontalPosition==0 ? attr : 0);
|
||||
|
@ -1162,7 +1185,6 @@ void menuModelSetup(event_t event)
|
|||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM:
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM:
|
||||
{
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
lcdDrawText(INDENT_WIDTH, y, STR_RECEIVER_NUM);
|
||||
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], attr | LEADING0 | LEFT, 2);
|
||||
if (attr) {
|
||||
|
@ -1177,7 +1199,6 @@ void menuModelSetup(event_t event)
|
|||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE:
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_REGISTER_RANGE:
|
||||
{
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
lcdDrawTextAlignedLeft(y, INDENT TR_MODULE);
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, BUTTON(TR_REGISTER), (menuHorizontalPosition == 0 ? attr : 0));
|
||||
lcdDrawText(lcdLastRightPos + 3, y, STR_MODULE_RANGE, (menuHorizontalPosition == 1 ? attr : 0));
|
||||
|
@ -1225,11 +1246,10 @@ void menuModelSetup(event_t event)
|
|||
case ITEM_MODEL_SETUP_EXTRA_MODULE_BIND:
|
||||
#endif
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND:
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND:
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE:
|
||||
{
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
ModuleData & moduleData = g_model.moduleData[moduleIdx];
|
||||
if (isModulePPM(moduleIdx)) {
|
||||
lcdDrawTextAlignedLeft(y, STR_PPMFRAME);
|
||||
|
@ -1366,7 +1386,6 @@ void menuModelSetup(event_t event)
|
|||
#if defined(PCBSKY9X) && defined(REVX)
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_OUTPUT_TYPE:
|
||||
{
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
ModuleData & moduleData = g_model.moduleData[moduleIdx];
|
||||
moduleData.ppm.outputType = editChoice(MODEL_SETUP_2ND_COLUMN, y, STR_OUTPUT_TYPE, STR_VOUTPUT_TYPE, moduleData.ppm.outputType, 0, 1, attr, event);
|
||||
break;
|
||||
|
@ -1377,7 +1396,6 @@ void menuModelSetup(event_t event)
|
|||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE: {
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
ModuleData &moduleData = g_model.moduleData[moduleIdx];
|
||||
lcdDrawTextAlignedLeft(y, STR_FAILSAFE);
|
||||
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VFAILSAFE, moduleData.failsafeMode, menuHorizontalPosition == 0 ? attr : 0);
|
||||
|
@ -1434,18 +1452,36 @@ void menuModelSetup(event_t event)
|
|||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_OPTIONS:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS:
|
||||
{
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
#if defined(MULTIMODULE)
|
||||
if (isModuleMultimodule(moduleIdx)) {
|
||||
if (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx)) {
|
||||
int optionValue = g_model.moduleData[moduleIdx].multi.optionValue;
|
||||
|
||||
const uint8_t multi_proto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true);
|
||||
const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto);
|
||||
if (pdef->optionsstr)
|
||||
lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr);
|
||||
const uint8_t multi_proto = g_model.moduleData[moduleIdx].getMultiProtocol();
|
||||
if (multi_proto < MODULE_SUBTYPE_MULTI_LAST) {
|
||||
const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto);
|
||||
if (pdef->optionsstr) {
|
||||
lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr);
|
||||
if (attr && pdef->optionsstr == STR_MULTI_RFTUNE) {
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT);
|
||||
lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
|
||||
lcdDrawText(lcdLastRightPos, y, ")", LEFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
lcdDrawText(INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]);
|
||||
if (attr && status.optionDisp == 2) {
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT);
|
||||
lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
|
||||
lcdDrawText(lcdLastRightPos, y, ")", LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
optionValue = 50 + 5 * optionValue;
|
||||
|
@ -1460,11 +1496,6 @@ void menuModelSetup(event_t event)
|
|||
}
|
||||
else {
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].multi.optionValue, -128, 127);
|
||||
if (pdef->optionsstr == STR_MULTI_RFTUNE) {
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN + 23, y, "RSSI(", LEFT);
|
||||
lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
|
||||
lcdDrawText(lcdLastRightPos, y, ")", LEFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1483,13 +1514,15 @@ void menuModelSetup(event_t event)
|
|||
break;
|
||||
}
|
||||
|
||||
#if defined(INTERNAL_MODULE_MULTI)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_POWER:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER:
|
||||
{
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
auto & module = g_model.moduleData[moduleIdx];
|
||||
// Lite FCC / Lite FLEX / Lite Pro Flex
|
||||
if (isModuleTypeR9MNonAccess(module.type)) {
|
||||
lcdDrawTextAlignedLeft(y, STR_RF_POWER);
|
||||
lcdDrawText(INDENT_WIDTH, y, STR_RF_POWER);
|
||||
if (isModuleR9M_FCC_VARIANT(moduleIdx)) {
|
||||
// FCC and FLEX modes ...
|
||||
if (isModuleTypeR9MLiteNonPro(module.type)) { // R9M lite FCC has only one power value, so displayed for info only
|
||||
|
@ -1558,27 +1591,47 @@ void menuModelSetup(event_t event)
|
|||
break;
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_AUTOBIND:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND:
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2)
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_DSM_AUTODTECT, attr, event);
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2)
|
||||
g_model.moduleData[moduleIdx].multi.autoBindMode = editCheckBox(g_model.moduleData[moduleIdx].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_DSM_AUTODTECT, attr, event);
|
||||
else
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_AUTOBIND, attr, event);
|
||||
g_model.moduleData[moduleIdx].multi.autoBindMode = editCheckBox(g_model.moduleData[moduleIdx].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_AUTOBIND, attr, event);
|
||||
break;
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_TELEM:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM:
|
||||
g_model.moduleData[moduleIdx].multi.disableTelemetry = editCheckBox(g_model.moduleData[moduleIdx].multi.disableTelemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_TELEM, attr, event);
|
||||
break;
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_MAPPING:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING:
|
||||
g_model.moduleData[moduleIdx].multi.disableMapping = editCheckBox(g_model.moduleData[moduleIdx].multi.disableMapping, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_CH_MAP, attr, event);
|
||||
break;
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS: {
|
||||
lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS);
|
||||
|
||||
char statusText[64];
|
||||
getMultiModuleStatus(EXTERNAL_MODULE).getStatusString(statusText);
|
||||
getMultiModuleStatus(moduleIdx).getStatusString(statusText);
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS:
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS: {
|
||||
lcdDrawTextAlignedLeft(y, STR_MODULE_SYNC);
|
||||
|
||||
char statusText[64];
|
||||
getMultiSyncStatus(EXTERNAL_MODULE).getRefreshString(statusText);
|
||||
getMultiSyncStatus(moduleIdx).getRefreshString(statusText);
|
||||
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
|
||||
break;
|
||||
}
|
||||
|
@ -1643,7 +1696,7 @@ void menuModelSetup(event_t event)
|
|||
if (old_editMode > 0 && s_editMode == 0) {
|
||||
switch(menuVerticalPosition) {
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND:
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE:
|
||||
case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM:
|
||||
if (menuHorizontalPosition == 0)
|
||||
checkModelIdUnique(g_eeGeneral.currModel, INTERNAL_MODULE);
|
||||
|
@ -1655,7 +1708,7 @@ void menuModelSetup(event_t event)
|
|||
checkModelIdUnique(g_eeGeneral.currModel, EXTRA_MODULE);
|
||||
break;
|
||||
#endif
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND:
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE:
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM:
|
||||
if (menuHorizontalPosition == 0)
|
||||
checkModelIdUnique(g_eeGeneral.currModel, EXTERNAL_MODULE);
|
||||
|
|
|
@ -224,15 +224,17 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
|
|||
if (func == FUNC_TRAINER) {
|
||||
maxParam = NUM_STICKS + 1;
|
||||
uint8_t param = CFN_CH_INDEX(cfn);
|
||||
if (param == NUM_STICKS + 1)
|
||||
lcdDrawText(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, "Chans", attr);
|
||||
if (param == 0)
|
||||
lcdDrawText(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, STR_STICKS, attr);
|
||||
else if (param == NUM_STICKS + 1)
|
||||
lcdDrawText(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, STR_CHANS, attr);
|
||||
else
|
||||
drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, CFN_CH_INDEX(cfn) == 0 ? 0 : MIXSRC_Rud + CFN_CH_INDEX(cfn) - 1, attr);
|
||||
drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, MIXSRC_Rud + param - 1, attr);
|
||||
}
|
||||
#if defined(GVARS)
|
||||
else if (func == FUNC_ADJUST_GVAR) {
|
||||
maxParam = MAX_GVARS-1;
|
||||
drawStringWithIndex(lcdNextPos, y, STR_GV, CFN_GVAR_INDEX(cfn)+1, attr);
|
||||
drawStringWithIndex(lcdNextPos + 2, y, STR_GV, CFN_GVAR_INDEX(cfn)+1, attr);
|
||||
if (active) CFN_GVAR_INDEX(cfn) = checkIncDec(event, CFN_GVAR_INDEX(cfn), 0, maxParam, eeFlags);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -237,8 +237,8 @@ void menuModelTelemetry(event_t event)
|
|||
|
||||
case ITEM_TELEMETRY_RSSI_LABEL:
|
||||
#if defined(MULTIMODULE)
|
||||
if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
lcdDrawTextAlignedLeft(y, "RSNR");
|
||||
if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A || g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT))
|
||||
lcdDrawTextAlignedLeft(y, "RQly");
|
||||
else
|
||||
lcdDrawTextAlignedLeft(y, "RSSI");
|
||||
#else
|
||||
|
|
|
@ -177,43 +177,6 @@ void displayTrims(uint8_t phase)
|
|||
}
|
||||
}
|
||||
|
||||
void drawTimerWithMode(coord_t x, coord_t y, uint8_t index)
|
||||
{
|
||||
const TimerData & timer = g_model.timers[index];
|
||||
|
||||
if (timer.mode) {
|
||||
const TimerState & timerState = timersStates[index];
|
||||
const uint8_t negative = (timerState.val<0 ? BLINK | INVERS : 0);
|
||||
LcdFlags att = RIGHT | DBLSIZE;
|
||||
if (timerState.val < 60 * 60) { // display MM:SS
|
||||
div_t qr = div(abs(timerState.val), 60);
|
||||
lcdDrawNumber(x - 5, y, qr.rem, att | LEADING0 | negative, 2);
|
||||
lcdDrawText(lcdLastLeftPos, y, ":", att|BLINK | negative);
|
||||
lcdDrawNumber(lcdLastLeftPos, y, qr.quot, att | negative);
|
||||
if (negative)
|
||||
lcdDrawText(lcdLastLeftPos, y, "-", att | negative);
|
||||
}
|
||||
else if (timerState.val < (99 * 60 * 60) + (59 * 60)) { // display HHhMM
|
||||
div_t qr = div(abs(timerState.val) / 60, 60);
|
||||
lcdDrawNumber(x - 5, y, qr.rem, att | LEADING0, 2);
|
||||
lcdDrawText(lcdLastLeftPos, y, "h", att);
|
||||
lcdDrawNumber(lcdLastLeftPos, y, qr.quot, att);
|
||||
if (negative)
|
||||
lcdDrawText(lcdLastLeftPos, y, "-", att);
|
||||
}
|
||||
else { //display HHHH for crazy large persistent timers
|
||||
lcdDrawText(x - 5, y, "h", att);
|
||||
lcdDrawNumber(lcdLastLeftPos, y, timerState.val / 3600, att);
|
||||
}
|
||||
uint8_t xLabel = (negative ? x-56 : x-49);
|
||||
uint8_t len = zlen(timer.name, LEN_TIMER_NAME);
|
||||
if (len > 0)
|
||||
lcdDrawSizedText(xLabel, y+FH, timer.name, len, RIGHT | ZCHAR);
|
||||
else
|
||||
lcdDrawTextAtIndex(xLabel, y+FH, STR_VTMRMODES, timer.mode, RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
void displayBattVoltage()
|
||||
{
|
||||
#if defined(BATTGRAPH)
|
||||
|
@ -459,7 +422,7 @@ void menuMainView(event_t event)
|
|||
displayVoltageOrAlarm();
|
||||
|
||||
// Timer 1
|
||||
drawTimerWithMode(125, 2*FH, 0);
|
||||
drawTimerWithMode(125, 2*FH, 0, RIGHT | DBLSIZE);
|
||||
|
||||
// Trims sliders
|
||||
displayTrims(mode);
|
||||
|
@ -597,7 +560,7 @@ void menuMainView(event_t event)
|
|||
}
|
||||
else {
|
||||
// Timer2
|
||||
drawTimerWithMode(87, 5*FH, 1);
|
||||
drawTimerWithMode(87, 5*FH, 1, RIGHT | DBLSIZE);
|
||||
}
|
||||
|
||||
// And ! in case of unexpected shutdown
|
||||
|
|
|
@ -45,8 +45,6 @@ void displayRssiLine()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t barCoord(int16_t value, int16_t min, int16_t max)
|
||||
{
|
||||
if (value <= min)
|
||||
|
@ -57,7 +55,6 @@ uint8_t barCoord(int16_t value, int16_t min, int16_t max)
|
|||
return ((int32_t)(BAR_WIDTH-1) * (value - min)) / (max - min);
|
||||
}
|
||||
|
||||
|
||||
bool displayGaugesTelemetryScreen(TelemetryScreenData & screen)
|
||||
{
|
||||
// Custom Screen with gauges
|
||||
|
@ -125,9 +122,11 @@ bool displayNumbersTelemetryScreen(TelemetryScreenData & screen)
|
|||
if (field) {
|
||||
LcdFlags att = (i==3 ? RIGHT|NO_UNIT : RIGHT|MIDSIZE|NO_UNIT);
|
||||
coord_t pos[] = {0, 65, 130};
|
||||
if (field >= MIXSRC_FIRST_TIMER && field <= MIXSRC_LAST_TIMER && i!=3) {
|
||||
if (field >= MIXSRC_FIRST_TIMER && field <= MIXSRC_LAST_TIMER && i != 3) {
|
||||
// there is not enough space on LCD for displaying "Tmr1" or "Tmr2" and still see the - sign, we write "T1" or "T2" instead
|
||||
drawStringWithIndex(pos[j], 1+FH+2*FH*i, "T", field-MIXSRC_FIRST_TIMER+1, 0);
|
||||
drawTimerWithMode(pos[j+1] + 2, 1+FH+2*FH*i, field - MIXSRC_FIRST_TIMER, RIGHT | DBLSIZE);
|
||||
continue;
|
||||
}
|
||||
else if (field >= MIXSRC_FIRST_TELEM && isGPSSensor(1+(field-MIXSRC_FIRST_TELEM)/3) && telemetryItems[(field-MIXSRC_FIRST_TELEM)/3].isAvailable()) {
|
||||
// we don't display GPS name, no space for it
|
||||
|
@ -146,7 +145,8 @@ bool displayNumbersTelemetryScreen(TelemetryScreenData & screen)
|
|||
att |= INVERS|BLINK;
|
||||
}
|
||||
}
|
||||
if(isSensorUnit(1+(field-MIXSRC_FIRST_TELEM)/3, UNIT_DATETIME) && field >= MIXSRC_FIRST_TELEM) {
|
||||
|
||||
if (isSensorUnit(1+(field-MIXSRC_FIRST_TELEM)/3, UNIT_DATETIME) && field >= MIXSRC_FIRST_TELEM) {
|
||||
drawTelemScreenDate(pos[j+1]-36, 6+FH+2*FH*i, field, SMLSIZE|NO_UNIT);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -173,6 +173,7 @@ uint8_t * lcdLoadBitmap(uint8_t * dest, const char * filename, uint16_t width, u
|
|||
#define BLINK_ON_PHASE (0)
|
||||
#else
|
||||
#define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6))
|
||||
#define SLOW_BLINK_ON_PHASE (g_blinkTmr10ms & (1<<7))
|
||||
#endif
|
||||
|
||||
inline pixel_t getPixel(unsigned int x, unsigned int y)
|
||||
|
|
|
@ -91,10 +91,10 @@ void menuModelMixOne(event_t event)
|
|||
}
|
||||
|
||||
MixData * md2 = mixAddress(s_currIdx) ;
|
||||
putsChn(PSIZE(TR_MIXER)*FW+FW, 0, md2->destCh+1,0);
|
||||
putsChn(PSIZE(TR_MIXES)*FW+FW, 0, md2->destCh+1,0);
|
||||
lcdDrawFilledRect(0, 0, LCD_W, FH, SOLID, FILL_WHITE|GREY_DEFAULT);
|
||||
|
||||
SUBMENU(STR_MIXER, MIX_FIELD_COUNT, {0, 0, 0, 0, 0, 1, CASE_FLIGHT_MODES((MAX_FLIGHT_MODES-1) | NAVIGATION_LINE_BY_LINE) 0, 0 /*, ...*/});
|
||||
SUBMENU(STR_MIXES, MIX_FIELD_COUNT, {0, 0, 0, 0, 0, 1, CASE_FLIGHT_MODES((MAX_FLIGHT_MODES-1) | NAVIGATION_LINE_BY_LINE) 0, 0 /*, ...*/});
|
||||
|
||||
int8_t sub = menuVerticalPosition;
|
||||
int8_t editMode = s_editMode;
|
||||
|
|
|
@ -107,6 +107,8 @@ enum MenuModelSetupItems {
|
|||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS,
|
||||
#if defined(MULTIMODULE)
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING,
|
||||
#endif
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER,
|
||||
ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE,
|
||||
|
@ -815,21 +817,11 @@ void menuModelSetup(event_t event)
|
|||
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_R9M_REGION, g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition==1 ? attr : 0));
|
||||
#if defined(MULTIMODULE)
|
||||
else if (isModuleMultimodule(EXTERNAL_MODULE)) {
|
||||
uint8_t multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false);
|
||||
|
||||
uint8_t multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol();
|
||||
// Do not use MODEL_SETUP_3RD_COLUMN here since some the protocol string are so long that we cannot afford the 2 spaces (+6) here
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].multi.customProto) {
|
||||
lcdDrawText(lcdNextPos + 3, y, STR_MULTI_CUSTOM, menuHorizontalPosition == 1 ? attr : 0);
|
||||
lcdDrawNumber(lcdNextPos + 3, y, g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false), menuHorizontalPosition == 2 ? attr : 0, 2);
|
||||
lcdDrawNumber(lcdNextPos + 3, y, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition == 3 ? attr : 0, 2);
|
||||
}
|
||||
else {
|
||||
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_MULTI_PROTOCOLS, multi_rfProto, menuHorizontalPosition==1 ? attr : 0);
|
||||
const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_rfProto);
|
||||
if (pdef->subTypeString) {
|
||||
lcdDrawTextAtIndex(lcdNextPos + 3, y, pdef->subTypeString, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==2 ? attr : 0);
|
||||
}
|
||||
}
|
||||
lcdDrawMultiProtocolString(lcdNextPos + 3, y, EXTERNAL_MODULE, multi_rfProto, menuHorizontalPosition == 1 ? attr : 0);
|
||||
if (MULTIMODULE_HAS_SUBTYPE(EXTERNAL_MODULE))
|
||||
lcdDrawMultiSubProtocolString(lcdNextPos + 3, y, EXTERNAL_MODULE, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==2 ? attr : 0);
|
||||
}
|
||||
#endif
|
||||
if (attr && menuHorizontalPosition == 0) {
|
||||
|
@ -858,21 +850,12 @@ void menuModelSetup(event_t event)
|
|||
}
|
||||
#if defined(MULTIMODULE)
|
||||
else if (isModuleMultimodule(EXTERNAL_MODULE)) {
|
||||
int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].multi.customProto == 1 ? MODULE_SUBTYPE_MULTI_CUSTOM : g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false);
|
||||
CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MODULE_SUBTYPE_MULTI_LAST, isMultiProtocolSelectable);
|
||||
int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol();
|
||||
CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MULTI_MAX_PROTOCOLS, isMultiProtocolSelectable);
|
||||
if (checkIncDec_Ret) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.customProto = (multiRfProto == MODULE_SUBTYPE_MULTI_CUSTOM);
|
||||
if (!g_model.moduleData[EXTERNAL_MODULE].multi.customProto)
|
||||
g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(multiRfProto);
|
||||
g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(multiRfProto);
|
||||
g_model.moduleData[EXTERNAL_MODULE].subType = 0;
|
||||
// Sensible default for DSM2 (same as for ppm): 7ch@22ms + Autodetect settings enabled
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = 1;
|
||||
}
|
||||
else {
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = 0;
|
||||
}
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.optionValue = 0;
|
||||
resetMultiProtocolsOptions(EXTERNAL_MODULE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -894,20 +877,10 @@ void menuModelSetup(event_t event)
|
|||
|
||||
#if defined(MULTIMODULE)
|
||||
case 2:
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].multi.customProto) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].setMultiProtocol(checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false), 0, 63, EE_MODEL));
|
||||
break;
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, getMaxMultiSubtype(EXTERNAL_MODULE));
|
||||
if (checkIncDec_Ret) {
|
||||
resetMultiProtocolsOptions(EXTERNAL_MODULE);
|
||||
}
|
||||
else {
|
||||
const mm_protocol_definition * pdef = getMultiProtocolDefinition(g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false));
|
||||
if (pdef->maxSubtype > 0)
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, pdef->maxSubtype);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Custom protocol, third column is subtype
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, 7);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
@ -1240,14 +1213,29 @@ void menuModelSetup(event_t event)
|
|||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
#if defined(MULTIMODULE)
|
||||
|
||||
if (isModuleMultimodule(moduleIdx)) {
|
||||
if (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx)) {
|
||||
int optionValue = g_model.moduleData[moduleIdx].multi.optionValue;
|
||||
|
||||
const uint8_t multi_proto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true);
|
||||
const mm_protocol_definition *pdef = getMultiProtocolDefinition(multi_proto);
|
||||
if (pdef->optionsstr)
|
||||
lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr);
|
||||
|
||||
const uint8_t multi_proto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol();
|
||||
if (multi_proto < MODULE_SUBTYPE_MULTI_LAST) {
|
||||
const mm_protocol_definition * pdef = getMultiProtocolDefinition(multi_proto);
|
||||
if (pdef->optionsstr)
|
||||
lcdDrawText(INDENT_WIDTH, y, pdef->optionsstr);
|
||||
if (pdef->optionsstr == STR_MULTI_RFTUNE) {
|
||||
lcdDrawText(MODEL_SETUP_3RD_COLUMN+22, y, "RSSI(", LEFT);
|
||||
lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
|
||||
lcdDrawText(lcdLastRightPos, y, ")", LEFT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
lcdDrawText(INDENT_WIDTH, y, mm_options_strings::options[status.optionDisp]);
|
||||
if (attr && status.optionDisp == 2) {
|
||||
lcdDrawText(MODEL_SETUP_3RD_COLUMN+22, y, "RSSI(", LEFT);
|
||||
lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
|
||||
lcdDrawText(lcdLastRightPos, y, ")", LEFT);
|
||||
}
|
||||
}
|
||||
if (multi_proto == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
optionValue = 50 + 5 * optionValue;
|
||||
|
||||
|
@ -1261,11 +1249,6 @@ void menuModelSetup(event_t event)
|
|||
}
|
||||
else {
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].multi.optionValue, -128, 127);
|
||||
if (pdef->optionsstr == STR_MULTI_RFTUNE) {
|
||||
lcdDrawText(MODEL_SETUP_3RD_COLUMN+22, y, "RSSI(", LEFT);
|
||||
lcdDrawNumber(lcdLastRightPos, y, TELEMETRY_RSSI(), LEFT);
|
||||
lcdDrawText(lcdLastRightPos, y, ")", LEFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1290,7 +1273,7 @@ void menuModelSetup(event_t event)
|
|||
{
|
||||
uint8_t moduleIdx = CURRENT_MODULE_EDITED(k);
|
||||
if (isModuleR9MNonAccess(moduleIdx)) {
|
||||
lcdDrawTextAlignedLeft(y, TR_RF_POWER);
|
||||
lcdDrawText(INDENT_WIDTH, y, STR_RFPOWER);
|
||||
if (isModuleR9M_FCC_VARIANT(moduleIdx)) {
|
||||
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_R9M_FCC_POWER_VALUES, g_model.moduleData[moduleIdx].pxx.power, LEFT | attr);
|
||||
if (attr)
|
||||
|
@ -1317,12 +1300,20 @@ void menuModelSetup(event_t event)
|
|||
|
||||
#if defined (MULTIMODULE)
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND:
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2)
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2)
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_DSM_AUTODTECT, attr, event);
|
||||
else
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, STR_MULTI_AUTOBIND, attr, event);
|
||||
break;
|
||||
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM:
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.disableTelemetry = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.disableTelemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_TELEM, attr, event);
|
||||
break;
|
||||
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING:
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.disableMapping = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.disableMapping, MODEL_SETUP_2ND_COLUMN, y, INDENT TR_DISABLE_CH_MAP, attr, event);
|
||||
break;
|
||||
|
||||
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS:
|
||||
{
|
||||
lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS);
|
||||
|
|
|
@ -216,15 +216,17 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
|
|||
if (func == FUNC_TRAINER) {
|
||||
maxParam = NUM_STICKS + 1;
|
||||
uint8_t param = CFN_CH_INDEX(cfn);
|
||||
if (param == NUM_STICKS + 1)
|
||||
lcdDrawText(lcdNextPos, y, "Chans", attr);
|
||||
if (param == 0)
|
||||
lcdDrawText(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, STR_STICKS, attr);
|
||||
else if (param == NUM_STICKS + 1)
|
||||
lcdDrawText(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, STR_CHANS, attr);
|
||||
else
|
||||
drawSource(lcdNextPos, y, CFN_CH_INDEX(cfn)==0 ? 0 : MIXSRC_Rud+CFN_CH_INDEX(cfn)-1, attr);
|
||||
drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, MIXSRC_Rud + param - 1, attr);
|
||||
}
|
||||
#if defined(GVARS)
|
||||
else if (func == FUNC_ADJUST_GVAR) {
|
||||
maxParam = MAX_GVARS-1;
|
||||
drawStringWithIndex(lcdNextPos, y, STR_GV, CFN_GVAR_INDEX(cfn)+1, attr);
|
||||
drawStringWithIndex(lcdNextPos + 2, y, STR_GV, CFN_GVAR_INDEX(cfn)+1, attr);
|
||||
if (active) CFN_GVAR_INDEX(cfn) = checkIncDec(event, CFN_GVAR_INDEX(cfn), 0, maxParam, eeFlags);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -228,8 +228,8 @@ void menuModelTelemetry(event_t event)
|
|||
|
||||
case ITEM_TELEMETRY_RSSI_LABEL:
|
||||
#if defined(MULTIMODULE)
|
||||
if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
lcdDrawTextAlignedLeft(y, "RSNR");
|
||||
if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A || g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT))
|
||||
lcdDrawTextAlignedLeft(y, "RQly");
|
||||
else
|
||||
lcdDrawTextAlignedLeft(y, "RSSI");
|
||||
#else
|
||||
|
|
|
@ -21,6 +21,39 @@
|
|||
#include "opentx.h"
|
||||
#include <math.h>
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
void lcdDrawMultiProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t protocol, LcdFlags flags)
|
||||
{
|
||||
if (protocol <= MODULE_SUBTYPE_MULTI_LAST) {
|
||||
lcdDrawTextAtIndex(x, y, STR_MULTI_PROTOCOLS, protocol, flags);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
if (status.protocolName[0] && status.isValid())
|
||||
lcdDrawText(x, y, status.protocolName, flags);
|
||||
else
|
||||
lcdDrawNumber(x, y, protocol + 3, flags); // Convert because of OpenTX FrSky fidling (OpenTX protocol tables and Multiprotocol tables don't match)
|
||||
}
|
||||
}
|
||||
|
||||
void lcdDrawMultiSubProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t subType, LcdFlags flags)
|
||||
{
|
||||
const mm_protocol_definition *pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol());
|
||||
if (subType <= pdef->maxSubtype && pdef->subTypeString != nullptr) {
|
||||
lcdDrawTextAtIndex(x, y, pdef->subTypeString, subType, flags);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
if (status.protocolName[0] && status.isValid())
|
||||
lcdDrawText(x, y, status.protocolSubName, flags);
|
||||
else
|
||||
lcdDrawNumber(x, y, subType, flags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void drawStringWithIndex(coord_t x, coord_t y, const char * str, uint8_t idx, LcdFlags flags)
|
||||
{
|
||||
if (flags & RIGHT) {
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
#define _STDLCD_DRAW_FUNCTIONS_H_
|
||||
|
||||
#include "lcd.h"
|
||||
|
||||
void lcdDrawMultiProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t protocol, LcdFlags flags = 0);
|
||||
void lcdDrawMultiSubProtocolString(coord_t x, coord_t y, uint8_t moduleIdx, uint8_t subType, LcdFlags flags = 0);
|
||||
void drawStringWithIndex(coord_t x, coord_t y, const char * str, uint8_t idx, LcdFlags att=0);
|
||||
void drawValueWithUnit(coord_t x, coord_t y, int val, uint8_t unit, LcdFlags att=0);
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ void displayMixInfos(coord_t y, MixData * md)
|
|||
void displayMixLine(coord_t y, MixData * md, bool active)
|
||||
{
|
||||
if(active && md->name[0]) {
|
||||
lcdDrawSizedText(FW*sizeof(TR_MIXER)+FW/2, 0, md->name, sizeof(md->name), ZCHAR);
|
||||
lcdDrawSizedText(FW*sizeof(TR_MIXES)+FW/2, 0, md->name, sizeof(md->name), ZCHAR);
|
||||
if (!md->flightModes || ((md->curve.value || md->swtch) && ((get_tmr10ms() / 200) & 1)))
|
||||
displayMixInfos(y, md);
|
||||
else
|
||||
|
@ -385,7 +385,7 @@ void menuModelMixAll(event_t event)
|
|||
break;
|
||||
}
|
||||
|
||||
lcdDrawNumber(FW*sizeof(TR_MIXER)+FW/2, 0, getMixesCount(), 0);
|
||||
lcdDrawNumber(FW*sizeof(TR_MIXES)+FW/2, 0, getMixesCount(), 0);
|
||||
lcdDrawText(lcdNextPos, 0, STR_MAX(MAX_MIXERS));
|
||||
|
||||
// Value
|
||||
|
@ -397,7 +397,7 @@ void menuModelMixAll(event_t event)
|
|||
#endif
|
||||
}
|
||||
|
||||
SIMPLE_MENU(STR_MIXER, menuTabModel, MENU_MODEL_MIXES, HEADER_LINE + s_maxLines);
|
||||
SIMPLE_MENU(STR_MIXES, menuTabModel, MENU_MODEL_MIXES, HEADER_LINE + s_maxLines);
|
||||
|
||||
#if LCD_W >= 212
|
||||
// Gauge
|
||||
|
|
|
@ -50,7 +50,7 @@ void menuRadioPowerMeter(event_t event)
|
|||
lcdRefresh();
|
||||
moduleState[g_moduleIdx].readModuleInformation(&reusableBuffer.moduleSetup.pxx2.moduleInformation, PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID);
|
||||
/* wait 1s to resume normal operation before leaving */
|
||||
watchdogSuspend(1000);
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(1000);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -568,13 +568,15 @@ void menuRadioSdManager(event_t _event)
|
|||
if (moduleState[EXTERNAL_MODULE].mode == MODULE_MODE_BIND) {
|
||||
if (reusableBuffer.sdManager.otaUpdateInformation.step == BIND_INIT) {
|
||||
if (reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount > 0) {
|
||||
popupMenuItemsCount = min<uint8_t>(reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount, PXX2_MAX_RECEIVERS_PER_MODULE);
|
||||
for (uint8_t i=0; i<popupMenuItemsCount; i++) {
|
||||
popupMenuItems[i] = reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[i];
|
||||
if(reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount != popupMenuItemsCount) {
|
||||
CLEAR_POPUP();
|
||||
popupMenuItemsCount = min<uint8_t>(reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount,PXX2_MAX_RECEIVERS_PER_MODULE);
|
||||
for (auto rx = 0; rx < popupMenuItemsCount; rx++) {
|
||||
popupMenuItems[rx] = reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[rx];
|
||||
}
|
||||
popupMenuTitle = STR_PXX2_SELECT_RX;
|
||||
POPUP_MENU_START(onUpdateReceiverSelection);
|
||||
}
|
||||
popupMenuTitle = STR_PXX2_SELECT_RX;
|
||||
CLEAR_POPUP();
|
||||
POPUP_MENU_START(onUpdateReceiverSelection);
|
||||
}
|
||||
else {
|
||||
POPUP_WAIT(STR_WAITING_FOR_RX);
|
||||
|
|
|
@ -44,7 +44,7 @@ void menuRadioSpectrumAnalyser(event_t event)
|
|||
lcdRefresh();
|
||||
moduleState[g_moduleIdx].readModuleInformation(&reusableBuffer.moduleSetup.pxx2.moduleInformation, PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID);
|
||||
/* wait 1s to resume normal operation before leaving */
|
||||
watchdogSuspend(1000);
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(1000);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ void readModelNotes()
|
|||
menuTextView(event);
|
||||
event = getEvent();
|
||||
lcdRefresh();
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
}
|
||||
|
||||
LED_ERROR_END();
|
||||
|
|
|
@ -665,7 +665,7 @@ bool isExternalModuleAvailable(int moduleType)
|
|||
#endif
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
if ((isModuleUsingSport(EXTERNAL_MODULE, moduleType) || isTrainerUsingModuleBay()) && isModuleUsingSport(INTERNAL_MODULE, g_model.moduleData[INTERNAL_MODULE].type))
|
||||
if (isTrainerUsingModuleBay() || (isModuleUsingSport(EXTERNAL_MODULE, moduleType) && isModuleUsingSport(INTERNAL_MODULE, g_model.moduleData[INTERNAL_MODULE].type)))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
|
@ -791,6 +791,37 @@ int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable)
|
|||
return retval;
|
||||
}
|
||||
#if defined(MULTIMODULE)
|
||||
|
||||
// This maps OpenTX multi type with Pascal's Multi type
|
||||
uint8_t convertMultiProtocol(uint8_t moduleIdx, uint8_t type)
|
||||
{
|
||||
|
||||
// 15 for Multimodule is FrskyX or D16 which we map as a subprotocol of 3 (FrSky)
|
||||
// all protos > frskyx are therefore also off by one
|
||||
if (type >= 15)
|
||||
type = type + 1;
|
||||
|
||||
// 25 is again a FrSky protocol (FrskyV) so shift again
|
||||
if (type >= 25)
|
||||
type = type + 1;
|
||||
|
||||
if (type == MODULE_SUBTYPE_MULTI_FRSKY) {
|
||||
int subtype = g_model.moduleData[moduleIdx].subType;
|
||||
if (subtype == MM_RF_FRSKY_SUBTYPE_D8) {
|
||||
//D8
|
||||
type = 3;
|
||||
}
|
||||
else if (subtype == MM_RF_FRSKY_SUBTYPE_V8) {
|
||||
//V8
|
||||
type = 25;
|
||||
}
|
||||
else {
|
||||
type = 15;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// Third row is number of subtypes -1 (max valid subtype)
|
||||
#define NO_SUBTYPE nullptr
|
||||
|
||||
|
@ -815,7 +846,7 @@ const char STR_SUBTYPE_SYMAX[] = "\003""Std""X5C";
|
|||
const char STR_SUBTYPE_SLT[] = "\006""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0";
|
||||
const char STR_SUBTYPE_CX10[] = "\007""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041";
|
||||
const char STR_SUBTYPE_CG023[] = "\005""Std\0 ""YD829";
|
||||
const char STR_SUBTYPE_BAYANG[] = "\007""Std\0 ""H8S3D\0 ""X16 AH\0 ""IRDrone""DHD D4";
|
||||
const char STR_SUBTYPE_BAYANG[] = "\007""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4";
|
||||
const char STR_SUBTYPE_MT99[] = "\006""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805";
|
||||
const char STR_SUBTYPE_MJXQ[] = "\007""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix";
|
||||
const char STR_SUBTYPE_FY326[] = "\005""Std\0 ""FY319";
|
||||
|
@ -836,53 +867,70 @@ const char STR_SUBTYPE_REDPINE[] = "\004""Fast""Slow";
|
|||
const char STR_SUBTYPE_POTENSIC[] = "\003""A20";
|
||||
const char STR_SUBTYPE_ZSX[] = "\007""280JJRC";
|
||||
const char STR_SUBTYPE_FLYZONE[] = "\005""FZ410";
|
||||
const char STR_SUBTYPE_FRSKYX_RX[] = "\003""FCC""LBT";
|
||||
const char STR_SUBTYPE_FX816[] = "\003""P38";
|
||||
const char STR_SUBTYPE_ESKY150[] = "\003""4CH""7CH";
|
||||
|
||||
const char* mm_options_strings::options[] = {
|
||||
nullptr,
|
||||
STR_MULTI_OPTION,
|
||||
STR_MULTI_RFTUNE,
|
||||
STR_MULTI_VIDFREQ,
|
||||
STR_MULTI_FIXEDID,
|
||||
STR_MULTI_TELEMETRY,
|
||||
STR_MULTI_SERVOFREQ,
|
||||
STR_MULTI_MAX_THROW,
|
||||
STR_MULTI_RFCHAN
|
||||
};
|
||||
|
||||
const mm_protocol_definition multi_protocols[] = {
|
||||
|
||||
{MODULE_SUBTYPE_MULTI_FLYSKY, 4, false, STR_SUBTYPE_FLYSKY, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_HUBSAN, 2, false, STR_SUBTYPE_HUBSAN, STR_MULTI_VIDFREQ},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKY, 5, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_HISKY, 1, false, STR_SUBTYPE_HISKY, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_V2X2, 1, false, STR_SUBTYPE_V2X2, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_DSM2, 3, false, STR_SUBTYPE_DSM, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_DEVO, 4, false, STR_SUBTYPE_DEVO, STR_MULTI_FIXEDID},
|
||||
{MODULE_SUBTYPE_MULTI_YD717, 4, false, STR_SUBTYPE_YD717, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_KN, 1, false, STR_SUBTYPE_KN, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SYMAX, 1, false, STR_SUBTYPE_SYMAX, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SLT, 4, false, STR_SUBTYPE_SLT, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CX10, 6, false, STR_SUBTYPE_CX10, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CG023, 1, false, STR_SUBTYPE_CG023, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_BAYANG, 4, false, STR_SUBTYPE_BAYANG, STR_MULTI_TELEMETRY},
|
||||
{MODULE_SUBTYPE_MULTI_MT99XX, 4, false, STR_SUBTYPE_MT99, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_MJXQ, 6, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_FY326, 1, false, STR_SUBTYPE_FY326, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SFHSS, 0, true, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_HONTAI, 3, false, STR_SUBTYPE_HONTAI, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_OLRS, 0, false, NO_SUBTYPE, STR_RF_POWER},
|
||||
{MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
|
||||
{MODULE_SUBTYPE_MULTI_Q2X2, 2, false, STR_SUBTYPE_Q2X2, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, STR_SUBTYPE_WK2x01, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_Q303, 3, false, STR_SUBTYPE_Q303, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CABELL, 7, false, STR_SUBTYPE_CABELL, STR_MULTI_OPTION},
|
||||
{MODULE_SUBTYPE_MULTI_H83D, 3, false, STR_SUBTYPE_H83D, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CORONA, 2, false, STR_SUBTYPE_CORONA, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_HITEC, 2, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_BUGS_MINI, 1, false, STR_SUBTYPE_BUGS_MINI, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_TRAXXAS, 0, false, STR_SUBTYPE_TRAXXAS, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_E01X, 2, false, STR_SUBTYPE_E01X, STR_MULTI_OPTION},
|
||||
{MODULE_SUBTYPE_MULTI_V911S, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_GD00X, 1, false, STR_SUBTYPE_GD00X, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_KF606, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_REDPINE, 1, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, STR_SUBTYPE_POTENSIC, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_ZSX, 0, false, STR_SUBTYPE_ZSX, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, STR_SUBTYPE_FLYZONE, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE},
|
||||
{MM_RF_CUSTOM_SELECTED, 7, true, NO_SUBTYPE, STR_MULTI_OPTION},
|
||||
// Protocol as defined in pulses\modules_constants.h, number of sub_protocols - 1, Failsafe supported, Disable channel mapping supported, Subtype string, Option type
|
||||
{MODULE_SUBTYPE_MULTI_FLYSKY, 4, false, true, STR_SUBTYPE_FLYSKY, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_HUBSAN, 2, false, false, STR_SUBTYPE_HUBSAN, STR_MULTI_VIDFREQ},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKY, 5, false, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_HISKY, 1, false, true, STR_SUBTYPE_HISKY, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_V2X2, 1, false, false, STR_SUBTYPE_V2X2, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_DSM2, 3, false, true, STR_SUBTYPE_DSM, STR_MULTI_MAX_THROW},
|
||||
{MODULE_SUBTYPE_MULTI_DEVO, 4, false, true, STR_SUBTYPE_DEVO, STR_MULTI_FIXEDID},
|
||||
{MODULE_SUBTYPE_MULTI_YD717, 4, false, false, STR_SUBTYPE_YD717, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_KN, 1, false, false, STR_SUBTYPE_KN, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SYMAX, 1, false, false, STR_SUBTYPE_SYMAX, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SLT, 4, false, true, STR_SUBTYPE_SLT, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CX10, 6, false, false, STR_SUBTYPE_CX10, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CG023, 1, false, false, STR_SUBTYPE_CG023, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_BAYANG, 4, false, false, STR_SUBTYPE_BAYANG, STR_MULTI_TELEMETRY},
|
||||
{MODULE_SUBTYPE_MULTI_MT99XX, 4, false, false, STR_SUBTYPE_MT99, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_MJXQ, 6, false, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_FY326, 1, false, false, STR_SUBTYPE_FY326, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SFHSS, 0, true, true, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_HONTAI, 3, false, false, STR_SUBTYPE_HONTAI, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_OLRS, 0, false, false, NO_SUBTYPE, STR_RF_POWER},
|
||||
{MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
|
||||
{MODULE_SUBTYPE_MULTI_Q2X2, 2, false, false, STR_SUBTYPE_Q2X2, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, true, STR_SUBTYPE_WK2x01, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_Q303, 3, false, false, STR_SUBTYPE_Q303, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CABELL, 7, false, false, STR_SUBTYPE_CABELL, STR_MULTI_OPTION},
|
||||
{MODULE_SUBTYPE_MULTI_H83D, 3, false, false, STR_SUBTYPE_H83D, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CORONA, 2, false, false, STR_SUBTYPE_CORONA, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_HITEC, 2, false, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_BUGS_MINI, 1, false, false, STR_SUBTYPE_BUGS_MINI, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_TRAXXAS, 0, false, false, STR_SUBTYPE_TRAXXAS, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_E01X, 2, false, false, STR_SUBTYPE_E01X, STR_MULTI_OPTION},
|
||||
{MODULE_SUBTYPE_MULTI_GD00X, 1, false, false, STR_SUBTYPE_GD00X, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_KF606, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_REDPINE, 1, false, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, false, STR_SUBTYPE_POTENSIC, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_ZSX, 0, false, false, STR_SUBTYPE_ZSX, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, false, STR_SUBTYPE_FLYZONE, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKYX_RX, 0, false, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_ESky, 0, false, true, NO_SUBTYPE, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_J6PRO, 0, false, true, NO_SUBTYPE, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_ESKY150, 1, false, false, STR_SUBTYPE_ESKY150, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FX816, 0, false, false, STR_SUBTYPE_FX816, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_HOTT, 0, true, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MM_RF_CUSTOM_SELECTED, 7, true, true, NO_SUBTYPE, STR_MULTI_OPTION},
|
||||
|
||||
// Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff)
|
||||
{0xfe, 0, false, NO_SUBTYPE, nullptr}
|
||||
{0xfe, 0, false, true, NO_SUBTYPE, nullptr}
|
||||
};
|
||||
|
||||
#undef NO_SUBTYPE
|
||||
|
|
|
@ -159,7 +159,7 @@ inline uint8_t MODULE_CHANNELS_ROWS(int moduleIdx)
|
|||
if (!IS_MODULE_ENABLED(moduleIdx))
|
||||
return HIDDEN_ROW;
|
||||
|
||||
if (isModuleDSM2(moduleIdx) || isModuleCrossfire(moduleIdx) || isModuleSBUS(moduleIdx) || (isModuleMultimodule(moduleIdx) && g_model.moduleData[moduleIdx].getMultiProtocol(true) != MODULE_SUBTYPE_MULTI_DSM2))
|
||||
if (isModuleDSM2(moduleIdx) || isModuleCrossfire(moduleIdx) || isModuleSBUS(moduleIdx) || (isModuleMultimodule(moduleIdx) && g_model.moduleData[moduleIdx].getMultiProtocol() != MODULE_SUBTYPE_MULTI_DSM2))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
|
@ -167,40 +167,97 @@ inline uint8_t MODULE_CHANNELS_ROWS(int moduleIdx)
|
|||
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
// When using packed, the pointer in here end up not being aligned, which clang and gcc complain about
|
||||
// Keep the order of the fields that the so that the size stays small
|
||||
struct mm_protocol_definition {
|
||||
uint8_t protocol;
|
||||
uint8_t maxSubtype;
|
||||
bool failsafe;
|
||||
const char *subTypeString;
|
||||
const char *optionsstr;
|
||||
};
|
||||
const mm_protocol_definition *getMultiProtocolDefinition (uint8_t protocol);
|
||||
#define MULTIMODULE_STATUS_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(moduleIdx) && getMultiSyncStatus(moduleIdx).isValid()) ? TITLE_ROW : HIDDEN_ROW,
|
||||
#define MULTIMODULE_MODULE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW,
|
||||
#define MULTIMODULE_MODE_ROWS(moduleIdx) (g_model.moduleData[moduleIdx].multi.customProto) ? (uint8_t) 3 :MULTIMODULE_HAS_SUBTYPE(g_model.moduleData[moduleIdx].getMultiProtocol(true)) ? (uint8_t)2 : (uint8_t)1
|
||||
inline uint8_t MULTI_DISABLE_CHAN_MAP_ROW(uint8_t moduleIdx)
|
||||
{
|
||||
if (!isModuleMultimodule(moduleIdx))
|
||||
return HIDDEN_ROW;
|
||||
|
||||
uint8_t protocol = g_model.moduleData[moduleIdx].getMultiProtocol();
|
||||
if (protocol < MODULE_SUBTYPE_MULTI_LAST) {
|
||||
const mm_protocol_definition * pdef = getMultiProtocolDefinition(protocol);
|
||||
if (pdef->disable_ch_mapping)
|
||||
return 0;
|
||||
}
|
||||
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
if (status.supportsDisableMapping() && status.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return HIDDEN_ROW;
|
||||
}
|
||||
|
||||
inline bool isMultiProtocolSelectable(int protocol)
|
||||
{
|
||||
return protocol != MODULE_SUBTYPE_MULTI_SCANNER;
|
||||
}
|
||||
|
||||
inline bool MULTIMODULE_PROTOCOL_KNOWN(uint8_t moduleIdx)
|
||||
{
|
||||
if (!isModuleMultimodule(moduleIdx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() < MODULE_SUBTYPE_MULTI_LAST) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
if (status.isValid()) {
|
||||
return status.protocolValid();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool MULTIMODULE_HAS_SUBTYPE(uint8_t moduleIdx)
|
||||
{
|
||||
return getMultiProtocolDefinition(moduleIdx)->maxSubtype > 0;
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (status.isValid()) {
|
||||
return status.protocolSubNbr > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() > MODULE_SUBTYPE_MULTI_LAST)
|
||||
return true;
|
||||
else
|
||||
return getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol())->maxSubtype > 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint8_t MULTIMODULE_RFPROTO_COLUMNS(uint8_t moduleIdx)
|
||||
{
|
||||
#if LCD_W < 212
|
||||
return (g_model.moduleData[moduleIdx].multi.customProto ? (uint8_t) 1 : MULTIMODULE_HAS_SUBTYPE(g_model.moduleData[moduleIdx].getMultiProtocol(true)) ? (uint8_t) 0 : HIDDEN_ROW);
|
||||
return (MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW);
|
||||
#else
|
||||
return (g_model.moduleData[moduleIdx].multi.customProto ? (uint8_t) 2 : MULTIMODULE_HAS_SUBTYPE(g_model.moduleData[moduleIdx].getMultiProtocol(true)) ? (uint8_t) 1 : 0);
|
||||
return (MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t) 1 : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx)
|
||||
{
|
||||
if (!isModuleMultimodule(moduleIdx))
|
||||
return false;
|
||||
|
||||
uint8_t protocol = g_model.moduleData[moduleIdx].getMultiProtocol();
|
||||
if (protocol < MODULE_SUBTYPE_MULTI_LAST) {
|
||||
return getMultiProtocolDefinition(protocol)->optionsstr != nullptr;
|
||||
}
|
||||
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
return status.optionDisp;
|
||||
}
|
||||
|
||||
#define MULTIMODULE_MODULE_ROWS(moduleIdx) MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, MULTI_DISABLE_CHAN_MAP_ROW(moduleIdx), // AUTOBIND, DISABLE TELEM, DISABLE CN.MAP
|
||||
#define MULTIMODULE_STATUS_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, (isModuleMultimodule(moduleIdx) && getMultiSyncStatus(moduleIdx).isValid()) ? TITLE_ROW : HIDDEN_ROW,
|
||||
#define MULTIMODULE_MODE_ROWS(moduleIdx) (g_model.moduleData[moduleIdx].multi.customProto) ? (uint8_t) 3 : MULTIMODULE_HAS_SUBTYPE(moduleIdx) ? (uint8_t)2 : (uint8_t)1
|
||||
#define MULTIMODULE_SUBTYPE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? MULTIMODULE_RFPROTO_COLUMNS(moduleIdx) : HIDDEN_ROW,
|
||||
#define MULTIMODULE_HASOPTIONS(moduleIdx) (getMultiProtocolDefinition(moduleIdx)->optionsstr != nullptr)
|
||||
#define MULTIMODULE_OPTIONS_ROW(moduleIdx) (isModuleMultimodule(moduleIdx) && MULTIMODULE_HASOPTIONS(g_model.moduleData[moduleIdx].getMultiProtocol(true))) ? (uint8_t) 0: HIDDEN_ROW
|
||||
#define MULTIMODULE_OPTIONS_ROW(moduleIdx) (isModuleMultimodule(moduleIdx) && MULTIMODULE_HASOPTIONS(moduleIdx)) ? (uint8_t) 0: HIDDEN_ROW
|
||||
|
||||
#else
|
||||
#define MULTIMODULE_STATUS_ROWS(moduleIdx)
|
||||
|
@ -212,7 +269,7 @@ inline uint8_t MULTIMODULE_RFPROTO_COLUMNS(uint8_t moduleIdx)
|
|||
|
||||
#define FAILSAFE_ROWS(moduleIdx) isModuleFailsafeAvailable(moduleIdx) ? (g_model.moduleData[moduleIdx].failsafeMode==FAILSAFE_CUSTOM ? (uint8_t)1 : (uint8_t)0) : HIDDEN_ROW
|
||||
#define MODULE_OPTION_ROW(moduleIdx) (isModuleR9MNonAccess(moduleIdx) || isModuleSBUS(moduleIdx) ? TITLE_ROW : MULTIMODULE_OPTIONS_ROW(moduleIdx))
|
||||
#define MODULE_POWER_ROW(moduleIdx) (isModuleMultimodule(moduleIdx) || isModuleR9MNonAccess(moduleIdx)) ? (isModuleR9MLiteNonPro(moduleIdx) ? (isModuleR9M_FCC_VARIANT(moduleIdx) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW
|
||||
#define MODULE_POWER_ROW(moduleIdx) (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) || isModuleR9MNonAccess(moduleIdx)) ? (isModuleR9MLiteNonPro(moduleIdx) ? (isModuleR9M_FCC_VARIANT(moduleIdx) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW
|
||||
|
||||
void editStickHardwareSettings(coord_t x, coord_t y, int idx, event_t event, LcdFlags flags);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ bool isBootloader(const char * filename)
|
|||
uint8_t buffer[1024];
|
||||
UINT count;
|
||||
|
||||
if (f_read(&file, buffer, 1024, &count) != FR_OK || count != 1024) {
|
||||
if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK || count != sizeof(buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -47,18 +47,18 @@ void bootloaderFlash(const char * filename)
|
|||
unlockFlash();
|
||||
}
|
||||
|
||||
for (int i=0; i<BOOTLOADER_SIZE; i+=1024) {
|
||||
watchdogSuspend(100/*1s*/);
|
||||
if (f_read(&file, buffer, 1024, &count) != FR_OK || count != 1024) {
|
||||
for (int i = 0; i < BOOTLOADER_SIZE; i += 1024) {
|
||||
watchdogSuspend(1000/*10s*/);
|
||||
if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK || count != sizeof(buffer)) {
|
||||
POPUP_WARNING(STR_SDCARD_ERROR);
|
||||
break;
|
||||
}
|
||||
if (i==0 && !isBootloaderStart(buffer)) {
|
||||
if (i == 0 && !isBootloaderStart(buffer)) {
|
||||
POPUP_WARNING(STR_INCOMPATIBLE);
|
||||
break;
|
||||
}
|
||||
for (int j=0; j<1024; j+=FLASH_PAGESIZE) {
|
||||
flashWrite(CONVERT_UINT_PTR(FIRMWARE_ADDRESS+i+j), (uint32_t *)(buffer+j));
|
||||
for (int j = 0; j < 1024; j += FLASH_PAGESIZE) {
|
||||
flashWrite(CONVERT_UINT_PTR(FIRMWARE_ADDRESS + i + j), CONVERT_UINT_PTR(buffer + j));
|
||||
}
|
||||
#if !defined(COLORLCD)
|
||||
drawProgressScreen("Bootloader", STR_WRITING, i, BOOTLOADER_SIZE);
|
||||
|
@ -70,6 +70,8 @@ void bootloaderFlash(const char * filename)
|
|||
#endif
|
||||
}
|
||||
|
||||
watchdogSuspend(0);
|
||||
|
||||
if (unlocked) {
|
||||
lockFlash();
|
||||
unlocked = 0;
|
||||
|
|
|
@ -102,7 +102,7 @@ bool FrskyDeviceFirmwareUpdate::readBuffer(uint8_t * buffer, uint8_t count, uint
|
|||
{
|
||||
watchdogSuspend(timeout);
|
||||
|
||||
switch(module) {
|
||||
switch (module) {
|
||||
case INTERNAL_MODULE:
|
||||
{
|
||||
uint32_t elapsed = 0;
|
||||
|
@ -177,8 +177,8 @@ const uint8_t * FrskyDeviceFirmwareUpdate::readFrame(uint32_t timeout)
|
|||
{
|
||||
RTOS_WAIT_MS(1);
|
||||
|
||||
switch(module) {
|
||||
#if defined(INTMODULE_USART) && !(defined(PCBXLITE) && !defined(PCBXLITES))
|
||||
switch (module) {
|
||||
#if defined(INTERNAL_MODULE_PXX2)
|
||||
case INTERNAL_MODULE:
|
||||
return readFullDuplexFrame(intmoduleFifo, timeout);
|
||||
#endif
|
||||
|
@ -236,8 +236,8 @@ void FrskyDeviceFirmwareUpdate::sendFrame()
|
|||
}
|
||||
}
|
||||
|
||||
switch(module) {
|
||||
#if defined(INTMODULE_USART) && !(defined(PCBXLITE) && !defined(PCBXLITES))
|
||||
switch (module) {
|
||||
#if defined(INTERNAL_MODULE_PXX2)
|
||||
case INTERNAL_MODULE:
|
||||
return intmoduleSendBuffer(outputTelemetryBuffer.data, ptr - outputTelemetryBuffer.data);
|
||||
#endif
|
||||
|
@ -332,10 +332,7 @@ const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename, P
|
|||
#endif
|
||||
|
||||
switch (module) {
|
||||
#if defined(INTMODULE_USART) && !(defined(PCBXLITE) && !defined(PCBXLITES))
|
||||
// on XLite we don't use TX + RX but the S.PORT line
|
||||
// this ifdef can be removed if we use .frsk instead of .frk
|
||||
// theorically it should be possible to use an ISRM module in an XLite
|
||||
#if defined(INTERNAL_MODULE_PXX2)
|
||||
case INTERNAL_MODULE:
|
||||
intmoduleSerialStart(57600, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b);
|
||||
break;
|
||||
|
@ -496,7 +493,7 @@ const char * FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename, Pro
|
|||
progressHandler(getBasename(filename), STR_DEVICE_RESET, 0, 0);
|
||||
|
||||
/* wait 2s off */
|
||||
watchdogSuspend(2000);
|
||||
watchdogSuspend(1000 /*10s*/);
|
||||
RTOS_WAIT_MS(2000);
|
||||
|
||||
const char * result = doFlashFirmware(filename, progressHandler);
|
||||
|
@ -512,12 +509,14 @@ const char * FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename, Pro
|
|||
POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
INTERNAL_MODULE_OFF();
|
||||
#endif
|
||||
EXTERNAL_MODULE_OFF();
|
||||
SPORT_UPDATE_POWER_OFF();
|
||||
|
||||
/* wait 2s off */
|
||||
watchdogSuspend(2000);
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(2000);
|
||||
telemetryClearFifo();
|
||||
|
||||
|
@ -550,7 +549,7 @@ const char * FrskyChipFirmwareUpdate::waitAnswer(uint8_t & status)
|
|||
uint8_t buffer[12];
|
||||
for (uint8_t i = 0; i < sizeof(buffer); i++) {
|
||||
uint32_t retry = 0;
|
||||
while(1) {
|
||||
while (true) {
|
||||
if (telemetryGetByte(&buffer[i])) {
|
||||
if ((i == 0 && buffer[0] != 0x7F) ||
|
||||
(i == 1 && buffer[1] != 0xFE) ||
|
||||
|
@ -573,6 +572,10 @@ const char * FrskyChipFirmwareUpdate::waitAnswer(uint8_t & status)
|
|||
|
||||
const char * FrskyChipFirmwareUpdate::startBootloader()
|
||||
{
|
||||
sportSendByte(0x03);
|
||||
RTOS_WAIT_MS(20);
|
||||
sportSendByte(0x02);
|
||||
RTOS_WAIT_MS(20);
|
||||
sportSendByte(0x01);
|
||||
|
||||
for (uint8_t i = 0; i < 30; i++)
|
||||
|
@ -583,6 +586,7 @@ const char * FrskyChipFirmwareUpdate::startBootloader()
|
|||
sportSendByte(0x7F);
|
||||
}
|
||||
|
||||
RTOS_WAIT_MS(20);
|
||||
sportSendByte(0xFA);
|
||||
|
||||
/*for (uint8_t i=0; i < 30; i++)
|
||||
|
@ -753,7 +757,7 @@ const char * FrskyChipFirmwareUpdate::flashFirmware(const char * filename, Progr
|
|||
|
||||
if (wait) {
|
||||
/* wait 2s off */
|
||||
watchdogSuspend(2000);
|
||||
watchdogSuspend(1000 /*10s*/);
|
||||
RTOS_WAIT_MS(2000);
|
||||
}
|
||||
|
||||
|
@ -773,7 +777,7 @@ const char * FrskyChipFirmwareUpdate::flashFirmware(const char * filename, Progr
|
|||
}
|
||||
|
||||
/* wait 2s off */
|
||||
watchdogSuspend(2000);
|
||||
watchdogSuspend(1000 /*10s*/);
|
||||
RTOS_WAIT_MS(2000);
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
|
|
|
@ -28,7 +28,7 @@ class ModuleFifo : public Fifo<uint8_t, PXX2_FRAME_MAXLENGTH> {
|
|||
public:
|
||||
bool getFrame(uint8_t * frame)
|
||||
{
|
||||
while (1) {
|
||||
while (true) {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -33,20 +33,21 @@ class MultiFirmwareUpdateDriver
|
|||
const char* flashFirmware(FIL* file, const char* label) const;
|
||||
|
||||
protected:
|
||||
virtual void init() const = 0;
|
||||
virtual void moduleOn() const = 0;
|
||||
virtual void init(bool inverted) const = 0;
|
||||
virtual bool getByte(uint8_t& byte) const = 0;
|
||||
virtual void sendByte(uint8_t byte) const = 0;
|
||||
virtual void clear() const = 0;
|
||||
virtual void deinit() const {}
|
||||
virtual void deinit(bool inverted) const {}
|
||||
|
||||
private:
|
||||
bool getRxByte(uint8_t& byte) const;
|
||||
bool checkRxByte(uint8_t byte) const;
|
||||
const char * waitForInitialSync() const;
|
||||
const char * waitForInitialSync(bool& inverted) const;
|
||||
const char * getDeviceSignature(uint8_t* signature) const;
|
||||
const char * loadAddress(uint32_t offset) const;
|
||||
const char * progPage(uint8_t* buffer, uint16_t size) const;
|
||||
void leaveProgMode() const;
|
||||
void leaveProgMode(bool inverted) const;
|
||||
};
|
||||
|
||||
#if defined(INTERNAL_MODULE_MULTI)
|
||||
|
@ -57,9 +58,13 @@ class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver
|
|||
MultiInternalUpdateDriver() {}
|
||||
|
||||
protected:
|
||||
void init() const override
|
||||
void moduleOn() const override
|
||||
{
|
||||
INTERNAL_MODULE_ON();
|
||||
}
|
||||
|
||||
void init(bool inverted) const override
|
||||
{
|
||||
intmoduleSerialStart(57600, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b);
|
||||
}
|
||||
|
||||
|
@ -78,7 +83,7 @@ class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver
|
|||
intmoduleFifo.clear();
|
||||
}
|
||||
|
||||
void deinit() const override
|
||||
void deinit(bool inverted) const override
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
@ -88,13 +93,18 @@ static const MultiInternalUpdateDriver multiInternalUpdateDriver;
|
|||
|
||||
#endif
|
||||
|
||||
class MultiExternalSoftSerialUpdateDriver: public MultiFirmwareUpdateDriver
|
||||
class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver
|
||||
{
|
||||
public:
|
||||
MultiExternalSoftSerialUpdateDriver() {}
|
||||
MultiExternalUpdateDriver() {}
|
||||
|
||||
protected:
|
||||
void init() const override
|
||||
void moduleOn() const override
|
||||
{
|
||||
EXTERNAL_MODULE_ON();
|
||||
}
|
||||
|
||||
void init(bool inverted) const override
|
||||
{
|
||||
#if !defined(EXTMODULE_USART)
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
@ -106,8 +116,10 @@ class MultiExternalSoftSerialUpdateDriver: public MultiFirmwareUpdateDriver
|
|||
GPIO_Init(EXTMODULE_TX_GPIO, &GPIO_InitStructure);
|
||||
#endif
|
||||
|
||||
EXTERNAL_MODULE_ON();
|
||||
telemetryPortInvertedInit(57600);
|
||||
if (inverted)
|
||||
telemetryPortInvertedInit(57600);
|
||||
else
|
||||
telemetryPortInit(57600, TELEMETRY_SERIAL_DEFAULT);
|
||||
}
|
||||
|
||||
bool getByte(uint8_t& byte) const override
|
||||
|
@ -125,14 +137,18 @@ class MultiExternalSoftSerialUpdateDriver: public MultiFirmwareUpdateDriver
|
|||
telemetryClearFifo();
|
||||
}
|
||||
|
||||
void deinit() const override
|
||||
void deinit(bool inverted) const override
|
||||
{
|
||||
telemetryPortInvertedInit(0);
|
||||
if (inverted)
|
||||
telemetryPortInvertedInit(0);
|
||||
else
|
||||
telemetryPortInit(0, 0);
|
||||
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
static const MultiExternalSoftSerialUpdateDriver multiExternalSoftSerialUpdateDriver;
|
||||
static const MultiExternalUpdateDriver multiExternalUpdateDriver;
|
||||
|
||||
bool MultiFirmwareUpdateDriver::getRxByte(uint8_t& byte) const
|
||||
{
|
||||
|
@ -159,19 +175,27 @@ bool MultiFirmwareUpdateDriver::checkRxByte(uint8_t byte) const
|
|||
return getRxByte(rxchar) ? rxchar == byte : false;
|
||||
}
|
||||
|
||||
const char * MultiFirmwareUpdateDriver::waitForInitialSync() const
|
||||
const char * MultiFirmwareUpdateDriver::waitForInitialSync(bool& inverted) const
|
||||
{
|
||||
uint8_t byte;
|
||||
int retries = 1000;
|
||||
int retries = 200;
|
||||
|
||||
clear();
|
||||
do {
|
||||
|
||||
// Invert at half-time
|
||||
if (retries == 100) {
|
||||
deinit(inverted);
|
||||
inverted = !inverted;
|
||||
init(inverted);
|
||||
}
|
||||
|
||||
// Send sync request
|
||||
sendByte(STK_GET_SYNC);
|
||||
sendByte(CRC_EOP);
|
||||
|
||||
getRxByte(byte);
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
|
||||
} while((byte != STK_INSYNC) && --retries);
|
||||
|
||||
|
@ -195,6 +219,7 @@ const char * MultiFirmwareUpdateDriver::getDeviceSignature(uint8_t* signature) c
|
|||
// Read signature
|
||||
sendByte(STK_READ_SIGN);
|
||||
sendByte(CRC_EOP);
|
||||
clear();
|
||||
|
||||
if (!checkRxByte(STK_INSYNC))
|
||||
return "NoSync";
|
||||
|
@ -245,7 +270,7 @@ const char * MultiFirmwareUpdateDriver::progPage(uint8_t* buffer, uint16_t size)
|
|||
uint8_t retries = 4;
|
||||
do {
|
||||
getRxByte(byte);
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
} while(!byte && --retries);
|
||||
|
||||
if (!retries || (byte != STK_OK))
|
||||
|
@ -254,35 +279,38 @@ const char * MultiFirmwareUpdateDriver::progPage(uint8_t* buffer, uint16_t size)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void MultiFirmwareUpdateDriver::leaveProgMode() const
|
||||
void MultiFirmwareUpdateDriver::leaveProgMode(bool inverted) const
|
||||
{
|
||||
sendByte(STK_LEAVE_PROGMODE);
|
||||
sendByte(CRC_EOP);
|
||||
|
||||
// eat last sync byte
|
||||
checkRxByte(STK_INSYNC);
|
||||
deinit();
|
||||
deinit(inverted);
|
||||
}
|
||||
|
||||
const char * MultiFirmwareUpdateDriver::flashFirmware(FIL* file, const char* label) const
|
||||
{
|
||||
const char* result = nullptr;
|
||||
init();
|
||||
moduleOn();
|
||||
|
||||
bool inverted = true; //false; // true
|
||||
init(inverted);
|
||||
|
||||
/* wait 500ms for power on */
|
||||
watchdogSuspend(500);
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(500);
|
||||
|
||||
result = waitForInitialSync();
|
||||
result = waitForInitialSync(inverted);
|
||||
if (result) {
|
||||
leaveProgMode();
|
||||
leaveProgMode(inverted);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned char signature[4]; // 3 bytes signature + STK_OK
|
||||
result = getDeviceSignature(signature);
|
||||
if (result) {
|
||||
leaveProgMode();
|
||||
leaveProgMode(inverted);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -291,7 +319,7 @@ const char * MultiFirmwareUpdateDriver::flashFirmware(FIL* file, const char* lab
|
|||
uint32_t writeOffset = 0;
|
||||
|
||||
if (signature[0] != 0x1E) {
|
||||
leaveProgMode();
|
||||
leaveProgMode(inverted);
|
||||
return "Wrong signature";
|
||||
}
|
||||
|
||||
|
@ -341,7 +369,7 @@ const char * MultiFirmwareUpdateDriver::flashFirmware(FIL* file, const char* lab
|
|||
#endif
|
||||
}
|
||||
|
||||
leaveProgMode();
|
||||
leaveProgMode(inverted);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -492,7 +520,7 @@ bool multiFlashFirmware(uint8_t moduleIdx, const char * filename)
|
|||
}
|
||||
}
|
||||
|
||||
const MultiFirmwareUpdateDriver* driver = &multiExternalSoftSerialUpdateDriver;
|
||||
const MultiFirmwareUpdateDriver* driver = &multiExternalUpdateDriver;
|
||||
#if defined(INTERNAL_MODULE_MULTI)
|
||||
if (moduleIdx == INTERNAL_MODULE)
|
||||
driver = &multiInternalUpdateDriver;
|
||||
|
@ -517,7 +545,7 @@ bool multiFlashFirmware(uint8_t moduleIdx, const char * filename)
|
|||
#endif
|
||||
|
||||
/* wait 2s off */
|
||||
watchdogSuspend(2000);
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(2000);
|
||||
|
||||
const char * result = driver->flashFirmware(&file, getBasename(filename));
|
||||
|
@ -534,12 +562,14 @@ bool multiFlashFirmware(uint8_t moduleIdx, const char * filename)
|
|||
POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
INTERNAL_MODULE_OFF();
|
||||
#endif
|
||||
EXTERNAL_MODULE_OFF();
|
||||
SPORT_UPDATE_POWER_OFF();
|
||||
|
||||
/* wait 2s off */
|
||||
watchdogSuspend(2000);
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(2000);
|
||||
|
||||
// reset telemetry protocol
|
||||
|
|
|
@ -76,22 +76,26 @@ class MultiFirmwareInformation {
|
|||
|
||||
bool isMultiExternalFirmware() const
|
||||
{
|
||||
return (boardType == FIRMWARE_MULTI_STM && telemetryInversion == true && optibootSupport == true && bootloaderCheck == true && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY);
|
||||
return (telemetryInversion == true && optibootSupport == true && bootloaderCheck == true && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY);
|
||||
}
|
||||
|
||||
const char * readMultiFirmwareInformation(const char * filename);
|
||||
const char * readMultiFirmwareInformation(FIL * file);
|
||||
|
||||
private:
|
||||
uint8_t boardType;
|
||||
uint8_t optibootSupport;
|
||||
uint8_t bootloaderCheck;
|
||||
uint8_t telemetryType;
|
||||
uint8_t telemetryInversion;
|
||||
bool optibootSupport:1;
|
||||
bool telemetryInversion:1;
|
||||
bool bootloaderCheck:1;
|
||||
uint8_t boardType:2;
|
||||
uint8_t telemetryType:2;
|
||||
bool spare:1;
|
||||
|
||||
/* For future use
|
||||
uint8_t firmwareVersionMajor;
|
||||
uint8_t firmwareVersionMinor;
|
||||
uint8_t firmwareVersionRevision;
|
||||
uint8_t firmwareVersionSubRevision;
|
||||
*/
|
||||
|
||||
const char * readV1Signature(const char * buffer);
|
||||
const char * readV2Signature(const char * buffer);
|
||||
|
|
|
@ -186,7 +186,7 @@ bool waitKeysReleased()
|
|||
#endif
|
||||
|
||||
while (keyDown()) {
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
|
||||
#if !defined(BOOT)
|
||||
if ((get_tmr10ms() - start) >= 300) { // wait no more than 3 seconds
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "stamp.h"
|
||||
#include "lua_api.h"
|
||||
#include "telemetry/frsky.h"
|
||||
#include "telemetry/multi.h"
|
||||
|
||||
#if defined(PCBX12S)
|
||||
#include "lua/lua_exports_x12s.inc" // this line must be after lua headers
|
||||
|
@ -442,7 +443,7 @@ When called without parameters, it will only return the status of the output buf
|
|||
|
||||
static int luaSportTelemetryPush(lua_State * L)
|
||||
{
|
||||
if (telemetryProtocol != PROTOCOL_TELEMETRY_FRSKY_SPORT) {
|
||||
if (!IS_FRSKY_SPORT_PROTOCOL()) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1506,6 +1507,40 @@ static int luaResetGlobalTimer(lua_State * L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*luadoc
|
||||
@function multiBuffer(address[,value])
|
||||
|
||||
This function reads/writes the Multi protocol buffer to interact with a protocol².
|
||||
|
||||
@param address to read/write in the buffer
|
||||
@param (optional): value to write in the buffer
|
||||
|
||||
@retval buffer value (number)
|
||||
|
||||
@status current Introduced in 2.3.2
|
||||
*/
|
||||
#if defined(MULTIMODULE)
|
||||
uint8_t * Multi_Buffer = nullptr;
|
||||
|
||||
static int luaMultiBuffer(lua_State * L)
|
||||
{
|
||||
uint8_t address = luaL_checkunsigned(L, 1);
|
||||
if (!Multi_Buffer)
|
||||
Multi_Buffer = (uint8_t *) malloc(MULTI_BUFFER_SIZE);
|
||||
|
||||
if (!Multi_Buffer || address >= MULTI_BUFFER_SIZE) {
|
||||
lua_pushinteger(L, 0);
|
||||
return 0;
|
||||
}
|
||||
uint16_t value = luaL_optunsigned(L, 2, 0x100);
|
||||
if (value < 0x100) {
|
||||
Multi_Buffer[address] = value;
|
||||
}
|
||||
lua_pushinteger(L, Multi_Buffer[address]);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*luadoc
|
||||
@function serialWrite(str)
|
||||
@param str (string) String to be written to the serial port.
|
||||
|
@ -1586,6 +1621,9 @@ const luaL_Reg opentxLib[] = {
|
|||
#if defined(CROSSFIRE)
|
||||
{ "crossfireTelemetryPop", luaCrossfireTelemetryPop },
|
||||
{ "crossfireTelemetryPush", luaCrossfireTelemetryPush },
|
||||
#endif
|
||||
#if defined(MULTIMODULE)
|
||||
{ "multiBuffer", luaMultiBuffer },
|
||||
#endif
|
||||
{ "serialWrite", luaSerialWrite },
|
||||
{ nullptr, nullptr } /* sentinel */
|
||||
|
|
|
@ -174,8 +174,8 @@ void checkEeprom()
|
|||
#else
|
||||
void checkEeprom()
|
||||
{
|
||||
#if defined(RAMBACKUP)
|
||||
if (TIME_TO_RAMBACKUP()) {
|
||||
#if defined(RTC_BACKUP_RAM) && !defined(SIMU)
|
||||
if (TIME_TO_BACKUP_RAM()) {
|
||||
rambackupWrite();
|
||||
rambackupDirtyMsk = 0;
|
||||
}
|
||||
|
@ -296,6 +296,8 @@ void guiMain(event_t evt)
|
|||
lcdRefreshWait(); // WARNING: make sure no code above this line does any change to the LCD display buffer!
|
||||
#endif
|
||||
|
||||
bool screenshotRequested = (mainRequestFlags & (1u << REQUEST_SCREENSHOT));
|
||||
|
||||
#if defined(LIBOPENUI)
|
||||
mainWindow.run();
|
||||
#else
|
||||
|
@ -305,7 +307,6 @@ void guiMain(event_t evt)
|
|||
// normal GUI from menus
|
||||
const char * warn = warningText;
|
||||
uint8_t menu = popupMenuItemsCount;
|
||||
|
||||
static bool popupDisplayed = false;
|
||||
if (warn || menu) {
|
||||
if (popupDisplayed == false) {
|
||||
|
@ -315,7 +316,7 @@ void guiMain(event_t evt)
|
|||
lcdStoreBackupBuffer();
|
||||
TIME_MEASURE_STOP(storebackup);
|
||||
}
|
||||
if (popupDisplayed == false || evt) {
|
||||
if (popupDisplayed == false || evt || screenshotRequested) {
|
||||
popupDisplayed = lcdRestoreBackupBuffer();
|
||||
if (warn) {
|
||||
DISPLAY_WARNING(evt);
|
||||
|
@ -368,6 +369,11 @@ void guiMain(event_t evt)
|
|||
DEBUG_TIMER_STOP(debugTimerMenus);
|
||||
}
|
||||
|
||||
if (screenshotRequested) {
|
||||
writeScreenshot();
|
||||
mainRequestFlags &= ~(1u << REQUEST_SCREENSHOT);
|
||||
}
|
||||
|
||||
if (refreshNeeded) {
|
||||
DEBUG_TIMER_START(debugTimerLcdRefresh);
|
||||
lcdRefresh();
|
||||
|
@ -376,7 +382,6 @@ void guiMain(event_t evt)
|
|||
#endif
|
||||
}
|
||||
#elif defined(GUI)
|
||||
|
||||
void handleGui(event_t event) {
|
||||
// if Lua standalone, run it and don't clear the screen (Lua will do it)
|
||||
// else if Lua telemetry view, run it and don't clear the screen
|
||||
|
@ -474,6 +479,11 @@ void guiMain(event_t evt)
|
|||
}
|
||||
|
||||
lcdRefresh();
|
||||
|
||||
if (mainRequestFlags & (1 << REQUEST_SCREENSHOT)) {
|
||||
writeScreenshot();
|
||||
mainRequestFlags &= ~(1 << REQUEST_SCREENSHOT);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -507,7 +517,7 @@ void perMain()
|
|||
event_t evt = getEvent(false);
|
||||
#endif
|
||||
|
||||
#if defined(RAMBACKUP)
|
||||
#if defined(RTC_BACKUP_RAM)
|
||||
if (globalData.unexpectedShutdown) {
|
||||
drawFatalErrorScreen(STR_EMERGENCY_MODE);
|
||||
return;
|
||||
|
@ -552,11 +562,6 @@ void perMain()
|
|||
DEBUG_TIMER_STOP(debugTimerGuiMain);
|
||||
#endif
|
||||
|
||||
if (mainRequestFlags & (1 << REQUEST_SCREENSHOT)) {
|
||||
writeScreenshot();
|
||||
mainRequestFlags &= ~(1 << REQUEST_SCREENSHOT);
|
||||
}
|
||||
|
||||
#if defined(PCBX9E) && !defined(SIMU)
|
||||
toplcdRefreshStart();
|
||||
setTopFirstTimer(getValue(MIXSRC_FIRST_TIMER+g_model.toplcdTimer));
|
||||
|
|
|
@ -228,7 +228,7 @@ int16_t applyLimits(uint8_t channel, int32_t value)
|
|||
#endif
|
||||
|
||||
if (isFunctionActive(FUNCTION_TRAINER_CHANNELS) && IS_TRAINER_INPUT_VALID()) {
|
||||
return ppmInput[channel];
|
||||
return ppmInput[channel] * 2;
|
||||
}
|
||||
|
||||
LimitData * lim = limitAddress(channel);
|
||||
|
@ -366,22 +366,22 @@ getvalue_t getValue(mixsrc_t i)
|
|||
#endif
|
||||
|
||||
else if (i <= MIXSRC_LAST_LOGICAL_SWITCH) {
|
||||
return getSwitch(SWSRC_FIRST_LOGICAL_SWITCH+i-MIXSRC_FIRST_LOGICAL_SWITCH) ? 1024 : -1024;
|
||||
return getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + i - MIXSRC_FIRST_LOGICAL_SWITCH) ? 1024 : -1024;
|
||||
}
|
||||
else if (i <= MIXSRC_LAST_TRAINER) {
|
||||
int16_t x = ppmInput[i-MIXSRC_FIRST_TRAINER];
|
||||
if (i<MIXSRC_FIRST_TRAINER+NUM_CAL_PPM) {
|
||||
x -= g_eeGeneral.trainer.calib[i-MIXSRC_FIRST_TRAINER];
|
||||
int16_t x = ppmInput[i - MIXSRC_FIRST_TRAINER];
|
||||
if (i < MIXSRC_FIRST_TRAINER + NUM_CAL_PPM) {
|
||||
x -= g_eeGeneral.trainer.calib[i - MIXSRC_FIRST_TRAINER];
|
||||
}
|
||||
return x*2;
|
||||
return x * 2;
|
||||
}
|
||||
else if (i <= MIXSRC_LAST_CH) {
|
||||
return ex_chans[i-MIXSRC_CH1];
|
||||
return ex_chans[i - MIXSRC_CH1];
|
||||
}
|
||||
|
||||
else if (i <= MIXSRC_LAST_GVAR) {
|
||||
#if defined(GVARS)
|
||||
return GVAR_VALUE(i-MIXSRC_GVAR1, getGVarFlightMode(mixerCurrentFlightMode, i - MIXSRC_GVAR1));
|
||||
return GVAR_VALUE(i - MIXSRC_GVAR1, getGVarFlightMode(mixerCurrentFlightMode, i - MIXSRC_GVAR1));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -399,11 +399,11 @@ getvalue_t getValue(mixsrc_t i)
|
|||
#endif
|
||||
}
|
||||
else if (i <= MIXSRC_LAST_TIMER) {
|
||||
return timersStates[i-MIXSRC_FIRST_TIMER].val;
|
||||
return timersStates[i - MIXSRC_FIRST_TIMER].val;
|
||||
}
|
||||
|
||||
else if (i <= MIXSRC_LAST_TELEM) {
|
||||
if(IS_FAI_FORBIDDEN(i)) {
|
||||
if (IS_FAI_FORBIDDEN(i)) {
|
||||
return 0;
|
||||
}
|
||||
i -= MIXSRC_FIRST_TELEM;
|
||||
|
|
|
@ -115,7 +115,7 @@ void per10ms()
|
|||
|
||||
if (watchdogTimeout) {
|
||||
watchdogTimeout -= 1;
|
||||
wdt_reset(); // Retrigger hardware watchdog
|
||||
WDG_RESET(); // Retrigger hardware watchdog
|
||||
}
|
||||
|
||||
#if defined(GUI)
|
||||
|
@ -869,7 +869,7 @@ static void checkRTCBattery()
|
|||
{
|
||||
if (isVBatBridgeEnabled()) {
|
||||
if (getRTCBatteryVoltage() < 200) {
|
||||
ALERT("BATTERY", STR_WARN_RTC_BATTERY_LOW, AU_ERROR);
|
||||
ALERT(STR_BATTERY, STR_WARN_RTC_BATTERY_LOW, AU_ERROR);
|
||||
}
|
||||
disableVBatBridge();
|
||||
}
|
||||
|
@ -901,7 +901,12 @@ void checkFailsafe()
|
|||
void checkRSSIAlarmsDisabled()
|
||||
{
|
||||
if (g_model.rssiAlarms.disabled) {
|
||||
ALERT(STR_RSSIALARM_WARN, STR_NO_RSSIALARM, AU_ERROR);
|
||||
#if !defined(INTERNAL_MODULE)
|
||||
if (!isModuleMultimoduleDSM2(EXTERNAL_MODULE))
|
||||
#else
|
||||
if (!isModuleMultimoduleDSM2(INTERNAL_MODULE) && !isModuleMultimoduleDSM2(EXTERNAL_MODULE))
|
||||
#endif
|
||||
ALERT(STR_RSSIALARM_WARN, STR_NO_RSSIALARM, AU_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -947,7 +952,7 @@ void checkAll()
|
|||
tmr10ms_t tgtime = get_tmr10ms() + 500;
|
||||
while (tgtime != get_tmr10ms()) {
|
||||
RTOS_WAIT_MS(1);
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1027,6 +1032,8 @@ void checkThrottleStick()
|
|||
#if defined(PWR_BUTTON_PRESS)
|
||||
uint32_t power = pwrCheck();
|
||||
if (power == e_power_off) {
|
||||
drawSleepBitmap();
|
||||
boardOff();
|
||||
break;
|
||||
}
|
||||
else if (power == e_power_press) {
|
||||
|
@ -1044,7 +1051,7 @@ void checkThrottleStick()
|
|||
|
||||
doLoopCommonActions();
|
||||
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
|
||||
RTOS_WAIT_MS(10);
|
||||
}
|
||||
|
@ -1084,7 +1091,7 @@ void alert(const char * title, const char * msg , uint8_t sound)
|
|||
|
||||
doLoopCommonActions();
|
||||
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
|
||||
const uint32_t pwr_check = pwrCheck();
|
||||
if (pwr_check == e_power_off) {
|
||||
|
@ -1906,6 +1913,10 @@ void opentxInit()
|
|||
globalData.unexpectedShutdown = 1;
|
||||
}
|
||||
|
||||
#if defined(RTC_BACKUP_RAM)
|
||||
SET_POWER_REASON(0);
|
||||
#endif
|
||||
|
||||
#if defined(SDCARD)
|
||||
// SDCARD related stuff, only done if not unexpectedShutdown
|
||||
if (!globalData.unexpectedShutdown) {
|
||||
|
@ -1971,7 +1982,7 @@ void opentxInit()
|
|||
|
||||
// handling of storage for radios that have no EEPROM
|
||||
#if !defined(EEPROM)
|
||||
#if defined(RAMBACKUP)
|
||||
#if defined(RTC_BACKUP_RAM) && !defined(SIMU)
|
||||
if (globalData.unexpectedShutdown) {
|
||||
// SDCARD not available, try to restore last model from RAM
|
||||
TRACE("rambackupRestore");
|
||||
|
@ -2027,20 +2038,22 @@ void opentxInit()
|
|||
opentxStart();
|
||||
}
|
||||
|
||||
// TODO Horus does not need this
|
||||
#if !defined(RTC_BACKUP_RAM)
|
||||
if (!g_eeGeneral.unexpectedShutdown) {
|
||||
g_eeGeneral.unexpectedShutdown = 1;
|
||||
storageDirty(EE_GENERAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GUI)
|
||||
lcdSetContrast();
|
||||
#endif
|
||||
|
||||
backlightOn();
|
||||
|
||||
startPulses();
|
||||
|
||||
wdt_enable(WDTO_500MS);
|
||||
WDG_ENABLE(WDG_DURATION);
|
||||
}
|
||||
|
||||
#if defined(SIMU)
|
||||
|
@ -2062,7 +2075,7 @@ int main()
|
|||
|
||||
// G: The WDT remains active after a WDT reset -- at maximum clock speed. So it's
|
||||
// important to disable it before commencing with system initialisation (or
|
||||
// we could put a bunch more wdt_reset()s in. But I don't like that approach
|
||||
// we could put a bunch more WDG_RESET()s in. But I don't like that approach
|
||||
// during boot up.)
|
||||
#if defined(PCBTARANIS)
|
||||
g_eeGeneral.contrast = LCD_CONTRAST_DEFAULT;
|
||||
|
@ -2080,7 +2093,9 @@ int main()
|
|||
#endif
|
||||
|
||||
#if defined(SPLASH) && !defined(STARTUP_ANIMATION)
|
||||
drawSplash();
|
||||
if (!UNEXPECTED_SHUTDOWN()) {
|
||||
drawSplash();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PCBHORUS)
|
||||
|
|
|
@ -586,8 +586,11 @@ void flightReset(uint8_t check=true);
|
|||
|
||||
PACK(struct GlobalData {
|
||||
uint8_t unexpectedShutdown:1;
|
||||
uint8_t externalAntennaEnabled: 1;
|
||||
uint8_t spare:6;
|
||||
uint8_t externalAntennaEnabled:1;
|
||||
uint8_t authenticationCount:2;
|
||||
uint8_t upgradeModulePopup:1;
|
||||
uint8_t internalModuleVersionChecked:1;
|
||||
uint8_t spare:2;
|
||||
});
|
||||
|
||||
extern GlobalData globalData;
|
||||
|
@ -1184,6 +1187,7 @@ union ReusableBuffer
|
|||
uint16_t freqMax;
|
||||
uint16_t freqMin;
|
||||
uint8_t dirty;
|
||||
uint8_t moduleOFF;
|
||||
} spectrumAnalyser;
|
||||
|
||||
struct {
|
||||
|
@ -1214,6 +1218,10 @@ union ReusableBuffer
|
|||
uint8_t maxNameLen;
|
||||
} modelFailsafe;
|
||||
|
||||
struct {
|
||||
ModuleInformation internalModule;
|
||||
} viewMain;
|
||||
|
||||
#if defined(STM32)
|
||||
// Data for the USB mass storage driver. If USB mass storage runs no menu is not allowed to be displayed
|
||||
uint8_t MSC_BOT_Data[MSC_MEDIA_PACKET];
|
||||
|
@ -1363,7 +1371,7 @@ extern uint8_t latencyToggleSwitch;
|
|||
|
||||
inline bool isAsteriskDisplayed()
|
||||
{
|
||||
#if defined(LOG_TELEMETRY) || !defined(WATCHDOG) || defined(DEBUG_LATENCY)
|
||||
#if defined(ASTERISK) || !defined(WATCHDOG) || defined(LOG_TELEMETRY) || defined(DEBUG_LATENCY)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -101,9 +101,8 @@ enum ModuleSubtypeR9M {
|
|||
/* Multi module */
|
||||
|
||||
enum ModuleSubtypeMulti {
|
||||
MODULE_SUBTYPE_MULTI_CUSTOM = -1,
|
||||
MODULE_SUBTYPE_MULTI_FIRST = MODULE_SUBTYPE_MULTI_CUSTOM,
|
||||
MODULE_SUBTYPE_MULTI_FLYSKY=0,
|
||||
MODULE_SUBTYPE_MULTI_FIRST = 0,
|
||||
MODULE_SUBTYPE_MULTI_FLYSKY = MODULE_SUBTYPE_MULTI_FIRST,
|
||||
MODULE_SUBTYPE_MULTI_HUBSAN,
|
||||
MODULE_SUBTYPE_MULTI_FRSKY,
|
||||
MODULE_SUBTYPE_MULTI_HISKY,
|
||||
|
@ -157,8 +156,11 @@ enum ModuleSubtypeMulti {
|
|||
MODULE_SUBTYPE_MULTI_SCANNER,
|
||||
MODULE_SUBTYPE_MULTI_FRSKYX_RX,
|
||||
MODULE_SUBTYPE_MULTI_AFHDS2A_RX,
|
||||
MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_AFHDS2A_RX
|
||||
MODULE_SUBTYPE_MULTI_HOTT,
|
||||
MODULE_SUBTYPE_MULTI_FX816,
|
||||
MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_FX816
|
||||
};
|
||||
#define MODULE_SUBTYPE_MULTI_XN297DP 63-3
|
||||
|
||||
enum MMDSM2Subtypes {
|
||||
MM_RF_DSM2_SUBTYPE_DSM2_22,
|
||||
|
|
|
@ -32,6 +32,43 @@
|
|||
#define CROSSFIRE_CHANNELS_COUNT 16
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
// When using packed, the pointer in here end up not being aligned, which clang and gcc complain about
|
||||
// Keep the order of the fields that the so that the size stays small
|
||||
struct mm_options_strings {
|
||||
static const char* options[];
|
||||
};
|
||||
|
||||
struct mm_protocol_definition {
|
||||
uint8_t protocol;
|
||||
uint8_t maxSubtype;
|
||||
bool failsafe;
|
||||
bool disable_ch_mapping;
|
||||
const char *subTypeString;
|
||||
const char *optionsstr;
|
||||
};
|
||||
|
||||
const mm_protocol_definition *getMultiProtocolDefinition (uint8_t protocol);
|
||||
|
||||
inline uint8_t getMaxMultiSubtype(uint8_t moduleIdx)
|
||||
{
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
const mm_protocol_definition *pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol());
|
||||
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() > MODULE_SUBTYPE_MULTI_LAST) {
|
||||
if (status.isValid())
|
||||
return (status.protocolSubNbr == 0 ? 0 : status.protocolSubNbr - 1);
|
||||
else
|
||||
return 7;
|
||||
}
|
||||
else {
|
||||
return max((uint8_t )(status.protocolSubNbr == 0 ? 0 : status.protocolSubNbr - 1), pdef->maxSubtype);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isModuleMultimodule(uint8_t idx)
|
||||
{
|
||||
return g_model.moduleData[idx].type == MODULE_TYPE_MULTIMODULE;
|
||||
|
@ -39,7 +76,7 @@ inline bool isModuleMultimodule(uint8_t idx)
|
|||
|
||||
inline bool isModuleMultimoduleDSM2(uint8_t idx)
|
||||
{
|
||||
return isModuleMultimodule(idx) && g_model.moduleData[idx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2;
|
||||
return isModuleMultimodule(idx) && g_model.moduleData[idx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2;
|
||||
}
|
||||
#else
|
||||
inline bool isModuleMultimodule(uint8_t)
|
||||
|
@ -341,6 +378,8 @@ inline int8_t sentModuleChannels(uint8_t idx)
|
|||
return CROSSFIRE_CHANNELS_COUNT;
|
||||
else if (isModuleMultimodule(idx) && !isModuleMultimoduleDSM2(idx))
|
||||
return 16;
|
||||
else if (isModuleSBUS(idx))
|
||||
return 16;
|
||||
else
|
||||
return 8 + g_model.moduleData[idx].channelsCount;
|
||||
}
|
||||
|
@ -405,8 +444,14 @@ inline bool isModuleFailsafeAvailable(uint8_t moduleIdx)
|
|||
|
||||
#if defined(MULTIMODULE)
|
||||
if (isModuleMultimodule(moduleIdx)){
|
||||
MultiModuleStatus& status = getMultiModuleStatus(moduleIdx);
|
||||
return status.isValid() && status.supportsFailsafe();
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
if (status.isValid()) {
|
||||
return status.supportsFailsafe();
|
||||
}
|
||||
else {
|
||||
const mm_protocol_definition * pdef = getMultiProtocolDefinition(g_model.moduleData[moduleIdx].getMultiProtocol());
|
||||
return pdef->failsafe;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -428,7 +473,15 @@ inline uint8_t getMaxRxNum(uint8_t idx)
|
|||
|
||||
#if defined(MULTIMODULE)
|
||||
if (isModuleMultimodule(idx))
|
||||
return g_model.moduleData[idx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_OLRS ? 4 : 15;
|
||||
{
|
||||
switch (g_model.moduleData[idx].getMultiProtocol()) {
|
||||
case MODULE_SUBTYPE_MULTI_OLRS:
|
||||
return 4;
|
||||
case MODULE_SUBTYPE_MULTI_BUGS:
|
||||
case MODULE_SUBTYPE_MULTI_BUGS_MINI:
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 63;
|
||||
|
@ -537,4 +590,24 @@ inline void setModuleType(uint8_t moduleIdx, uint8_t moduleType)
|
|||
|
||||
extern bool isExternalAntennaEnabled();
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
inline void resetMultiProtocolsOptions(uint8_t moduleIdx)
|
||||
{
|
||||
if (!isModuleMultimodule(moduleIdx))
|
||||
return;
|
||||
|
||||
// Sensible default for DSM2 (same as for ppm): 7ch@22ms + Autodetect settings enabled
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) {
|
||||
g_model.moduleData[moduleIdx].multi.autoBindMode = 1;
|
||||
}
|
||||
else {
|
||||
g_model.moduleData[moduleIdx].multi.autoBindMode = 0;
|
||||
}
|
||||
g_model.moduleData[moduleIdx].multi.optionValue = 0;
|
||||
g_model.moduleData[moduleIdx].multi.disableTelemetry = 0;
|
||||
g_model.moduleData[moduleIdx].multi.disableMapping = 0;
|
||||
g_model.moduleData[moduleIdx].multi.lowPowerMode = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _MODULES_HELPERS_H_
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "multi.h"
|
||||
|
||||
// for the MULTI protocol definition
|
||||
// see https://github.com/pascallanger/DIY-Multiprotocol-TX-Module
|
||||
|
@ -31,9 +32,59 @@
|
|||
#define MULTI_CHANS 16
|
||||
#define MULTI_CHAN_BITS 11
|
||||
|
||||
static void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe);
|
||||
#define MULTI_NORMAL 0x00
|
||||
#define MULTI_FAILSAFE 0x01
|
||||
#define MULTI_DATA 0x02
|
||||
|
||||
static void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe);
|
||||
void sendChannels(uint8_t moduleIdx);
|
||||
#if defined(LUA)
|
||||
static void sendSport(uint8_t moduleIdx);
|
||||
static void sendHott(uint8_t moduleIdx);
|
||||
#endif
|
||||
|
||||
void multiPatchCustom(uint8_t moduleIdx)
|
||||
{
|
||||
if (g_model.moduleData[moduleIdx].multi.customProto) {
|
||||
uint8_t type = g_model.moduleData[moduleIdx].getMultiProtocol() - 1; // custom where starting at 1, otx list at 0
|
||||
int subtype = g_model.moduleData[moduleIdx].subType;
|
||||
|
||||
g_model.moduleData[moduleIdx].multi.customProto = 0;
|
||||
|
||||
if (type == 2) { // multi PROTO_FRSKYD
|
||||
g_model.moduleData[moduleIdx].subType = 1; // D8
|
||||
return;
|
||||
}
|
||||
else if (type == 14) { // multi PROTO_FRSKYX
|
||||
g_model.moduleData[moduleIdx].setMultiProtocol(2);
|
||||
switch (subtype) {
|
||||
case 0: //D16-16
|
||||
g_model.moduleData[moduleIdx].subType = 0;
|
||||
break;
|
||||
case 1: //D16-8
|
||||
g_model.moduleData[moduleIdx].subType = 2;
|
||||
break;
|
||||
case 2: //EU-16
|
||||
g_model.moduleData[moduleIdx].subType = 4;
|
||||
break;
|
||||
case 3: //EU-8
|
||||
g_model.moduleData[moduleIdx].subType = 5;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (type == 24) { // multi PROTO_FRSKYV
|
||||
g_model.moduleData[moduleIdx].setMultiProtocol(2);
|
||||
g_model.moduleData[moduleIdx].subType = 3;
|
||||
return;
|
||||
}
|
||||
if (type > 14)
|
||||
type -= 1;
|
||||
if (type > 24)
|
||||
type -= 1;
|
||||
g_model.moduleData[moduleIdx].setMultiProtocol(type);
|
||||
}
|
||||
}
|
||||
|
||||
static void sendMulti(uint8_t moduleIdx, uint8_t b)
|
||||
{
|
||||
|
@ -46,22 +97,6 @@ static void sendMulti(uint8_t moduleIdx, uint8_t b)
|
|||
sendByteSbus(b);
|
||||
}
|
||||
|
||||
static void sendSetupFrame(uint8_t moduleIdx)
|
||||
{
|
||||
// Old multi firmware will mark config messsages as invalid frame and throw them away
|
||||
sendMulti(moduleIdx, 'M');
|
||||
sendMulti(moduleIdx, 'P');
|
||||
sendMulti(moduleIdx, 0x80); // Module Configuration
|
||||
sendMulti(moduleIdx, 1); // 1 byte data
|
||||
uint8_t config = 0x01 | 0x02; // inversion + multi_telemetry
|
||||
#if !defined(PPM_PIN_SERIAL)
|
||||
// TODO why PPM_PIN_SERIAL would change MULTI protocol?
|
||||
config |= 0x04; // input synchronsisation
|
||||
#endif
|
||||
|
||||
sendMulti(moduleIdx, config);
|
||||
}
|
||||
|
||||
static void sendFailsafeChannels(uint8_t moduleIdx)
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
|
@ -95,21 +130,64 @@ static void sendFailsafeChannels(uint8_t moduleIdx)
|
|||
void setupPulsesMulti(uint8_t moduleIdx)
|
||||
{
|
||||
static int counter[2] = {0,0}; //TODO
|
||||
static uint8_t invert[2] = {0x00, //internal
|
||||
#if defined(PCBTARANIS) || defined(PCBHORUS)
|
||||
0x08 //external
|
||||
#else
|
||||
0x00 //external
|
||||
#endif
|
||||
};
|
||||
uint8_t type=MULTI_NORMAL;
|
||||
|
||||
// Failsafe packets
|
||||
if (counter[moduleIdx] % 1000 == 0 && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_RECEIVER) {
|
||||
type|=MULTI_FAILSAFE;
|
||||
}
|
||||
|
||||
// Invert telemetry if needed
|
||||
if (invert[moduleIdx] & 0x80 && !g_model.moduleData[moduleIdx].multi.disableTelemetry) {
|
||||
if (getMultiModuleStatus(moduleIdx).isValid()) {
|
||||
invert[moduleIdx] &= 0x08; // Telemetry received, stop searching
|
||||
}
|
||||
else if (counter[moduleIdx] % 100 == 0) {
|
||||
invert[moduleIdx] ^= 0x08; // Try inverting telemetry
|
||||
}
|
||||
}
|
||||
|
||||
// Every 1000 cycles (=9s) send a config packet that configures the multimodule (inversion, telemetry type)
|
||||
counter[moduleIdx]++;
|
||||
if (counter[moduleIdx] % 1000 == 500) {
|
||||
sendSetupFrame(moduleIdx);
|
||||
}
|
||||
else if (counter[moduleIdx] % 1000 == 0 && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_RECEIVER) {
|
||||
sendFrameProtocolHeader(moduleIdx, true);
|
||||
|
||||
// Send header
|
||||
sendFrameProtocolHeader(moduleIdx, type&MULTI_FAILSAFE);
|
||||
|
||||
// Send channels
|
||||
if (type & MULTI_FAILSAFE)
|
||||
sendFailsafeChannels(moduleIdx);
|
||||
}
|
||||
else {
|
||||
// Normal Frame
|
||||
sendFrameProtocolHeader(moduleIdx, false);
|
||||
else
|
||||
sendChannels(moduleIdx);
|
||||
|
||||
// Multi V1.3.X.X -> Send byte 26, Protocol (bits 7 & 6), RX_Num (bits 5 & 4), invert, not used, disable telemetry, disable mapping
|
||||
sendMulti(moduleIdx, (uint8_t) (((g_model.moduleData[moduleIdx].getMultiProtocol()+3)&0xC0)
|
||||
| (g_model.header.modelId[moduleIdx] & 0x30)
|
||||
| (invert[moduleIdx] & 0x08)
|
||||
//| 0x04 // Future use
|
||||
| (g_model.moduleData[moduleIdx].multi.disableTelemetry << 1)
|
||||
| g_model.moduleData[moduleIdx].multi.disableMapping));
|
||||
|
||||
// Multi V1.3.X.X -> Send protocol additional data: max 9 bytes
|
||||
#if defined(LUA)
|
||||
if (getMultiModuleStatus(moduleIdx).isValid()) {
|
||||
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
|
||||
if (status.minor >= 3 && !(status.flags & 0x80)) { //Version 1.3.x.x or more and Buffer not full
|
||||
// SPort send
|
||||
if (IS_D16_MULTI(moduleIdx) && outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && outputTelemetryBuffer.size) {
|
||||
sendSport(moduleIdx); //8 bytes of additional data
|
||||
}
|
||||
else if (IS_HOTT_MULTI(moduleIdx)) {
|
||||
sendHott(moduleIdx); //1 byte of additional data
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void setupPulsesMultiExternalModule()
|
||||
|
@ -166,7 +244,7 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe)
|
|||
{// byte 1+2, protocol information
|
||||
|
||||
// Our enumeration starts at 0
|
||||
int type = g_model.moduleData[moduleIdx].getMultiProtocol(false) + 1;
|
||||
int type = g_model.moduleData[moduleIdx].getMultiProtocol() + 1;
|
||||
int subtype = g_model.moduleData[moduleIdx].subType;
|
||||
int8_t optionValue = g_model.moduleData[moduleIdx].multi.optionValue;
|
||||
|
||||
|
@ -186,16 +264,18 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe)
|
|||
protoByte |= MULTI_SEND_RANGECHECK;
|
||||
|
||||
// rfProtocol
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) {
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2) {
|
||||
|
||||
// Autobinding should always be done in DSMX 11ms
|
||||
if (g_model.moduleData[moduleIdx].multi.autoBindMode && moduleState[moduleIdx].mode == MODULE_MODE_BIND)
|
||||
subtype = MM_RF_DSM2_SUBTYPE_AUTO;
|
||||
|
||||
// Multi module in DSM mode wants the number of channels to be used as option value
|
||||
optionValue = sentModuleChannels(moduleIdx);
|
||||
|
||||
}
|
||||
if (optionValue)
|
||||
optionValue = 0x80 | sentModuleChannels(moduleIdx); // Max throw
|
||||
else
|
||||
optionValue = sentModuleChannels(moduleIdx);
|
||||
}
|
||||
|
||||
// 15 for Multimodule is FrskyX or D16 which we map as a subprotocol of 3 (FrSky)
|
||||
// all protos > frskyx are therefore also off by one
|
||||
|
@ -206,7 +286,7 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe)
|
|||
if (type >= 25)
|
||||
type = type + 1;
|
||||
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_FRSKY) {
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) {
|
||||
if (subtype == MM_RF_FRSKY_SUBTYPE_D8) {
|
||||
//D8
|
||||
type = 3;
|
||||
|
@ -230,28 +310,27 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe)
|
|||
|
||||
// Set the highest bit of option byte in AFHDS2A protocol to instruct MULTI to passthrough telemetry bytes instead
|
||||
// of sending Frsky D telemetry
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
optionValue = optionValue | 0x80;
|
||||
|
||||
// For custom protocol send unmodified type byte
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MM_RF_CUSTOM_SELECTED)
|
||||
type = g_model.moduleData[moduleIdx].getMultiProtocol(false);
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MM_RF_CUSTOM_SELECTED)
|
||||
type = g_model.moduleData[moduleIdx].getMultiProtocol();
|
||||
|
||||
|
||||
uint8_t headerByte = 0x54;
|
||||
uint8_t headerByte = 0x55;
|
||||
// header, byte 0, 0x55 for proto 0-31, 0x54 for proto 32-63
|
||||
if (type & 0x20)
|
||||
headerByte &= 0xFE;
|
||||
|
||||
if (failsafe)
|
||||
headerByte = 0x56;
|
||||
|
||||
// header, byte 0, 0x55 for proto 0-31 0x54 for 32-63
|
||||
if (type <= 31)
|
||||
sendMulti(moduleIdx, headerByte+1);
|
||||
else
|
||||
sendMulti(moduleIdx, headerByte);
|
||||
headerByte |= 0x02;
|
||||
|
||||
sendMulti(moduleIdx, headerByte);
|
||||
|
||||
// protocol byte
|
||||
protoByte |= (type & 0x1f);
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(true) != MODULE_SUBTYPE_MULTI_DSM2)
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() != MODULE_SUBTYPE_MULTI_DSM2)
|
||||
protoByte |= (g_model.moduleData[moduleIdx].multi.autoBindMode << 6);
|
||||
|
||||
sendMulti(moduleIdx, protoByte);
|
||||
|
@ -265,3 +344,32 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe)
|
|||
// byte 3
|
||||
sendMulti(moduleIdx, (uint8_t) optionValue);
|
||||
}
|
||||
|
||||
#if defined(LUA)
|
||||
void sendSport(uint8_t moduleIdx)
|
||||
{
|
||||
// example: B7 30 30 0C 80 00 00 00 13
|
||||
uint8_t j=0;
|
||||
|
||||
// unstuff and remove crc
|
||||
for (uint8_t i = 0; i < outputTelemetryBuffer.size - 1 && j < 8; i++, j++) {
|
||||
if (outputTelemetryBuffer.data[i] == BYTE_STUFF) {
|
||||
i++;
|
||||
sendMulti(moduleIdx, outputTelemetryBuffer.data[i] ^ STUFF_MASK);
|
||||
}
|
||||
else {
|
||||
sendMulti(moduleIdx, outputTelemetryBuffer.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
outputTelemetryBuffer.reset(); // empty buffer
|
||||
}
|
||||
|
||||
void sendHott(uint8_t moduleIdx)
|
||||
{
|
||||
if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0 && Multi_Buffer[5] >= 0xD7 && Multi_Buffer[5] <= 0xDF) {
|
||||
// HoTT Lua script is running
|
||||
sendMulti(moduleIdx, Multi_Buffer[5]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include "pulses_common.h"
|
||||
|
||||
void multiPatchCustom(uint8_t moduleIdx);
|
||||
|
||||
class UartMultiPulses: public DataBuffer<uint8_t, 64>
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -307,6 +307,9 @@ static void enablePulsesInternalModule(uint8_t protocol)
|
|||
#if defined(PXX2)
|
||||
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
|
||||
intmoduleSerialStart(PXX2_HIGHSPEED_BAUDRATE, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b);
|
||||
#if defined(HARDWARE_INTERNAL_MODULE) && defined(INTERNAL_MODULE_PXX2) && defined(ACCESS_LIB)
|
||||
globalData.authenticationCount = 0;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ class BindInformation {
|
|||
|
||||
class OtaUpdateInformation: public BindInformation {
|
||||
public:
|
||||
char filename[32+1];
|
||||
char filename[_MAX_LFN + 1];
|
||||
uint32_t address;
|
||||
};
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "pulses/pxx1.h"
|
||||
|
||||
template <class PxxTransport>
|
||||
uint8_t Pxx1Pulses<PxxTransport>::addFlag1(uint8_t module)
|
||||
void Pxx1Pulses<PxxTransport>::addFlag1(uint8_t module, uint8_t sendFailsafe)
|
||||
{
|
||||
uint8_t flag1 = (g_model.moduleData[module].subType << 6);
|
||||
if (moduleState[module].mode == MODULE_MODE_BIND) {
|
||||
|
@ -31,21 +31,10 @@ uint8_t Pxx1Pulses<PxxTransport>::addFlag1(uint8_t module)
|
|||
else if (moduleState[module].mode == MODULE_MODE_RANGECHECK) {
|
||||
flag1 |= PXX_SEND_RANGECHECK;
|
||||
}
|
||||
else {
|
||||
bool failsafeNeeded = g_model.moduleData[module].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[module].failsafeMode != FAILSAFE_RECEIVER;
|
||||
if (moduleState[module].counter-- == 0) {
|
||||
// counter is also used for knowing if the frame is odd / even
|
||||
moduleState[module].counter = 1000;
|
||||
if (failsafeNeeded) {
|
||||
flag1 |= PXX_SEND_FAILSAFE;
|
||||
}
|
||||
}
|
||||
if (failsafeNeeded && moduleState[module].counter == 0 && g_model.moduleData[module].channelsCount > 0) {
|
||||
flag1 |= PXX_SEND_FAILSAFE;
|
||||
}
|
||||
else if (sendFailsafe && g_model.moduleData[module].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[module].failsafeMode != FAILSAFE_RECEIVER) {
|
||||
flag1 |= PXX_SEND_FAILSAFE;
|
||||
}
|
||||
PxxTransport::addByte(flag1);
|
||||
return flag1;
|
||||
}
|
||||
|
||||
template <class PxxTransport>
|
||||
|
@ -72,6 +61,7 @@ void Pxx1Pulses<PxxTransport>::addExtraFlags(uint8_t module)
|
|||
if (module == EXTERNAL_MODULE && isSportLineUsedByInternalModule()) {
|
||||
extraFlags |= (1 << 5);
|
||||
}
|
||||
|
||||
PxxTransport::addByte(extraFlags);
|
||||
}
|
||||
|
||||
|
@ -146,7 +136,7 @@ void Pxx1Pulses<PxxTransport>::addChannels(uint8_t port, uint8_t sendFailsafe, u
|
|||
}
|
||||
|
||||
template <class PxxTransport>
|
||||
void Pxx1Pulses<PxxTransport>::add8ChannelsFrame(uint8_t module, uint8_t sendUpperChannels)
|
||||
void Pxx1Pulses<PxxTransport>::add8ChannelsFrame(uint8_t module, uint8_t sendUpperChannels, uint8_t sendFailsafe)
|
||||
{
|
||||
PxxTransport::initCrc();
|
||||
|
||||
|
@ -157,13 +147,13 @@ void Pxx1Pulses<PxxTransport>::add8ChannelsFrame(uint8_t module, uint8_t sendUpp
|
|||
PxxTransport::addByte(g_model.header.modelId[module]);
|
||||
|
||||
// Flag1
|
||||
uint8_t flag1 = addFlag1(module);
|
||||
addFlag1(module, sendFailsafe);
|
||||
|
||||
// Flag2
|
||||
PxxTransport::addByte(0);
|
||||
|
||||
// Channels
|
||||
addChannels(module, flag1 & PXX_SEND_FAILSAFE, sendUpperChannels);
|
||||
addChannels(module, sendFailsafe, sendUpperChannels);
|
||||
|
||||
// Extra flags
|
||||
addExtraFlags(module);
|
||||
|
@ -181,24 +171,42 @@ void Pxx1Pulses<PxxTransport>::add8ChannelsFrame(uint8_t module, uint8_t sendUpp
|
|||
template <class PxxTransport>
|
||||
void Pxx1Pulses<PxxTransport>::setupFrame(uint8_t module)
|
||||
{
|
||||
uint8_t sendUpperChannels = 0;
|
||||
uint8_t sendFailsafe = 0;
|
||||
|
||||
PxxTransport::initFrame(PXX_PULSES_PERIOD);
|
||||
|
||||
#if defined(PXX_FREQUENCY_HIGH)
|
||||
if (moduleState[module].protocol == PROTOCOL_CHANNELS_PXX1_SERIAL) {
|
||||
add8ChannelsFrame(module, 0);
|
||||
if (moduleState[module].counter-- == 0) {
|
||||
sendFailsafe = 1;
|
||||
moduleState[module].counter = 1000;
|
||||
}
|
||||
add8ChannelsFrame(module, 0, sendFailsafe);
|
||||
if (sentModuleChannels(module) > 8) {
|
||||
add8ChannelsFrame(module, 8);
|
||||
add8ChannelsFrame(module, 8, sendFailsafe);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t sendUpperChannels = 0;
|
||||
if (moduleState[module].counter & 0x01) {
|
||||
sendUpperChannels = g_model.moduleData[module].channelsCount;
|
||||
if (sendUpperChannels && moduleState[module].counter == 1) {
|
||||
sendFailsafe = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (moduleState[module].counter == 0) {
|
||||
sendFailsafe = 1;
|
||||
}
|
||||
}
|
||||
|
||||
add8ChannelsFrame(module, sendUpperChannels);
|
||||
add8ChannelsFrame(module, sendUpperChannels, sendFailsafe);
|
||||
|
||||
if (moduleState[module].counter-- == 0) {
|
||||
moduleState[module].counter = 1000;
|
||||
}
|
||||
}
|
||||
|
||||
template class Pxx1Pulses<StandardPxx1Transport<PwmPxxBitTransport> >;
|
||||
|
|
|
@ -163,10 +163,10 @@ class Pxx1Pulses: public PxxTransport
|
|||
PxxTransport::addByteWithoutCrc(Pxx1CrcMixin::crc);
|
||||
}
|
||||
|
||||
uint8_t addFlag1(uint8_t port);
|
||||
void addFlag1(uint8_t port, uint8_t sendFailsafe);
|
||||
void addExtraFlags(uint8_t port);
|
||||
void addChannels(uint8_t port, uint8_t sendFailsafe, uint8_t sendUpperChannels);
|
||||
void add8ChannelsFrame(uint8_t port, uint8_t sendUpperChannels);
|
||||
void add8ChannelsFrame(uint8_t port, uint8_t sendUpperChannels, uint8_t sendFailsafe);
|
||||
};
|
||||
|
||||
typedef Pxx1Pulses<UartPxx1Transport> UartPxx1Pulses;
|
||||
|
|
|
@ -446,7 +446,7 @@ bool Pxx2OtaUpdate::waitStep(uint8_t step, uint8_t timeout)
|
|||
OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation;
|
||||
uint8_t elapsed = 0;
|
||||
|
||||
watchdogSuspend(100);
|
||||
watchdogSuspend(100 /*1s*/);
|
||||
|
||||
while (step != destination->step) {
|
||||
if (elapsed++ > timeout) {
|
||||
|
@ -535,7 +535,7 @@ void Pxx2OtaUpdate::flashFirmware(const char * filename, ProgressHandler progres
|
|||
{
|
||||
pausePulses();
|
||||
|
||||
watchdogSuspend(100);
|
||||
watchdogSuspend(100 /*1s*/);
|
||||
RTOS_WAIT_MS(100);
|
||||
|
||||
moduleState[module].mode = MODULE_MODE_OTA_UPDATE;
|
||||
|
|
|
@ -1,357 +0,0 @@
|
|||
//This file was auto-generated by generate_datacopy.py script on Fri May 10 15:48:58 2019. Do not edit this file!
|
||||
|
||||
|
||||
|
||||
template <class A, class B>
|
||||
void copyCurveRef(A * dest, B * src)
|
||||
{
|
||||
dest->type = src->type;
|
||||
dest->value = src->value;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyMixData(A * dest, B * src)
|
||||
{
|
||||
dest->weight = src->weight;
|
||||
dest->destCh = src->destCh;
|
||||
dest->srcRaw = src->srcRaw;
|
||||
dest->carryTrim = src->carryTrim;
|
||||
dest->mixWarn = src->mixWarn;
|
||||
dest->mltpx = src->mltpx;
|
||||
dest->spare = src->spare;
|
||||
dest->offset = src->offset;
|
||||
dest->swtch = src->swtch;
|
||||
dest->flightModes = src->flightModes;
|
||||
copyCurveRef(&dest->curve, &src->curve);
|
||||
dest->delayUp = src->delayUp;
|
||||
dest->delayDown = src->delayDown;
|
||||
dest->speedUp = src->speedUp;
|
||||
dest->speedDown = src->speedDown;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyExpoData(A * dest, B * src)
|
||||
{
|
||||
dest->mode = src->mode;
|
||||
dest->scale = src->scale;
|
||||
dest->srcRaw = src->srcRaw;
|
||||
dest->carryTrim = src->carryTrim;
|
||||
dest->chn = src->chn;
|
||||
dest->swtch = src->swtch;
|
||||
dest->flightModes = src->flightModes;
|
||||
dest->weight = src->weight;
|
||||
dest->spare = src->spare;
|
||||
dest->offset = src->offset;
|
||||
copyCurveRef(&dest->curve, &src->curve);
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyLimitData(A * dest, B * src)
|
||||
{
|
||||
dest->min = src->min;
|
||||
dest->max = src->max;
|
||||
dest->ppmCenter = src->ppmCenter;
|
||||
dest->offset = src->offset;
|
||||
dest->symetrical = src->symetrical;
|
||||
dest->revert = src->revert;
|
||||
dest->spare = src->spare;
|
||||
dest->curve = src->curve;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyLogicalSwitchData(A * dest, B * src)
|
||||
{
|
||||
dest->func = src->func;
|
||||
dest->v1 = src->v1;
|
||||
dest->v3 = src->v3;
|
||||
dest->andsw = src->andsw;
|
||||
dest->andswtype = src->andswtype;
|
||||
dest->spare = src->spare;
|
||||
dest->v2 = src->v2;
|
||||
dest->delay = src->delay;
|
||||
dest->duration = src->duration;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyCustomFunctionData(A * dest, B * src)
|
||||
{
|
||||
dest->swtch = src->swtch;
|
||||
dest->func = src->func;
|
||||
copyCustomFunctionData_all(&dest->all, &src->all);
|
||||
dest->active = src->active;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copytrim_t(A * dest, B * src)
|
||||
{
|
||||
dest->value = src->value;
|
||||
dest->mode = src->mode;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyFlightModeData(A * dest, B * src)
|
||||
{
|
||||
for (int i=0; i<6; i++) {
|
||||
copytrim_t(&dest->trim[i], &src->trim[i]);
|
||||
}
|
||||
dest->swtch = src->swtch;
|
||||
dest->spare = src->spare;
|
||||
dest->fadeIn = src->fadeIn;
|
||||
dest->fadeOut = src->fadeOut;
|
||||
memcpy(dest->gvars, src->gvars, sizeof(dest->gvars));
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyCurveHeader(A * dest, B * src)
|
||||
{
|
||||
dest->type = src->type;
|
||||
dest->smooth = src->smooth;
|
||||
dest->points = src->points;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyGVarData(A * dest, B * src)
|
||||
{
|
||||
dest->min = src->min;
|
||||
dest->max = src->max;
|
||||
dest->popup = src->popup;
|
||||
dest->prec = src->prec;
|
||||
dest->unit = src->unit;
|
||||
dest->spare = src->spare;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyTimerData(A * dest, B * src)
|
||||
{
|
||||
dest->mode = src->mode;
|
||||
dest->swtch = src->swtch;
|
||||
dest->start = src->start;
|
||||
dest->value = src->value;
|
||||
dest->countdownBeep = src->countdownBeep;
|
||||
dest->minuteBeep = src->minuteBeep;
|
||||
dest->persistent = src->persistent;
|
||||
dest->countdownStart = src->countdownStart;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copySwashRingData(A * dest, B * src)
|
||||
{
|
||||
dest->type = src->type;
|
||||
dest->value = src->value;
|
||||
dest->collectiveSource = src->collectiveSource;
|
||||
dest->aileronSource = src->aileronSource;
|
||||
dest->elevatorSource = src->elevatorSource;
|
||||
dest->collectiveWeight = src->collectiveWeight;
|
||||
dest->aileronWeight = src->aileronWeight;
|
||||
dest->elevatorWeight = src->elevatorWeight;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyScriptData(A * dest, B * src)
|
||||
{
|
||||
memcpy(dest->file, src->file, sizeof(dest->file));
|
||||
memcpy(dest->name, src->name, sizeof(dest->name));
|
||||
memcpy(dest->inputs, src->inputs, sizeof(dest->inputs));
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyRssiAlarmData(A * dest, B * src)
|
||||
{
|
||||
dest->disabled = src->disabled;
|
||||
dest->spare = src->spare;
|
||||
dest->warning = src->warning;
|
||||
dest->spare2 = src->spare2;
|
||||
dest->critical = src->critical;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyVarioData(A * dest, B * src)
|
||||
{
|
||||
dest->source = src->source;
|
||||
dest->centerSilent = src->centerSilent;
|
||||
dest->centerMax = src->centerMax;
|
||||
dest->centerMin = src->centerMin;
|
||||
dest->min = src->min;
|
||||
dest->max = src->max;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyTelemetrySensor(A * dest, B * src)
|
||||
{
|
||||
dest->id = src->id;
|
||||
copyTelemetrySensor_frskyInstance(&dest->frskyInstance, &src->frskyInstance);
|
||||
memcpy(dest->label, src->label, sizeof(dest->label));
|
||||
dest->subId = src->subId;
|
||||
dest->type = src->type;
|
||||
dest->unit = src->unit;
|
||||
dest->prec = src->prec;
|
||||
dest->autoOffset = src->autoOffset;
|
||||
dest->filter = src->filter;
|
||||
dest->logs = src->logs;
|
||||
dest->persistent = src->persistent;
|
||||
dest->onlyPositive = src->onlyPositive;
|
||||
dest->spare = src->spare;
|
||||
dest->param = src->param;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyTrainerModuleData(A * dest, B * src)
|
||||
{
|
||||
dest->mode = src->mode;
|
||||
dest->spare1 = src->spare1;
|
||||
dest->channelsStart = src->channelsStart;
|
||||
dest->channelsCount = src->channelsCount;
|
||||
dest->frameLength = src->frameLength;
|
||||
dest->delay = src->delay;
|
||||
dest->pulsePol = src->pulsePol;
|
||||
dest->spare2 = src->spare2;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyModuleData(A * dest, B * src)
|
||||
{
|
||||
dest->type = src->type;
|
||||
dest->rfProtocol = src->rfProtocol;
|
||||
dest->channelsStart = src->channelsStart;
|
||||
dest->channelsCount = src->channelsCount;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyModelHeader(A * dest, B * src)
|
||||
{
|
||||
memcpy(dest->name, src->name, sizeof(dest->name));
|
||||
memcpy(dest->modelId, src->modelId, sizeof(dest->modelId));
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyCustomScreenData(A * dest, B * src)
|
||||
{
|
||||
memcpy(dest->layoutName, src->layoutName, sizeof(dest->layoutName));
|
||||
dest->layoutData = src->layoutData;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyModelData(A * dest, B * src)
|
||||
{
|
||||
copyModelHeader(&dest->header, &src->header);
|
||||
for (int i=0; i<3; i++) {
|
||||
copyTimerData(&dest->timers[i], &src->timers[i]);
|
||||
}
|
||||
dest->telemetryProtocol = src->telemetryProtocol;
|
||||
dest->thrTrim = src->thrTrim;
|
||||
dest->noGlobalFunctions = src->noGlobalFunctions;
|
||||
dest->displayTrims = src->displayTrims;
|
||||
dest->ignoreSensorIds = src->ignoreSensorIds;
|
||||
dest->trimInc = src->trimInc;
|
||||
dest->disableThrottleWarning = src->disableThrottleWarning;
|
||||
dest->displayChecklist = src->displayChecklist;
|
||||
dest->extendedLimits = src->extendedLimits;
|
||||
dest->extendedTrims = src->extendedTrims;
|
||||
dest->throttleReversed = src->throttleReversed;
|
||||
dest->beepANACenter = src->beepANACenter;
|
||||
for (int i=0; i<64; i++) {
|
||||
copyMixData(&dest->mixData[i], &src->mixData[i]);
|
||||
}
|
||||
for (int i=0; i<32; i++) {
|
||||
copyLimitData(&dest->limitData[i], &src->limitData[i]);
|
||||
}
|
||||
for (int i=0; i<64; i++) {
|
||||
copyExpoData(&dest->expoData[i], &src->expoData[i]);
|
||||
}
|
||||
for (int i=0; i<32; i++) {
|
||||
copyCurveHeader(&dest->curves[i], &src->curves[i]);
|
||||
}
|
||||
memcpy(dest->points, src->points, sizeof(dest->points));
|
||||
for (int i=0; i<64; i++) {
|
||||
copyLogicalSwitchData(&dest->logicalSw[i], &src->logicalSw[i]);
|
||||
}
|
||||
for (int i=0; i<64; i++) {
|
||||
copyCustomFunctionData(&dest->customFn[i], &src->customFn[i]);
|
||||
}
|
||||
copySwashRingData(&dest->swashR, &src->swashR);
|
||||
for (int i=0; i<9; i++) {
|
||||
copyFlightModeData(&dest->flightModeData[i], &src->flightModeData[i]);
|
||||
}
|
||||
for (int i=0; i<9; i++) {
|
||||
copyGVarData(&dest->gvars[i], &src->gvars[i]);
|
||||
}
|
||||
for (int i=0; i<2; i++) {
|
||||
copyModuleData(&dest->moduleData[i], &src->moduleData[i]);
|
||||
}
|
||||
memcpy(dest->failsafeChannels, src->failsafeChannels, sizeof(dest->failsafeChannels));
|
||||
copyTrainerModuleData(&dest->trainerData, &src->trainerData);
|
||||
memcpy(dest->modelRegistrationID, src->modelRegistrationID, sizeof(dest->modelRegistrationID));
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyStepsCalibData(A * dest, B * src)
|
||||
{
|
||||
dest->count = src->count;
|
||||
memcpy(dest->steps, src->steps, sizeof(dest->steps));
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyCalibData(A * dest, B * src)
|
||||
{
|
||||
dest->mid = src->mid;
|
||||
dest->spanNeg = src->spanNeg;
|
||||
dest->spanPos = src->spanPos;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyTrainerMix(A * dest, B * src)
|
||||
{
|
||||
dest->srcChn = src->srcChn;
|
||||
dest->mode = src->mode;
|
||||
dest->studWeight = src->studWeight;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyTrainerData(A * dest, B * src)
|
||||
{
|
||||
memcpy(dest->calib, src->calib, sizeof(dest->calib));
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyRadioData(A * dest, B * src)
|
||||
{
|
||||
for (int i=0; i<13; i++) {
|
||||
copyCalibData(&dest->calib[i], &src->calib[i]);
|
||||
}
|
||||
dest->stickMode = src->stickMode;
|
||||
dest->telemetryBaudrate = src->telemetryBaudrate;
|
||||
// dest->splashSpares = src->splashSpares;
|
||||
dest->switchesDelay = src->switchesDelay;
|
||||
for (int i=0; i<64; i++) {
|
||||
copyCustomFunctionData(&dest->customFn[i], &src->customFn[i]);
|
||||
}
|
||||
dest->slidersConfig = src->slidersConfig;
|
||||
dest->switchConfig = src->switchConfig;
|
||||
dest->potsConfig = src->potsConfig;
|
||||
memcpy(dest->ownerRegistrationID, src->ownerRegistrationID, sizeof(dest->ownerRegistrationID));
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyCustomFunctionData_all(A * dest, B * src)
|
||||
{
|
||||
dest->val = src->val;
|
||||
dest->mode = src->mode;
|
||||
dest->param = src->param;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyTelemetrySensor_frskyInstance(A * dest, B * src)
|
||||
{
|
||||
dest->physID = src->physID;
|
||||
dest->rxIndex = src->rxIndex;
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
void copyModuleData_ppm(A * dest, B * src)
|
||||
{
|
||||
dest->delay = src->delay;
|
||||
dest->pulsePol = src->pulsePol;
|
||||
dest->outputType = src->outputType;
|
||||
dest->frameLength = src->frameLength;
|
||||
}
|
||||
|
|
@ -729,7 +729,7 @@ void RlcFile::nextRlcWriteStep()
|
|||
void RlcFile::flush()
|
||||
{
|
||||
while (!eepromIsTransferComplete())
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
|
||||
ENABLE_SYNC_WRITE(true);
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ void ModelCell::setRfModuleData(uint8_t moduleIdx, ModuleData* modData)
|
|||
}
|
||||
else {
|
||||
// do we care here about MM_RF_CUSTOM_SELECTED? probably not...
|
||||
moduleData[moduleIdx].rfProtocol = modData->getMultiProtocol(false);
|
||||
moduleData[moduleIdx].rfProtocol = modData->getMultiProtocol();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ void rambackupWrite()
|
|||
{
|
||||
copyRadioData(&ramBackupUncompressed.radio, &g_eeGeneral);
|
||||
copyModelData(&ramBackupUncompressed.model, &g_model);
|
||||
ramBackup->size = compress(ramBackup->data, 4094, (const uint8_t *)&ramBackupUncompressed, sizeof(ramBackupUncompressed));
|
||||
ramBackup->size = compress(ramBackup->data, sizeof(ramBackup->data), (const uint8_t *)&ramBackupUncompressed, sizeof(ramBackupUncompressed));
|
||||
TRACE("RamBackupWrite sdsize=%d backupsize=%d rlcsize=%d", sizeof(ModelData)+sizeof(RadioData), sizeof(Backup::RamBackupUncompressed), ramBackup->size);
|
||||
}
|
||||
|
33
radio/src/storage/rtc_backup.h
Normal file
33
radio/src/storage/rtc_backup.h
Normal file
|
@ -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.
|
||||
*/
|
||||
|
||||
#ifndef _RAM_BACKUP_H_
|
||||
#define _RAM_BACKUP_H_
|
||||
|
||||
#include "definitions.h"
|
||||
|
||||
PACK(struct RamBackup {
|
||||
uint16_t size;
|
||||
uint8_t data[4094];
|
||||
});
|
||||
|
||||
extern RamBackup * ramBackup;
|
||||
|
||||
#endif // _RAM_BACKUP_H_
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#if defined(SIMU)
|
||||
#define WRITE_DELAY_10MS 100
|
||||
#elif defined(RAMBACKUP)
|
||||
#elif defined(RTC_BACKUP_RAM)
|
||||
#define WRITE_DELAY_10MS 1500 /* 15s */
|
||||
#elif defined(PCBTARANIS)
|
||||
#define WRITE_DELAY_10MS 500
|
||||
|
@ -37,10 +37,11 @@ extern uint8_t storageDirtyMsk;
|
|||
extern tmr10ms_t storageDirtyTime10ms;
|
||||
#define TIME_TO_WRITE() (storageDirtyMsk && (tmr10ms_t)(get_tmr10ms() - storageDirtyTime10ms) >= (tmr10ms_t)WRITE_DELAY_10MS)
|
||||
|
||||
#if defined(RAMBACKUP)
|
||||
#if defined(RTC_BACKUP_RAM)
|
||||
#include "storage/rtc_backup.h"
|
||||
extern uint8_t rambackupDirtyMsk;
|
||||
extern tmr10ms_t rambackupDirtyTime10ms;
|
||||
#define TIME_TO_RAMBACKUP() (rambackupDirtyMsk && (tmr10ms_t)(get_tmr10ms() - rambackupDirtyTime10ms) >= (tmr10ms_t)100)
|
||||
#define TIME_TO_BACKUP_RAM() (rambackupDirtyMsk && (tmr10ms_t)(get_tmr10ms() - rambackupDirtyTime10ms) >= (tmr10ms_t)100)
|
||||
#endif
|
||||
|
||||
//
|
||||
|
@ -69,7 +70,7 @@ void checkExternalAntenna();
|
|||
#include "sdcard_common.h"
|
||||
#endif
|
||||
|
||||
#if defined(RAMBACKUP)
|
||||
#if defined(RTC_BACKUP_RAM)
|
||||
#include "rambackup.h"
|
||||
#endif
|
||||
|
||||
|
|
|
@ -19,11 +19,12 @@
|
|||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "pulses/multi.h"
|
||||
|
||||
uint8_t storageDirtyMsk;
|
||||
tmr10ms_t storageDirtyTime10ms;
|
||||
|
||||
#if defined(RAMBACKUP)
|
||||
#if defined(RTC_BACKUP_RAM)
|
||||
uint8_t rambackupDirtyMsk;
|
||||
tmr10ms_t rambackupDirtyTime10ms;
|
||||
#endif
|
||||
|
@ -33,7 +34,7 @@ void storageDirty(uint8_t msk)
|
|||
storageDirtyMsk |= msk;
|
||||
storageDirtyTime10ms = get_tmr10ms();
|
||||
|
||||
#if defined(RAMBACKUP)
|
||||
#if defined(RTC_BACKUP_RAM)
|
||||
rambackupDirtyMsk = storageDirtyMsk;
|
||||
rambackupDirtyTime10ms = storageDirtyTime10ms;
|
||||
#endif
|
||||
|
@ -133,11 +134,19 @@ void postModelLoad(bool alarms)
|
|||
if (!isInternalModuleAvailable(g_model.moduleData[INTERNAL_MODULE].type)) {
|
||||
memclear(&g_model.moduleData[INTERNAL_MODULE], sizeof(ModuleData));
|
||||
}
|
||||
#if defined(MULTIMODULE)
|
||||
else if (isModuleMultimodule(INTERNAL_MODULE))
|
||||
multiPatchCustom(INTERNAL_MODULE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!isExternalModuleAvailable(g_model.moduleData[EXTERNAL_MODULE].type)) {
|
||||
memclear(&g_model.moduleData[EXTERNAL_MODULE], sizeof(ModuleData));
|
||||
}
|
||||
#if defined(MULTIMODULE)
|
||||
else if (isModuleMultimodule(EXTERNAL_MODULE))
|
||||
multiPatchCustom(EXTERNAL_MODULE);
|
||||
#endif
|
||||
|
||||
AUDIO_FLUSH();
|
||||
flightReset(false);
|
||||
|
|
|
@ -487,10 +487,10 @@ char * strAppendUnsigned(char * dest, uint32_t value, uint8_t digits, uint8_t ra
|
|||
}
|
||||
}
|
||||
uint8_t idx = digits;
|
||||
while(idx > 0) {
|
||||
uint32_t rem = value % radix;
|
||||
dest[--idx] = (rem >= 10 ? 'A'-10 : '0') + rem;
|
||||
value /= radix;
|
||||
while (idx > 0) {
|
||||
div_t qr = div(value, radix);
|
||||
dest[--idx] = (qr.rem >= 10 ? 'A' - 10 : '0') + qr.rem;
|
||||
value = qr.quot;
|
||||
}
|
||||
dest[digits] = '\0';
|
||||
return &dest[digits];
|
||||
|
|
|
@ -568,7 +568,6 @@ void checkSwitches()
|
|||
#endif
|
||||
|
||||
while (true) {
|
||||
|
||||
#if defined(PCBFRSKY)
|
||||
#define GETADC_COUNT 1
|
||||
#endif
|
||||
|
@ -728,6 +727,8 @@ void checkSwitches()
|
|||
#if defined(PWR_BUTTON_PRESS)
|
||||
uint32_t power = pwrCheck();
|
||||
if (power == e_power_off) {
|
||||
drawSleepBitmap();
|
||||
boardOff();
|
||||
break;
|
||||
}
|
||||
else if (power == e_power_press) {
|
||||
|
@ -746,7 +747,7 @@ void checkSwitches()
|
|||
|
||||
doLoopCommonActions();
|
||||
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
|
||||
RTOS_WAIT_MS(10);
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ endif()
|
|||
|
||||
if(MULTIMODULE)
|
||||
add_definitions(-DMULTIMODULE)
|
||||
set(SRC ${SRC} pulses/multi.cpp telemetry/spektrum.cpp telemetry/flysky_ibus.cpp telemetry/hitec.cpp telemetry/multi.cpp io/multi_firmware_update.cpp)
|
||||
set(SRC ${SRC} pulses/multi.cpp telemetry/spektrum.cpp telemetry/flysky_ibus.cpp telemetry/hitec.cpp telemetry/hott.cpp telemetry/multi.cpp io/multi_firmware_update.cpp)
|
||||
endif()
|
||||
|
||||
if(CROSSFIRE)
|
||||
|
|
|
@ -138,4 +138,13 @@ void delay_ms(uint32_t ms);
|
|||
}
|
||||
#endif
|
||||
|
||||
#define INIT_KEYS_PINS(GPIO) \
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_ ## GPIO ## _PINS; \
|
||||
GPIO_Init(GPIO, &GPIO_InitStructure)
|
||||
|
||||
#define SET_KEYS_PINS_HIGH(GPIO) \
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_ ## GPIO ## _PINS; \
|
||||
GPIO_Init(GPIO, &GPIO_InitStructure); \
|
||||
GPIO_SetBits(GPIO, KEYS_ ## GPIO ## _PINS)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,8 @@ if(CPU_TYPE_FULL STREQUAL STM32F429xI)
|
|||
../f4/system_stm32f4xx.c
|
||||
../../../../../targets/${TARGET_DIR}/startup_stm32f42_43xxx.s
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rtc.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_pwr.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_syscfg.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_exti.c
|
||||
|
@ -25,6 +27,8 @@ elseif(CPU_TYPE_FULL STREQUAL STM32F407xE)
|
|||
../f4/system_stm32f4xx.c
|
||||
../../../../../targets/${TARGET_DIR}/startup_stm32f40_41xxx.s
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rtc.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_pwr.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_syscfg.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c
|
||||
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_exti.c
|
||||
|
@ -114,6 +118,7 @@ if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14)
|
|||
../../../../../thirdparty/libopenui/src/libopenui_globals.cpp
|
||||
../../../../../targets/${TARGET_DIR}/sdram_driver.c
|
||||
../../../../../targets/common/arm/stm32/sdio_sd.c
|
||||
../../../../../targets/common/arm/stm32/rtc_driver.cpp
|
||||
../../../../../targets/${TARGET_DIR}/haptic_driver.cpp
|
||||
../../../../../syscalls.c
|
||||
)
|
||||
|
@ -125,6 +130,12 @@ if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14)
|
|||
../../../../../serial.cpp
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
set(BOOTLOADER_SRC
|
||||
${BOOTLOADER_SRC}
|
||||
../../../../../targets/${TARGET_DIR}/i2c_driver.cpp
|
||||
)
|
||||
remove_definitions(-DDEBUG)
|
||||
endif()
|
||||
|
||||
remove_definitions(-DDEBUG)
|
||||
|
@ -132,6 +143,8 @@ remove_definitions(-DDISK_CACHE)
|
|||
remove_definitions(-DLUA)
|
||||
remove_definitions(-DCLI)
|
||||
remove_definitions(-DUSB_SERIAL)
|
||||
remove_definitions(-DWATCHDOG)
|
||||
|
||||
add_definitions(-DBOOT)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-mcpu=${MCU} -mthumb -nostartfiles -lm -T${RADIO_SRC_DIR}/targets/${TARGET_DIR}/stm32_ramboot.ld -Wl,-Map=bootloader.map,--cref,--no-warn-mismatch,--gc-sections")
|
||||
|
|
|
@ -69,13 +69,13 @@ FlashCheckRes valid;
|
|||
MemoryType memoryType;
|
||||
uint32_t unlocked = 0;
|
||||
|
||||
void interrupt10ms(void)
|
||||
void interrupt10ms()
|
||||
{
|
||||
tenms |= 1; // 10 mS has passed
|
||||
tenms |= 1u; // 10 mS has passed
|
||||
|
||||
uint8_t index = 0;
|
||||
uint8_t in = readKeys();
|
||||
for (uint8_t i = 1; i != uint8_t(1 << TRM_BASE); i <<= 1) {
|
||||
for (uint8_t i = 1; i != uint8_t(1u << TRM_BASE); i <<= 1) {
|
||||
uint8_t value = (in & i);
|
||||
keys[index].input(value);
|
||||
++index;
|
||||
|
@ -195,8 +195,6 @@ int main()
|
|||
FRESULT fr;
|
||||
uint32_t nameCount = 0;
|
||||
|
||||
wdt_reset();
|
||||
|
||||
RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | KEYS_RCC_AHB1Periph |
|
||||
LCD_RCC_AHB1Periph | BACKLIGHT_RCC_AHB1Periph |
|
||||
AUX_SERIAL_RCC_AHB1Periph | I2C_RCC_AHB1Periph |
|
||||
|
@ -212,12 +210,12 @@ int main()
|
|||
pwrInit();
|
||||
keysInit();
|
||||
|
||||
#if defined(PCBHORUS)
|
||||
// wait a bit for the inputs to stabilize...
|
||||
for (uint32_t i = 0; i < 50000; i++) {
|
||||
wdt_reset();
|
||||
if (!WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) {
|
||||
for (uint32_t i = 0; i < 150000; i++) {
|
||||
__ASM volatile ("nop");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// LHR & RHL trims not pressed simultanously
|
||||
if (readTrims() != BOOTLOADER_KEYS) {
|
||||
|
@ -265,12 +263,12 @@ int main()
|
|||
#if defined(PWR_BUTTON_PRESS)
|
||||
// wait until power button is released
|
||||
while (pwrPressed()) {
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
|
||||
if (tenms) {
|
||||
tenms = 0;
|
||||
|
@ -506,16 +504,12 @@ int main()
|
|||
lcdRefresh();
|
||||
lcdRefreshWait();
|
||||
|
||||
#if !defined(EEPROM)
|
||||
// Use jump on radios with emergency mode
|
||||
// to avoid triggering it with a soft reset
|
||||
|
||||
// Jump to proper application address
|
||||
jumpTo(APP_START_ADDRESS);
|
||||
#else
|
||||
// Use software reset everywhere else
|
||||
NVIC_SystemReset();
|
||||
#if defined(RTC_BACKUP_RAM)
|
||||
rtcInit();
|
||||
RTC->BKP0R = SOFTRESET_REQUEST;
|
||||
#endif
|
||||
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,5 +517,5 @@ int main()
|
|||
}
|
||||
|
||||
#if defined(PCBHORUS)
|
||||
void *__dso_handle = 0;
|
||||
void *__dso_handle = nullptr;
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,13 @@
|
|||
|
||||
#include "opentx.h"
|
||||
|
||||
void waitFlashIdle()
|
||||
{
|
||||
do {
|
||||
WDG_RESET();
|
||||
} while (FLASH->SR & FLASH_FLAG_BSY);
|
||||
}
|
||||
|
||||
//After reset, write is not allowed in the Flash control register (FLASH_CR) to protect the
|
||||
//Flash memory against possible unwanted operations due, for example, to electric
|
||||
//disturbances. The following sequence is used to unlock this register:
|
||||
|
@ -37,21 +44,16 @@ void unlockFlash()
|
|||
|
||||
void lockFlash()
|
||||
{
|
||||
while (FLASH->SR & FLASH_SR_BSY);
|
||||
waitFlashIdle();
|
||||
FLASH->CR |= FLASH_CR_LOCK;
|
||||
}
|
||||
|
||||
void waitFlashIdle()
|
||||
{
|
||||
while (FLASH->SR & FLASH_FLAG_BSY) {
|
||||
wdt_reset();
|
||||
}
|
||||
}
|
||||
|
||||
#define SECTOR_MASK ((uint32_t)0xFFFFFF07)
|
||||
|
||||
void eraseSector(uint32_t sector)
|
||||
{
|
||||
WDG_ENABLE(3000); // some sectors may take > 1s to erase
|
||||
|
||||
waitFlashIdle();
|
||||
|
||||
FLASH->CR &= CR_PSIZE_MASK;
|
||||
|
@ -66,9 +68,11 @@ void eraseSector(uint32_t sector)
|
|||
/* if the erase operation is completed, disable the SER Bit */
|
||||
FLASH->CR &= (~FLASH_CR_SER);
|
||||
FLASH->CR &= SECTOR_MASK;
|
||||
|
||||
WDG_ENABLE(WDG_DURATION);
|
||||
}
|
||||
|
||||
void flashWrite(uint32_t * address, uint32_t * buffer) // page size is 256 bytes
|
||||
void flashWrite(uint32_t * address, const uint32_t * buffer) // page size is 256 bytes
|
||||
{
|
||||
#define SECTOR_ADDRESS (((uint32_t)address) & 0xFFFFF)
|
||||
|
||||
|
@ -110,7 +114,6 @@ void flashWrite(uint32_t * address, uint32_t * buffer) // page size is 256 bytes
|
|||
eraseSector(4 + FLASH_BANK);
|
||||
}
|
||||
else if ((((uint32_t)address) & 0x3FFF) == 0) {
|
||||
|
||||
// test other 16KB sectors
|
||||
if (SECTOR_ADDRESS == 0x04000) {
|
||||
eraseSector(1 + FLASH_BANK);
|
||||
|
@ -141,7 +144,7 @@ void flashWrite(uint32_t * address, uint32_t * buffer) // page size is 256 bytes
|
|||
|
||||
/* Wait for operation to be completed */
|
||||
waitFlashIdle();
|
||||
FLASH->CR &= (~FLASH_CR_PG);
|
||||
FLASH->CR &= ~FLASH_CR_PG;
|
||||
|
||||
/* Check the written value */
|
||||
if (*address != *buffer) {
|
||||
|
@ -192,7 +195,7 @@ uint32_t isBootloaderStart(const uint8_t * buffer)
|
|||
{
|
||||
const uint32_t * block = (const uint32_t *)buffer;
|
||||
|
||||
for (int i=0; i<256; i++) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (block[i] == 0x544F4F42/*BOOT*/) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -59,17 +59,14 @@ void rtcGetTime(struct gtm * t)
|
|||
|
||||
void rtcInit()
|
||||
{
|
||||
RTC_InitTypeDef RTC_InitStruct;
|
||||
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
|
||||
PWR_BackupAccessCmd(ENABLE);
|
||||
RCC_LSEConfig(RCC_LSE_ON);
|
||||
|
||||
// Prevent lockup in case of 32kHz oscillator failure
|
||||
uint32_t i = 0;
|
||||
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
|
||||
{
|
||||
if ( ++i > 1000000 )
|
||||
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {
|
||||
if (++i > 1000000)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -77,6 +74,9 @@ void rtcInit()
|
|||
RCC_RTCCLKCmd(ENABLE);
|
||||
RTC_WaitForSynchro();
|
||||
|
||||
#if !defined(BOOT)
|
||||
RTC_InitTypeDef RTC_InitStruct;
|
||||
|
||||
// RTC time base = LSE / ((AsynchPrediv+1) * (SynchPrediv+1)) = 1 Hz*/
|
||||
RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
|
||||
RTC_InitStruct.RTC_AsynchPrediv = 127;
|
||||
|
@ -86,8 +86,9 @@ void rtcInit()
|
|||
struct gtm utm;
|
||||
rtcGetTime(&utm);
|
||||
g_rtcTime = gmktime(&utm);
|
||||
#endif
|
||||
|
||||
#if defined(RAMBACKUP)
|
||||
#if defined(RTC_BACKUP_RAM) && !defined(BOOT)
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
|
||||
PWR_BackupRegulatorCmd(ENABLE);
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,11 @@ set(HAPTIC YES)
|
|||
set(GUI_DIR colorlcd)
|
||||
set(NAVIGATION_TYPE horus)
|
||||
set(TARGET_DIR horus)
|
||||
set(LINKER_SCRIPT targets/horus/stm32f4_flash.ld)
|
||||
set(RTC_BACKUP_RAM YES)
|
||||
set(LUA YES)
|
||||
set(PPM_LIMITS_SYMETRICAL YES)
|
||||
set(USB_SERIAL ON CACHE BOOL "Enable USB serial (CDC)")
|
||||
|
||||
if(BOOTLOADER)
|
||||
set(LINKER_SCRIPT targets/horus/stm32f4_flash_bootloader.ld)
|
||||
|
@ -21,10 +26,6 @@ else()
|
|||
set(LINKER_SCRIPT targets/horus/stm32f4_flash.ld)
|
||||
endif()
|
||||
|
||||
set(RAMBACKUP YES)
|
||||
set(PPM_LIMITS_SYMETRICAL YES)
|
||||
set(USB_SERIAL ON CACHE BOOL "Enable USB serial (CDC)")
|
||||
|
||||
option(YAML_STORAGE "Enable YAML storage" NO)
|
||||
if(YAML_STORAGE)
|
||||
set(STORAGE_FORMAT YAML)
|
||||
|
@ -104,7 +105,13 @@ endif()
|
|||
add_definitions(-DPCBREV=${PCBREV})
|
||||
add_definitions(-DPCBREV_${PCBREV})
|
||||
|
||||
set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} ${BITMAPS_TARGET} truetype_fonts)
|
||||
set(RADIO_DEPENDENCIES
|
||||
${RADIO_DEPENDENCIES}
|
||||
${BITMAPS_TARGET}
|
||||
truetype_fonts
|
||||
)
|
||||
|
||||
set(FIRMWARE_DEPENDENCIES datacopy)
|
||||
|
||||
add_definitions(-DPCBHORUS -DSTM32F429_439xx -DSDRAM -DCOLORLCD -DHARDWARE_KEYS)
|
||||
add_definitions(-DEEPROM_VARIANT=0 -DAUDIO -DVOICE -DRTCLOCK)
|
||||
|
@ -198,9 +205,13 @@ set(STM32LIB_SRC
|
|||
)
|
||||
|
||||
if(PYTHONINTERP_FOUND)
|
||||
add_custom_target(datacopy
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_BINARY_DIR}/radio/src/datacopy.cpp
|
||||
WORKING_DIRECTORY ${RADIO_DIRECTORY}/src
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${RADIO_DIRECTORY}/util/generate_datacopy.py datastructs.h -DPCBHORUS -DPCBX10 -DCPUARM -DCOLORLCD -DBACKUP -Itargets/horus > storage/datacopy.cpp
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${RADIO_DIRECTORY}/util/generate_datacopy.py datastructs.h -DPCBHORUS -DPCBX10 -DCPUARM -DCOLORLCD -DBACKUP -Itargets/horus > ${PROJECT_BINARY_DIR}/radio/src/datacopy.cpp
|
||||
DEPENDS ${RADIO_DIRECTORY}/src/datastructs.h ${RADIO_DIRECTORY}/util/generate_datacopy.py
|
||||
)
|
||||
)
|
||||
add_custom_target(datacopy
|
||||
DEPENDS ${PROJECT_BINARY_DIR}/radio/src/datacopy.cpp
|
||||
)
|
||||
endif()
|
||||
|
|
|
@ -29,10 +29,6 @@ extern "C" {
|
|||
}
|
||||
#endif
|
||||
|
||||
uint32_t shutdownRequest; // Stores intentional shutdown to avoid reboot loop
|
||||
uint32_t shutdownReason; // Used for detecting unexpected reboots regardless of reason
|
||||
uint32_t powerupReason __NOINIT; // Stores power up reason beyond initialization for emergency mode activation
|
||||
|
||||
HardwareOptions hardwareOptions;
|
||||
|
||||
void watchdogInit(unsigned int duration)
|
||||
|
@ -40,7 +36,7 @@ void watchdogInit(unsigned int duration)
|
|||
IWDG->KR = 0x5555; // Unlock registers
|
||||
IWDG->PR = 3; // Divide by 32 => 1kHz clock
|
||||
IWDG->KR = 0x5555; // Unlock registers
|
||||
IWDG->RLR = duration; // 1.5 seconds nominal
|
||||
IWDG->RLR = duration;
|
||||
IWDG->KR = 0xAAAA; // reload
|
||||
IWDG->KR = 0xCCCC; // start
|
||||
}
|
||||
|
@ -173,6 +169,7 @@ void boardInit()
|
|||
#endif
|
||||
|
||||
ledInit();
|
||||
|
||||
#if defined(PCBX10) && !defined(RADIO_T16)
|
||||
sportUpdateInit();
|
||||
#endif
|
||||
|
@ -189,7 +186,7 @@ void boardOff()
|
|||
backlightEnable(0);
|
||||
|
||||
while (pwrPressed()) {
|
||||
wdt_reset();
|
||||
WDG_RESET();
|
||||
}
|
||||
|
||||
SysTick->CTRL = 0; // turn off systick
|
||||
|
@ -209,8 +206,12 @@ void boardOff()
|
|||
// Shutdown the Haptic
|
||||
hapticDone();
|
||||
|
||||
shutdownRequest = SHUTDOWN_REQUEST;
|
||||
shutdownReason = NORMAL_POWER_OFF;
|
||||
#if defined(RTC_BACKUP_RAM)
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, DISABLE);
|
||||
PWR_BackupRegulatorCmd(DISABLE);
|
||||
#endif
|
||||
|
||||
RTC->BKP0R = SHUTDOWN_REQUEST;
|
||||
|
||||
pwrOff();
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ DRESULT __disk_write(BYTE drv, const BYTE * buff, DWORD sector, UINT count);
|
|||
#define FLASH_PAGESIZE 256
|
||||
void unlockFlash();
|
||||
void lockFlash();
|
||||
void flashWrite(uint32_t * address, uint32_t * buffer);
|
||||
void flashWrite(uint32_t * address, const uint32_t * buffer);
|
||||
uint32_t isFirmwareStart(const uint8_t * buffer);
|
||||
uint32_t isBootloaderStart(const uint8_t * buffer);
|
||||
|
||||
|
@ -305,28 +305,22 @@ void rotaryEncoderInit();
|
|||
void rotaryEncoderCheck();
|
||||
|
||||
// WDT driver
|
||||
#define WDTO_500MS 500
|
||||
extern uint32_t powerupReason;
|
||||
|
||||
#define SHUTDOWN_REQUEST 0xDEADBEEF
|
||||
#define NO_SHUTDOWN_REQUEST ~SHUTDOWN_REQUEST
|
||||
#define DIRTY_SHUTDOWN 0xCAFEDEAD
|
||||
#define NORMAL_POWER_OFF ~DIRTY_SHUTDOWN
|
||||
#define WDG_DURATION 500 /*ms*/
|
||||
|
||||
void watchdogInit(unsigned int duration);
|
||||
#if defined(SIMU)
|
||||
#define WAS_RESET_BY_WATCHDOG() (false)
|
||||
#define WAS_RESET_BY_SOFTWARE() (false)
|
||||
#define WAS_RESET_BY_WATCHDOG_OR_SOFTWARE() (false)
|
||||
#define wdt_enable(x)
|
||||
#define wdt_reset()
|
||||
#define WDG_ENABLE(x)
|
||||
#define WDG_RESET()
|
||||
#else
|
||||
#if defined(WATCHDOG)
|
||||
#define wdt_enable(x) watchdogInit(x)
|
||||
#define wdt_reset() IWDG->KR = 0xAAAA
|
||||
#define WDG_ENABLE(x) watchdogInit(x)
|
||||
#define WDG_RESET() IWDG->KR = 0xAAAA
|
||||
#else
|
||||
#define wdt_enable(x)
|
||||
#define wdt_reset()
|
||||
#define WDG_ENABLE(x)
|
||||
#define WDG_RESET()
|
||||
#endif
|
||||
#define WAS_RESET_BY_WATCHDOG() (RCC->CSR & (RCC_CSR_WDGRSTF | RCC_CSR_WWDGRSTF))
|
||||
#define WAS_RESET_BY_SOFTWARE() (RCC->CSR & RCC_CSR_SFTRSTF)
|
||||
|
@ -453,14 +447,41 @@ extern volatile uint32_t pwm_interrupt_count;
|
|||
#define BATTERY_MAX 115 // 11.5V
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
enum PowerReason {
|
||||
SHUTDOWN_REQUEST = 0xDEADBEEF,
|
||||
SOFTRESET_REQUEST = 0xCAFEDEAD,
|
||||
};
|
||||
|
||||
constexpr uint32_t POWER_REASON_SIGNATURE = 0x0178746F;
|
||||
|
||||
inline bool UNEXPECTED_SHUTDOWN()
|
||||
{
|
||||
#if defined(SIMU) || defined(NO_UNEXPECTED_SHUTDOWN)
|
||||
return false;
|
||||
#else
|
||||
if (WAS_RESET_BY_WATCHDOG())
|
||||
return true;
|
||||
else if (WAS_RESET_BY_SOFTWARE())
|
||||
return RTC->BKP0R != SOFTRESET_REQUEST;
|
||||
else
|
||||
return RTC->BKP1R == POWER_REASON_SIGNATURE && RTC->BKP0R != SHUTDOWN_REQUEST;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void SET_POWER_REASON(uint32_t value)
|
||||
{
|
||||
RTC->BKP0R = value;
|
||||
RTC->BKP1R = POWER_REASON_SIGNATURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && !defined(SIMU)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Power driver
|
||||
#define SOFT_PWR_CTRL
|
||||
extern uint32_t shutdownRequest; // Stores intentional shutdown to avoid reboot loop
|
||||
extern uint32_t shutdownReason; // Used for detecting unexpected reboots regardless of reason
|
||||
void pwrInit();
|
||||
uint32_t pwrCheck();
|
||||
void pwrOn();
|
||||
|
@ -468,11 +489,6 @@ void pwrOff();
|
|||
void pwrResetHandler();
|
||||
bool pwrPressed();
|
||||
uint32_t pwrPressedDuration();
|
||||
#if defined(SIMU) || defined(NO_UNEXPECTED_SHUTDOWN)
|
||||
#define UNEXPECTED_SHUTDOWN() (false)
|
||||
#else
|
||||
#define UNEXPECTED_SHUTDOWN() ((powerupReason == DIRTY_SHUTDOWN) || WAS_RESET_BY_WATCHDOG_OR_SOFTWARE())
|
||||
#endif
|
||||
|
||||
// Led driver
|
||||
void ledInit();
|
||||
|
|
|
@ -48,7 +48,7 @@ void bootloaderInitScreen()
|
|||
|
||||
backlightEnable(BACKLIGHT_LEVEL_MAX);
|
||||
|
||||
//TODO: load/decompress bitmaps
|
||||
// TODO: load/decompress bitmaps
|
||||
extern void loadFonts();
|
||||
loadFonts();
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str)
|
|||
lcd->clear(DEFAULT_BGCOLOR);
|
||||
|
||||
if (st == ST_START) {
|
||||
bootloaderDrawTitle(88, "HORUS BOOTLOADER");
|
||||
bootloaderDrawTitle(88, "OpenTX Bootloader");
|
||||
|
||||
lcd->drawBitmapPattern(90, 72, LBM_FLASH, DEFAULT_COLOR);
|
||||
lcd->drawText(124, 75, "Write Firmware");
|
||||
|
|
|
@ -199,34 +199,21 @@ uint32_t switchState(uint8_t index)
|
|||
void keysInit()
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
|
||||
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOB_PINS;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
INIT_KEYS_PINS(GPIOB);
|
||||
|
||||
#if defined(KEYS_GPIOC_PINS)
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOC_PINS;
|
||||
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
||||
INIT_KEYS_PINS(GPIOC);
|
||||
#endif
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOD_PINS;
|
||||
GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOE_PINS;
|
||||
GPIO_Init(GPIOE, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOG_PINS;
|
||||
GPIO_Init(GPIOG, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOH_PINS;
|
||||
GPIO_Init(GPIOH, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOI_PINS;
|
||||
GPIO_Init(GPIOI, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = KEYS_GPIOJ_PINS;
|
||||
GPIO_Init(GPIOJ, &GPIO_InitStructure);
|
||||
INIT_KEYS_PINS(GPIOD);
|
||||
INIT_KEYS_PINS(GPIOE);
|
||||
INIT_KEYS_PINS(GPIOG);
|
||||
INIT_KEYS_PINS(GPIOH);
|
||||
INIT_KEYS_PINS(GPIOI);
|
||||
INIT_KEYS_PINS(GPIOJ);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "board.h"
|
||||
#include "storage/rtc_backup.h"
|
||||
|
||||
void pwrInit()
|
||||
{
|
||||
|
@ -81,9 +82,6 @@ void pwrOn()
|
|||
GPIO_Init(PWR_ON_GPIO, &GPIO_InitStructure);
|
||||
|
||||
GPIO_SetBits(PWR_ON_GPIO, PWR_ON_GPIO_PIN);
|
||||
|
||||
shutdownRequest = NO_SHUTDOWN_REQUEST;
|
||||
shutdownReason = DIRTY_SHUTDOWN;
|
||||
}
|
||||
|
||||
void pwrOff()
|
||||
|
@ -105,38 +103,7 @@ void pwrResetHandler()
|
|||
__ASM volatile ("nop");
|
||||
__ASM volatile ("nop");
|
||||
|
||||
// We get here whether we are powering up normally, we had an unexpected reboot or we have just powered down normally.
|
||||
// We want:
|
||||
// - In the 2nd case, to power ON as soon as possible if an unexpected reboot happened
|
||||
// (we get there running on remaining capacitor charge, soft power having been cut by the RESET).
|
||||
// - In the 3rd case, NOT power on as that would prevent from turning the system off.
|
||||
// - The 1st case does not need to be handled here, but will be as a result of the handling for the 3rd case, see below.
|
||||
//
|
||||
// shutdownRequest is used to handle the 3rd case. If we really powered down on purpose this will still be set to SHUTDOWN_REQUEST
|
||||
// as we left it in pwrOff(). If however we had an unexpected reboot, it would be set to NO_SHUTDOWN_REQUEST as we set it in pwrOn().
|
||||
// Any other value (e.g. resulting from data corruption) would also keep power on for safety, so this variable can NOT be used
|
||||
// to detect an unexpected reboot (on a normal power on the contents of the variable are random).
|
||||
//
|
||||
// shutdownReason is used to differentiate between an unexpected reboot and a normal power on. We set it to DIRTY_SHUTDOWN in pwrOn()
|
||||
// in anticipation of a potential reboot. Should there be one the value should be preserved and signal below that we rebooted unexpectedly.
|
||||
// If it is NOT set to DIRTY_SHUTDOWN we likely had a normal boot and its contents are random. Due to the need to initialize it to detect a
|
||||
// potential failure ASAP we cannot use it to determine in the firmware why we got there, it has to be buffered.
|
||||
//
|
||||
// powerupReason is there to cater for that, and is what is used in the firmware to decide whether we have to enter emergency mode.
|
||||
// This variable needs to be in a RAM section that is not initialized or zeroed, since once we exit this pwrResetHandler() function the
|
||||
// C runtime would otherwise overwrite it during program init.
|
||||
// Only for X12, X10 power circuit causes inability to shut down on some samples.
|
||||
|
||||
#if defined(PCBX12S)
|
||||
if (shutdownRequest != SHUTDOWN_REQUEST || WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) {
|
||||
if (shutdownReason == DIRTY_SHUTDOWN) {
|
||||
powerupReason = DIRTY_SHUTDOWN;
|
||||
}
|
||||
if (WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) {
|
||||
pwrOn();
|
||||
}
|
||||
#else
|
||||
if (WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) {
|
||||
pwrOn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -228,8 +228,14 @@ void telemetryPortSetDirectionOutput()
|
|||
TELEMETRY_USART->CR1 &= ~USART_CR1_RE; // turn off receiver
|
||||
}
|
||||
|
||||
void sportWaitTransmissionComplete()
|
||||
{
|
||||
while (!(TELEMETRY_USART->SR & USART_SR_TC));
|
||||
}
|
||||
|
||||
void telemetryPortSetDirectionInput()
|
||||
{
|
||||
sportWaitTransmissionComplete();
|
||||
TELEMETRY_DIR_GPIO->BSRRH = TELEMETRY_DIR_GPIO_PIN; // output disable
|
||||
TELEMETRY_USART->CR1 |= USART_CR1_RE; // turn on receiver
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue