1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-13 03:19:53 +03:00

Support of FRM302 module. (#7533)

AFHDS3 support added
This commit is contained in:
Jakub 2020-06-22 16:44:35 +02:00 committed by GitHub
parent 6d29faa48b
commit 5bf197439a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 2435 additions and 164 deletions

View file

@ -18,6 +18,7 @@ set(firmwares_SRCS
rawswitch.cpp
sensordata.cpp
telem_data.cpp
afhds3.cpp
er9x/er9xeeprom.cpp
er9x/er9xinterface.cpp
ersky9x/ersky9xeeprom.cpp

View file

@ -0,0 +1,12 @@
#include "afhds3.h"
#include "macros.h"
QString Afhds3Data::protocolToString(unsigned int protocol) {
const char * const afhds3Protocols[] = {
"PWM/IBUS",
"PWM/SBUS",
"PPM/IBUS",
"PPM/SBUS",
};
return CHECK_IN_ARRAY(afhds3Protocols, protocol);
}

View file

@ -0,0 +1,12 @@
#ifndef AFHDS3_H
#define AFHDS3_H
#include <QtCore>
class Afhds3Data
{
Q_DECLARE_TR_FUNCTIONS(Afhds3)
public:
static QString protocolToString(unsigned int protocol);
};
#endif // AFHDS3_H

View file

@ -21,6 +21,7 @@
#include "moduledata.h"
#include "eeprominterface.h"
#include "multiprotocols.h"
#include "afhds3.h"
#include "radiodataconversionstate.h"
void ModuleData::convert(RadioDataConversionState & cstate)
@ -87,7 +88,6 @@ QString ModuleData::rfProtocolToString() const
switch (protocol) {
case PULSES_MULTIMODULE:
return Multiprotocols::protocolToString((int)multi.rfProtocol);
default:
return CPN_STR_UNKNOWN_ITEM;
}
@ -108,10 +108,10 @@ QString ModuleData::subTypeToString(int type) const
switch (protocol) {
case PULSES_MULTIMODULE:
return Multiprotocols::subTypeToString((int)multi.rfProtocol, (unsigned)type);
case PULSES_PXX_R9M:
return CHECK_IN_ARRAY(strings, type);
case PULSES_AFHDS3:
return Afhds3Data::protocolToString(type);
default:
return CPN_STR_UNKNOWN_ITEM;
}
@ -119,8 +119,8 @@ QString ModuleData::subTypeToString(int type) const
QString ModuleData::powerValueToString(Firmware * fw) const
{
const QStringList & strRef = powerValueStrings(subType, fw);
return strRef.value(pxx.power, CPN_STR_UNKNOWN_ITEM);
const QStringList & strRef = powerValueStrings((enum PulsesProtocol)protocol, subType, fw);
return strRef.value(protocol == PULSES_AFHDS3 ? afhds3.rfPower : pxx.power, CPN_STR_UNKNOWN_ITEM);
}
// static
@ -159,14 +159,15 @@ QString ModuleData::protocolToString(unsigned protocol)
"FrSky ACCESS R9M 2019",
"FrSky ACCESS R9M Lite",
"FrSky ACCESS R9M Lite Pro",
"FrSky XJT lite (D16)", "FrSky XJT lite (D8)", "FrSky XJT lite (LR12)"
"FrSky XJT lite (D16)", "FrSky XJT lite (D8)", "FrSky XJT lite (LR12)",
"AFHDS3"
};
return CHECK_IN_ARRAY(strings, protocol);
}
// static
QStringList ModuleData::powerValueStrings(int subType, Firmware * fw)
QStringList ModuleData::powerValueStrings(enum PulsesProtocol protocol, int subType, Firmware * fw)
{
static const QStringList strings[] = {
{ tr("10mW - 16CH"), tr("100mW - 16CH"), tr("500mW - 16CH"), tr("Auto <= 1W - 16CH") }, // full-size FCC
@ -174,12 +175,21 @@ QStringList ModuleData::powerValueStrings(int subType, Firmware * fw)
{ tr("100mW - 16CH") }, // mini FCC
{ tr("25mW - 8CH"), tr("25mW - 16CH"), tr("100mW - 16CH (no telemetry)") } // mini EU
};
int strIdx = 0;
if (subType == MODULE_SUBTYPE_R9M_EU)
strIdx += 1;
if (fw->getCapability(HasModuleR9MMini))
strIdx += 2;
return strings[strIdx];
static const QStringList afhds3Strings = {
tr("25 mW"), tr("100 mW"), tr("500 mW"), tr("1 W"), tr("2 W")
};
switch(protocol) {
case PULSES_AFHDS3:
return afhds3Strings;
default:
int strIdx = 0;
if (subType == MODULE_SUBTYPE_R9M_EU)
strIdx += 1;
if (fw->getCapability(HasModuleR9MMini))
strIdx += 2;
return strings[strIdx];
}
}
bool ModuleData::hasFailsafes(Firmware * fw) const
@ -193,7 +203,8 @@ bool ModuleData::hasFailsafes(Firmware * fw) const
protocol == PULSES_ACCESS_R9M_LITE ||
protocol == PULSES_ACCESS_R9M_LITE_PRO ||
protocol == PULSES_XJT_LITE_X16 ||
protocol == PULSES_MULTIMODULE
protocol == PULSES_MULTIMODULE ||
protocol == PULSES_AFHDS3
);
}
@ -230,6 +241,8 @@ int ModuleData::getMaxChannelCount()
else
return 16;
break;
case PULSES_AFHDS3:
return 18;
case PULSES_OFF:
break;
default:

View file

@ -58,6 +58,7 @@ enum PulsesProtocol {
PULSES_XJT_LITE_X16,
PULSES_XJT_LITE_D8,
PULSES_XJT_LITE_LR12,
PULSES_AFHDS3,
PULSES_PROTOCOL_LAST
};
@ -190,6 +191,11 @@ class ModuleData {
int optionValue;
} multi;
struct Afhds3 {
unsigned int rxFreq;
unsigned int rfPower;
} afhds3;
struct PXX {
unsigned int power; // 0 10 mW, 1 100 mW, 2 500 mW, 3 1W
bool receiverTelemetryOff; // false = receiver telem enabled
@ -213,7 +219,7 @@ class ModuleData {
QString powerValueToString(Firmware * fw) const;
static QString indexToString(int index, Firmware * fw);
static QString protocolToString(unsigned protocol);
static QStringList powerValueStrings(int subType, Firmware * fw);
static QStringList powerValueStrings(enum PulsesProtocol protocol, int subType, Firmware * fw);
bool hasFailsafes(Firmware * fw) const;
int getMaxChannelCount();
};

View file

@ -2113,6 +2113,40 @@ class ModuleUnionField: public UnionField<unsigned int> {
unsigned int version;
};
class Afhds3Field: public UnionField::TransformedMember {
public:
Afhds3Field(DataField * parent, ModuleData& module):
UnionField::TransformedMember(parent, internalField),
internalField(this, "AFHDS3")
{
ModuleData::Afhds3& afhds3 = module.afhds3;
internalField.Append(new UnsignedField<3>(this, minBindPower));
internalField.Append(new UnsignedField<3>(this, afhds3.rfPower));
internalField.Append(new UnsignedField<1>(this, emissionFCC));
internalField.Append(new BoolField<1>(this, operationModeUnicast));
internalField.Append(new BoolField<1>(this, operationModeUnicast));
internalField.Append(new UnsignedField<16>(this, defaultFailSafeTimout));
internalField.Append(new UnsignedField<16>(this, afhds3.rxFreq));
}
bool select(const unsigned int& attr) const override {
return attr == PULSES_AFHDS3;
}
void beforeExport() override {}
void afterImport() override {}
private:
StructField internalField;
unsigned int minBindPower = 0;
unsigned int emissionFCC = 0;
unsigned int defaultFailSafeTimout = 1000;
bool operationModeUnicast = true;
};
class AccessField: public UnionField::TransformedMember {
public:
AccessField(DataField * parent, ModuleData& module):
@ -2173,8 +2207,10 @@ class ModuleUnionField: public UnionField<unsigned int> {
ModuleUnionField(DataField * parent, ModuleData & module, Board::Type board, unsigned int version):
UnionField<unsigned int>(parent, module.protocol)
{
if (version >= 219)
if (version >= 219) {
Append(new AccessField(parent, module));
Append(new Afhds3Field(parent, module));
}
Append(new PxxField(parent, module, version));
Append(new MultiField(parent, module));
Append(new PPMField(parent, module.ppm));

View file

@ -107,6 +107,9 @@ class ProtocolsConversionTable: public ConversionTable
addConversion(PULSES_XJT_LITE_X16, val);
addConversion(PULSES_XJT_LITE_D8, val);
addConversion(PULSES_XJT_LITE_LR12, val++);
if (version >= 219) {
addConversion(PULSES_AFHDS3, val++);
}
}
};

View file

@ -823,6 +823,7 @@ bool OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
case PULSES_SBUS:
case PULSES_MULTIMODULE:
case PULSES_CROSSFIRE:
case PULSES_AFHDS3:
return true;
case PULSES_ACCESS_R9M:
return IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board) || board == BOARD_TARANIS_X9DP_2019 || board == BOARD_X10_EXPRESS || (IS_FAMILY_HORUS_OR_T16(board) && id.contains("internalaccess"));
@ -832,7 +833,7 @@ bool OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
case PULSES_XJT_LITE_X16:
case PULSES_XJT_LITE_D8:
case PULSES_XJT_LITE_LR12:
return (IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board));
return (IS_TARANIS_XLITE(board) || IS_TARANIS_X9LITE(board));
default:
return false;
}
@ -1184,19 +1185,25 @@ void addOpenTxCommonOptions(OpenTxFirmware * firmware)
enum RfOptions {
NONE = 0,
EU = 1 << 0,
FLEX = 1 << 1
FLEX = 1 << 1,
AFHDS3 = 1 << 2
};
void addOpenTxRfOptions(OpenTxFirmware * firmware, uint8_t options)
{
static const Firmware::Option opt_eu("eu", Firmware::tr("Removes D8 FrSky protocol support which is not legal for use in the EU on radios sold after Jan 1st, 2015"));
static const Firmware::Option opt_fl("flexr9m", Firmware::tr("Enable non certified firmwares"));
if (options == EU + FLEX)
static const Firmware::Option opt_afhds3("afhds3", Firmware::tr("Enable AFHDS3 support"));
if ((options & (EU + FLEX)) == EU + FLEX)
firmware->addOptionsGroup({opt_eu, opt_fl});
else if (options == EU)
else if ((options & EU) != 0)
firmware->addOption(opt_eu);
else if (options == FLEX)
else if ((options & FLEX) != 0)
firmware->addOption(opt_fl);
if ((options & AFHDS3) != 0)
firmware->addOption(opt_afhds3);
}
void addOpenTxFontOptions(OpenTxFirmware * firmware)
@ -1245,13 +1252,13 @@ void registerOpenTxFirmwares()
firmware->addOption("noras", Firmware::tr("Disable RAS (SWR)"));
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, EU + FLEX);
addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3);
/* FrSky Taranis X9D+ 2019 board */
firmware = new OpenTxFirmware("opentx-x9d+2019", Firmware::tr("FrSky Taranis X9D+ 2019"), BOARD_TARANIS_X9DP_2019);
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
/* FrSky Taranis X9D board */
firmware = new OpenTxFirmware("opentx-x9d", Firmware::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D);
@ -1259,7 +1266,7 @@ void registerOpenTxFirmwares()
firmware->addOption("haptic", Firmware::tr("Haptic module installed"));
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, EU + FLEX);
addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3);
/* FrSky Taranis X9E board */
firmware = new OpenTxFirmware("opentx-x9e", Firmware::tr("FrSky Taranis X9E"), BOARD_TARANIS_X9E);
@ -1267,37 +1274,37 @@ void registerOpenTxFirmwares()
firmware->addOption("horussticks", Firmware::tr("Horus gimbals installed (Hall sensors)"));
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, EU + FLEX);
addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3);
/* FrSky X9-Lite board */
firmware = new OpenTxFirmware("opentx-x9lite", Firmware::tr("FrSky Taranis X9-Lite"), BOARD_TARANIS_X9LITE);
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
/* FrSky X9-LiteS board */
firmware = new OpenTxFirmware("opentx-x9lites", Firmware::tr("FrSky Taranis X9-Lite S"), BOARD_TARANIS_X9LITES);
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
/* FrSky X7 board */
firmware = new OpenTxFirmware("opentx-x7", Firmware::tr("FrSky Taranis X7 / X7S"), BOARD_TARANIS_X7);
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, EU + FLEX);
addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3);
/* FrSky X7 Access board */
firmware = new OpenTxFirmware("opentx-x7access", Firmware::tr("FrSky Taranis X7 / X7S Access"), BOARD_TARANIS_X7_ACCESS);
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
/* FrSky X-Lite S/PRO board */
firmware = new OpenTxFirmware("opentx-xlites", Firmware::tr("FrSky Taranis X-Lite S/PRO"), BOARD_TARANIS_XLITES);
addOpenTxTaranisOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
/* FrSky X-Lite board */
firmware = new OpenTxFirmware("opentx-xlite", Firmware::tr("FrSky Taranis X-Lite"), BOARD_TARANIS_XLITE);
@ -1311,13 +1318,13 @@ void registerOpenTxFirmwares()
addOpenTxFrskyOptions(firmware);
firmware->addOption("internalaccess", Firmware::tr("Support for ACCESS internal module replacement"));
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, EU + FLEX);
addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3);
/* FrSky X10 Express board */
firmware = new OpenTxFirmware("opentx-x10express", Firmware::tr("FrSky Horus X10 Express / X10S Express"), BOARD_X10_EXPRESS);
addOpenTxFrskyOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
/* FrSky X12 (Horus) board */
firmware = new OpenTxFirmware("opentx-x12s", Firmware::tr("FrSky Horus X12S"), BOARD_HORUS_X12S);
@ -1325,7 +1332,7 @@ void registerOpenTxFirmwares()
firmware->addOption("internalaccess", Firmware::tr("Support for ACCESS internal module replacement"));
firmware->addOption("pcbdev", Firmware::tr("Use ONLY with first DEV pcb version"));
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, EU + FLEX);
addOpenTxRfOptions(firmware, EU + FLEX + AFHDS3);
/* Jumper T12 board */
firmware = new OpenTxFirmware("opentx-t12", QCoreApplication::translate("Firmware", "Jumper T12 / T12 Pro"), BOARD_JUMPER_T12);
@ -1336,20 +1343,20 @@ void registerOpenTxFirmwares()
firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module"));
addOpenTxFontOptions(firmware);
registerOpenTxFirmware(firmware);
addOpenTxRfOptions(firmware, FLEX);
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
/* Jumper T16 board */
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"));
addOpenTxRfOptions(firmware, FLEX);
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
registerOpenTxFirmware(firmware);
/* Radiomaster TX16S board */
firmware = new OpenTxFirmware("opentx-tx16s", Firmware::tr("Radiomaster TX16s / TX16s Hall / TX16s Masterfire"), BOARD_RADIOMASTER_TX16S);
addOpenTxFrskyOptions(firmware);
addOpenTxRfOptions(firmware, FLEX);
addOpenTxRfOptions(firmware, FLEX + AFHDS3);
static const Firmware::Option opt_bt("bluetooth", Firmware::tr("Support for bluetooth module"));
static const Firmware::Option opt_internal_gps("internalgps", Firmware::tr("Support internal GPS"));
firmware->addOptionsGroup({opt_bt, opt_internal_gps});

View file

