1
0
Fork 0
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:
Bertrand Songis 2019-12-05 09:29:11 +01:00
commit 4c484017a4
No known key found for this signature in database
GPG key ID: F189F79290FEC50F
161 changed files with 3683 additions and 10306 deletions

2
.gitmodules vendored
View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -111,6 +111,7 @@ class LimitData {
QString revertToString() const;
QString nameToString(int index) const;
void clear();
bool isEmpty() const;
};
class CurvePoint {

View file

@ -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 {

View file

@ -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);

View file

@ -164,9 +164,10 @@ class ModuleData {
struct Multi {
unsigned int rfProtocol;
bool disableTelemetry;
bool disableMapping;
bool autoBindMode;
bool lowPowerMode;
bool customProto;
int optionValue;
} multi;

View file

@ -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)));
}

View file

@ -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;

View file

@ -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:

View file

@ -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"));

View file

@ -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);

View file

@ -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 {

View file

@ -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();
}
}

View file

@ -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_

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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">

View file

@ -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
View file

@ -0,0 +1 @@
*/opentx.sdcard.version

View 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 }

View 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 }

View 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 }

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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;
})
});

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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) {

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -44,7 +44,7 @@ void readModelNotes()
menuTextView(event);
event = getEvent();
lcdRefresh();
wdt_reset();
WDG_RESET();
}
LED_ERROR_END();

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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 */

View file

@ -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));

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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,

View file

@ -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_

View file

@ -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

View file

@ -23,6 +23,8 @@
#include "pulses_common.h"
void multiPatchCustom(uint8_t moduleIdx);
class UartMultiPulses: public DataBuffer<uint8_t, 64>
{
public:

View file

@ -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

View file

@ -148,7 +148,7 @@ class BindInformation {
class OtaUpdateInformation: public BindInformation {
public:
char filename[32+1];
char filename[_MAX_LFN + 1];
uint32_t address;
};

View file

@ -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> >;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -729,7 +729,7 @@ void RlcFile::nextRlcWriteStep()
void RlcFile::flush()
{
while (!eepromIsTransferComplete())
wdt_reset();
WDG_RESET();
ENABLE_SYNC_WRITE(true);

View file

@ -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();
}
}

View file

@ -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);
}

View 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_

View file

@ -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

View file

@ -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);

View file

@ -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];

View file

@ -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);
}

View file

@ -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)

View file

@ -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

View file

@ -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")

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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()

View file

@ -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();
}

View file

@ -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();

View file

@ -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");

View file

@ -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);
}

View file

@ -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
}

View file

@ -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