@ -192,6 +192,8 @@ void TimerPanel::on_name_editingFinished()
#define MASK_SBUSPPM_FIELDS (1<<11)
#define MASK_SUBTYPES (1<<12)
#define MASK_ACCESS (1<<13)
#define MASK_RX_FREQ (1<<14)
#define MASK_RF_POWER (1<<15)
quint8 ModulePanel::failsafesValueDisplayType = ModulePanel::FAILSAFE_DISPLAY_PERCENT;
@ -271,7 +273,7 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
connect(ui->multiProtocol, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ModulePanel::onMultiProtocolChanged);
connect(this, &ModulePanel::channelsRangeChanged, this, &ModulePanel::setupFailsafes);
connect(ui->btnGrpValueType, static_cast<void(QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &ModulePanel::onFailsafesDisplayValueTypeChanged);
connect(ui->rxFreq, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &ModulePanel::onRfFreqChanged);
connect(ui->clearRx1, SIGNAL(clicked()), this, SLOT(onClearAccessRxClicked()));
connect(ui->clearRx2, SIGNAL(clicked()), this, SLOT(onClearAccessRxClicked()));
connect(ui->clearRx3, SIGNAL(clicked()), this, SLOT(onClearAccessRxClicked()));
@ -391,7 +393,7 @@ void ModulePanel::update()
mask |= MASK_PROTOCOL;
switch (protocol) {
case PULSES_PXX_R9M:
mask |= MASK_R9M | MASK_SUBTYPES;
mask |= MASK_R9M | MASK_RF_POWER | MASK_SUBTYPES;
case PULSES_ACCESS_R9M:
case PULSES_ACCESS_R9M_LITE:
case PULSES_ACCESS_R9M_LITE_PRO:
@ -450,6 +452,11 @@ void ModulePanel::update()
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_AFHDS3:
module.channelsCount = 18;
mask |= MASK_CHANNELS_RANGE| MASK_CHANNELS_COUNT | MASK_FAILSAFES;
mask |= MASK_SUBTYPES | MASK_RX_FREQ | MASK_RF_POWER;
break;
case PULSES_OFF:
break;
default:
@ -516,16 +523,16 @@ void ModulePanel::update()
}
// R9M options
ui->r9mPower->setVisible(mask & MASK_R9M);
ui->label_r9mPower->setVisible(mask & MASK_R9M);
ui->r9mPower->setVisible(mask & MASK_RF_POWER);
ui->label_r9mPower->setVisible(mask & MASK_RF_POWER);
ui->warning_r9mPower->setVisible((mask & MASK_R9M) && module.subType == MODULE_SUBTYPE_R9M_EU);
ui->warning_r9mFlex->setVisible((mask & MASK_R9M) && module.subType > MODULE_SUBTYPE_R9M_EU);
if (mask & MASK_R9M) {
if (mask & MASK_RF_POWER) {
const QSignalBlocker blocker(ui->r9mPower);
ui->r9mPower->clear();
ui->r9mPower->addItems(ModuleData::powerValueStrings(module.subType, firmware));
ui->r9mPower->setCurrentIndex(module.pxx.power);
ui->r9mPower->addItems(ModuleData::powerValueStrings(protocol, module.subType, firmware));
ui->r9mPower->setCurrentIndex(mask & MASK_R9M ? module.pxx.power : module.afhds3.rfPower);
}
// module subtype
@ -542,6 +549,9 @@ void ModulePanel::update()
if (firmware->getCapability(HasModuleR9MFlex))
i = 2;
break;
case PULSES_AFHDS3:
numEntries = 4;
break;
default:
break;
}
@ -606,6 +616,8 @@ void ModulePanel::update()
// Failsafes
ui->label_failsafeMode->setVisible(mask & MASK_FAILSAFES);
ui->failsafeMode->setVisible(mask & MASK_FAILSAFES);
//hide reciever mode for afhds3
qobject_cast<QListView *>(ui->failsafeMode->view())->setRowHidden(FAILSAFE_RECEIVER, protocol == PULSES_AFHDS3);
if ((mask & MASK_FAILSAFES) && module.failsafeMode == FAILSAFE_CUSTOM) {
if (ui->failsafesGroupBox->isHidden()) {
@ -635,6 +647,9 @@ void ModulePanel::update()
}
}
}
ui->label_rxFreq->setVisible((mask & MASK_RX_FREQ));
ui->rxFreq->setVisible((mask & MASK_RX_FREQ));
}
void ModulePanel::on_trainerMode_currentIndexChanged(int index)
@ -666,9 +681,14 @@ void ModulePanel::on_ppmPolarity_currentIndexChanged(int index)
void ModulePanel::on_r9mPower_currentIndexChanged(int index)
{
if (!lock && module.pxx.power != (unsigned int)index) {
module.pxx.power = index;
emit modified();
if (!lock) {
if (module.protocol == PULSES_AFHDS3 && module.afhds3.rfPower != (unsigned int)index) {
module.afhds3.rfPower = index;
emit modified();
}
else if(module.pxx.power != (unsigned int)index)
module.pxx.power = index;
}
}
@ -766,12 +786,21 @@ void ModulePanel::onSubTypeChanged()
if (!lock && module.subType != type) {
lock=true;
module.subType = type;
update();
if (module.protocol != PULSES_AFHDS3) {
update();
}
emit modified();
lock = false;
}
}
void ModulePanel::onRfFreqChanged(int freq) {
if (module.afhds3.rxFreq != (unsigned int)freq) {
module.afhds3.rxFreq = (unsigned int)freq;
emit modified();
}
}
void ModulePanel::on_disableTelem_stateChanged(int state)
{
module.multi.disableTelemetry = (state == Qt::Checked);

View file

@ -97,6 +97,7 @@ class ModulePanel : public ModelPanel
void onFailsafeUsecChanged(int value);
void onFailsafePercentChanged(double value);
void onFailsafesDisplayValueTypeChanged(int type);
void onRfFreqChanged(int freq);
void updateFailsafe(unsigned channel);
void on_optionValue_editingFinished();
void onClearAccessRxClicked();

View file

@ -126,6 +126,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
@ -173,6 +179,15 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string/>
</property>
@ -214,6 +229,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
@ -417,6 +438,7 @@
<item>
<widget class="QCheckBox" name="autoBind">
<property name="text">
<string/>
</property>
</widget>
</item>
@ -485,6 +507,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
@ -529,6 +557,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
@ -573,6 +607,15 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> ms</string>
</property>
@ -617,19 +660,58 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_rxFreq">
<property name="text">
<string>RX Frequency</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_option">
<property name="text">
<string>Option value</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="optionValue">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_ppmOutputType">
<property name="text">
<string>Output type</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QComboBox" name="ppmOutputType">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@ -652,21 +734,7 @@
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_option">
<property name="text">
<string>Option value</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="optionValue">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<item row="7" column="0" colspan="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -679,6 +747,34 @@
</property>
</spacer>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="rxFreq">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="suffix">
<string> Hz</string>
</property>
<property name="minimum">
<number>50</number>
</property>
<property name="maximum">
<number>400</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
@ -711,11 +807,17 @@
<item row="0" column="1">
<widget class="QComboBox" name="protocol">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>180</width>
<height>0</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
@ -754,11 +856,17 @@
<item row="2" column="1">
<widget class="QComboBox" name="multiProtocol">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
@ -774,11 +882,17 @@
<item row="3" column="1">
<widget class="QComboBox" name="multiSubType">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
@ -847,11 +961,17 @@
<item row="5" column="1">
<widget class="QComboBox" name="failsafeMode">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
@ -901,11 +1021,17 @@
<item row="6" column="1">
<widget class="QComboBox" name="trainerMode">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
@ -934,17 +1060,17 @@
<string>Master/SBUS in battery compartment</string>
</property>
</item>
<item>
<item>
<property name="text">
<string>Master/Bluetooth</string>
</property>
</item>
<item>
<item>
<property name="text">
<string>Slave/Bluetooth</string>
</property>
</item>
<item>
<item>
<property name="text">
<string>Master/Multi</string>
</property>

View file

@ -224,6 +224,11 @@ QString ModelPrinter::printModule(int idx)
str << printLabelValue(tr("Sub Type"), module.subTypeToString());
str << printLabelValue(tr("RF Output Power"), module.powerValueToString(firmware));
}
if (module.protocol == PULSES_AFHDS3) {
str << printLabelValue(tr("Output Type"), module.subTypeToString());
str << printLabelValue(tr("RF Output Power"), module.powerValueToString(firmware));
str << printLabelValue(tr("RX Output Frequency"), QString("%1Hz").arg(module.afhds3.rxFreq));
}
}
}
result = str.join(" ");

View file

@ -269,7 +269,8 @@ enum TelemetryProtocol
PROTOCOL_TELEMETRY_HITEC,
PROTOCOL_TELEMETRY_HOTT,
PROTOCOL_TELEMETRY_MULTIMODULE,
PROTOCOL_TELEMETRY_LAST=PROTOCOL_TELEMETRY_MULTIMODULE,
PROTOCOL_TELEMETRY_AFHDS3,
PROTOCOL_TELEMETRY_LAST=PROTOCOL_TELEMETRY_AFHDS3,
PROTOCOL_TELEMETRY_LUA
};

View file

@ -454,6 +454,24 @@ PACK(struct ModuleData {
uint8_t receivers; // 5 bits spare
char receiverName[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME];
}) pxx2);
NOBACKUP(PACK(struct {
uint8_t bindPower:3;
uint8_t runPower:3;
uint8_t emi:1;
uint8_t telemetry:1;
uint16_t failsafeTimeout;
uint8_t rx_freq[2];
uint16_t rxFreq()
{
return (uint16_t)rx_freq[0] | (((uint16_t)rx_freq[1]) << 8);
}
void setRxFreq(uint16_t value)
{
rx_freq[0] = value & 0xFF;
rx_freq[1] = value >> 8;
}
} afhds3));
};
// Helper functions to set both of the rfProto protocol at the same time

View file

@ -118,12 +118,22 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS,
#endif
#if defined(AFHDS3)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS_PROTOCOL,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS,
#endif
ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS,
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
#if defined(AFHDS3)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_RX_FREQ,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_ACTUAL_POWER,
#endif
ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS,
@ -132,6 +142,7 @@ enum MenuModelSetupItems {
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,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_OPTIONS,
@ -204,11 +215,6 @@ inline uint8_t MODULE_TYPE_ROWS(int moduleIdx)
{
if (isModuleXJT(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx))
return 1;
#if defined(MULTIMODULE)
else if (isModuleMultimodule(moduleIdx)) {
return 0;
}
#endif
else
return 0;
}
@ -300,6 +306,9 @@ void onBluetoothConnectMenu(const char * result)
#if defined(PXX2)
#include "common/stdlcd/model_setup_pxx2.cpp"
#endif
#if defined(AFHDS3)
#include "common/stdlcd/model_setup_afhds3.cpp"
#endif
#if defined(HARDWARE_INTERNAL_MODULE)
#define INTERNAL_MODULE_ROWS \
@ -364,9 +373,12 @@ void menuModelSetup(event_t event)
MULTIMODULE_TYPE_ROWS(EXTERNAL_MODULE) // PROTOCOL
MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE) // SUBTYPE
MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE)
AFHDS3_PROTOCOL_ROW(EXTERNAL_MODULE)
AFHDS3_MODE_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
AFHDS3_MODULE_ROWS(EXTERNAL_MODULE)
MODULE_POWER_ROW(EXTERNAL_MODULE),
IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)),
MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE)
@ -406,6 +418,7 @@ void menuModelSetup(event_t event)
MODULE_TYPE_ROWS(EXTERNAL_MODULE),
MULTIMODULE_SUBTYPE_ROWS(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
@ -1047,6 +1060,21 @@ void menuModelSetup(event_t event)
break;
#endif
#if defined(AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS_PROTOCOL:
lcdDrawTextAlignedLeft(y, TR_PROTO);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_AFHDS3_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].subType, attr);
if (attr && s_editMode > 0 && menuHorizontalPosition == 0) {
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, AFHDS_SUBTYPE_FIRST, AFHDS_SUBTYPE_LAST);
}
break;
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE:
lcdDrawText(INDENT_WIDTH, y, TR_TELEMETRY_TYPE);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y,
g_model.moduleData[EXTERNAL_MODULE].afhds3.telemetry ? STR_AFHDS3_ONE_TO_ONE_TELEMETRY : TR_AFHDS3_ONE_TO_MANY);
break;
#endif
#if defined(PCBTARANIS)
case ITEM_MODEL_SETUP_TRAINER_LABEL:
lcdDrawTextAlignedLeft(y, STR_TRAINER);
@ -1352,7 +1380,7 @@ void menuModelSetup(event_t event)
if (attr && l_posHorz > 0) {
if (s_editMode > 0) {
if (l_posHorz == 1) {
if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx)) {
if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx) || isModuleAFHDS3(moduleIdx)) {
#if defined(PCBXLITE)
if (EVT_KEY_MASK(event) == KEY_ENTER) {
#elif defined(NAVIGATION_9X)
@ -1361,6 +1389,12 @@ void menuModelSetup(event_t event)
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
#endif
killEvents(event);
#if defined(AFHDS3)
if (isModuleAFHDS3(moduleIdx)) {
startBindMenuAfhds3(moduleIdx);
continue;
}
#endif
startBindMenu(moduleIdx);
continue;
}
@ -1604,6 +1638,14 @@ void menuModelSetup(event_t event)
module.multi.lowPowerMode = editCheckBox(module.multi.lowPowerMode, MODEL_SETUP_2ND_COLUMN, y, IS_RX_MULTI(moduleIdx) ? STR_MULTI_LNA_DISABLE : STR_MULTI_LOWPOWER, attr, event);
}
#endif
#if defined(AFHDS3)
else if (isModuleAFHDS3(EXTERNAL_MODULE)) {
lcdDrawText(INDENT_WIDTH, y, STR_RFPOWER);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_AFHDS3_POWERS, g_model.moduleData[EXTERNAL_MODULE].afhds3.runPower, LEFT | attr);
if (attr)
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].afhds3.runPower, afhds3::RUN_POWER::RUN_POWER_FIRST, afhds3::RUN_POWER::RUN_POWER_LAST);
}
#endif
}
break;
@ -1630,7 +1672,25 @@ void menuModelSetup(event_t event)
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;
#endif
#if defined(AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_RX_FREQ:
lcdDrawText(INDENT_WIDTH, y, STR_AFHDS3_RX_FREQ);
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.moduleData[EXTERNAL_MODULE].afhds3.rxFreq(), attr | LEFT);
if (attr) {
uint16_t rxFreq = g_model.moduleData[EXTERNAL_MODULE].afhds3.rxFreq();
CHECK_INCDEC_MODELVAR(event, rxFreq, MIN_FREQ, MAX_FREQ);
g_model.moduleData[EXTERNAL_MODULE].afhds3.setRxFreq(rxFreq);
}
break;
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_ACTUAL_POWER:
lcdDrawText(INDENT_WIDTH, y, STR_AFHDS3_ACTUAL_POWER);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_AFHDS3_POWERS, actualAfhdsRunPower(EXTERNAL_MODULE), LEFT);
break;
#endif
#if defined(MULTIMODULE)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS:
#endif
@ -1638,7 +1698,7 @@ void menuModelSetup(event_t event)
lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS);
char statusText[64];
getMultiModuleStatus(moduleIdx).getStatusString(statusText);
getModuleStatusString(moduleIdx, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
@ -1647,9 +1707,26 @@ void menuModelSetup(event_t event)
#endif
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS: {
lcdDrawTextAlignedLeft(y, STR_MODULE_SYNC);
char statusText[64];
getModuleSyncStatusString(moduleIdx, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
#endif
#if defined(AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS: {
lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS);
char statusText[64];
getMultiSyncStatus(moduleIdx).getRefreshString(statusText);
getModuleStatusString(moduleIdx, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS: {
lcdDrawText(INDENT_WIDTH, y, STR_AFHDS3_POWER_SOURCE);
char statusText[64];
getModuleSyncStatusString(moduleIdx, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}

View file

@ -101,6 +101,11 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS,
#endif
#if defined(AFHDS3)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS,
#endif
ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
@ -110,6 +115,10 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING,
#endif
#if defined(AFHDS3)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_RX_FREQ,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_ACTUAL_POWER,
#endif
ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE,
@ -247,7 +256,7 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event)
inline uint8_t EXTERNAL_MODULE_TYPE_ROW()
{
if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE))
if (isModuleXJT(EXTERNAL_MODULE) || isModuleR9MNonAccess(EXTERNAL_MODULE) || isModuleDSM2(EXTERNAL_MODULE) || isModuleAFHDS3(EXTERNAL_MODULE))
return 1;
else
return 0;
@ -304,6 +313,10 @@ void onBluetoothConnectMenu(const char * result)
#if defined(PXX2)
#include "common/stdlcd/model_setup_pxx2.cpp"
#endif
#if defined(AFHDS3)
#include "common/stdlcd/model_setup_afhds3.cpp"
#endif
void menuModelSetup(event_t event)
{
@ -360,11 +373,13 @@ void menuModelSetup(event_t event)
EXTERNAL_MODULE_TYPE_ROW(),
MULTIMODULE_TYPE_ROW(EXTERNAL_MODULE)
MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE)
AFHDS3_MODE_ROWS(EXTERNAL_MODULE)
MODULE_CHANNELS_ROWS(EXTERNAL_MODULE),
IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)),
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum for ACCESS
IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)),
MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE)
AFHDS3_MODULE_ROWS(EXTERNAL_MODULE)
MODULE_POWER_ROW(EXTERNAL_MODULE),
FAILSAFE_ROWS(EXTERNAL_MODULE),
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons
@ -810,6 +825,11 @@ void menuModelSetup(event_t event)
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));
#if defined(AFHDS3)
else if (isModuleAFHDS3(EXTERNAL_MODULE)) {
lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_AFHDS3_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].subType, (menuHorizontalPosition==1 ? attr : 0));
}
#endif
if (attr && menuHorizontalPosition == 0) {
if (s_editMode > 0) {
g_model.moduleData[EXTERNAL_MODULE].type = MODULE_TYPE_NONE;
@ -850,6 +870,11 @@ void menuModelSetup(event_t event)
MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LAST, EE_MODEL,
isR9MModeAvailable);
}
#if defined(AFHDS3)
else if (isModuleAFHDS3(EXTERNAL_MODULE)) {
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, AFHDS_SUBTYPE_FIRST, AFHDS_SUBTYPE_LAST);
}
#endif
else {
g_model.moduleData[EXTERNAL_MODULE].subType = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].subType,
MODULE_SUBTYPE_PXX1_ACCST_D16, MODULE_SUBTYPE_PXX1_LAST, EE_MODEL,
@ -898,6 +923,7 @@ void menuModelSetup(event_t event)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL:
{
lcdDrawTextAlignedLeft(y, TR_TYPE);
uint8_t multi_rfProto = g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol();
lcdDrawMultiProtocolString(MODEL_SETUP_2ND_COLUMN, y, EXTERNAL_MODULE, multi_rfProto, menuHorizontalPosition == 0 ? attr : 0);
if (MULTIMODULE_HAS_SUBTYPE(EXTERNAL_MODULE))
@ -946,7 +972,6 @@ void menuModelSetup(event_t event)
}
break;
#endif
case ITEM_MODEL_SETUP_TRAINER_LABEL:
lcdDrawTextAlignedLeft(y, STR_TRAINER);
break;
@ -1170,8 +1195,14 @@ void menuModelSetup(event_t event)
if (attr && l_posHorz > 0) {
if (s_editMode > 0) {
if (l_posHorz == 1) {
if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx)) {
if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx) || isModuleAFHDS3(moduleIdx)) {
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
#if defined(AFHDS3)
if (isModuleAFHDS3(moduleIdx)) {
startBindMenuAfhds3(moduleIdx);
continue;
}
#endif
startBindMenu(moduleIdx);
continue;
}
@ -1327,6 +1358,14 @@ void menuModelSetup(event_t event)
else if (isModuleMultimodule(moduleIdx)) {
g_model.moduleData[EXTERNAL_MODULE].multi.lowPowerMode = editCheckBox(g_model.moduleData[EXTERNAL_MODULE].multi.lowPowerMode, MODEL_SETUP_2ND_COLUMN, y, IS_RX_MULTI(moduleIdx) ? STR_MULTI_LNA_DISABLE : STR_MULTI_LOWPOWER, attr, event);
}
#endif
#if defined(AFHDS3)
else if (isModuleAFHDS3(EXTERNAL_MODULE)) {
lcdDrawText(INDENT_WIDTH, y, STR_RFPOWER);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_AFHDS3_POWERS, g_model.moduleData[EXTERNAL_MODULE].afhds3.runPower, LEFT | attr);
if (attr)
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].afhds3.runPower, afhds3::RUN_POWER::RUN_POWER_FIRST, afhds3::RUN_POWER::RUN_POWER_LAST);
}
#endif
break;
}
@ -1346,26 +1385,68 @@ void menuModelSetup(event_t event)
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;
#endif
#if defined(AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_RX_FREQ:
lcdDrawText(INDENT_WIDTH, y, STR_AFHDS3_RX_FREQ);
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.moduleData[EXTERNAL_MODULE].afhds3.rxFreq(), attr | LEFT);
if (attr) {
uint16_t rxFreq = g_model.moduleData[EXTERNAL_MODULE].afhds3.rxFreq();
CHECK_INCDEC_MODELVAR(event, rxFreq, MIN_FREQ, MAX_FREQ);
g_model.moduleData[EXTERNAL_MODULE].afhds3.setRxFreq(rxFreq);
}
break;
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_ACTUAL_POWER:
lcdDrawText(INDENT_WIDTH, y, STR_AFHDS3_ACTUAL_POWER);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_AFHDS3_POWERS, actualAfhdsRunPower(EXTERNAL_MODULE), LEFT);
break;
#endif
#if defined (MULTIMODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS:
{
lcdDrawTextAlignedLeft(y, STR_MODULE_STATUS);
lcdDrawText(INDENT_WIDTH, y, STR_MODULE_STATUS);
char statusText[64];
getMultiModuleStatus(EXTERNAL_MODULE).getStatusString(statusText);
getModuleStatusString(EXTERNAL_MODULE, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS:
{
lcdDrawTextAlignedLeft(y, STR_MODULE_SYNC);
lcdDrawText(INDENT_WIDTH, y, STR_MODULE_SYNC);
char statusText[64];
getMultiSyncStatus(EXTERNAL_MODULE).getRefreshString(statusText);
getModuleSyncStatusString(EXTERNAL_MODULE, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
#endif
#if defined (AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE:
lcdDrawTextAlignedLeft(y, STR_TYPE);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y,
g_model.moduleData[EXTERNAL_MODULE].afhds3.telemetry ? STR_AFHDS3_ONE_TO_ONE_TELEMETRY : TR_AFHDS3_ONE_TO_MANY);
break;
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS:
{
lcdDrawTextAlignedLeft(y, TR_MODULE_STATUS);
char statusText[64];
getModuleStatusString(EXTERNAL_MODULE, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS:
{
lcdDrawText(INDENT_WIDTH, y, STR_AFHDS3_POWER_SOURCE);
char statusText[64];
getModuleSyncStatusString(EXTERNAL_MODULE, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
#endif
#if defined(PXX2)
case ITEM_MODEL_SETUP_REGISTRATION_ID:
lcdDrawTextAlignedLeft(y, STR_REG_ID);

View file

@ -98,6 +98,11 @@ enum MenuModelSetupItems {
#if defined(MULTIMODULE)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS,
#endif
#if defined(AFHDS3)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS,
#endif
ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
@ -107,6 +112,10 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING,
#endif
#if defined(AFHDS3)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_RX_FREQ,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_ACTUAL_POWER,
#endif
ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE,
@ -115,7 +124,6 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_2,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_3,
ITEM_MODEL_SETUP_TRAINER_LABEL,
ITEM_MODEL_SETUP_TRAINER_MODE,
#if defined(BLUETOOTH)
@ -156,6 +164,10 @@ void onBluetoothConnectMenu(const char * result)
#include "common/stdlcd/model_setup_pxx1.cpp"
#if defined(AFHDS3)
#include "common/stdlcd/model_setup_afhds3.cpp"
#endif
void onPXX2R9MBindModeMenu(const char * result)
{
if (result == STR_16CH_WITH_TELEMETRY) {
@ -502,7 +514,7 @@ int getSwitchWarningsCount()
inline uint8_t MODULE_TYPE_ROWS(int moduleIdx)
{
if (isModuleXJT(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx) || isModulePXX2(moduleIdx))
if (isModuleXJT(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleDSM2(moduleIdx) || isModulePXX2(moduleIdx) || isModuleAFHDS3(moduleIdx))
return 1;
#if defined(MULTIMODULE)
else if (isModuleMultimodule(moduleIdx)) {
@ -622,11 +634,13 @@ bool menuModelSetup(event_t event)
LABEL(ExternalModule),
MODULE_TYPE_ROWS(EXTERNAL_MODULE),
MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE)
AFHDS3_MODE_ROWS(EXTERNAL_MODULE)
MODULE_CHANNELS_ROWS(EXTERNAL_MODULE),
IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)),
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), // RxNum for ACCESS
IF_NOT_PXX2_MODULE(EXTERNAL_MODULE, MODULE_OPTION_ROW(EXTERNAL_MODULE)),
MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE)
AFHDS3_MODULE_ROWS(EXTERNAL_MODULE)
MODULE_POWER_ROW(EXTERNAL_MODULE),
FAILSAFE_ROWS(EXTERNAL_MODULE),
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 1), // Range check and Register buttons
@ -1074,6 +1088,11 @@ bool menuModelSetup(event_t event)
if (MULTIMODULE_HAS_SUBTYPE(moduleIdx))
lcdDrawMultiSubProtocolString(MODEL_SETUP_4TH_COLUMN, y, moduleIdx, g_model.moduleData[moduleIdx].subType, menuHorizontalPosition==2 ? attr : 0);
}
#endif
#if defined(AFHDS3)
else if (isModuleAFHDS3(moduleIdx)) {
lcdDrawTextAtIndex(lcdNextPos + 15, y, STR_AFHDS3_PROTOCOLS, g_model.moduleData[moduleIdx].subType, (menuHorizontalPosition==1 ? attr : 0));
}
#endif
if (attr && menuHorizontalPosition == 0 && moduleIdx == EXTERNAL_MODULE) {
if (s_editMode > 0) {
@ -1143,6 +1162,11 @@ bool menuModelSetup(event_t event)
g_model.moduleData[moduleIdx].subType = checkIncDec(event, g_model.moduleData[moduleIdx].subType, MODULE_SUBTYPE_R9M_FCC,
MODULE_SUBTYPE_R9M_LAST, EE_MODEL, isR9MModeAvailable);
}
#if defined(AFHDS3)
else if (isModuleAFHDS3(moduleIdx)) {
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, AFHDS_SUBTYPE_FIRST, AFHDS_SUBTYPE_LAST);
}
#endif
else {
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].subType, MODULE_SUBTYPE_PXX1_ACCST_D16, MODULE_SUBTYPE_PXX1_LAST);
}
@ -1552,8 +1576,14 @@ bool menuModelSetup(event_t event)
if (attr && l_posHorz>0) {
if (s_editMode>0) {
if (l_posHorz == 1) {
if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx)) {
if (isModuleR9MNonAccess(moduleIdx) || isModuleD16(moduleIdx) || isModuleAFHDS3(moduleIdx)) {
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
#if defined(AFHDS3)
if (isModuleAFHDS3(moduleIdx)) {
startBindMenuAfhds3(moduleIdx);
continue;
}
#endif
startBindMenu(moduleIdx);
continue;
}
@ -1707,6 +1737,14 @@ bool menuModelSetup(event_t event)
lcdDrawText(MENUS_MARGIN_LEFT, y, IS_RX_MULTI(moduleIdx) ? STR_MULTI_LNA_DISABLE : STR_MULTI_LOWPOWER);
g_model.moduleData[moduleIdx].multi.lowPowerMode = editCheckBox(g_model.moduleData[moduleIdx].multi.lowPowerMode, MODEL_SETUP_2ND_COLUMN, y, attr, event);
}
#endif
#if defined(AFHDS3)
else if (isModuleAFHDS3(moduleIdx)) {
lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_RFPOWER);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_AFHDS3_POWERS, g_model.moduleData[moduleIdx].afhds3.runPower, LEFT | attr);
if (attr)
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[moduleIdx].afhds3.runPower, afhds3::RUN_POWER::RUN_POWER_FIRST, afhds3::RUN_POWER::RUN_POWER_LAST);
}
#endif
}
break;
@ -1722,7 +1760,6 @@ bool menuModelSetup(event_t event)
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MULTI_AUTOBIND);
g_model.moduleData[moduleIdx].multi.autoBindMode = editCheckBox(g_model.moduleData[moduleIdx].multi.autoBindMode, MODEL_SETUP_2ND_COLUMN, y, attr, event);
break;
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_TELEM:
#endif
@ -1730,7 +1767,6 @@ bool menuModelSetup(event_t event)
lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_DISABLE_TELEM);
g_model.moduleData[moduleIdx].multi.disableTelemetry = editCheckBox(g_model.moduleData[moduleIdx].multi.disableTelemetry, MODEL_SETUP_2ND_COLUMN, y, attr, event);
break;
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_DISABLE_MAPPING:
#endif
@ -1738,29 +1774,65 @@ bool menuModelSetup(event_t event)
lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_DISABLE_CH_MAP);
g_model.moduleData[moduleIdx].multi.disableMapping = editCheckBox(g_model.moduleData[moduleIdx].multi.disableMapping, MODEL_SETUP_2ND_COLUMN, y, attr, event);
break;
#endif
#if defined(AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE:
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_TYPE);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y,
g_model.moduleData[EXTERNAL_MODULE].afhds3.telemetry ? STR_AFHDS3_ONE_TO_ONE_TELEMETRY : TR_AFHDS3_ONE_TO_MANY);
break;
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_RX_FREQ:
lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_AFHDS3_RX_FREQ);
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.moduleData[moduleIdx].afhds3.rxFreq(), attr | LEFT, 0, NULL, "Hz");
if (attr) {
uint16_t rxFreq = g_model.moduleData[moduleIdx].afhds3.rxFreq();
CHECK_INCDEC_MODELVAR(event, rxFreq, MIN_FREQ, MAX_FREQ);
g_model.moduleData[moduleIdx].afhds3.setRxFreq(rxFreq);
}
break;
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_ACTUAL_POWER:
lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_AFHDS3_ACTUAL_POWER);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_AFHDS3_POWERS, actualAfhdsRunPower(moduleIdx), LEFT);
break;
#endif
#if defined(MULTIMODULE) || defined(AFHDS3)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_STATUS:
#endif
#if defined(AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS:
#endif
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS:
{
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MODULE_STATUS);
char statusText[64];
getMultiModuleStatus(moduleIdx).getStatusString(statusText);
getModuleStatusString(moduleIdx, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS:
#endif
#if defined(AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS:
#endif
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS:
{
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MODULE_SYNC);
#if defined(AFHDS3)
if (isModuleAFHDS3(moduleIdx)) {
lcdDrawText(MENUS_MARGIN_LEFT + INDENT_WIDTH, y, STR_AFHDS3_POWER_SOURCE);
}
else
#endif
{
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MODULE_SYNC);
}
char statusText[64];
getMultiSyncStatus(moduleIdx).getRefreshString(statusText);
getModuleSyncStatusString(moduleIdx, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}

View file

@ -0,0 +1,48 @@
/*
* 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.
*/
void onBindMenuAfhds3(const char * result)
{
uint8_t moduleIdx = CURRENT_MODULE_EDITED(menuVerticalPosition - HEADER_LINE);
if (result == STR_AFHDS3_ONE_TO_ONE_TELEMETRY) {
g_model.moduleData[EXTERNAL_MODULE].afhds3.telemetry = 1;
}
else if (result == STR_AFHDS3_ONE_TO_MANY) {
g_model.moduleData[EXTERNAL_MODULE].afhds3.telemetry = 0;
}
else {
return;
}
moduleState[moduleIdx].mode = MODULE_MODE_BIND;
}
void startBindMenuAfhds3(uint8_t moduleIdx)
{
uint8_t selection = 0;
#if defined(AFHDS3)
POPUP_MENU_ADD_ITEM(STR_AFHDS3_ONE_TO_ONE_TELEMETRY);
POPUP_MENU_ADD_ITEM(STR_AFHDS3_ONE_TO_MANY);
#endif
POPUP_MENU_SELECT_ITEM(selection);
POPUP_MENU_START(onBindMenuAfhds3);
}

View file

@ -551,6 +551,7 @@ bool isModuleUsingSport(uint8_t moduleBay, uint8_t moduleType)
case MODULE_TYPE_ISRM_PXX2:
case MODULE_TYPE_R9M_LITE_PXX2:
case MODULE_TYPE_R9M_LITE_PRO_PXX2:
case MODULE_TYPE_AFHDS3:
return false;
case MODULE_TYPE_XJT_PXX1:
@ -663,6 +664,11 @@ bool isExternalModuleAvailable(int moduleType)
return false;
#endif
#if !defined(AFHDS3)
if (moduleType == MODULE_TYPE_AFHDS3)
return false;
#endif
return true;
}
@ -708,6 +714,12 @@ bool isTelemetryProtocolAvailable(int protocol)
}
#endif
#if !defined(AFHDS3)
if (protocol == PROTOCOL_TELEMETRY_AFHDS3) {
return false;
}
#endif
#if defined(PCBHORUS)
if (protocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) {
return false;

View file

@ -147,7 +147,7 @@ inline uint8_t MODULE_BIND_ROWS(int moduleIdx)
else
return 2;
}
else if (isModuleXJTD8(moduleIdx) || isModuleSBUS(moduleIdx)) {
else if (isModuleXJTD8(moduleIdx) || isModuleSBUS(moduleIdx) || isModuleAFHDS3(moduleIdx)) {
return 1;
}
else if (isModulePPM(moduleIdx) || isModulePXX1(moduleIdx) || isModulePXX2(moduleIdx) || isModuleDSM2(moduleIdx)) {
@ -276,9 +276,10 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx)
#define MULTIMODULE_TYPE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW,
#define MULTIMODULE_SUBTYPE_ROWS(moduleIdx) isModuleMultimodule(moduleIdx) ? MULTIMODULE_RFPROTO_COLUMNS(moduleIdx) : HIDDEN_ROW,
#define MULTIMODULE_OPTIONS_ROW(moduleIdx) (isModuleMultimodule(moduleIdx) && MULTIMODULE_HASOPTIONS(moduleIdx)) ? (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
#define MODULE_POWER_ROW(moduleIdx) (MULTIMODULE_PROTOCOL_KNOWN(moduleIdx) || isModuleR9MNonAccess(moduleIdx) || isModuleAFHDS3(moduleIdx)) ? (isModuleR9MLiteNonPro(moduleIdx) ? (isModuleR9M_FCC_VARIANT(moduleIdx) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW
#else
#define MULTIMODULE_TYPE_ROWS(moduleIdx)
#define MULTIMODULE_STATUS_ROWS(moduleIdx)
#define MULTIMODULE_MODULE_ROWS(moduleIdx)
#define MULTIMODULE_TYPE_ROW(moduleIdx)
@ -286,11 +287,28 @@ inline uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx)
#define MULTIMODULE_TYPE_ROWS(moduleIdx)
#define MULTIMODULE_MODE_ROWS(moduleIdx) (uint8_t)0
#define MULTIMODULE_OPTIONS_ROW(moduleIdx) HIDDEN_ROW
#define MODULE_POWER_ROW(moduleIdx) isModuleR9MNonAccess(moduleIdx) ? (isModuleR9MLiteNonPro(moduleIdx) ? (isModuleR9M_FCC_VARIANT(moduleIdx) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW
#define MODULE_POWER_ROW(moduleIdx) isModuleR9MNonAccess(moduleIdx) || isModuleAFHDS3(moduleIdx) ? (isModuleR9MLiteNonPro(moduleIdx) ? (isModuleR9M_FCC_VARIANT(moduleIdx) ? READONLY_ROW : (uint8_t)0) : (uint8_t)0) : HIDDEN_ROW
#endif
#if defined(AFHDS3)
#define AFHDS3_PROTOCOL_ROW(moduleIdx) isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW,
#define AFHDS3_MODE_ROWS(moduleIdx) isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? TITLE_ROW : HIDDEN_ROW,
#define AFHDS3_MODULE_ROWS(moduleIdx) isModuleAFHDS3(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW, isModuleAFHDS3(moduleIdx) ? (uint8_t) TITLE_ROW : HIDDEN_ROW,
#else
#define AFHDS3_PROTOCOL_ROW(moduleIdx)
#define AFHDS3_MODE_ROWS(moduleIdx)
#define AFHDS3_MODULE_ROWS(moduleIdx)
#endif
#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))
inline uint8_t MODULE_OPTION_ROW(uint8_t moduleIdx) {
if(isModuleR9MNonAccess(moduleIdx) || isModuleSBUS(moduleIdx))
return TITLE_ROW;
if(isModuleAFHDS3(moduleIdx))
return HIDDEN_ROW;
return MULTIMODULE_OPTIONS_ROW(moduleIdx);
}
void editStickHardwareSettings(coord_t x, coord_t y, int idx, event_t event, LcdFlags flags);

706
radio/src/pulses/afhds3.cpp Normal file
View file

@ -0,0 +1,706 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "afhds3.h"
#include "../debug.h"
#include "../definitions.h"
#include <cstdio>
#define FAILSAFE_HOLD 1
#define FAILSAFE_CUSTOM 2
#define MAX_RETRIES_AFHDS3 5
extern void processFlySkySensor(const uint8_t * packet, uint8_t type);
extern void extmoduleSerialStart(uint32_t baudrate, uint32_t period_half_us, bool inverted);
namespace afhds3
{
static const char* const moduleStateText[] =
{
"Not ready",
"HW Error",
"Binding",
"Connecting",
"Connected",
"Standby",
"Waiting for update",
"Updating",
"Updating RX",
"Updating RX failed",
"Testing",
"Ready",
"HW test"
};
static const char* const powerSourceText[] =
{
"Unknown",
"Internal",
"External"
};
static const COMMAND periodicRequestCommands[] =
{
COMMAND::MODULE_STATE,
COMMAND::MODULE_POWER_STATUS,
COMMAND::MODULE_GET_CONFIG,
COMMAND::VIRTUAL_FAILSAFE
};
//Address used in transmitted frames - it constrains of target address and source address
const uint8_t FrameAddress = DeviceAddress::TRANSMITTER | (DeviceAddress::MODULE << 4);
//Static collection of afhds3 object instances by module
PulsesData* AFHDS3PulsesData[EXTERNAL_MODULE + 1] = { nullptr, nullptr };
//friends function that can access telemetry parsing method
void processTelemetryData(uint8_t module, uint8_t data, uint8_t* rxBuffer, uint8_t& rxBufferCount, uint8_t maxSize)
{
if (AFHDS3PulsesData[module]) {
AFHDS3PulsesData[module]->processTelemetryData(data, rxBuffer, rxBufferCount, maxSize);
}
}
void CommandFifo::clearCommandFifo()
{
memclear(commandFifo, sizeof(commandFifo));
setIndex = getIndex = 0;
}
void CommandFifo::enqueueACK(COMMAND command, uint8_t frameNumber)
{
uint32_t next = nextIndex(setIndex);
if (next != getIndex) {
commandFifo[setIndex].command = command;
commandFifo[setIndex].frameType = FRAME_TYPE::RESPONSE_ACK;
commandFifo[setIndex].payload = 0;
commandFifo[setIndex].payloadSize = 0;
commandFifo[setIndex].frameNumber = frameNumber;
commandFifo[setIndex].useFrameNumber = true;
setIndex = next;
}
}
void CommandFifo::enqueue(COMMAND command, FRAME_TYPE frameType, bool useData, uint8_t byteContent)
{
uint32_t next = nextIndex(setIndex);
if (next != getIndex) {
commandFifo[setIndex].command = command;
commandFifo[setIndex].frameType = frameType;
commandFifo[setIndex].payload = byteContent;
commandFifo[setIndex].payloadSize = useData ? 1 : 0;
commandFifo[setIndex].frameNumber = 0;
commandFifo[setIndex].useFrameNumber = false;
setIndex = next;
}
}
void PulsesData::getStatusString(char * buffer) const
{
strcpy(buffer, this->state <= ModuleState::STATE_READY ? moduleStateText[this->state] : "Unknown");
}
void PulsesData::getPowerStatus(char* buffer) const
{
strcpy(buffer, this->powerSource <= MODULE_POWER_SOURCE::EXTERNAL ? powerSourceText[this->powerSource] : "Unknown");
}
void PulsesData::processTelemetryData(uint8_t byte, uint8_t* rxBuffer, uint8_t& rxBufferCount, uint8_t maxSize)
{
if (rxBufferCount == 0 && byte != AfhdsSpecialChars::START) {
TRACE("AFHDS3 [SKIP] %02X", byte);
this->esc_state = 0;
return;
}
if (byte == AfhdsSpecialChars::ESC) {
this->esc_state = rxBufferCount;
return;
}
if (rxBufferCount > 1 && byte == AfhdsSpecialChars::END) {
rxBuffer[rxBufferCount++] = byte;
parseData(rxBuffer, rxBufferCount);
rxBufferCount = 0;
return;
}
if (this->esc_state && byte == AfhdsSpecialChars::ESC_END) {
byte = AfhdsSpecialChars::END;
}
else if (esc_state && byte == AfhdsSpecialChars::ESC_ESC) {
byte = AfhdsSpecialChars::ESC;
}
//reset esc index
this->esc_state = 0;
if (rxBufferCount >= maxSize) {
TRACE("AFHDS3 [BUFFER OVERFLOW]");
rxBufferCount = 0;
}
rxBuffer[rxBufferCount++] = byte;
}
bool PulsesData::isConnectedUnicast()
{
return cfg.config.telemetry == TELEMETRY::TELEMETRY_ENABLED && this->state == ModuleState::STATE_SYNC_DONE;
}
bool PulsesData::isConnectedMulticast()
{
return cfg.config.telemetry == TELEMETRY::TELEMETRY_DISABLED && this->state == ModuleState::STATE_SYNC_RUNNING;
}
void PulsesData::setupFrame()
{
if (operationState == State::AWAITING_RESPONSE) {
if (repeatCount++ < MAX_RETRIES_AFHDS3) {
return; //re-send
}
else
{
TRACE("AFHDS3 [NO RESP] module state %d", this->state);
clearFrameData();
this->state = ModuleState::STATE_NOT_READY;
}
}
else if (operationState == State::UNKNOWN) {
this->state = ModuleState::STATE_NOT_READY;
}
repeatCount = 0;
if (this->state == ModuleState::STATE_NOT_READY) {
TRACE("AFHDS3 [GET MODULE READY]");
putFrame(COMMAND::MODULE_READY, FRAME_TYPE::REQUEST_GET_DATA);
return;
}
//check waiting commands
if (!isEmpty()) {
Frame f = commandFifo[getIndex];
putFrame(f.command, f.frameType, &f.payload, f.payloadSize, f.useFrameNumber ? &f.frameNumber : &frame_index);
getIndex = nextIndex(getIndex);
TRACE("AFHDS3 [CMD QUEUE] cmd: %d frameType %d, useFrameNumber %d frame Number %d size %d", f.command, f.frameType, f.useFrameNumber, f.frameNumber, f.payloadSize);
return;
}
//config should be loaded already
if (syncSettings()) {
return;
}
//if module is ready but not started
if (this->state == ModuleState::STATE_READY || this->state == ModuleState::STATE_STANDBY) {
cmdCount = 0;
repeatCount = 0;
requestInfoAndRun(true);
return;
}
::ModuleSettingsMode moduleMode = getModuleMode(module_index);
if (moduleMode == ::ModuleSettingsMode::MODULE_MODE_BIND) {
if (state != STATE_BINDING) {
TRACE("AFHDS3 [BIND]");
setConfigFromModel();
putFrame(COMMAND::MODULE_SET_CONFIG, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, cfg.buffer, sizeof(cfg.buffer));
requestedModuleMode = MODULE_MODE_E::BIND;
enqueue(COMMAND::MODULE_MODE, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, true, requestedModuleMode);
return;
}
}
else if (moduleMode == ::ModuleSettingsMode::MODULE_MODE_RANGECHECK) {
if (cfg.config.runPower != RUN_POWER::RUN_POWER_FIRST) {
TRACE("AFHDS3 [RANGE CHECK]");
cfg.config.runPower = RUN_POWER::RUN_POWER_FIRST;
uint8_t data[] = { 0x13, 0x20, 0x02, cfg.config.runPower, 0 };
TRACE("AFHDS3 SET TX POWER %d", moduleData->afhds3.runPower);
putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data));
return;
}
}
else if (moduleMode == ::ModuleSettingsMode::MODULE_MODE_NORMAL) { //exit bind
if (state == STATE_BINDING) {
TRACE("AFHDS3 [EXIT BIND]");
requestedModuleMode = MODULE_MODE_E::RUN;
putFrame(COMMAND::MODULE_MODE, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, &requestedModuleMode, 1);
return;
}
}
bool isConnected = isConnectedUnicast() || isConnectedMulticast();
if (cmdCount++ >= 150) {
cmdCount = 0;
if (cmdIndex >= sizeof(periodicRequestCommands)) {
cmdIndex = 0;
}
COMMAND cmd = periodicRequestCommands[cmdIndex++];
if (cmd == COMMAND::VIRTUAL_FAILSAFE) {
if (isConnected) {
if (isConnectedMulticast()) {
TRACE("AFHDS ONE WAY FAILSAFE");
uint16_t failSafe[MAX_CHANNELS + 1] = { ((MAX_CHANNELS << 8) | CHANNELS_DATA_MODE::FAIL_SAFE), 0 };
setFailSafe((int16_t*) (&failSafe[1]));
putFrame(COMMAND::CHANNELS_FAILSAFE_DATA, FRAME_TYPE::REQUEST_SET_NO_RESP, (uint8_t*) failSafe, MAX_CHANNELS * 2 + 2);
}
else {
TRACE("AFHDS TWO WAYS FAILSAFE");
uint8_t failSafe[3 + MAX_CHANNELS * 2] = { 0x11, 0x60, MAX_CHANNELS * 2 };
setFailSafe((int16_t*) (failSafe + 3));
putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, failSafe, 3 + MAX_CHANNELS * 2);
}
}
else {
putFrame(COMMAND::MODULE_STATE, FRAME_TYPE::REQUEST_GET_DATA);
}
}
else
{
putFrame(cmd, FRAME_TYPE::REQUEST_GET_DATA);
}
}
else if (isConnected) {
sendChannelsData();
}
else {
//default frame - request state
putFrame(MODULE_STATE, FRAME_TYPE::REQUEST_GET_DATA);
}
}
void PulsesData::init(uint8_t moduleIndex, bool resetFrameCount)
{
module_index = moduleIndex;
AFHDS3PulsesData[module_index] = this;
//clear local vars because it is member of union
moduleData = &g_model.moduleData[module_index];
operationState = State::UNKNOWN;
state = ModuleState::STATE_NOT_READY;
clearFrameData();
}
void PulsesData::clearFrameData()
{
TRACE("AFHDS3 clearFrameData");
reset();
clearCommandFifo();
repeatCount = 0;
cmdCount = 0;
cmdIndex = 0;
this->frame_index = 1;
this->timeout = 0;
this->esc_state = 0;
}
void PulsesData::putBytes(uint8_t* data, int length)
{
for (int i = 0; i < length; i++) {
uint8_t byte = data[i];
this->crc += byte;
if (END == byte) {
sendByte(ESC);
sendByte(ESC_END);
}
else if (ESC == byte) {
sendByte(ESC);
sendByte(ESC_ESC);
}
else {
sendByte(byte);
}
}
}
void PulsesData::putFrame(COMMAND command, FRAME_TYPE frame, uint8_t* data, uint8_t dataLength, uint8_t* frameIndex)
{
//header
operationState = State::SENDING_COMMAND;
reset();
this->crc = 0;
sendByte(START);
if (frameIndex == nullptr) {
frameIndex = &this->frame_index;
}
uint8_t buffer[] = { FrameAddress, *frameIndex, frame, command };
putBytes(buffer, 4);
//payload
if (dataLength > 0) {
putBytes(data, dataLength);
}
//footer
uint8_t crcValue = this->crc ^ 0xff;
putBytes(&crcValue, 1);
sendByte(END);
*frameIndex = *frameIndex + 1;
switch (frame) {
case FRAME_TYPE::REQUEST_GET_DATA:
case FRAME_TYPE::REQUEST_SET_EXPECT_ACK:
case FRAME_TYPE::REQUEST_SET_EXPECT_DATA:
operationState = State::AWAITING_RESPONSE;
break;
default:
operationState = State::IDLE;
}
flush();
}
bool checkCRC(const uint8_t* data, uint8_t size)
{
uint8_t crc = 0;
//skip start byte
for (uint8_t i = 1; i < size; i++) {
crc += data[i];
}
return (crc ^ 0xff) == data[size];
}
bool containsData(enum FRAME_TYPE frameType)
{
return (frameType == FRAME_TYPE::RESPONSE_DATA ||
frameType == FRAME_TYPE::REQUEST_SET_EXPECT_DATA ||
frameType == FRAME_TYPE::REQUEST_SET_EXPECT_ACK ||
frameType == FRAME_TYPE::REQUEST_SET_EXPECT_DATA ||
frameType == FRAME_TYPE::REQUEST_SET_NO_RESP);
}
void PulsesData::setState(uint8_t state)
{
if (state == this->state) {
return;
}
uint8_t oldState = this->state;
this->state = state;
if (oldState == ModuleState::STATE_BINDING) {
setModuleMode(module_index, ::ModuleSettingsMode::MODULE_MODE_NORMAL);
}
if (state == ModuleState::STATE_NOT_READY) {
operationState = State::UNKNOWN;
}
}
void PulsesData::requestInfoAndRun(bool send)
{
if (!send) {
enqueue(COMMAND::MODULE_VERSION, FRAME_TYPE::REQUEST_GET_DATA);
}
enqueue(COMMAND::MODULE_POWER_STATUS, FRAME_TYPE::REQUEST_GET_DATA);
requestedModuleMode = MODULE_MODE_E::RUN;
enqueue(COMMAND::MODULE_MODE, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, true, (uint8_t) MODULE_MODE_E::RUN);
if (send) {
putFrame(COMMAND::MODULE_VERSION, FRAME_TYPE::REQUEST_GET_DATA);
}
}
void PulsesData::parseData(uint8_t* rxBuffer, uint8_t rxBufferCount)
{
if (!checkCRC(rxBuffer, rxBufferCount - 2)) {
TRACE("AFHDS3 [INVALID CRC]");
return;
}
AfhdsFrame* responseFrame = reinterpret_cast<AfhdsFrame*>(rxBuffer);
if (containsData((enum FRAME_TYPE) responseFrame->frameType)) {
switch (responseFrame->command) {
case COMMAND::MODULE_READY:
TRACE("AFHDS3 [MODULE_READY] %02X", responseFrame->value);
if (responseFrame->value == MODULE_STATUS_READY) {
setState(ModuleState::STATE_READY);
requestInfoAndRun();
}
else {
setState(ModuleState::STATE_NOT_READY);
}
break;
case COMMAND::MODULE_GET_CONFIG:
std::memcpy((void*) cfg.buffer, &responseFrame->value, sizeof(cfg.buffer));
TRACE("AFHDS3 [MODULE_GET_CONFIG] bind power %d run power %d mode %d pwm/ppm %d ibus/sbus %d", cfg.config.bindPower, cfg.config.runPower, cfg.config.telemetry, cfg.config.pulseMode, cfg.config.serialMode);
break;
case COMMAND::MODULE_VERSION:
std::memcpy((void*) &version, &responseFrame->value, sizeof(version));
TRACE("AFHDS3 [MODULE_VERSION] Product %d, HW %d, BOOT %d, FW %d", version.productNumber, version.hardwereVersion, version.bootloaderVersion, version.firmwareVersion);
break;
case COMMAND::MODULE_POWER_STATUS:
powerSource = (enum MODULE_POWER_SOURCE) responseFrame->value;
TRACE("AFHDS3 [MODULE_POWER_STATUS], %d", powerSource);
break;
case COMMAND::MODULE_STATE:
TRACE("AFHDS3 [MODULE_STATE] %02X", responseFrame->value);
setState(responseFrame->value);
break;
case COMMAND::MODULE_MODE:
TRACE("AFHDS3 [MODULE_MODE] %02X", responseFrame->value);
if (responseFrame->value != CMD_RESULT::SUCCESS) {
setState(ModuleState::STATE_NOT_READY);
}
else {
if (requestedModuleMode == MODULE_MODE_E::RUN) {
enqueue(COMMAND::MODULE_GET_CONFIG, FRAME_TYPE::REQUEST_GET_DATA);
enqueue(COMMAND::MODULE_STATE, FRAME_TYPE::REQUEST_GET_DATA);
}
requestedModuleMode = MODULE_MODE_UNKNOWN;
}
break;
case COMMAND::MODULE_SET_CONFIG:
if (responseFrame->value != CMD_RESULT::SUCCESS) {
setState(ModuleState::STATE_NOT_READY);
}
TRACE("AFHDS3 [MODULE_SET_CONFIG], %02X", responseFrame->value);
break;
case COMMAND::TELEMETRY_DATA:
{
uint8_t* telemetry = &responseFrame->value;
if (telemetry[0] == 0x22) {
telemetry++;
while (telemetry < rxBuffer + rxBufferCount) {
uint8_t length = telemetry[0];
uint8_t id = telemetry[1];
if (id == 0xFE) {
id = 0xF7; //use new id because format is different
}
if (length == 0 || telemetry + length > rxBuffer + rxBufferCount) {
break;
}
if (length == 4) {
//one byte value fill missing byte
uint8_t data[] = { id, telemetry[2], telemetry[3], 0 };
::processFlySkySensor(data, 0xAA);
}
if (length == 5) {
if (id == 0xFA) {
telemetry[1] = 0xF8; //remap to afhds3 snr
}
::processFlySkySensor(telemetry + 1, 0xAA);
}
else if (length == 6 && id == FRM302_STATUS) {
//convert to ibus
uint16_t t = (uint16_t) (((int16_t) telemetry[3] * 10) + 400);
uint8_t dataTemp[] = { ++id, telemetry[2], (uint8_t) (t & 0xFF), (uint8_t) (t >> 8) };
::processFlySkySensor(dataTemp, 0xAA);
uint8_t dataVoltage[] = { ++id, telemetry[2], telemetry[4], telemetry[5] };
::processFlySkySensor(dataVoltage, 0xAA);
}
else if (length == 7) {
::processFlySkySensor(telemetry + 1, 0xAC);
}
telemetry += length;
}
}
}
break;
case COMMAND::COMMAND_RESULT:
{
//AfhdsFrameData* respData = responseFrame->GetData();
//TRACE("COMMAND RESULT %02X result %d datalen %d", respData->CommandResult.command, respData->CommandResult.result, respData->CommandResult.respLen);
}
break;
}
}
if (responseFrame->frameType == FRAME_TYPE::REQUEST_GET_DATA || responseFrame->frameType == FRAME_TYPE::REQUEST_SET_EXPECT_DATA) {
TRACE("Command %02X NOT IMPLEMENTED!", responseFrame->command);
}
else if (responseFrame->frameType == FRAME_TYPE::REQUEST_SET_EXPECT_ACK) {
//check if such request is not queued
if (!isEmpty()) {
Frame f = commandFifo[getIndex];
if (f.frameType == FRAME_TYPE::RESPONSE_ACK && f.frameNumber == responseFrame->frameNumber) {
TRACE("ACK for frame %02X already queued", responseFrame->frameNumber);
return;
}
}
TRACE("AFHDS3 [QUEUE ACK] cmd %02X type %02X number %02X", responseFrame->command, responseFrame->frameType, responseFrame->frameNumber);
enqueueACK((enum COMMAND) responseFrame->command, responseFrame->frameNumber);
}
else if (responseFrame->frameType == FRAME_TYPE::RESPONSE_DATA || responseFrame->frameType == FRAME_TYPE::RESPONSE_ACK) {
if (operationState == State::AWAITING_RESPONSE) {
operationState = State::IDLE;
}
}
}
inline bool isSbus(uint8_t mode)
{
return (mode & 1);
}
inline bool isPWM(uint8_t mode)
{
return mode < 2;
}
RUN_POWER PulsesData::getMaxRunPower()
{
if (powerSource == MODULE_POWER_SOURCE::EXTERNAL) {
return RUN_POWER::PLUS_33dBm;
}
return RUN_POWER::PLUS_27dbm;
}
RUN_POWER PulsesData::actualRunPower()
{
uint8_t actualRfPower = cfg.config.runPower;
if (getMaxRunPower() < actualRfPower) {
actualRfPower = getMaxRunPower();
}
return (RUN_POWER) actualRfPower;
}
RUN_POWER PulsesData::getRunPower()
{
RUN_POWER targetPower = (RUN_POWER) moduleData->afhds3.runPower;
if (getMaxRunPower() < targetPower) {
targetPower = getMaxRunPower();
}
return targetPower;
}
bool PulsesData::syncSettings()
{
RUN_POWER targetPower = getRunPower();
/*not sure if we need to prevent them in bind mode*/
if (getModuleMode(module_index) != ::ModuleSettingsMode::MODULE_MODE_BIND && targetPower != cfg.config.runPower) {
cfg.config.runPower = moduleData->afhds3.runPower;
uint8_t data[] = { 0x13, 0x20, 0x02, moduleData->afhds3.runPower, 0 };
TRACE("AFHDS3 SET TX POWER %d", moduleData->afhds3.runPower);
putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data));
return true;
}
//other settings only in 2 way mode (state must be synchronized)
if (this->state != ModuleState::STATE_SYNC_DONE) {
return false;
}
if (moduleData->afhds3.rxFreq() != cfg.config.pwmFreq) {
cfg.config.pwmFreq = moduleData->afhds3.rxFreq();
uint8_t data[] = { 0x17, 0x70, 0x02, (uint8_t) (moduleData->afhds3.rxFreq() & 0xFF), (uint8_t) (moduleData->afhds3.rxFreq() >> 8) };
TRACE("AFHDS3 SET RX FREQ");
putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data));
return true;
}
PULSE_MODE modelPulseMode = isPWM(moduleData->subType) ? PULSE_MODE::PWM_MODE : PULSE_MODE::PPM_MODE;
if (modelPulseMode != cfg.config.pulseMode) {
cfg.config.pulseMode = modelPulseMode;
TRACE("AFHDS3 PWM/PPM %d", modelPulseMode);
uint8_t data[] = { 0x16, 0x70, 0x01, (uint8_t) (modelPulseMode) };
putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data));
return true;
}
SERIAL_MODE modelSerialMode = isSbus(moduleData->subType) ? SERIAL_MODE::SBUS_MODE : SERIAL_MODE::IBUS;
if (modelSerialMode != cfg.config.serialMode) {
cfg.config.serialMode = modelSerialMode;
TRACE("AFHDS3 IBUS/SBUS %d", modelSerialMode);
uint8_t data[] = { 0x18, 0x70, 0x01, (uint8_t) (modelSerialMode) };
putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data));
return true;
}
if (moduleData->afhds3.failsafeTimeout != cfg.config.failSafeTimout) {
moduleData->afhds3.failsafeTimeout = cfg.config.failSafeTimout;
uint8_t data[] = { 0x12, 0x60, 0x02, (uint8_t) (moduleData->afhds3.failsafeTimeout & 0xFF), (uint8_t) (moduleData->afhds3.failsafeTimeout >> 8) };
putFrame(COMMAND::SEND_COMMAND, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, data, sizeof(data));
TRACE("AFHDS3 FAILSAFE TMEOUT, %d", moduleData->afhds3.failsafeTimeout);
return true;
}
return false;
}
void PulsesData::sendChannelsData()
{
uint8_t channels_start = moduleData->channelsStart;
uint8_t channelsCount = 8 + moduleData->channelsCount;
uint8_t channels_last = channels_start + channelsCount;
int16_t buffer[MAX_CHANNELS + 1] = { ((MAX_CHANNELS << 8) | CHANNELS_DATA_MODE::CHANNELS), 0 };
for (uint8_t channel = channels_start, index = 1; channel < channels_last; channel++, index++) {
int16_t channelValue = convert(::getChannelValue(channel));
buffer[index] = channelValue;
}
putFrame(COMMAND::CHANNELS_FAILSAFE_DATA, FRAME_TYPE::REQUEST_SET_NO_RESP, (uint8_t*) buffer, sizeof(buffer));
}
void PulsesData::stop()
{
TRACE("AFHDS3 STOP");
requestedModuleMode = MODULE_MODE_E::STANDBY;
putFrame(COMMAND::MODULE_MODE, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, &requestedModuleMode, 1);
}
void PulsesData::setConfigFromModel()
{
cfg.config.bindPower = moduleData->afhds3.bindPower;
cfg.config.runPower = getRunPower();
cfg.config.emiStandard = EMI_STANDARD::FCC;
cfg.config.telemetry = moduleData->afhds3.telemetry; //always use bidirectional mode
cfg.config.pwmFreq = moduleData->afhds3.rxFreq();
cfg.config.serialMode = isSbus(moduleData->subType) ? SERIAL_MODE::SBUS_MODE : SERIAL_MODE::IBUS;
cfg.config.pulseMode = isPWM(moduleData->subType) ? PULSE_MODE::PWM_MODE : PULSE_MODE::PPM_MODE;
//use max channels - because channel count can not be changed after bind
cfg.config.channelCount = MAX_CHANNELS;
cfg.config.failSafeTimout = moduleData->afhds3.failsafeTimeout;
setFailSafe(cfg.config.failSafeMode);
}
inline int16_t PulsesData::convert(int channelValue)
{
//pulseValue = limit<uint16_t>(0, 988 + ((channelValue + 1024) / 2), 0xfff);
//988 - 750 = 238
//238 * 20 = 4760
//2250 - 2012 = 238
//238 * 20 = 4760
// 988 ---- 2012
//-10240 ---- 10240
//-1024 ---- 1024
return ::limit<int16_t>(FAILSAFE_MIN, channelValue * 10, FAILSAFE_MAX);
}
uint8_t PulsesData::setFailSafe(int16_t* target)
{
int16_t pulseValue = 0;
uint8_t channels_start = moduleData->channelsStart;
uint8_t channels_last = channels_start + 8 + moduleData->channelsCount;
for (uint8_t channel = channels_start; channel < channels_last; channel++) {
if (moduleData->failsafeMode == FAILSAFE_CUSTOM) {
pulseValue = convert(g_model.failsafeChannels[channel]);
}
else if (moduleData->failsafeMode == FAILSAFE_HOLD) {
pulseValue = FAILSAFE_KEEP_LAST;
}
else {
pulseValue = convert(::getChannelValue(channel));
}
target[channel - channels_start] = pulseValue;
}
//return max channels because channel count can not be change after bind
return (uint8_t) (MAX_CHANNELS);
}
}

595
radio/src/pulses/afhds3.h Normal file
View file

@ -0,0 +1,595 @@
/*
* 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 PULSES_AFHDS3_H_
#define PULSES_AFHDS3_H_
#include "bitfield.h"
#include "definitions.h"
#include "dataconstants.h"
#include "opentx_types.h"
#include "myeeprom.h"
#include "opentx_helpers.h"
#include "pulses_common.h"
#include <cstring>
#include "fifo.h"
#define AFHDS_MAX_PULSES 72
//max number of transitions measured so far 290 + 10%
#define AFHDS_MAX_PULSES_TRANSITIONS 320
//#define AFHDS3_SLOW
#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)
#define AFHDS3_BAUDRATE 1500000
#define AFHDS3_COMMAND_TIMEOUT 5
#elif !defined(AFHDS3_SLOW)
// 1s = 1 000 000 us
// 1000000/115200 = 8,68 us
// actual timer is ticking in 0,5 us = 8,68*2 = 17,36 because it must be integer take 17
// difference 1000000 / x = 8.5 --> x = 117 647 = difference = 1.2 %
// allowed half a bit difference on the last bit -- should be fine
#define AFHDS3_BAUDRATE 115200
//Because timer is ticking with 0.5us
#define BITLEN_AFHDS (17)
#define AFHDS3_COMMAND_TIMEOUT 15
#else
// 1000000/57600 = 17,36 us
#define AFHDS3_BAUDRATE 57600
// 64* 86 = 11 110
#define AFHDS3_COMMAND_TIMEOUT 20
#define BITLEN_AFHDS (35)
#endif
#define AFHDS3_FRAME_HALF_US AFHDS3_COMMAND_TIMEOUT * 2000
//get channel value outside of afhds3 namespace
int32_t getChannelValue(uint8_t channel);
//use uint16_t instead of pulse_duration_t
namespace afhds3
{
enum AfhdsSpecialChars
{
END = 0xC0, //Frame end
START = END,
ESC_END = 0xDC, //Escaped frame end - in case END occurs in fame then ESC ESC_END must be used
ESC = 0xDB, //Escaping character
ESC_ESC = 0xDD, //Escaping character in case ESC occurs in fame then ESC ESC_ESC must be used
};
struct Data
{
#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)
uint8_t pulses[AFHDS_MAX_PULSES];
uint8_t * ptr;
#else
uint32_t pulsesSize;
uint16_t pulses[AFHDS_MAX_PULSES_TRANSITIONS];
uint32_t total;
#endif
uint8_t frame_index;
uint8_t crc;
uint8_t state;
uint8_t timeout;
uint8_t esc_state;
void reset()
{
#if !(defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO))
total = 0;
#endif
pulsesSize = 0;
}
#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)
void sendByte(uint8_t b)
{
*ptr++ = b;
}
const uint8_t* getData()
{
return pulses;
}
void flush()
{
}
#else
inline void _send_level(uint16_t v)
{
if (pulsesSize >= AFHDS_MAX_PULSES_TRANSITIONS) {
return;
}
pulses[pulsesSize++] = v;
total += v;
}
void sendByte(uint8_t b)
{
if (pulsesSize >= AFHDS_MAX_PULSES_TRANSITIONS) {
return;
}
//use 8n1
//parity: If the parity is enabled, then the MSB bit of the data to be transmitted is changed by the parity bit
//start is always 0
bool level = 0;
uint16_t length = BITLEN_AFHDS; //start bit
for (uint8_t i = 0; i <= 8; i++)
{ //8 data bits + Stop=1
bool next_level = b & 1;
if (level == next_level) {
length += BITLEN_AFHDS;
}
else {
_send_level(length);
length = BITLEN_AFHDS;
level = next_level;
}
b = (b >> 1) | 0x80; // shift left to get next bit, fill msb with stop bit - needed just once
}
_send_level(length); //last bit (stop)
}
//add remaining time of frame
void flush()
{
uint16_t diff = AFHDS3_FRAME_HALF_US - total;
pulses[pulsesSize - 1] += diff;
//ensure 2 ms break
if (pulses[pulsesSize - 1] < 4000)
{
pulses[pulsesSize - 1] = 4050;
}
total += diff;
}
const uint16_t* getData()
{
return pulses;
}
#endif
uint32_t getSize()
{
return pulsesSize;
}
};
enum DeviceAddress
{
TRANSMITTER = 0x01,
MODULE = 0x03,
};
enum FRAME_TYPE
{
REQUEST_GET_DATA = 0x01, //Get data response: ACK + DATA
REQUEST_SET_EXPECT_DATA = 0x02, //Set data response: ACK + DATA
REQUEST_SET_EXPECT_ACK = 0x03, //Set data response: ACK
REQUEST_SET_NO_RESP = 0x05, //Set data response: none
RESPONSE_DATA = 0x10, //Response ACK + DATA
RESPONSE_ACK = 0x20, //Response ACK
NOT_USED = 0xff
};
enum COMMAND
{
MODULE_READY = 0x01,
MODULE_STATE = 0x02,
MODULE_MODE = 0x03,
MODULE_SET_CONFIG = 0x04,
MODULE_GET_CONFIG = 0x06,
CHANNELS_FAILSAFE_DATA = 0x07,
TELEMETRY_DATA = 0x09,
SEND_COMMAND = 0x0C,
COMMAND_RESULT = 0x0D,
MODULE_POWER_STATUS = 0x0F,
MODULE_VERSION = 0x1F,
VIRTUAL_FAILSAFE = 0x99, // virtual command used to trigger failsafe
UNDEFINED = 0xFF
};
enum COMMAND_DIRECTION
{
RADIO_TO_MODULE = 0,
MODULE_TO_RADIO = 1
};
enum DATA_TYPE
{
READY_DT, // 8 bytes 0x01 Not ready 0x02 Ready
STATE_DT, // See MODULE_STATE
MODE_DT,
MOD_CONFIG_DT,
CHANNELS_DT,
TELEMETRY_DT,
MODULE_POWER_DT,
MODULE_VERSION_DT,
EMPTY_DT,
};
//enum used by command response -> translate to ModuleState
enum MODULE_READY_E
{
MODULE_STATUS_UNKNOWN = 0x00,
MODULE_STATUS_NOT_READY = 0x01,
MODULE_STATUS_READY = 0x02
};
enum ModuleState
{
STATE_NOT_READY = 0x00, //virtual
STATE_HW_ERROR = 0x01,
STATE_BINDING = 0x02,
STATE_SYNC_RUNNING = 0x03,
STATE_SYNC_DONE = 0x04,
STATE_STANDBY = 0x05,
STATE_UPDATING_WAIT = 0x06,
STATE_UPDATING_MOD = 0x07,
STATE_UPDATING_RX = 0x08,
STATE_UPDATING_RX_FAILED = 0x09,
STATE_RF_TESTING = 0x0a,
STATE_READY = 0x0b, //virtual
STATE_HW_TEST = 0xff,
};
//used for set command
enum MODULE_MODE_E
{
STANDBY = 0x01,
BIND = 0x02, //after bind module will enter run mode
RUN = 0x03,
RX_UPDATE = 0x04, //after successful update module will enter standby mode, otherwise hw error will be raised
MODULE_MODE_UNKNOWN = 0xFF
};
enum CMD_RESULT
{
FAILURE = 0x01,
SUCCESS = 0x02,
};
#define MIN_FREQ 50
#define MAX_FREQ 400
#define MAX_CHANNELS 18
#define FAILSAFE_KEEP_LAST 0x8000
#define FAILSAFE_MIN -15000
#define FAILSAFE_MAX 15000
enum BIND_POWER
{
MIN_16dBm = 0x00,
BIND_POWER_FIRST = MIN_16dBm,
MIN_5dBm = 0x01,
MIN_0dbm = 0x02,
PLUS_5dBm = 0x03,
PLUS_14dBm = 0x04,
BIND_POWER_LAST = PLUS_14dBm,
};
enum RUN_POWER
{
PLUS_15bBm = 0x00,
RUN_POWER_FIRST = PLUS_15bBm,
PLUS_20bBm = 0x01,
PLUS_27dbm = 0x02,
PLUS_30dBm = 0x03,
PLUS_33dBm = 0x04,
RUN_POWER_LAST = PLUS_33dBm,
};
enum EMI_STANDARD
{
FCC = 0x00,
CE = 0x01
};
enum TELEMETRY
{
TELEMETRY_DISABLED = 0x00,
TELEMETRY_ENABLED = 0x01
};
enum PULSE_MODE
{
PWM_MODE = 0x00,
PPM_MODE = 0x01,
};
enum SERIAL_MODE
{
IBUS = 0x00,
SBUS_MODE = 0x02
};
PACK(struct Config_s {
uint8_t bindPower;
uint8_t runPower;
uint8_t emiStandard;
uint8_t telemetry;
uint16_t pwmFreq;
uint8_t pulseMode;
uint8_t serialMode;
uint8_t channelCount;
uint16_t failSafeTimout;
int16_t failSafeMode[MAX_CHANNELS];
});
union Config_u
{
Config_s config;
uint8_t buffer[sizeof(Config_s)];
};
enum CHANNELS_DATA_MODE
{
CHANNELS = 0x01,
FAIL_SAFE = 0x02,
};
PACK(struct ChannelsData {
uint8_t mode;
uint8_t channelsNumber;
int16_t data[MAX_CHANNELS];
});
union ChannelsData_u
{
ChannelsData data;
uint8_t buffer[sizeof(ChannelsData)];
};
PACK(struct TelemetryData
{
uint8_t sensorType;
uint8_t length;
uint8_t type;
uint8_t semsorID;
uint8_t data[8];
});
enum MODULE_POWER_SOURCE
{
INTERNAL = 0x01,
EXTERNAL = 0x02,
};
PACK(struct ModuleVersion
{
uint32_t productNumber;
uint32_t hardwereVersion;
uint32_t bootloaderVersion;
uint32_t firmwareVersion;
uint32_t rfVersion;
});
PACK(struct CommandResult_s
{
uint16_t command;
uint8_t result;
uint8_t respLen;
});
union AfhdsFrameData
{
uint8_t value;
Config_s Config;
ChannelsData Channels;
TelemetryData Telemetry;
ModuleVersion Version;
CommandResult_s CommandResult;
};
PACK(struct AfhdsFrame
{
uint8_t startByte;
uint8_t address;
uint8_t frameNumber;
uint8_t frameType;
uint8_t command;
uint8_t value;
AfhdsFrameData* GetData()
{
return reinterpret_cast<AfhdsFrameData*>(&value);
}
});
#define FRM302_STATUS 0x56
enum State
{
UNKNOWN = 0,
SENDING_COMMAND,
AWAITING_RESPONSE,
IDLE
};
//one byte frames for request queue
struct Frame
{
enum COMMAND command;
enum FRAME_TYPE frameType;
uint8_t payload;
uint8_t frameNumber;
bool useFrameNumber;
uint8_t payloadSize;
};
//simple fifo implementation because Pulses is used as member of union and can not be non trivial type
struct CommandFifo
{
Frame commandFifo[8];
volatile uint32_t setIndex;
volatile uint32_t getIndex;
void clearCommandFifo();
inline uint32_t nextIndex(uint32_t idx)
{
return (idx + 1) & (sizeof(commandFifo) / sizeof(commandFifo[0]) - 1);
}
inline uint32_t prevIndex(uint32_t idx)
{
if (idx == 0)
{
return (sizeof(commandFifo) / sizeof(commandFifo[0]) - 1);
}
return (idx - 1);
}
inline bool isEmpty() const
{
return (getIndex == setIndex);
}
inline void skip()
{
getIndex = nextIndex(getIndex);
}
void enqueueACK(COMMAND command, uint8_t frameNumber);
void enqueue(COMMAND command, FRAME_TYPE frameType, bool useData = false, uint8_t byteContent = 0);
};
void processTelemetryData(uint8_t module, uint8_t byte, uint8_t* rxBuffer, uint8_t& rxBufferCount, uint8_t maxSize);
class PulsesData: public Data, CommandFifo
{
public:
/**
* Initialize class for operation
* @param moduleIndex index of module one of INTERNAL_MODULE, EXTERNAL_MODULE
* @param resetFrameCount flag if current frame count should be reseted
*/
void init(uint8_t moduleIndex, bool resetFrameCount = true);
/**
* Fills DMA buffers with frame to be send depending on actual state
*/
void setupFrame();
/**
* Gets actual module status into provided buffer
* @param statusText target buffer for status
*/
void getStatusString(char * statusText) const;
/**
* Gets actual power source and voltage
*/
void getPowerStatus(char* buffer) const;
RUN_POWER actualRunPower();
/**
* Sends stop command to prevent any further module operations
*/
void stop();
protected:
void setConfigFromModel();
private:
inline void putBytes(uint8_t* data, int length);
inline void putFrame(COMMAND command, FRAME_TYPE frameType, uint8_t* data = nullptr, uint8_t dataLength = 0, uint8_t* frame_index = nullptr);
void parseData(uint8_t* rxBuffer, uint8_t rxBufferCount);
void setState(uint8_t state);
bool syncSettings();
void requestInfoAndRun(bool send = false);
uint8_t setFailSafe(int16_t* target);
inline int16_t convert(int channelValue);
void sendChannelsData();
void clearFrameData();
void processTelemetryData(uint8_t byte, uint8_t* rxBuffer, uint8_t& rxBufferCount, uint8_t maxSize);
//friendship declaration - use for passing telemetry
friend void processTelemetryData(uint8_t module, uint8_t byte, uint8_t* rxBuffer, uint8_t& rxBufferCount, uint8_t maxSize);
/**
* Returns max power that currently can be set - use it to validate before synchronization of settings
*/
RUN_POWER getMaxRunPower();
RUN_POWER getRunPower();
bool isConnectedUnicast();
bool isConnectedMulticast();
/**
* Index of the module
*/
uint8_t module_index;
/**
* Target mode to be set to the module one of MODULE_MODE_E
*/
uint8_t requestedModuleMode;
/**
* Internal operation state one of UNKNOWN, SENDING_COMMAND, AWAITING_RESPONSE, IDLE
* Used to avoid sending commands when not allowed to
*/
State operationState;
/**
* Actual repeat count for requested command/operation - incremented by every attempt sending anything
*/
uint16_t repeatCount;
/**
* Command count used for counting actual number of commands sent in run mode
*/
uint32_t cmdCount;
/**
* Command index of command to be send when cmdCount reached necessary value
*/
uint32_t cmdIndex;
/**
* Actual power source of the module - should be requested time to time
* Currently requested once
*/
enum MODULE_POWER_SOURCE powerSource;
/**
* Pointer to module config - it is making operations easier and faster
*/
ModuleData* moduleData;
/**
* Actual module configuration - must be requested from module
*/
Config_u cfg;
/**
* Actual module version - must be requested from module
*/
ModuleVersion version;
};
} /* Namespace ahfds3 */
#endif /* PULSES_AFHDS3_H_ */

View file

@ -37,6 +37,7 @@ enum ModuleType {
MODULE_TYPE_R9M_LITE_PRO_PXX2,
MODULE_TYPE_SBUS,
MODULE_TYPE_XJT_LITE_PXX2,
MODULE_TYPE_AFHDS3, //no more protocols possible because of 4 bits value
MODULE_TYPE_COUNT,
MODULE_TYPE_MAX = MODULE_TYPE_COUNT - 1
};
@ -218,4 +219,13 @@ enum AntennaModes {
ANTENNA_MODE_LAST = ANTENNA_MODE_EXTERNAL
};
enum AfhdsModes {
AFHDS_SUBTYPE_FIRST,
AFHDS_SUBTYPE_PWM_IBUS = AFHDS_SUBTYPE_FIRST,
AFHDS_SUBTYPE_PWM_SBUS,
AFHDS_SUBTYPE_PPM_IBUS,
AFHDS_SUBTYPE_PPM_SBUS,
AFHDS_SUBTYPE_LAST = AFHDS_SUBTYPE_PPM_SBUS
};
#endif // _MODULES_CONSTANTS_H_

View file

@ -299,8 +299,32 @@ inline bool isModuleSBUS(uint8_t moduleIdx)
return g_model.moduleData[moduleIdx].type == MODULE_TYPE_SBUS;
}
inline bool isModuleAFHDS3(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_AFHDS3;
}
inline bool isModulePxx2(uint8_t idx)
{
if (idx != EXTERNAL_MODULE)
return false;
#if defined(PXX2)
#if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
if (g_model.moduleData[idx].type == MODULE_TYPE_XJT_LITE_PXX2 ||
g_model.moduleData[idx].type == MODULE_TYPE_R9M_LITE_PRO_PXX2)
return true;
#endif
#if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
if (g_model.moduleData[idx].type == MODULE_TYPE_R9M_LITE_PXX2)
return true;
#endif
#endif
return false;
}
// order is the same as in enum Protocols in myeeprom.h (none, ppm, pxx, pxx2, dsm, crossfire, multi, r9m, r9m2, sbus)
static const int8_t maxChannelsModules[] = { 0, 8, 8, 16, -2, 8, 4, 8, 16, 8}; // relative to 8!
//qba667 count is not matching!
static const int8_t maxChannelsModules[] = { 0, 8, 8, 16, -2, 8, 4, 8, 16, 8, 10}; // relative to 8!
static const int8_t maxChannelsXJT[] = { 0, 8, 0, 4 }; // relative to 8!
constexpr int8_t MAX_TRAINER_CHANNELS_M8 = MAX_TRAINER_CHANNELS - 8;
@ -325,6 +349,9 @@ inline int8_t maxModuleChannels_M8(uint8_t moduleIdx)
return 8; // always 16 channels in FCC / FLEX
}
}
else if (isModuleAFHDS3(moduleIdx)) {
return 10;
}
else {
return maxChannelsModules[g_model.moduleData[moduleIdx].type];
}
@ -401,7 +428,7 @@ inline bool isModuleFailsafeAvailable(uint8_t moduleIdx)
return g_model.moduleData[moduleIdx].subType == MODULE_SUBTYPE_PXX1_ACCST_D16;
#if defined(MULTIMODULE)
if (isModuleMultimodule(moduleIdx)){
if (isModuleMultimodule(moduleIdx)) {
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
if (status.isValid()) {
return status.supportsFailsafe();
@ -413,6 +440,11 @@ inline bool isModuleFailsafeAvailable(uint8_t moduleIdx)
}
#endif
#if defined(AFHDS3)
if (isModuleAFHDS3(moduleIdx))
return true;
#endif
if (isModuleR9M(moduleIdx))
return true;
@ -421,7 +453,7 @@ inline bool isModuleFailsafeAvailable(uint8_t moduleIdx)
inline bool isModuleBindRangeAvailable(uint8_t moduleIdx)
{
return isModulePXX2(moduleIdx) || isModulePXX1(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx);
return isModulePXX2(moduleIdx) || isModulePXX1(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx) || isModuleAFHDS3(moduleIdx);
}
inline bool isModuleRangeAvailable(uint8_t moduleIdx)
@ -548,6 +580,30 @@ inline void resetAccessAuthenticationCount()
#endif
}
inline void resetAfhds3Options(uint8_t moduleIdx)
{
auto & data = g_model.moduleData[moduleIdx];
data.rfProtocol = 0;
data.subType = 0;
#if defined(AFHDS3)
data.afhds3.bindPower = 0;
data.afhds3.runPower = 0;
data.afhds3.emi = 0;
data.afhds3.telemetry = 1;
data.afhds3.rx_freq[0] = 50;
data.afhds3.rx_freq[1] = 0;
data.afhds3.failsafeTimeout = 1000;
data.channelsCount = 14 - 8;
data.failsafeMode = 1;
//" PWM+i"" PWM+s"" PPM+i"" PPM+s"
data.subType = 0;
for (uint8_t channel = 0; channel < MAX_OUTPUT_CHANNELS; channel++) {
g_model.failsafeChannels[channel] = 0;
}
#endif
}
inline void setModuleType(uint8_t moduleIdx, uint8_t moduleType)
{
ModuleData & moduleData = g_model.moduleData[moduleIdx];
@ -558,6 +614,8 @@ inline void setModuleType(uint8_t moduleIdx, uint8_t moduleType)
moduleData.sbus.refreshRate = -31;
else if (moduleData.type == MODULE_TYPE_PPM)
setDefaultPpmFrameLength(moduleIdx);
else if (moduleData.type == MODULE_TYPE_AFHDS3)
resetAfhds3Options(moduleIdx);
else
resetAccessAuthenticationCount();
}

View file

@ -28,6 +28,7 @@ InternalModulePulsesData intmodulePulsesData __DMA;
ExternalModulePulsesData extmodulePulsesData __DMA;
TrainerPulsesData trainerPulsesData __DMA;
//use only for PXX
void ModuleState::startBind(BindInformation * destination, ModuleCallback bindCallback)
{
bindInformation = destination;
@ -40,6 +41,56 @@ void ModuleState::startBind(BindInformation * destination, ModuleCallback bindCa
#endif
}
void getModuleStatusString(uint8_t moduleIdx, char * statusText)
{
*statusText = 0;
#if defined(MULTIMODULE)
if (isModuleMultimodule(moduleIdx)) {
//change it
getMultiModuleStatus(moduleIdx).getStatusString(statusText);
}
#endif
#if defined(AFHDS3)
if (moduleIdx == EXTERNAL_MODULE && isModuleAFHDS3(moduleIdx)) {
extmodulePulsesData.afhds3.getStatusString(statusText);
}
#endif
}
void getModuleSyncStatusString(uint8_t moduleIdx, char * statusText)
{
*statusText = 0;
#if defined(MULTIMODULE)
if (isModuleMultimodule(moduleIdx)) {
getMultiSyncStatus(moduleIdx).getRefreshString(statusText);
}
#endif
#if defined(AFHDS3)
if (moduleIdx == EXTERNAL_MODULE && isModuleAFHDS3(moduleIdx)) {
extmodulePulsesData.afhds3.getPowerStatus(statusText);
}
#endif
}
#if defined(AFHDS3)
uint8_t actualAfhdsRunPower(int moduleIndex)
{
if (moduleIndex == EXTERNAL_MODULE && isModuleAFHDS3(moduleIndex)) {
return (uint8_t)extmodulePulsesData.afhds3.actualRunPower();
}
return 0;
}
#endif
ModuleSettingsMode getModuleMode(int moduleIndex)
{
return (ModuleSettingsMode)moduleState[moduleIndex].mode;
}
void setModuleMode(int moduleIndex, ModuleSettingsMode mode)
{
moduleState[moduleIndex].mode = mode;
}
uint8_t getModuleType(uint8_t module)
{
uint8_t type = g_model.moduleData[module].type;
@ -136,6 +187,12 @@ uint8_t getRequiredProtocol(uint8_t module)
break;
#endif
#if defined(AFHDS3)
case MODULE_TYPE_AFHDS3:
protocol = PROTOCOL_CHANNELS_AFHDS3;
break;
#endif
default:
protocol = PROTOCOL_CHANNELS_NONE;
break;
@ -214,6 +271,14 @@ void enablePulsesExternalModule(uint8_t protocol)
break;
#endif
#if defined(AFHDS3)
case PROTOCOL_CHANNELS_AFHDS3:
extmodulePulsesData.afhds3.init(EXTERNAL_MODULE);
extmoduleSerialStart(AFHDS3_BAUDRATE, AFHDS3_COMMAND_TIMEOUT * 2000, false);
break;
#endif
default:
break;
}
@ -281,6 +346,13 @@ bool setupPulsesExternalModule(uint8_t protocol)
return true;
#endif
#if defined(AFHDS3)
case PROTOCOL_CHANNELS_AFHDS3:
extmodulePulsesData.afhds3.setupFrame();
scheduleNextMixerCalculation(EXTERNAL_MODULE, AFHDS3_COMMAND_TIMEOUT);
return true;
#endif
default:
scheduleNextMixerCalculation(EXTERNAL_MODULE, 50/*ms*/);
return false;
@ -438,3 +510,8 @@ void setCustomFailsafe(uint8_t moduleIndex)
}
}
}
int32_t getChannelValue(uint8_t channel) {
return channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
}

View file

@ -27,6 +27,7 @@
#include "pxx1.h"
#include "pxx2.h"
#include "multi.h"
#include "afhds3.h"
#include "modules_helpers.h"
#include "ff.h"
@ -56,29 +57,14 @@
#define IS_MULTIMODULE_PROTOCOL(protocol) (0)
#endif
#define IS_SBUS_PROTOCOL(protocol) (protocol == PROTOCOL_CHANNELS_SBUS)
#if defined(AFHDS3)
#define IS_AFHDS3_PROTOCOL(protocol) (protocol == PROTOCOL_CHANNELS_AFHDS3)
#else
#define IS_AFHDS3_PROTOCOL(protocol) (0)
#endif
extern uint8_t s_pulses_paused;
enum ModuleSettingsMode
{
MODULE_MODE_NORMAL,
MODULE_MODE_SPECTRUM_ANALYSER,
MODULE_MODE_POWER_METER,
MODULE_MODE_GET_HARDWARE_INFO,
MODULE_MODE_MODULE_SETTINGS,
MODULE_MODE_RECEIVER_SETTINGS,
MODULE_MODE_BEEP_FIRST,
MODULE_MODE_REGISTER = MODULE_MODE_BEEP_FIRST,
MODULE_MODE_BIND,
MODULE_MODE_SHARE,
MODULE_MODE_RANGECHECK,
MODULE_MODE_RESET,
MODULE_MODE_AUTHENTICATION,
MODULE_MODE_OTA_UPDATE,
};
PACK(struct PXX2Version {
uint8_t major;
uint8_t revision:4;
@ -293,6 +279,10 @@ union ExternalModulePulsesData {
Dsm2PulsesData dsm2;
#endif
#if defined(AFHDS3)
afhds3::PulsesData afhds3;
#endif
PpmPulsesData<pulse_duration_t> ppm;
CrossfirePulsesData crossfire;
@ -338,6 +328,11 @@ void extmodulePxx1SerialStart();
void extmodulePpmStart();
void intmoduleStop();
void extmoduleStop();
void getModuleStatusString(uint8_t moduleIdx, char * statusText);
void getModuleSyncStatusString(uint8_t moduleIdx, char * statusText);
#if defined(AFHDS3)
uint8_t actualAfhdsRunPower(int moduleIndex);
#endif
void extramodulePpmStart();
inline void startPulses()
@ -369,6 +364,7 @@ enum ChannelsProtocols {
PROTOCOL_CHANNELS_SBUS,
PROTOCOL_CHANNELS_PXX2_LOWSPEED,
PROTOCOL_CHANNELS_PXX2_HIGHSPEED,
PROTOCOL_CHANNELS_AFHDS3
};
inline void stopPulses()
@ -434,4 +430,4 @@ inline bool isModuleInBeepMode()
return false;
}
#endif // _PULSES_H_
#endif // _PULSES_H_

View file

@ -31,6 +31,27 @@
typedef uint16_t trainer_pulse_duration_t;
enum ModuleSettingsMode
{
MODULE_MODE_NORMAL,
MODULE_MODE_SPECTRUM_ANALYSER,
MODULE_MODE_POWER_METER,
MODULE_MODE_GET_HARDWARE_INFO,
MODULE_MODE_MODULE_SETTINGS,
MODULE_MODE_RECEIVER_SETTINGS,
MODULE_MODE_BEEP_FIRST,
MODULE_MODE_REGISTER = MODULE_MODE_BEEP_FIRST,
MODULE_MODE_BIND,
MODULE_MODE_SHARE,
MODULE_MODE_RANGECHECK,
MODULE_MODE_RESET,
MODULE_MODE_AUTHENTICATION,
MODULE_MODE_OTA_UPDATE,
};
ModuleSettingsMode getModuleMode(int moduleIndex);
void setModuleMode(int moduleIndex, ModuleSettingsMode mode);
template <class T, int SIZE>
class DataBuffer {
public:

View file

@ -148,7 +148,7 @@ endif()
if(MULTIMODULE)
add_definitions(-DMULTIMODULE)
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)
set(SRC ${SRC} pulses/multi.cpp telemetry/spektrum.cpp telemetry/hitec.cpp telemetry/hott.cpp telemetry/multi.cpp io/multi_firmware_update.cpp)
endif()
if(CROSSFIRE)
@ -163,6 +163,18 @@ if(CROSSFIRE)
)
endif()
if(AFHDS3)
add_definitions(-DAFHDS3)
set(PULSES_SRC
${PULSES_SRC}
afhds3.cpp
)
endif()
if(MULTIMODULE OR AFHDS3)
set(SRC ${SRC} telemetry/flysky_ibus.cpp )
endif()
add_definitions(-DCPUARM)
add_definitions(-DGPS)
add_definitions(-DBOLD_FONT -DBATTGRAPH -DTHRTRACE)

View file

@ -2,6 +2,7 @@ option(DISK_CACHE "Enable SD card disk cache" ON)
option(UNEXPECTED_SHUTDOWN "Enable the Unexpected Shutdown screen" ON)
option(PXX1 "PXX1 protocol support" ON)
option(PXX2 "PXX2 protocol support" OFF)
option(AFHDS3 "AFHDS3 TX Module" ON)
option(MULTIMODULE "DIY Multiprotocol TX Module (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module)" ON)
set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)")

View file

@ -316,6 +316,30 @@ void extmoduleSendNextFrame()
break;
#endif
#if defined(AFHDS3)
case PROTOCOL_CHANNELS_AFHDS3:
{
#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)
extmoduleSendBuffer(extmodulePulsesData.afhds3.getData(), extmodulePulsesData.afhds3.getSize());
#else
const uint16_t* dataPtr = extmodulePulsesData.afhds3.getData();
uint32_t dataSize = extmodulePulsesData.afhds3.getSize();
//Peripheral data size
//we know that afdhds3 uses 2 byte values!
uint32_t dmaSize = (EXTMODULE_TIMER_DMA_SIZE & (DMA_SxCR_PSIZE_0 | DMA_SxCR_PSIZE_1)) | DMA_SxCR_MSIZE_0;
EXTMODULE_TIMER->CCR2 = dataPtr[dataSize -1] - 4000; // 2mS in advance
EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | dmaSize | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(dataPtr);
EXTMODULE_TIMER_DMA_STREAM->NDTR = (uint32_t)dataSize;
EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
#endif
}
break;
#endif
#if defined(DSM2)
case PROTOCOL_CHANNELS_SBUS:
#if defined(PCBX10) || PCBREV >= 13

View file

@ -45,7 +45,8 @@ void telemetryPortInit(uint32_t baudrate, uint8_t mode)
USART_DeInit(TELEMETRY_USART);
return;
}
//deinit inverted mode
telemetryPortInvertedInit(0);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TELEMETRY_DMA_TX_Stream_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
@ -136,6 +137,9 @@ void telemetryPortInit(uint32_t baudrate, uint8_t mode)
// soft serial vars
static uint8_t rxBitCount;
static uint8_t rxByte;
// single bit length expresses in half us
static uint16_t bitLength;
static uint16_t probeTimeFromStartBit;
void telemetryPortInvertedInit(uint32_t baudrate)
{
@ -155,6 +159,20 @@ void telemetryPortInvertedInit(uint32_t baudrate)
rxBitCount = 0;
switch(baudrate) {
case 115200:
bitLength = 17;
probeTimeFromStartBit = 23; //because pin is not probed immediately
break;
case 57600:
bitLength = 35; //34 was used before - I prefer to use use 35 because of lower error
probeTimeFromStartBit = 48; // 48 used in original implementation
break;
default:
bitLength = 2000000/baudrate; //because of 0,5 us tick
probeTimeFromStartBit = 3000000/baudrate;
}
// configure bit sample timer
TELEMETRY_TIMER->PSC = (PERI2_FREQUENCY * TIMER_MULT_APB2) / 2000000 - 1; // 0.5uS
TELEMETRY_TIMER->CCER = 0;
@ -196,7 +214,7 @@ void telemetryPortInvertedRxBit()
{
if (rxBitCount < 8) {
if (rxBitCount == 0) {
TELEMETRY_TIMER->ARR = 34;
TELEMETRY_TIMER->ARR = bitLength;
rxByte = 0;
}
else {
@ -209,7 +227,6 @@ void telemetryPortInvertedRxBit()
++rxBitCount;
}
else if (rxBitCount == 8) {
telemetryNoDMAFifo.push(rxByte);
rxBitCount = 0;
@ -360,7 +377,7 @@ extern "C" void TELEMETRY_EXTI_IRQHandler(void)
if (rxBitCount == 0) {
TELEMETRY_TIMER->ARR = 48; // 1,5 cycle from start at 57600bps
TELEMETRY_TIMER->ARR = probeTimeFromStartBit; // 1,5 cycle from start at 57600bps
TELEMETRY_TIMER->CR1 |= TIM_CR1_CEN;
// disable start bit interrupt

View file

@ -10,6 +10,7 @@ set(TARGET_DIR sky9x)
set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} 9x_bitmaps)
set(PPM_LIMITS_SYMETRICAL YES)
set(PXX1 YES)
set(AFHDS3 NO)
add_definitions(-DDISABLE_MULTI_UPDATE)
if(PCB STREQUAL 9XRPRO)

View file

@ -2,6 +2,7 @@ option(SHUTDOWN_CONFIRMATION "Shutdown confirmation" OFF)
option(LCD_DUAL_BUFFER "Dual LCD Buffer" OFF)
option(PXX1 "PXX1 protocol support" ON)
option(PXX2 "PXX2 protocol support" OFF)
option(AFHDS3 "AFHDS3 TX Module" OFF)
option(INTERNAL_MODULE_PPM "Support for PPM internal module" OFF)
option(AUTOUPDATE "Auto update internal chips from SD" OFF)

View file

@ -278,7 +278,25 @@ void extmoduleSendNextFrame()
extmoduleSendBuffer(extmodulePulsesData.pxx2.getData(), extmodulePulsesData.pxx2.getSize());
break;
#endif
#if defined(AFHDS3)
case PROTOCOL_CHANNELS_AFHDS3:
{
#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)
extmoduleSendBuffer(extmodulePulsesData.afhds3.getData(), extmodulePulsesData.afhds3.getSize());
#else
const uint16_t* dataPtr = extmodulePulsesData.afhds3.getData();
uint32_t dataSize = extmodulePulsesData.afhds3.getSize();
EXTMODULE_TIMER->CCR2 = dataPtr[dataSize -1] - 4000; // 2mS in advance
EXTMODULE_TIMER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
EXTMODULE_TIMER_DMA_STREAM->CR |= EXTMODULE_TIMER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1;
EXTMODULE_TIMER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&EXTMODULE_TIMER->ARR);
EXTMODULE_TIMER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(dataPtr);
EXTMODULE_TIMER_DMA_STREAM->NDTR = dataSize;
EXTMODULE_TIMER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA
#endif
}
break;
#endif
#if defined(SBUS) || defined(DSM2) || defined(MULTIMODULE)
case PROTOCOL_CHANNELS_SBUS:
EXTMODULE_TIMER->CCER = EXTMODULE_TIMER_OUTPUT_ENABLE | (GET_SBUS_POLARITY(EXTERNAL_MODULE) ? 0 : EXTMODULE_TIMER_OUTPUT_POLARITY); // reverse polarity for Sbus if needed

View file

@ -40,7 +40,8 @@ void telemetryPortInit(uint32_t baudrate, uint8_t mode)
USART_DeInit(TELEMETRY_USART);
return;
}
//deinit inverted mode
telemetryPortInvertedInit(0);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TELEMETRY_DMA_TX_Stream_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
@ -87,11 +88,10 @@ void telemetryPortInit(uint32_t baudrate, uint8_t mode)
// soft serial vars
static uint8_t rxBitCount;
static uint8_t rxByte;
// single bit length expresses in half us
static uint16_t bitLength;
static uint16_t probeTimeFromStartBit;
//TODO:
// - only 57600 supported for now
// - handle other bitrates as well?
//
void telemetryPortInvertedInit(uint32_t baudrate)
{
if (baudrate == 0) {
@ -116,6 +116,20 @@ void telemetryPortInvertedInit(uint32_t baudrate)
rxBitCount = 0;
switch(baudrate) {
case 115200:
bitLength = 17;
probeTimeFromStartBit = 25;
break;
case 57600:
bitLength = 35; //34 was used before - I prefer to use use 35 because of lower error
probeTimeFromStartBit = 52; //round down - 48 used in original implementation
break;
default:
bitLength = 2000000/baudrate; //because of 0,5 us tick
probeTimeFromStartBit = 3000000/baudrate;
}
// configure bit sample timer
TELEMETRY_TIMER->PSC = (PERI2_FREQUENCY * TIMER_MULT_APB2) / 2000000 - 1; // 0.5uS
TELEMETRY_TIMER->CCER = 0;
@ -162,7 +176,7 @@ void telemetryPortInvertedRxBit()
{
if (rxBitCount < 8) {
if (rxBitCount == 0) {
TELEMETRY_TIMER->ARR = 34;
TELEMETRY_TIMER->ARR = bitLength;
rxByte = 0;
}
else {
@ -333,7 +347,7 @@ void check_telemetry_exti()
if (rxBitCount == 0) {
TELEMETRY_TIMER->ARR = 48; // 1,5 cycle from start at 57600bps
TELEMETRY_TIMER->ARR = probeTimeFromStartBit; // 1,5 cycle from start at 57600bps
TELEMETRY_TIMER->CR1 |= TIM_CR1_CEN;
// disable start bit interrupt

View file

@ -61,7 +61,8 @@ enum
AFHDS2A_ID_GPS_DIST = 0x14, // 2 bytes distance from home m unsigned
AFHDS2A_ID_ARMED = 0x15, // 2 bytes
AFHDS2A_ID_FLIGHT_MODE = 0x16, // 2 bytes
AFHDS3_FRM_TEMP = 0x57, //virtual
AFHDS3_FRM_EXT_V = 0x58, //virtual
AFHDS2A_ID_PRES = 0x41, // Pressure
AFHDS2A_ID_ODO1 = 0x7C, // Odometer1
AFHDS2A_ID_ODO2 = 0x7D, // Odometer2
@ -79,8 +80,9 @@ enum
AFHDS2A_ID_S88 = 0x88,
AFHDS2A_ID_S89 = 0x89,
AFHDS2A_ID_S8a = 0x8A,
AFHDS2A_ID_ALT_FLYSKY = 0xF9, // Altitude 2 bytes signed in m - used in FlySky native TX - SIGNED value
AFHDS2A_ID_RX_SIG_AFHDS3 = 0xF7, // SIG
AFHDS2A_ID_RX_SNR_AFHDS3 = 0xF8, // SNR
AFHDS2A_ID_ALT_FLYSKY = 0xF9, // Altitude 2 bytes signed in m - used in FlySky native TX
AFHDS2A_ID_RX_SNR = 0xFA, // SNR
AFHDS2A_ID_RX_NOISE = 0xFB, // Noise
AFHDS2A_ID_RX_RSSI = 0xFC, // RSSI
@ -120,6 +122,8 @@ const FlySkySensor flySkySensors[] = {
{AFHDS2A_ID_FLIGHT_MODE, ZSTR_FLIGHT_MODE, UNIT_RAW, 0}, // 2 bytes index
{AFHDS2A_ID_PRES, ZSTR_PRES, UNIT_RAW, 2}, // 4 bytes In fact Temperature + Pressure -> Altitude
{AFHDS2A_ID_PRES | 0x100, ZSTR_TEMP2, UNIT_CELSIUS, 1}, // 2 bytes Temperature
{AFHDS3_FRM_TEMP, ZSTR_TEMP2, UNIT_CELSIUS, 1}, // 2 bytes temperature
{AFHDS3_FRM_EXT_V, ZSTR_TXV, UNIT_VOLTS, 2}, // 2 bytes voltage
{AFHDS2A_ID_ODO1, ZSTR_ODO1, UNIT_METERS, 2}, // 2 bytes Odometer1 -- some magic with 330 needed
{AFHDS2A_ID_ODO2, ZSTR_ODO2, UNIT_METERS, 2}, // 2 bytes Odometer2 -- some magic with 330 needed
{AFHDS2A_ID_SPE, ZSTR_ASPD, UNIT_KMH, 2}, // 2 bytes Speed km/h -- some magic with 330 needed
@ -128,7 +132,8 @@ const FlySkySensor flySkySensors[] = {
{AFHDS2A_ID_GPS_LON, ZSTR_GPS, UNIT_RAW, 7}, // 4 bytes signed WGS84 in degrees * 1E7
{AFHDS2A_ID_GPS_ALT, ZSTR_GPSALT, UNIT_METERS, 2}, // 4 bytes signed GPS alt m*100
{AFHDS2A_ID_ALT, ZSTR_ALT, UNIT_METERS, 2}, // 4 bytes signed Alt m*100
{AFHDS2A_ID_RX_SIG_AFHDS3, ZSTR_RX_QUALITY, UNIT_RAW, 0}, // RX error rate
{AFHDS2A_ID_RX_SNR_AFHDS3, ZSTR_RX_SNR, UNIT_DB, 1}, // RX SNR
{AFHDS2A_ID_RX_SNR, ZSTR_RX_SNR, UNIT_DB, 0}, // RX SNR
{AFHDS2A_ID_RX_NOISE, ZSTR_RX_NOISE, UNIT_DB, 0}, // RX Noise
{AFHDS2A_ID_RX_RSSI, ZSTR_RSSI, UNIT_DB, 0}, // RX RSSI (0xfc)
@ -140,7 +145,7 @@ const FlySkySensor flySkySensors[] = {
int32_t getALT(uint32_t value);
static void processFlySkySensor(const uint8_t * packet, uint8_t type)
void processFlySkySensor(const uint8_t * packet, uint8_t type)
{
uint8_t buffer[8];
uint16_t id = packet[0];
@ -156,13 +161,17 @@ static void processFlySkySensor(const uint8_t * packet, uint8_t type)
if (id == 0) id = 0x100; // Some part of OpenTX does not like sensor with id and instance 0, remap to 0x100
if (id == AFHDS2A_ID_RX_NOISE || id == AFHDS2A_ID_RX_RSSI) {
value = -value;
value = 135 - value;
}
else if (id == AFHDS2A_ID_RX_ERR_RATE) {
value = 100 - value;
telemetryData.rssi.set(value);
if (value > 0) telemetryStreaming = TELEMETRY_TIMEOUT10ms;
}
else if(id == AFHDS2A_ID_RX_SIG_AFHDS3) {
telemetryData.rssi.set(value);
if(value>0) telemetryStreaming = TELEMETRY_TIMEOUT10ms;
}
else if (id == AFHDS2A_ID_PRES && value) {
// Extract temperature to a new sensor
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, id | 0x100, 0, instance, ((value >> 19) - 400), UNIT_CELSIUS, 1);
@ -216,7 +225,7 @@ static void processFlySkySensor(const uint8_t * packet, uint8_t type)
for (const FlySkySensor * sensor = flySkySensors; sensor->id; sensor++) {
if (sensor->id != id) continue;
if (sensor->unit == UNIT_CELSIUS) value -= 400; // Temperature sensors have 40 degree offset
else if (sensor->unit == UNIT_VOLTS) value = (uint16_t) value; // Voltage types are unsigned 16bit integers
else if (sensor->unit == UNIT_VOLTS) value = (int16_t) value; // Voltage types are unsigned 16bit integers
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, id, 0, instance, value, sensor->unit, sensor->precision);
return;
}
@ -390,4 +399,4 @@ int32_t getALT(uint32_t value)
if (neg ^ tempNegative) result = result * -1;
return result;
}
}

View file

@ -21,6 +21,8 @@
#ifndef _FLYSKY_IBUS_H
#define _FLYSKY_IBUS_H
void processFlySkySensor(const uint8_t *packet, uint8_t type);
void processFlySkyTelemetryData(uint8_t data, uint8_t * rxBuffer, uint8_t &rxBufferCount);
void flySkySetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance);

View file

@ -20,6 +20,7 @@
#include "opentx.h"
#include "multi.h"
#include "pulses/afhds3.h"
uint8_t telemetryStreaming = 0;
uint8_t telemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE]; // Receive buffer. 9 bytes (full packet), worst case 18 bytes with byte-stuffing (+1)
@ -59,6 +60,13 @@ void processTelemetryData(uint8_t data)
}
#endif
#if defined(AFHDS3)
if (telemetryProtocol == PROTOCOL_TELEMETRY_AFHDS3) {
afhds3::processTelemetryData(EXTERNAL_MODULE, data, telemetryRxBuffer, telemetryRxBufferCount, TELEMETRY_RX_PACKET_SIZE);
return;
}
#endif
processFrskyTelemetryData(data);
}
@ -103,7 +111,7 @@ void telemetryWakeup()
#endif
#if defined(EXTMODULE_USART)
while (extmoduleFifo.getFrame(frame)) {
while (isModulePxx2(EXTERNAL_MODULE) && extmoduleFifo.getFrame(frame)) {
processPXX2Frame(EXTERNAL_MODULE, frame);
}
#endif
@ -294,6 +302,13 @@ void telemetryInit(uint8_t protocol)
}
#endif
#if defined(AFHDS3) && !defined(SIMU)
else if (protocol == PROTOCOL_TELEMETRY_AFHDS3) {
telemetryPortInvertedInit(AFHDS3_BAUDRATE);
telemetryPortSetDirectionInput();
}
#endif
else {
telemetryPortInit(FRSKY_SPORT_BAUDRATE, TELEMETRY_SERIAL_WITHOUT_DMA);
#if defined(LUA)

View file

@ -28,11 +28,13 @@
#if defined(MULTIMODULE)
#include "spektrum.h"
#include "flysky_ibus.h"
#include "hitec.h"
#include "hott.h"
#include "multi.h"
#endif
#if defined(MULTIMODULE) || defined(AFHDS3)
#include "flysky_ibus.h"
#endif
extern uint8_t telemetryStreaming; // >0 (true) == data is streaming in. 0 = no data detected for some time
@ -54,7 +56,7 @@ constexpr uint8_t TELEMETRY_TIMEOUT10ms = 100; // 1 second
#define TELEMETRY_SERIAL_8E2 1
#define TELEMETRY_SERIAL_WITHOUT_DMA 2
#if defined(CROSSFIRE) || defined(MULTIMODULE)
#if defined(CROSSFIRE) || defined(MULTIMODULE) || defined(AFHDS3)
#define TELEMETRY_RX_PACKET_SIZE 128
// multi module Spektrum telemetry is 18 bytes, FlySky is 37 bytes
#else
@ -162,6 +164,11 @@ inline uint8_t modelTelemetryProtocol()
return PROTOCOL_TELEMETRY_MULTIMODULE;
}
#endif
#endif
#if defined(AFHDS3)
if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_AFHDS3) {
return PROTOCOL_TELEMETRY_AFHDS3;
}
#endif
// default choice
return PROTOCOL_TELEMETRY_FRSKY_SPORT;

View file

@ -526,13 +526,15 @@ int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, ui
crossfireSetDefault(index, id, instance);
break;
#endif
#if defined(MULTIMODULE) || defined(AFHDS3)
case PROTOCOL_TELEMETRY_FLYSKY_IBUS:
flySkySetDefault(index,id, subId, instance);
break;
#endif
#if defined(MULTIMODULE)
case PROTOCOL_TELEMETRY_SPEKTRUM:
spektrumSetDefault(index, id, subId, instance);
break;
case PROTOCOL_TELEMETRY_FLYSKY_IBUS:
flySkySetDefault(index,id, subId, instance);
break;
case PROTOCOL_TELEMETRY_HITEC:
hitecSetDefault(index, id, subId, instance);
break;

View file

@ -68,6 +68,8 @@ ISTR(XJT_ACCST_RF_PROTOCOLS);
ISTR(ISRM_RF_PROTOCOLS);
ISTR(R9M_PXX2_RF_PROTOCOLS);
ISTR(DSM_PROTOCOLS);
ISTR(AFHDS3_PROTOCOLS);
ISTR(AFHDS3_POWERS);
ISTR(CURVE_TYPES);
ISTR(VSENSORTYPES);
ISTR(VFORMULAS);
@ -468,6 +470,7 @@ const char STR_BINDING_1_8_TELEM_OFF[] = TR_BINDING_CH1_8_TELEM_OFF;
const char STR_BINDING_9_16_TELEM_ON[] = TR_BINDING_CH9_16_TELEM_ON;
const char STR_BINDING_9_16_TELEM_OFF[] = TR_BINDING_CH9_16_TELEM_OFF;
const char STR_CHANNELRANGE[] = TR_CHANNELRANGE;
const char STR_RXFREQUENCY[] = TR_RXFREQUENCY;
const char STR_ANTENNACONFIRM1[] = TR_ANTENNACONFIRM1;
const char STR_ANTENNACONFIRM2[] = TR_ANTENNACONFIRM2;
const char STR_USE_INTERNAL_ANTENNA[] = TR_USE_INTERNAL_ANTENNA;
@ -715,8 +718,16 @@ const char STR_MULTI_SERVOFREQ[] = TR_MULTI_SERVOFREQ;
const char STR_MULTI_MAX_THROW[] = TR_MULTI_MAX_THROW;
const char STR_MULTI_RFCHAN[] = TR_MULTI_RFCHAN;
const char STR_NEEDS_FILE[] = TR_NEEDS_FILE;
const char STR_EXT_MULTI_SPEC[] = TR_EXT_MULTI_SPEC;
const char STR_INT_MULTI_SPEC[] = TR_INT_MULTI_SPEC;
const char STR_EXT_MULTI_SPEC[] = TR_EXT_MULTI_SPEC;
const char STR_INT_MULTI_SPEC[] = TR_INT_MULTI_SPEC;
#if defined(AFHDS3)
const char STR_AFHDS3_RX_FREQ[] = TR_AFHDS3_RX_FREQ;
const char STR_AFHDS3_ACTUAL_POWER[] = TR_AFHDS3_ACTUAL_POWER;
const char STR_AFHDS3_POWER_SOURCE[] = TR_AFHDS3_POWER_SOURCE;
const char STR_AFHDS3_ONE_TO_ONE_TELEMETRY[] =TR_AFHDS3_ONE_TO_ONE_TELEMETRY;
const char STR_AFHDS3_ONE_TO_MANY[] = TR_AFHDS3_ONE_TO_MANY;
#endif
#if LCD_W < 212
const char STR_SUBTYPE[] = TR_SUBTYPE;

View file

@ -164,6 +164,16 @@ extern const char STR_DSM_PROTOCOLS[];
extern const char STR_MULTI_PROTOCOLS[];
#endif
#if defined(AFHDS3)
extern const char STR_AFHDS3_ONE_TO_ONE_TELEMETRY[];
extern const char STR_AFHDS3_ONE_TO_MANY[];
extern const char STR_AFHDS3_PROTOCOLS[];
extern const char STR_AFHDS3_POWERS[];
extern const char STR_AFHDS3_RX_FREQ[];
extern const char STR_AFHDS3_ACTUAL_POWER[];
extern const char STR_AFHDS3_POWER_SOURCE[];
#endif
extern const char STR_CURVE_TYPES[];
extern const char STR_VSENSORTYPES[];
extern const char STR_VFORMULAS[];
@ -764,6 +774,7 @@ extern const char STR_BINDING_1_8_TELEM_OFF[];
extern const char STR_BINDING_9_16_TELEM_ON[];
extern const char STR_BINDING_9_16_TELEM_OFF[];
extern const char STR_CHANNELRANGE[];
extern const char STR_RXFREQUENCY[];
extern const char STR_ANTENNASELECTION[];
extern const char STR_ANTENNACONFIRM1[];
extern const char STR_ANTENNACONFIRM2[];

View file

@ -935,6 +935,12 @@
#define TR_UNIT "Jednotky"
#define TR_TELEMETRY_NEWSENSOR INDENT "Přidat senzor ručně"
#define TR_CHANNELRANGE TR(INDENT "Kanály", INDENT "Rozsah kanálů")
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", TR("Power src.", "Power source"))
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "Opravdu přepnout?"
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\023"

View file

@ -941,6 +941,12 @@
#define TR_UNIT "Einheit"
#define TR_TELEMETRY_NEWSENSOR INDENT "Sensor hinzufügen ..."
#define TR_CHANNELRANGE TR(INDENT "Kanäle", INDENT "Ausgangs Kanäle") //wg 9XR-Pro
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "Ant. umschalten"
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\023"

View file

@ -663,6 +663,11 @@
#define TR_MULTI_SERVOFREQ TR("Servo rate", "Servo update rate")
#define TR_MULTI_MAX_THROW TR("Max. Throw", "Enable max. throw")
#define TR_MULTI_RFCHAN TR("RF Channel", "Select RF channel")
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_SYNCMENU "[Sync]"
#define TR_LIMIT INDENT "Limit"
#define TR_MINRSSI "Min Rssi"
@ -940,6 +945,7 @@
#define TR_UNIT "Unit"
#define TR_TELEMETRY_NEWSENSOR INDENT "Add a new sensor..."
#define TR_CHANNELRANGE TR(INDENT "Ch. Range", INDENT "Channel Range")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "EXT. ANTENNA"
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\023"

View file

@ -938,6 +938,12 @@
#define TR_UNIT "Unidad"
#define TR_TELEMETRY_NEWSENSOR INDENT "Añadir sensor..."
#define TR_CHANNELRANGE INDENT "Canales"
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "ANTENA EXT."
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\020"

View file

@ -954,6 +954,12 @@
#define TR_UNIT "Unit"
#define TR_TELEMETRY_NEWSENSOR INDENT "Add a new sensor..."
#define TR_CHANNELRANGE INDENT "Channel Range"
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "EXT. ANTENNA"
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\023"

View file

@ -956,6 +956,12 @@
#define TR_UNIT "Unité"
#define TR_TELEMETRY_NEWSENSOR TR(INDENT"Nouveau capteur...", INDENT "Ajout d'un nouveau capteur...")
#define TR_CHANNELRANGE TR(INDENT "Canaux", INDENT "Plage de canaux")
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "Vraiment changer?"
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\021"

View file

@ -956,6 +956,12 @@
#define TR_UNIT "Unita"
#define TR_TELEMETRY_NEWSENSOR INDENT "Aggiungi nuovo sensore"
#define TR_CHANNELRANGE INDENT "Numero Canali"
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "ANTENNA EST."
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\023"

View file

@ -942,6 +942,12 @@
#define TR_UNIT "Eenheid"
#define TR_TELEMETRY_NEWSENSOR INDENT "Sensor toevoegen ..."
#define TR_CHANNELRANGE TR(INDENT "Kanalen", INDENT "Uitgangs Kanalen") //wg 9XR-Pro
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "Antennes wisselen?"
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\023"

View file

@ -955,6 +955,12 @@
#define TR_UNIT "Jedn"
#define TR_TELEMETRY_NEWSENSOR INDENT "Dodaj nowy czujnik..."
#define TR_CHANNELRANGE TR(INDENT "ZakrKn",INDENT "Zakres kanału")
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "EXT. ANTENNA"
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\023"

View file

@ -945,6 +945,12 @@
#define TR_UNIT "Unit"
#define TR_TELEMETRY_NEWSENSOR INDENT "Add a new sensor..."
#define TR_CHANNELRANGE INDENT "Channel Range"
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "EXT. ANTENNA"
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\023"

View file

@ -955,6 +955,12 @@
#define TR_UNIT "Enhet"
#define TR_TELEMETRY_NEWSENSOR INDENT "Lägg till sensor..."
#define TR_CHANNELRANGE INDENT "Kanalområde"
#define TR_AFHDS3_RX_FREQ TR("RX freq.", "RX frequency")
#define TR_AFHDS3_ONE_TO_ONE_TELEMETRY TR("Unicast/Tel.", "Unicast/Telemetry")
#define TR_AFHDS3_ONE_TO_MANY "Multicast"
#define TR_AFHDS3_ACTUAL_POWER TR("Act. pow", "Actual power")
#define TR_AFHDS3_POWER_SOURCE TR("Power src.", "Power source")
#define TR_RXFREQUENCY TR(INDENT "RX Freq.", INDENT "RX Frequency")
#define TR_ANTENNACONFIRM1 "EXT. ANTENNA"
#if defined(PCBX12S)
#define LEN_ANTENNA_MODES "\023"

View file

@ -87,7 +87,7 @@
#endif
#define LEN_EXTERNAL_MODULE_PROTOCOLS "\014"
#define TR_EXTERNAL_MODULE_PROTOCOLS "OFF\0 ""PPM\0 ""XJT\0 ""ISRM\0 ""DSM2\0 ""CRSF\0 ""MULTI\0 ""R9M\0 ""R9M ACCESS\0 " TR_MODULE_R9M_LITE "R9ML ACCESS\0""R9MLP\0 ""R9MLP ACCESS""SBUS\0 ""XJT Lite"
#define TR_EXTERNAL_MODULE_PROTOCOLS "OFF\0 ""PPM\0 ""XJT\0 ""ISRM\0 ""DSM2\0 ""CRSF\0 ""MULTI\0 ""R9M\0 ""R9M ACCESS\0 " TR_MODULE_R9M_LITE "R9ML ACCESS\0""R9MLP\0 ""R9MLP ACCESS""SBUS\0 ""XJT Lite\0 ""AFHDS3"
#define LEN_INTERNAL_MODULE_PROTOCOLS LEN_EXTERNAL_MODULE_PROTOCOLS
#define TR_INTERNAL_MODULE_PROTOCOLS TR_EXTERNAL_MODULE_PROTOCOLS
@ -125,4 +125,11 @@
#define TR_DSM_PROTOCOLS "LP45""DSM2""DSMX"
#define LEN_MULTI_PROTOCOLS "\007"
#define TR_MULTI_PROTOCOLS "FlySky\0""Hubsan\0""FrSky\0 ""Hisky\0 ""V2x2\0 ""DSM\0 ""Devo\0 ""YD717\0 ""KN\0 ""SymaX\0 ""SLT\0 ""CX10\0 ""CG023\0 ""Bayang\0""ESky\0 ""MT99XX\0""MJXq\0 ""Shenqi\0""FY326\0 ""SFHSS\0 ""J6 Pro\0""FQ777\0 ""Assan\0 ""Hontai\0""OpenLrs""FlSky2A""Q2x2\0 ""Walkera""Q303\0 ""GW008\0 ""DM002\0 ""Cabell\0""Esky150""H8 3D\0 ""Corona\0""CFlie\0 ""Hitec\0 ""WFly\0 ""Bugs\0 ""BugMini""Traxxas""NCC1701""E01X\0 ""V911S\0 ""GD00X\0 ""V761\0 ""KF606\0 ""Redpine""Potensi""ZSX\0 ""FlyZone""Scanner""FrSkyRX""FS2A_RX""HoTT\0 ""FX816\0 ""BayanRX""Pelikan""Tiger\0 ""XK\0 ""XN297DU""FrSkyX2""FrSkyR9""Propel\0""FrSkyL\0""Skyartc""ESky-v2""DSM RX\0""JJRC345""Q90C\0 "
#define LEN_AFHDS3_PROTOCOLS "\x008"
#define TR_AFHDS3_PROTOCOLS "PWM/IBUS""PWM/SBUS""PPM/IBUS""PPM/SBUS"
#define LEN_AFHDS3_POWERS "\006"
#define TR_AFHDS3_POWERS "25 mW\0""100 mW""500 mW""1 W\0 ""2 W\0 "

View file

@ -77,7 +77,8 @@ options_taranis_x9d = {
"internalppm": ("INTERNAL_MODULE_PPM", "YES", "NO"),
"shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"),
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None)
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"afhds3": ("AFHDS3", "YES", "NO")
}
options_taranis_x9dp = {
@ -93,7 +94,8 @@ options_taranis_x9dp = {
"internalppm": ("INTERNAL_MODULE_PPM", "YES", "NO"),
"shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"),
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None)
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"afhds3": ("AFHDS3", "YES", "NO")
}
options_taranis_x9lite = {
@ -110,7 +112,8 @@ options_taranis_x9lite = {
"shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"),
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"internalpxx1": ("INTERNAL_MODULE_PXX1", "YES", "NO"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None)
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"afhds3": ("AFHDS3", "YES", "NO")
}
options_taranis_xlite = {
@ -124,7 +127,8 @@ options_taranis_xlite = {
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
"shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"),
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None)
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"afhds3": ("AFHDS3", "YES", "NO")
}
options_taranis_xlites = {
@ -140,7 +144,8 @@ options_taranis_xlites = {
"shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"),
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"internalpxx1": ("INTERNAL_MODULE_PXX1", "YES", "NO"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None)
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"afhds3": ("AFHDS3", "YES", "NO")
}
options_taranis_x9e = {
@ -156,7 +161,8 @@ options_taranis_x9e = {
"shutdownconfirm": ("SHUTDOWN_CONFIRMATION", "YES", "NO"),
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"horussticks": ("STICKS", "HORUS", "STANDARD"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None)
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"afhds3": ("AFHDS3", "YES", "NO")
}
options_horus_x12s = {
@ -170,7 +176,8 @@ options_horus_x12s = {
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"pcbdev": ("PCBREV", "10", None),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"internalaccess": [("INTERNAL_MODULE_PXX1", "NO", None), ("INTERNAL_MODULE_PXX2", "YES", None)]
"internalaccess": [("INTERNAL_MODULE_PXX1", "NO", None), ("INTERNAL_MODULE_PXX2", "YES", None)],
"afhds3": ("AFHDS3", "YES", "NO")
}
options_horus_x10 = {
@ -183,7 +190,8 @@ options_horus_x10 = {
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"internalaccess": [("INTERNAL_MODULE_PXX1", "NO", None), ("INTERNAL_MODULE_PXX2", "YES", None)]
"internalaccess": [("INTERNAL_MODULE_PXX1", "NO", None), ("INTERNAL_MODULE_PXX2", "YES", None)],
"afhds3": ("AFHDS3", "YES", "NO")
}
options_horus_x10express = {
@ -196,7 +204,8 @@ options_horus_x10express = {
"faichoice": ("FAI", "CHOICE", None),
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
"eu": ("MODULE_PROTOCOL_D8", "NO", "YES"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None)
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"afhds3": ("AFHDS3", "YES", "NO")
}
options_jumper_t12 = {
@ -209,6 +218,7 @@ options_jumper_t12 = {
"nooverridech": ("OVERRIDE_CHANNEL_FUNCTION", "NO", "YES"),
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"internalmulti": ("INTERNAL_MODULE_MULTI", "YES", "NO"),
"afhds3": ("AFHDS3", "YES", "NO")
}
options_jumper_t16 = {
@ -222,6 +232,7 @@ options_jumper_t16 = {
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"internalmulti": ("INTERNAL_MODULE_MULTI", "YES", "NO"),
"bluetooth": ("BLUETOOTH", "YES", "NO"),
"afhds3": ("AFHDS3", "YES", "NO")
}
options_radiomaster_tx16s = {
@ -235,4 +246,5 @@ options_radiomaster_tx16s = {
"flexr9m": ("MODULE_PROTOCOL_FLEX", "YES", None),
"bluetooth": ("BLUETOOTH", "YES", "NO"),
"internalgps": ("INTERNAL_GPS", "YES", "NO"),
"afhds3": ("AFHDS3", "YES", "NO")
}