Merge pull request #728 from EdgeTX/nv14-internal-module

Nv14 internal module
This commit is contained in:
Raphael Coeffic
2021-09-21 08:18:47 +02:00
committed by GitHub
25 changed files with 1327 additions and 296 deletions
+13 -1
View File
@@ -463,8 +463,18 @@ PACK(struct ModuleData {
#if defined(AFHDS2)
NOBACKUP(struct {
uint8_t rx_id[4];
uint8_t mode;
uint8_t mode:3;
uint8_t rfPower:1;
uint8_t reserved:4;
uint8_t rx_freq[2];
void setDefault() {
rx_id[0] = rx_id[1] = rx_id[2] = rx_id[3] = 0;
mode = 0;
rfPower = 0;
rx_freq[0] = 50;
rx_freq[1] = 0;
}
} flysky);
#endif
#if defined(AFHDS3)
@@ -475,6 +485,8 @@ PACK(struct ModuleData {
uint8_t telemetry:1;
uint16_t failsafeTimeout;
uint8_t rx_freq[2];
uint8_t mode:2;
uint8_t reserved:6;
uint16_t rxFreq()
{
return (uint16_t)rx_freq[0] | (((uint16_t)rx_freq[1]) << 8);
+191 -100
View File
@@ -21,6 +21,7 @@
#include "model_setup.h"
#include "multi_rfprotos.h"
#include "io/multi_protolist.h"
#include "pulses/flysky.h"
#include "opentx.h"
#include "libopenui.h"
@@ -803,46 +804,178 @@ class ModuleWindow : public FormGroup {
// Module parameters
if (isModuleXJT(moduleIdx)) {
auto xjtChoice = new Choice(this, grid.getFieldSlot(2, 1), STR_XJT_ACCST_RF_PROTOCOLS, MODULE_SUBTYPE_PXX1_OFF, MODULE_SUBTYPE_PXX1_ACCST_LR12,
GET_SET_DEFAULT(g_model.moduleData[moduleIdx].rfProtocol));
xjtChoice->setAvailableHandler([](int index) {
return index != MODULE_SUBTYPE_PXX1_OFF;
});
}
else if (isModuleDSM2(moduleIdx)) {
new Choice(this, grid.getFieldSlot(2, 1), STR_DSM_PROTOCOLS, DSM2_PROTO_LP45, DSM2_PROTO_DSMX,
auto xjtChoice = new Choice(
this, grid.getFieldSlot(2, 1), STR_XJT_ACCST_RF_PROTOCOLS,
MODULE_SUBTYPE_PXX1_OFF, MODULE_SUBTYPE_PXX1_ACCST_LR12,
GET_SET_DEFAULT(g_model.moduleData[moduleIdx].rfProtocol));
xjtChoice->setAvailableHandler(
[](int index) { return index != MODULE_SUBTYPE_PXX1_OFF; });
} else if (isModuleDSM2(moduleIdx)) {
new Choice(this, grid.getFieldSlot(2, 1), STR_DSM_PROTOCOLS,
DSM2_PROTO_LP45, DSM2_PROTO_DSMX,
GET_SET_DEFAULT(g_model.moduleData[moduleIdx].rfProtocol));
} else if (isModuleR9M(moduleIdx)) {
rfChoice =
new Choice(this, grid.getFieldSlot(2, 1), STR_R9M_REGION,
MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_EU,
GET_DEFAULT(g_model.moduleData[moduleIdx].subType),
[=](int32_t newValue) {
g_model.moduleData[moduleIdx].subType = newValue;
SET_DIRTY();
update();
rfChoice->setFocus(SET_FOCUS_DEFAULT);
});
} else if (isModulePXX2(moduleIdx)) {
rfChoice =
new Choice(this, grid.getFieldSlot(2, 1), STR_ISRM_RF_PROTOCOLS, 0,
MODULE_SUBTYPE_ISRM_PXX2_ACCST_LR12,
GET_DEFAULT(g_model.moduleData[moduleIdx].subType),
[=](int32_t newValue) {
g_model.moduleData[moduleIdx].subType = newValue;
SET_DIRTY();
update();
rfChoice->setFocus(SET_FOCUS_DEFAULT);
});
}
else if (isModuleR9M(moduleIdx)) {
rfChoice = new Choice(this, grid.getFieldSlot(2, 1), STR_R9M_REGION, MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_EU,
GET_DEFAULT(g_model.moduleData[moduleIdx].subType),
[=](int32_t newValue) {
g_model.moduleData[moduleIdx].subType = newValue;
SET_DIRTY();
update();
rfChoice->setFocus(SET_FOCUS_DEFAULT);
});
}
else if (isModulePXX2(moduleIdx)) {
rfChoice = new Choice(this, grid.getFieldSlot(2, 1), STR_ISRM_RF_PROTOCOLS, 0, MODULE_SUBTYPE_ISRM_PXX2_ACCST_LR12,
GET_DEFAULT(g_model.moduleData[moduleIdx].subType),
[=](int32_t newValue) {
g_model.moduleData[moduleIdx].subType = newValue;
SET_DIRTY();
update();
rfChoice->setFocus(SET_FOCUS_DEFAULT);
});
}
#if defined(AFHDS2) || defined(AFHDS3)
else if (isModuleFlySky(moduleIdx)) {
rfChoice = new Choice(this, grid.getFieldSlot(2, 1), STR_FLYSKY_PROTOCOLS, 0, MODULE_SUBTYPE_ISRM_PXX2_ACCST_LR12,
GET_DEFAULT(g_model.moduleData[moduleIdx].subType),
[=](int32_t newValue) {
g_model.moduleData[moduleIdx].subType = newValue;
SET_DIRTY();
update();
rfChoice->setFocus(SET_FOCUS_DEFAULT);
});
rfChoice =
new Choice(this, grid.getFieldSlot(2, 1),
STR_FLYSKY_PROTOCOLS, 0, FLYSKY_SUBTYPE_AFHDS2A,
GET_DEFAULT(g_model.moduleData[moduleIdx].subType),
[=](int32_t newValue) {
g_model.moduleData[moduleIdx].subType = newValue;
SET_DIRTY();
update();
rfChoice->setFocus(SET_FOCUS_DEFAULT);
});
if (moduleIdx == INTERNAL_MODULE) {
g_model.moduleData[moduleIdx].subType = FLYSKY_SUBTYPE_AFHDS2A;
rfChoice->setAvailableHandler(
[](int v) { return v == FLYSKY_SUBTYPE_AFHDS2A; });
} else {
g_model.moduleData[moduleIdx].subType = FLYSKY_SUBTYPE_AFHDS3;
rfChoice->setAvailableHandler(
[](int v) { return v == FLYSKY_SUBTYPE_AFHDS3; });
}
// RX options:
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_OPTIONS, 0,
COLOR_THEME_PRIMARY1);
#if defined(AFHDS2)
if (isModuleAFHDS2A(moduleIdx)) {
// PPM / PWM
new Choice(
this, grid.getFieldSlot(2, 0), STR_FLYSKY_PULSE_PROTO, 0, 1,
[=]() { return g_model.moduleData[moduleIdx].flysky.mode >> 1; },
[=](int v) {
g_model.moduleData[moduleIdx].flysky.mode =
(g_model.moduleData[moduleIdx].flysky.mode & 1) |
((v & 1) << 1);
});
// SBUS / iBUS
new Choice(
this, grid.getFieldSlot(2, 1), STR_FLYSKY_SERIAL_PROTO, 0, 1,
[=]() { return g_model.moduleData[moduleIdx].flysky.mode & 1; },
[=](int v) {
g_model.moduleData[moduleIdx].flysky.mode =
(g_model.moduleData[moduleIdx].flysky.mode & 2) | (v & 1);
});
}
#endif
#if defined(AFHDS3)
if (isModuleAFHDS3(moduleIdx)) {
// PPM / PWM
new Choice(
this, grid.getFieldSlot(2, 0), STR_FLYSKY_PULSE_PROTO, 0, 1,
[=]() { return g_model.moduleData[moduleIdx].afhds3.mode >> 1; },
[=](int v) {
g_model.moduleData[moduleIdx].afhds3.mode =
(g_model.moduleData[moduleIdx].afhds3.mode & 1) |
((v & 1) << 1);
});
// SBUS / iBUS
new Choice(
this, grid.getFieldSlot(2, 1), STR_FLYSKY_SERIAL_PROTO, 0, 1,
[=]() { return g_model.moduleData[moduleIdx].afhds3.mode & 1; },
[=](int v) {
g_model.moduleData[moduleIdx].afhds3.mode =
(g_model.moduleData[moduleIdx].afhds3.mode & 2) | (v & 1);
});
// TYPE
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_TYPE, 0,
COLOR_THEME_PRIMARY1);
// This is chosen when binding (menu? see stdlcd/model_setup_afhds3.cpp)
new StaticText(this, grid.getFieldSlot(),
g_model.moduleData[moduleIdx].afhds3.telemetry
? STR_AFHDS3_ONE_TO_ONE_TELEMETRY
: TR_AFHDS3_ONE_TO_MANY,
0, COLOR_THEME_PRIMARY1);
// Status
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_MODULE_STATUS, 0,
COLOR_THEME_PRIMARY1);
new DynamicText(this, grid.getFieldSlot(), [=] {
char msg[64] = "";
getModuleStatusString(moduleIdx, msg);
return std::string(msg);
});
// Power source
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_AFHDS3_POWER_SOURCE,
0, COLOR_THEME_PRIMARY1);
new DynamicText(this, grid.getFieldSlot(), [=] {
char msg[64] = "";
getModuleSyncStatusString(moduleIdx, msg);
return std::string(msg);
});
// RX Freq
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_AFHDS3_RX_FREQ, 0,
COLOR_THEME_PRIMARY1);
auto edit = new NumberEdit(
this, grid.getFieldSlot(2, 0), MIN_FREQ, MAX_FREQ,
GET_DEFAULT(g_model.moduleData[moduleIdx].afhds3.rxFreq()));
edit->setSetValueHandler([=](int32_t newValue) {
g_model.moduleData[moduleIdx].afhds3.setRxFreq(
(uint16_t)newValue);
});
edit->setSuffix(STR_HZ);
// Module actual power
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_AFHDS3_ACTUAL_POWER,
0, COLOR_THEME_PRIMARY1);
new DynamicText(this, grid.getFieldSlot(), [=] {
char msg[64] = "";
getStringAtIndex(msg, STR_AFHDS3_POWERS,
actualAfhdsRunPower(moduleIdx));
return std::string(msg);
});
// Module power
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_RF_POWER, 0,
COLOR_THEME_PRIMARY1);
new Choice(
this, grid.getFieldSlot(2, 0), STR_AFHDS3_POWERS,
afhds3::RUN_POWER::RUN_POWER_FIRST,
afhds3::RUN_POWER::RUN_POWER_LAST,
GET_SET_DEFAULT(g_model.moduleData[moduleIdx].afhds3.runPower));
}
#endif
}
#endif
#if defined(MULTIMODULE)
else if (isModuleMultimodule(moduleIdx)) {
Choice * mmSubProto = nullptr;
@@ -1030,62 +1163,6 @@ class ModuleWindow : public FormGroup {
GET_SET_DEFAULT(g_model.moduleData[moduleIdx].multi.disableMapping));
}
}
#endif
#if defined(AFHDS3)
else if (isModuleAFHDS3(moduleIdx)) {
rfChoice = new Choice(this, grid.getFieldSlot(2, 1), STR_AFHDS3_PROTOCOLS, AFHDS_SUBTYPE_FIRST, AFHDS_SUBTYPE_LAST,
GET_SET_DEFAULT(g_model.moduleData[moduleIdx].subType));
// TYPE
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_TYPE, 0, COLOR_THEME_PRIMARY1);
new StaticText(this, grid.getFieldSlot(),
g_model.moduleData[EXTERNAL_MODULE].afhds3.telemetry ? STR_AFHDS3_ONE_TO_ONE_TELEMETRY : TR_AFHDS3_ONE_TO_MANY,
0, COLOR_THEME_PRIMARY1);
// Status
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_MODULE_STATUS, 0, COLOR_THEME_PRIMARY1);
new DynamicText(this, grid.getFieldSlot(), [=] {
char msg[64] = "";
getModuleStatusString(moduleIdx, msg);
return std::string(msg);
});
// Power source
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_AFHDS3_POWER_SOURCE, 0, COLOR_THEME_PRIMARY1);
new DynamicText(this, grid.getFieldSlot(), [=] {
char msg[64] = "";
getModuleSyncStatusString(moduleIdx, msg);
return std::string(msg);
});
// RX Freq
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_AFHDS3_RX_FREQ, 0, COLOR_THEME_PRIMARY1);
auto edit = new NumberEdit(this, grid.getFieldSlot(2,0), MIN_FREQ, MAX_FREQ, GET_DEFAULT(g_model.moduleData[moduleIdx].afhds3.rxFreq()));
edit->setSetValueHandler([=](int32_t newValue) {
g_model.moduleData[EXTERNAL_MODULE].afhds3.setRxFreq((uint16_t)newValue);
});
edit->setSuffix(STR_HZ);
// Module actual power
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_AFHDS3_ACTUAL_POWER, 0, COLOR_THEME_PRIMARY1);
new DynamicText(this, grid.getFieldSlot(), [=] {
char msg[64] = "";
getStringAtIndex(msg, STR_AFHDS3_POWERS, actualAfhdsRunPower(moduleIdx));
return std::string(msg);
});
// Module power
grid.nextLine();
new StaticText(this, grid.getLabelSlot(true), STR_RF_POWER, 0, COLOR_THEME_PRIMARY1);
new Choice(this, grid.getFieldSlot(2, 0), STR_AFHDS3_POWERS, afhds3::RUN_POWER::RUN_POWER_FIRST, afhds3::RUN_POWER::RUN_POWER_LAST,
GET_SET_DEFAULT(g_model.moduleData[moduleIdx].afhds3.runPower));
}
#endif
grid.nextLine();
@@ -1126,7 +1203,9 @@ class ModuleWindow : public FormGroup {
// Module parameters
// Bind and Range buttons
if (!isModuleRFAccess(moduleIdx) && (isModuleModelIndexAvailable(moduleIdx)|| isModuleBindRangeAvailable(moduleIdx))) {
if (!isModuleRFAccess(moduleIdx) &&
(isModuleModelIndexAvailable(moduleIdx) ||
isModuleBindRangeAvailable(moduleIdx))) {
uint8_t thirdColumn = 0;
new StaticText(this, grid.getLabelSlot(true), STR_RECEIVER, 0, COLOR_THEME_PRIMARY1);
@@ -1151,10 +1230,13 @@ class ModuleWindow : public FormGroup {
bindButton = new TextButton(this, grid.getFieldSlot(2 + thirdColumn, 0 + thirdColumn), STR_MODULE_BIND);
bindButton->setPressHandler([=]() -> uint8_t {
if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) {
rangeButton->check(false);
if (rangeButton) rangeButton->check(false);
}
if (moduleState[moduleIdx].mode == MODULE_MODE_BIND) {
moduleState[moduleIdx].mode = MODULE_MODE_NORMAL;
#if defined(AFHDS2)
if (isModuleFlySky(moduleIdx)) resetPulsesAFHDS2();
#endif
return 0;
} else {
#if defined(MULTIMODULE)
@@ -1163,6 +1245,11 @@ class ModuleWindow : public FormGroup {
}
#endif
moduleState[moduleIdx].mode = MODULE_MODE_BIND;
#if defined(AFHDS2)
if (isModuleFlySky(moduleIdx)) {
resetPulsesAFHDS2();
}
#endif
return 1;
}
return 0;
@@ -1172,7 +1259,8 @@ class ModuleWindow : public FormGroup {
bindButton->check(false);
}
#if defined(MULTIMODULE)
if (isModuleMultimodule(moduleIdx) && getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) {
if (isModuleMultimodule(moduleIdx) &&
getMultiBindStatus(moduleIdx) == MULTI_BIND_FINISHED) {
setMultiBindStatus(moduleIdx, MULTI_BIND_NONE);
moduleState[moduleIdx].mode = MODULE_MODE_NORMAL;
bindButton->check(false);
@@ -1180,8 +1268,11 @@ class ModuleWindow : public FormGroup {
#endif
});
rangeButton = new TextButton(this, grid.getFieldSlot(2 + thirdColumn, 1 + thirdColumn), STR_MODULE_RANGE);
rangeButton->setPressHandler([=]() -> uint8_t {
if (isModuleRangeAvailable(moduleIdx)) {
rangeButton = new TextButton(
this, grid.getFieldSlot(2 + thirdColumn, 1 + thirdColumn),
STR_MODULE_RANGE);
rangeButton->setPressHandler([=]() -> uint8_t {
if (moduleState[moduleIdx].mode == MODULE_MODE_BIND) {
bindButton->check(false);
moduleState[moduleIdx].mode = MODULE_MODE_NORMAL;
@@ -1189,8 +1280,7 @@ class ModuleWindow : public FormGroup {
if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) {
moduleState[moduleIdx].mode = MODULE_MODE_NORMAL;
return 0;
}
else {
} else {
moduleState[moduleIdx].mode = MODULE_MODE_RANGECHECK;
auto rssiDialog = new DynamicMessageDialog(
this, "Range Test",
@@ -1207,7 +1297,8 @@ class ModuleWindow : public FormGroup {
});
return 1;
}
});
});
}
}
grid.nextLine();
+2
View File
@@ -236,6 +236,8 @@ void RadioVersionPage::build(FormWindow * window)
auto options = new OptionsText(window, grid.getFieldSlot(1,0));
grid.nextLine(options->height() + 4);
//TODO: NV14 internal module version (NV14internalModuleFwVersion)
#if defined(PXX2)
// Module and receivers versions
auto moduleVersions = new TextButton(window, grid.getLineSlot(), STR_MODULES_RX_VERSION);
+3 -3
View File
@@ -573,7 +573,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:
case MODULE_TYPE_FLYSKY:
return false;
case MODULE_TYPE_XJT_PXX1:
@@ -628,7 +628,7 @@ bool isInternalModuleAvailable(int moduleType)
}
#if (defined(AFHDS3) || defined(AFHDS2A)) && (defined(INTERNAL_MODULE_AFHDS2A) || defined(INTERNAL_MODULE_AFHDS3))
if (moduleType == MODULE_TYPE_AFHDS3) {
if (moduleType == MODULE_TYPE_FLYSKY) {
return true;
}
#endif
@@ -713,7 +713,7 @@ bool isExternalModuleAvailable(int moduleType)
#endif
#if !defined(AFHDS3)
if (moduleType == MODULE_TYPE_AFHDS3)
if (moduleType == MODULE_TYPE_FLYSKY)
return false;
#endif
+2
View File
@@ -27,6 +27,8 @@
#include <map>
#include <list>
#define AFHDS2_PERIOD (2 * 1000) /* us */
struct FlySkySerialPulsesData {
uint8_t pulses[64];
uint8_t * ptr;
+13 -6
View File
@@ -549,7 +549,7 @@ inline bool isSbus(uint8_t mode)
inline bool isPWM(uint8_t mode)
{
return mode < 2;
return !(mode & 2);
}
RUN_POWER PulsesData::getMaxRunPower() const
@@ -604,7 +604,9 @@ bool PulsesData::syncSettings()
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;
PULSE_MODE modelPulseMode = isPWM(moduleData->afhds3.mode)
? PULSE_MODE::PWM_MODE
: PULSE_MODE::PPM_MODE;
if (modelPulseMode != cfg.config.pulseMode) {
cfg.config.pulseMode = modelPulseMode;
TRACE("AFHDS3 PWM/PPM %d", modelPulseMode);
@@ -613,7 +615,9 @@ bool PulsesData::syncSettings()
return true;
}
SERIAL_MODE modelSerialMode = isSbus(moduleData->subType) ? SERIAL_MODE::SBUS_MODE : SERIAL_MODE::IBUS;
SERIAL_MODE modelSerialMode = isSbus(moduleData->afhds3.mode)
? SERIAL_MODE::SBUS_MODE
: SERIAL_MODE::IBUS;
if (modelSerialMode != cfg.config.serialMode) {
cfg.config.serialMode = modelSerialMode;
TRACE("AFHDS3 IBUS/SBUS %d", modelSerialMode);
@@ -660,9 +664,12 @@ void PulsesData::setConfigFromModel()
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.serialMode = isSbus(moduleData->afhds3.mode)
? SERIAL_MODE::SBUS_MODE
: SERIAL_MODE::IBUS;
cfg.config.pulseMode = isPWM(moduleData->afhds3.mode) ? 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);
+741
View File
@@ -0,0 +1,741 @@
/*
* Copyright (C) OpenTX
*
* Dedicate for FlySky NV14 board.
*
* 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 "opentx.h"
#include "flysky.h"
#include "telemetry/flysky_nv14.h"
#define IS_VALID_COMMAND_ID(id) ((id) < CMD_LAST)
#ifndef custom_log
#define custom_log
#endif
// 0:OFF, 1:RF frame only, 2:TX frame only, 3:Both RF and TX frame
enum DEBUG_RF_FRAME_PRINT_E {
FRAME_PRINT_OFF = 0,
RF_FRAME_ONLY = 1,
TX_FRAME_ONLY = 2,
BOTH_FRAME_PRINT = 3
};
#define DEBUG_RF_FRAME_PRINT FRAME_PRINT_OFF
//#define DEBUG_RF_FRAME_PRINT BOTH_FRAME_PRINT
#define FLYSKY_MODULE_TIMEOUT 155 /* ms */
#define FLYSKY_PERIOD 4 /*ms*/
#define NUM_OF_NV14_CHANNELS (14)
#define VALID_CH_DATA(v) ((v) > 900 && (v) < 2100)
#define FAILSAVE_SEND_COUNTER_MAX (400)
#define gRomData g_model.moduleData[INTERNAL_MODULE].flysky
#define SET_DIRTY() storageDirty(EE_MODEL)
enum FlySkyBindState_E {
BIND_LOW_POWER,
BIND_NORMAL_POWER,
BIND_EXIT,
};
enum FlySkyRxPulse_E { FLYSKY_PWM, FLYSKY_PPM };
enum FlySkyRxPort_E { FLYSKY_IBUS, FLYSKY_SBUS };
enum FlySkyFirmwareType_E { FLYSKY_RX_FIRMWARE, FLYSKY_RF_FIRMWARE };
enum FlySkyChannelDataType_E {
FLYSKY_CHANNEL_DATA_NORMAL,
FLYSKY_CHANNEL_DATA_FAILSAFE
};
enum FlySkyPulseModeValue_E { PWM_IBUS, PWM_SBUS, PPM_IBUS, PPM_SBUS };
enum FlySkyPulseProtocol_E {
FLYSKY_AFHDS1,
FLYSKY_AFHDS2,
FLYSKY_AFHDS2A,
};
enum FlySkyModuleState_E {
STATE_SET_TX_POWER = 0,
STATE_INIT = 1,
STATE_GET_FW_VERSION_INIT = 2,
STATE_BIND = 3,
STATE_SET_RECEIVER_ID = 4,
STATE_SET_RX_PWM_PPM = 5,
STATE_SET_RX_IBUS_SBUS = 6,
STATE_SET_RX_FREQUENCY = 7,
STATE_UPDATE_RF_FIRMWARE = 8,
STATE_UPDATE_RX_FIRMWARE = 9,
STATE_UPDATE_HALL_FIRMWARE = 10,
STATE_UPDATE_RF_PROTOCOL = 11,
STATE_GET_RECEIVER_CONFIG = 12,
STATE_GET_RX_VERSION_INFO = 13,
STATE_GET_RF_VERSION_INFO = 14,
STATE_SET_RANGE_TEST = 15,
STATE_RANGE_TEST_RUNNING = 16,
STATE_IDLE = 17,
STATE_DISCONNECT = 18,
STATE_SEND_CHANNELS = 19,
};
#define AfhdsPwmMode (gRomData.mode & 2 ? FLYSKY_PPM : FLYSKY_PWM)
#define AfhdsIbusMode (gRomData.mode & 1 ? FLYSKY_SBUS : FLYSKY_IBUS)
struct rf_info_t {
uint8_t bind_power;
uint8_t protocol;
// 0: normal, COMMAND_ID0C_UPDATE_RF_FIRMWARE or CMD_UPDATE_FIRMWARE_END
uint8_t fw_state;
};
// static STRUCT_HALL rxBuffer = {0};
static uint32_t rfRxCount = 0;
static uint8_t lastState = STATE_IDLE;
static uint32_t set_loop_cnt = 0;
uint32_t NV14internalModuleFwVersion;
static rf_info_t rf_info = {
.bind_power = BIND_LOW_POWER,
.protocol = FLYSKY_AFHDS2A, // never updated currently
.fw_state = 0,
};
typedef struct __attribute__((packed)) rxParams {
uint8_t outputMode;
uint8_t outputSerialMode;
uint16_t outputFreq;
} rxParams;
typedef struct __attribute__((packed)) fwVersion {
uint8_t target;
uint32_t version;
} fwVersion;
struct __attribute__((packed)) afhds2Resp {
uint8_t startByte;
uint8_t frame_number;
uint8_t frame_type;
uint8_t command_id;
uint8_t value;
};
uint8_t emptyRxID[] = {0, 0, 0, 0};
void setFlyskyState(uint8_t state);
void onFlySkyBindReceiver();
void onFlySkyModuleSetPower(bool isPowerOn);
void afhds2Command(uint8_t type, uint8_t cmd);
void onFlySkyGetVersionInfoStart(uint8_t isRfTransfer);
// void usbDownloadTransmit(uint8_t *buffer, uint32_t size);
// extern uint32_t NV14internalModuleFwVersion;
#define END 0xC0
#define ESC 0xDB
#define ESC_END 0xDC
#define ESC_ESC 0xDD
#define FRAME_TYPE_REQUEST_ACK 0x01
#define FRAME_TYPE_REQUEST_NACK 0x02
#define FRAME_TYPE_ANSWER 0x10
enum FlySkyModuleCommandID {
CMD_NONE=0,
CMD_RF_INIT=1,
CMD_BIND=2,
CMD_SET_RECEIVER_ID=3,
CMD_RF_GET_CONFIG=4,
CMD_SEND_CHANNEL_DATA=5,
CMD_RX_SENSOR_DATA=6,
CMD_SET_RX_PWM_PPM=7,
CMD_SET_RX_SERVO_FREQ=8,
CMD_GET_VERSION_INFO=9,
CMD_SET_RX_IBUS_SBUS=0xA,
CMD_SET_RX_IBUS_SERVO_EXT=0xB,
CMD_UPDATE_RF_FIRMWARE = 0x0C,
CMD_SET_TX_POWER = 0x0D,
CMD_SET_RF_PROTOCOL,
CMD_TEST_RANGE,
CMD_TEST_RF_RESERVED,
CMD_UPDATE_RX_FIRMWARE = 0x20,
CMD_LAST
};
bool isFlySkyUsbDownload(void) { return rf_info.fw_state != 0; }
// void usbSetFrameTransmit(uint8_t packetID, uint8_t *dataBuf, uint32_t nBytes)
// {
// // send to host via usb
// uint8_t *pt = (uint8_t*)&rxBuffer;
// // rxBuffer.head = HALL_PROTOLO_HEAD;
// rxBuffer.hallID.hall_Id.packetID = packetID;//0x08;
// rxBuffer.hallID.hall_Id.senderID = 0x03;
// rxBuffer.hallID.hall_Id.receiverID = 0x02;
// if ( packetID == 0x08 ) {
// uint8_t fwVerision[40];
// for(uint32_t idx = 40; idx > 0; idx--)
// {
// if ( idx <= nBytes ) {
// fwVerision[idx-1] = dataBuf[idx-1];
// }
// else fwVerision[idx-1] = 0;
// }
// dataBuf = fwVerision;
// nBytes = 40;
// }
// rxBuffer.length = nBytes;
// TRACE_NOCRLF("\r\nToUSB: 55 %02X %02X ", rxBuffer.hallID.ID, nBytes);
// for ( uint32_t idx = 0; idx < nBytes; idx++ )
// {
// rxBuffer.data[idx] = dataBuf[idx];
// TRACE_NOCRLF("%02X ", rxBuffer.data[idx]);
// }
// #if !defined(SIMU)
// uint16_t checkSum = calc_crc16(pt, rxBuffer.length+3);
// TRACE(" CRC:%04X;", checkSum);
// pt[rxBuffer.length + 3] = checkSum & 0xFF;
// pt[rxBuffer.length + 4] = checkSum >> 8;
// usbDownloadTransmit(pt, rxBuffer.length + 5);
// #endif
// }
void onFlySkyModuleSetPower(bool isPowerOn)
{
if (isPowerOn) {
INTERNAL_MODULE_ON();
resetPulsesAFHDS2();
} else {
moduleState[INTERNAL_MODULE].mode = MODULE_MODE_NORMAL;
INTERNAL_MODULE_OFF();
}
}
void setFlyskyState(uint8_t state) { intmodulePulsesData.flysky.state = state; }
void onFlySkyUsbDownloadStart(uint8_t fw_state) { rf_info.fw_state = fw_state; }
void onFlySkyGetVersionInfoStart(uint8_t isRfTransfer)
{
lastState = intmodulePulsesData.flysky.state;
setFlyskyState(isRfTransfer ? STATE_GET_RF_VERSION_INFO
: STATE_GET_RX_VERSION_INFO);
}
inline void initFlySkyArray()
{
intmodulePulsesData.flysky.ptr = intmodulePulsesData.flysky.pulses;
intmodulePulsesData.flysky.crc = 0;
}
inline void putFlySkyByte(uint8_t byte)
{
if (END == byte) {
*intmodulePulsesData.flysky.ptr++ = ESC;
*intmodulePulsesData.flysky.ptr++ = ESC_END;
} else if (ESC == byte) {
*intmodulePulsesData.flysky.ptr++ = ESC;
*intmodulePulsesData.flysky.ptr++ = ESC_ESC;
} else {
*intmodulePulsesData.flysky.ptr++ = byte;
}
}
inline void putFlySkyFrameByte(uint8_t byte)
{
intmodulePulsesData.flysky.crc += byte;
putFlySkyByte(byte);
}
inline void putFlySkyFrameCmd(uint8_t type, uint8_t cmd)
{
intmodulePulsesData.flysky.crc += type + cmd;
putFlySkyByte(type);
putFlySkyByte(cmd);
}
inline void putFlySkyFrameBytes(uint8_t* data, int length)
{
for (int i = 0; i < length; i++) {
intmodulePulsesData.flysky.crc += data[i];
putFlySkyByte(data[i]);
}
}
inline void putFlySkyFrameHeader()
{
initFlySkyArray();
*intmodulePulsesData.flysky.ptr++ = END;
putFlySkyFrameByte(intmodulePulsesData.flysky.frame_index);
}
inline void putFlySkyFrameFooter()
{
if (++intmodulePulsesData.flysky.frame_index == 0) {
intmodulePulsesData.flysky.frame_index = 1;
}
putFlySkyByte(intmodulePulsesData.flysky.crc ^ 0xff);
*intmodulePulsesData.flysky.ptr++ = END;
}
void afhds2Command(uint8_t type, uint8_t cmd)
{
putFlySkyFrameHeader();
putFlySkyFrameCmd(type, cmd);
putFlySkyFrameFooter();
}
inline void putFlySkySendChannelData()
{
uint16_t pulseValue = 0;
uint8_t channels_start = g_model.moduleData[INTERNAL_MODULE].channelsStart;
uint8_t channels_last =
channels_start + 8 + g_model.moduleData[INTERNAL_MODULE].channelsCount;
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_NACK, CMD_SEND_CHANNEL_DATA);
if (moduleState[INTERNAL_MODULE].counter-- == 0) {
moduleState[INTERNAL_MODULE].counter = FAILSAVE_SEND_COUNTER_MAX;
putFlySkyFrameByte(FLYSKY_CHANNEL_DATA_FAILSAFE);
putFlySkyFrameByte(channels_last - channels_start);
for (uint8_t channel = channels_start; channel < channels_last; channel++) {
if (g_model.moduleData[INTERNAL_MODULE].failsafeMode == FAILSAFE_CUSTOM) {
int16_t failsafeValue = g_model.failsafeChannels[channel];
pulseValue =
limit<uint16_t>(0, 988 + ((failsafeValue + 1024) / 2), 0xfff);
} else if (g_model.moduleData[INTERNAL_MODULE].failsafeMode ==
FAILSAFE_HOLD) {
// protocol uses hold by default
pulseValue = 0xfff;
} else {
int16_t failsafeValue =
-1024 + 2 * PPM_CH_CENTER(channel) - 2 * PPM_CENTER;
pulseValue =
limit<uint16_t>(0, 988 + ((failsafeValue + 1024) / 2), 0xfff);
}
putFlySkyFrameByte(pulseValue & 0xff);
putFlySkyFrameByte(pulseValue >> 8);
}
if (DEBUG_RF_FRAME_PRINT & RF_FRAME_ONLY) {
TRACE("------FAILSAFE------");
}
} else {
putFlySkyFrameByte(FLYSKY_CHANNEL_DATA_NORMAL);
putFlySkyFrameByte(channels_last - channels_start);
for (uint8_t channel = channels_start; channel < channels_last; channel++) {
int channelValue =
channelOutputs[channel] + 2 * PPM_CH_CENTER(channel) - 2 * PPM_CENTER;
pulseValue = limit<uint16_t>(0, 988 + ((channelValue + 1024) / 2), 0xfff);
putFlySkyFrameByte(pulseValue & 0xff);
putFlySkyFrameByte(pulseValue >> 8);
}
}
}
void putFlySkyUpdateFirmwareStart(uint8_t cmd)
{
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, cmd);
}
bool checkFlySkyFrameCrc(const uint8_t* ptr, uint8_t size)
{
uint8_t crc = 0;
for (uint8_t i = 0; i < size; i++) {
crc += ptr[i];
}
if (DEBUG_RF_FRAME_PRINT & RF_FRAME_ONLY) {
if (ptr[2] != 0x06 || (set_loop_cnt++ % 50 == 0)) {
TRACE_NOCRLF("RF(%0d): C0", INTMODULE_USART_AFHDS2_BAUDRATE);
for (int idx = 0; idx <= size; idx++) {
TRACE_NOCRLF(" %02X", ptr[idx]);
}
TRACE_NOCRLF(" C0;" CRLF);
if ((crc ^ 0xff) != ptr[size]) {
TRACE("ErrorCRC %02X especting %02X", crc ^ 0xFF, ptr[size]);
}
}
}
return (crc ^ 0xff) == ptr[size];
}
inline void debugFrame(const uint8_t* rxBuffer, uint8_t rxBufferCount)
{
// debug print the content of the packet
char buffer[64 * 3];
char* pos = buffer;
if (rxBufferCount * 3 > sizeof(buffer)) rxBufferCount = 64;
for (int i = 0; i < rxBufferCount; i++) {
pos += snprintf(pos, buffer + sizeof(buffer) - pos, "%02X ", rxBuffer[i]);
}
(*pos) = 0;
TRACE("count [%d] data: %s", rxBufferCount, buffer);
}
inline void parseResponse()
{
afhds2Resp* resp =
reinterpret_cast<afhds2Resp*>(intmodulePulsesData.flysky.telemetry);
uint8_t dataLen = intmodulePulsesData.flysky.telemetry_index;
if (resp->startByte != END || dataLen < 2) return;
dataLen -= 2;
if (!checkFlySkyFrameCrc(intmodulePulsesData.flysky.telemetry + 1, dataLen)) {
return;
}
if ((moduleState[INTERNAL_MODULE].mode != MODULE_MODE_BIND) &&
(resp->frame_type == FRAME_TYPE_ANSWER) &&
((intmodulePulsesData.flysky.frame_index - 1) != resp->frame_number)) {
return;
} else if (resp->frame_type == FRAME_TYPE_REQUEST_ACK) {
intmodulePulsesData.flysky.frame_index = resp->frame_number;
}
debugFrame(&resp->command_id, dataLen - 2);
switch (resp->command_id) {
default:
if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_NORMAL &&
intmodulePulsesData.flysky.state >= STATE_IDLE) {
setFlyskyState(STATE_SEND_CHANNELS);
if (DEBUG_RF_FRAME_PRINT & RF_FRAME_ONLY)
TRACE("State back to channel data");
}
break;
case CMD_RF_INIT:
if (resp->value == 0x01) { // action only RF ready
if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_BIND)
setFlyskyState(STATE_BIND);
else
setFlyskyState(STATE_GET_FW_VERSION_INIT); // get version first
} else {
// Try one more time;
resetPulsesAFHDS2();
setFlyskyState(STATE_INIT);
}
break;
case CMD_BIND: {
if (resp->frame_type != FRAME_TYPE_ANSWER) {
setFlyskyState(STATE_IDLE);
return;
}
if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_BIND)
moduleState[INTERNAL_MODULE].mode = MODULE_MODE_NORMAL;
*((uint32_t*)gRomData.rx_id) =
*(reinterpret_cast<const uint32_t*>(&resp->value));
g_model.header.modelId[INTERNAL_MODULE] = gRomData.rx_id[3];
if (DEBUG_RF_FRAME_PRINT & RF_FRAME_ONLY)
TRACE("New Rx ID: %02X %02X %02X %02X", gRomData.rx_id[0],
gRomData.rx_id[1], gRomData.rx_id[2], gRomData.rx_id[3]);
SET_DIRTY();
resetPulsesAFHDS2();
setFlyskyState(STATE_INIT);
break;
}
case CMD_RF_GET_CONFIG:
setFlyskyState(STATE_GET_RECEIVER_CONFIG);
intmodulePulsesData.flysky.timeout = FLYSKY_MODULE_TIMEOUT;
break;
case CMD_RX_SENSOR_DATA:
flySkyNv14ProcessTelemetryPacket(&resp->value, dataLen - 3);
if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_NORMAL &&
intmodulePulsesData.flysky.state >= STATE_IDLE) {
setFlyskyState(STATE_SEND_CHANNELS);
}
break;
case CMD_SET_RECEIVER_ID: {
// range check seems to be not working
// it disconnects receiver
// if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_RANGECHECK) {
// setFlyskyState(STATE_SET_RANGE_TEST);
//}
// else
setFlyskyState(STATE_SEND_CHANNELS);
return;
}
case CMD_TEST_RANGE:
if (moduleState[INTERNAL_MODULE].mode != MODULE_MODE_RANGECHECK)
resetPulsesAFHDS2();
else
setFlyskyState(STATE_RANGE_TEST_RUNNING);
break;
case CMD_SET_TX_POWER:
setFlyskyState(STATE_INIT);
break;
case CMD_SET_RX_PWM_PPM:
setFlyskyState(STATE_SET_RX_IBUS_SBUS);
break;
case CMD_SET_RX_IBUS_SBUS:
setFlyskyState(STATE_SET_RX_FREQUENCY);
break;
case CMD_SET_RX_SERVO_FREQ:
setFlyskyState(STATE_SEND_CHANNELS);
break;
case CMD_UPDATE_RF_FIRMWARE: {
rf_info.fw_state = STATE_UPDATE_RF_FIRMWARE;
setFlyskyState(STATE_IDLE);
break;
}
case CMD_GET_VERSION_INFO: {
if (intmodulePulsesData.flysky.state == STATE_GET_FW_VERSION_INIT) {
memcpy(&NV14internalModuleFwVersion, &resp->value + 1,
sizeof(NV14internalModuleFwVersion));
setFlyskyState(STATE_SET_RECEIVER_ID);
break;
}
// if (dataLen > 4) {
// usbSetFrameTransmit(0x08, (uint8_t*) &resp->value + 1, dataLen - 4);
// }
if (lastState == STATE_GET_RF_VERSION_INFO ||
lastState == STATE_GET_RX_VERSION_INFO) {
lastState = STATE_INIT;
}
setFlyskyState(lastState);
break;
}
}
}
bool isrxBufferMsgOK(void)
{
bool isMsgOK = (0 != rfRxCount);
rfRxCount = 0;
return isMsgOK && isFlySkyUsbDownload();
}
void processInternalFlySkyTelemetryData(uint8_t byte)
{
// #if !defined(SIMU)
// parseFlyskyData(&rxBuffer, byte);
// #endif
// if (rxBuffer.valid) {
// rfRxCount++;
// rxBuffer.valid = 0;
// uint8_t *pt = (uint8_t*)&rxBuffer;
// //rxBuffer.head = HALL_PROTOLO_HEAD;
// pt[rxBuffer.length + 3] = rxBuffer.checkSum & 0xFF;
// pt[rxBuffer.length + 4] = rxBuffer.checkSum >> 8;
// if((DEBUG_RF_FRAME_PRINT & RF_FRAME_ONLY)) {
// TRACE("RF: %02X %02X %02X ...%04X; CRC:%04X", pt[0], pt[1], pt[2],
// rxBuffer.checkSum, calc_crc16(pt, rxBuffer.length+3));
// }
// //FW UPDATE done
// if (0x01 == rxBuffer.length && (0x05 == rxBuffer.data[0] || 0x06 ==
// rxBuffer.data[0])) {
// setFlyskyState(STATE_INIT);
// rf_info.fw_state = 0;
// }
// usbDownloadTransmit(pt, rxBuffer.length + 5);
// }
if (byte == END && intmodulePulsesData.flysky.telemetry_index > 0) {
parseResponse();
intmodulePulsesData.flysky.telemetry_index = 0;
} else {
if (byte == ESC) {
intmodulePulsesData.flysky.esc_state = 1;
} else {
if (intmodulePulsesData.flysky.esc_state) {
intmodulePulsesData.flysky.esc_state = 0;
if (byte == ESC_END)
byte = END;
else if (byte == ESC_ESC)
byte = ESC;
}
intmodulePulsesData.flysky
.telemetry[intmodulePulsesData.flysky.telemetry_index++] = byte;
if (intmodulePulsesData.flysky.telemetry_index >=
sizeof(intmodulePulsesData.flysky.telemetry)) {
// TODO buffer is full, log an error?
intmodulePulsesData.flysky.telemetry_index = 0;
}
}
}
}
void resetPulsesAFHDS2()
{
NV14internalModuleFwVersion = 0;
intmodulePulsesData.flysky.frame_index = 1;
setFlyskyState(STATE_SET_TX_POWER);
intmodulePulsesData.flysky.timeout = 0;
intmodulePulsesData.flysky.esc_state = 0;
uint16_t rx_freq = gRomData.rx_freq[0];
rx_freq += (gRomData.rx_freq[1] * 256);
if (50 > rx_freq || 400 < rx_freq) {
gRomData.rx_freq[0] = 50;
}
}
void setupPulsesAFHDS2()
{
putFlySkyFrameHeader();
if (intmodulePulsesData.flysky.state == STATE_DISCONNECT) {
TRACE("STATE_DISCONNECT");
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RECEIVER_ID);
putFlySkyFrameBytes(emptyRxID, 4);
} else if (intmodulePulsesData.flysky.state < STATE_SEND_CHANNELS) {
if (++intmodulePulsesData.flysky.timeout >=
FLYSKY_MODULE_TIMEOUT / FLYSKY_PERIOD) {
intmodulePulsesData.flysky.timeout = 0;
switch (intmodulePulsesData.flysky.state) {
case STATE_INIT: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_RF_INIT);
} break;
case STATE_BIND: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_BIND);
putFlySkyFrameByte(rf_info.bind_power);
uint32_t txID =
0; // internal module firmware does not allow changing TX id
putFlySkyFrameBytes((uint8_t*)(&txID), 4);
} break;
case STATE_SET_RECEIVER_ID: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RECEIVER_ID);
putFlySkyFrameBytes(gRomData.rx_id, 4);
} break;
case STATE_GET_RECEIVER_CONFIG: {
putFlySkyFrameCmd(FRAME_TYPE_ANSWER, CMD_RF_GET_CONFIG);
putFlySkyFrameByte(AfhdsPwmMode); // 00:PWM, 01:PPM
putFlySkyFrameByte(AfhdsIbusMode); // 00:I-BUS, 01:S-BUS
putFlySkyFrameByte(
gRomData.rx_freq[0] < 50
? 50
: gRomData.rx_freq[0]); // receiver servo freq bit[7:0]
putFlySkyFrameByte(
gRomData.rx_freq[1]); // receiver servo freq bit[15:8]
setFlyskyState(STATE_INIT);
} break;
case STATE_SET_TX_POWER: {
uint8_t power =
moduleState[INTERNAL_MODULE].mode == MODULE_MODE_RANGECHECK ? 0
: gRomData.rfPower ? 170
: 90;
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_TX_POWER);
putFlySkyFrameByte(power);
} break;
case STATE_SET_RANGE_TEST: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_TEST_RANGE);
putFlySkyFrameByte(moduleState[INTERNAL_MODULE].mode ==
MODULE_MODE_RANGECHECK);
} break;
case STATE_RANGE_TEST_RUNNING: {
if (moduleState[INTERNAL_MODULE].mode != MODULE_MODE_RANGECHECK) {
// this will send stop command
setFlyskyState(STATE_SET_RANGE_TEST);
}
} break;
case STATE_SET_RX_PWM_PPM: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RX_PWM_PPM);
putFlySkyFrameByte(AfhdsPwmMode); // 00:PWM, 01:PPM
} break;
case STATE_SET_RX_IBUS_SBUS: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RX_IBUS_SBUS);
putFlySkyFrameByte(AfhdsIbusMode); // 0x00:I-BUS, 0x01:S-BUS
} break;
case STATE_SET_RX_FREQUENCY: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RX_SERVO_FREQ);
putFlySkyFrameBytes(gRomData.rx_freq, 2);
} break;
case STATE_UPDATE_RF_PROTOCOL: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RF_PROTOCOL);
putFlySkyFrameByte(
rf_info.protocol); // 0x00:AFHDS1 0x01:AFHDS2 0x02:AFHDS2A
} break;
case STATE_UPDATE_RX_FIRMWARE: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_UPDATE_RX_FIRMWARE);
} break;
case STATE_UPDATE_RF_FIRMWARE: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_UPDATE_RF_FIRMWARE);
} break;
case STATE_GET_RX_VERSION_INFO: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_GET_VERSION_INFO);
putFlySkyFrameByte(FLYSKY_RX_FIRMWARE);
} break;
case STATE_GET_FW_VERSION_INIT:
case STATE_GET_RF_VERSION_INFO: {
putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_GET_VERSION_INFO);
putFlySkyFrameByte(FLYSKY_RF_FIRMWARE);
} break;
case STATE_IDLE:
initFlySkyArray();
break;
default:
setFlyskyState(STATE_INIT);
initFlySkyArray();
if ((DEBUG_RF_FRAME_PRINT & TX_FRAME_ONLY)) {
TRACE("State back to INIT\r\n");
}
return;
}
} else {
initFlySkyArray();
return;
}
} else {
if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_BIND)
moduleState[INTERNAL_MODULE].mode = MODULE_MODE_NORMAL;
putFlySkySendChannelData();
}
putFlySkyFrameFooter();
if (intmodulePulsesData.flysky.state < STATE_SEND_CHANNELS) {
// uint8_t size = intmodulePulsesData.flysky.ptr -
// intmodulePulsesData.flysky.pulses;
// debugFrame(intmodulePulsesData.flysky.pulses, size);
}
if ((DEBUG_RF_FRAME_PRINT & TX_FRAME_ONLY)) {
/* print each command, except channel data by interval */
uint8_t* data = intmodulePulsesData.flysky.pulses;
if (data[3] != CMD_SEND_CHANNEL_DATA || (set_loop_cnt++ % 100 == 0)) {
uint8_t size = intmodulePulsesData.flysky.ptr - data;
TRACE_NOCRLF("TX(State%0d)%0dB:", intmodulePulsesData.flysky.state, size);
for (int idx = 0; idx < size; idx++) {
TRACE_NOCRLF(" %02X", data[idx]);
}
TRACE_NOCRLF(";" CRLF);
}
}
}
// void usbDownloadTransmit(uint8_t *buffer, uint32_t size)
// {
// if (USB_SERIAL_MODE != getSelectedUsbMode()) return;
// buffer[0] = HALL_PROTOLO_HEAD;
// for (uint32_t idx = 0; idx < size; idx++)
// {
// #if !defined(SIMU)
// usbSerialPutc(buffer[idx]);
// #endif
// }
// }
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (C) OpenTX
*
* Dedicate for FlySky NV14 board.
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#define INTMODULE_USART_AFHDS2_BAUDRATE 921600
void setupPulsesAFHDS2();
void resetPulsesAFHDS2();
void processInternalFlySkyTelemetryData(uint8_t byte);
+1 -2
View File
@@ -37,8 +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_AFHDS2A,
MODULE_TYPE_FLYSKY, //no more protocols possible because of 4 bits value
MODULE_TYPE_COUNT,
MODULE_TYPE_MAX = MODULE_TYPE_COUNT - 1
};
+90 -23
View File
@@ -24,7 +24,6 @@
#include "libopenui/src/bitfield.h"
#include "definitions.h"
#include "opentx_helpers.h"
#include "telemetry/telemetry.h"
#include "storage/storage.h"
#include "globals.h"
@@ -35,6 +34,67 @@
#define CROSSFIRE_CHANNELS_COUNT 16
#define GHOST_CHANNELS_COUNT 16
#if defined (MULTIMODULE)
#define IS_D16_MULTI(module) \
(((g_model.moduleData[module].getMultiProtocol() == \
MODULE_SUBTYPE_MULTI_FRSKY) && \
(g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16 || \
g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_8CH || \
g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT || \
g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH || \
g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_CLONED)) || \
(g_model.moduleData[module].getMultiProtocol() == \
MODULE_SUBTYPE_MULTI_FRSKYX2))
#define IS_R9_MULTI(module) \
(g_model.moduleData[module].getMultiProtocol() == \
MODULE_SUBTYPE_MULTI_FRSKY_R9)
#define IS_HOTT_MULTI(module) \
(g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT)
#define IS_CONFIG_MULTI(module) \
(g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_CONFIG)
#define IS_DSM_MULTI(module) \
(g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2)
#define IS_RX_MULTI(module) \
((g_model.moduleData[module].getMultiProtocol() == \
MODULE_SUBTYPE_MULTI_AFHDS2A_RX) || \
(g_model.moduleData[module].getMultiProtocol() == \
MODULE_SUBTYPE_MULTI_FRSKYX_RX) || \
(g_model.moduleData[module].getMultiProtocol() == \
MODULE_SUBTYPE_MULTI_BAYANG_RX) || \
(g_model.moduleData[module].getMultiProtocol() == \
MODULE_SUBTYPE_MULTI_DSM_RX))
#if defined(HARDWARE_INTERNAL_MODULE)
#define IS_FRSKY_SPORT_PROTOCOL() \
(telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || \
(telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && \
(IS_D16_MULTI(INTERNAL_MODULE) || IS_D16_MULTI(EXTERNAL_MODULE) || \
IS_R9_MULTI(INTERNAL_MODULE) || IS_R9_MULTI(EXTERNAL_MODULE))))
#else
#define IS_FRSKY_SPORT_PROTOCOL() \
(telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || \
(telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && \
(IS_D16_MULTI(EXTERNAL_MODULE) || IS_R9_MULTI(EXTERNAL_MODULE))))
#endif
#else
#define IS_D16_MULTI(module) false
#define IS_R9_MULTI(module) false
#define IS_HOTT_MULTI(module) false
#define IS_CONFIG_MULTI(module) false
#define IS_DSM_MULTI(module) false
#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT)
#define IS_RX_MULTI(module) false
#endif
#define IS_SPEKTRUM_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_SPEKTRUM)
#if defined(MULTIMODULE)
// When using packed, the pointer in here end up not being aligned, which clang and gcc complain about
// Keep the order of the fields that the so that the size stays small
@@ -101,6 +161,11 @@ inline bool isModuleTypeXJT(uint8_t type)
return type == MODULE_TYPE_XJT_PXX1 || type == MODULE_TYPE_XJT_LITE_PXX2;
}
inline bool isModuleNone(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_NONE;
}
inline bool isModuleXJT(uint8_t idx)
{
return isModuleTypeXJT(g_model.moduleData[idx].type);
@@ -322,7 +387,7 @@ inline bool isModuleSBUS(uint8_t moduleIdx)
inline bool isModuleFlySky(uint8_t idx)
{
return
(g_model.moduleData[idx].type == MODULE_TYPE_AFHDS3);
(g_model.moduleData[idx].type == MODULE_TYPE_FLYSKY);
}
inline bool isModuleAFHDS2A(uint8_t idx)
@@ -524,8 +589,8 @@ inline bool isModuleFailsafeAvailable(uint8_t moduleIdx)
}
#endif
#if defined(AFHDS3)
if (isModuleAFHDS3(moduleIdx))
#if defined(AFHDS3) || defined(AFHDS2)
if (isModuleFlySky(moduleIdx))
return true;
#endif
@@ -537,12 +602,16 @@ inline bool isModuleFailsafeAvailable(uint8_t moduleIdx)
inline bool isModuleBindRangeAvailable(uint8_t moduleIdx)
{
return isModulePXX2(moduleIdx) || isModulePXX1(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx) || isModuleAFHDS3(moduleIdx);
return isModulePXX2(moduleIdx) || isModulePXX1(moduleIdx) ||
isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx) ||
isModuleFlySky(moduleIdx);
}
inline bool isModuleRangeAvailable(uint8_t moduleIdx)
{
return isModuleBindRangeAvailable(moduleIdx) && !IS_RX_MULTI(moduleIdx);
return isModuleBindRangeAvailable(moduleIdx)
&& !IS_RX_MULTI(moduleIdx)
&& !isModuleFlySky(moduleIdx);
}
constexpr uint8_t MAX_RXNUM = 63;
@@ -595,6 +664,18 @@ inline bool isBindCh9To16Allowed(uint8_t moduleIndex)
}
}
#if defined(PCBTARANIS) || defined(PCBHORUS)
inline bool isSportLineUsedByInternalModule()
{
return g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_XJT_PXX1;
}
#else
inline bool isSportLineUsedByInternalModule()
{
return false;
}
#endif
inline bool isTelemAllowedOnBind(uint8_t moduleIndex)
{
#if defined(HARDWARE_INTERNAL_MODULE)
@@ -700,8 +781,10 @@ 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)
else if (moduleData.type == MODULE_TYPE_FLYSKY) {
// TODO: what if AFHDS2A
resetAfhds3Options(moduleIdx);
}
else
resetAccessAuthenticationCount();
}
@@ -760,20 +843,4 @@ inline void getMultiOptionValues(int8_t multi_proto, int8_t & min, int8_t & max)
}
#endif
inline const char * getRssiLabel()
{
#if defined(MULTIMODULE)
if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A
|| g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT)) {
return "RQly";
}
#endif
#if defined(GHOST)
if (telemetryProtocol == PROTOCOL_TELEMETRY_GHOST) {
return "RQly";
}
#endif
return "RSSI";
}
#endif // _MODULES_HELPERS_H_
+23 -6
View File
@@ -19,10 +19,12 @@
*/
#include "opentx.h"
#include "io/frsky_pxx2.h"
#include "pulses/pxx2.h"
#include "mixer_scheduler.h"
#include "io/frsky_pxx2.h"
#include "io/multi_protolist.h"
#include "pulses/pxx2.h"
#include "pulses/flysky.h"
uint8_t s_pulses_paused = 0;
ModuleState moduleState[NUM_MODULES];
@@ -189,7 +191,7 @@ uint8_t getRequiredProtocol(uint8_t module)
#endif
#if defined(AFHDS3) || defined(AFHDS2)
case MODULE_TYPE_AFHDS3:
case MODULE_TYPE_FLYSKY:
if (isModuleAFHDS3(module)) {
protocol = PROTOCOL_CHANNELS_AFHDS3;
} else if (isModuleAFHDS2A(module)) {
@@ -489,9 +491,11 @@ static void enablePulsesInternalModule(uint8_t protocol)
#if defined(AFHDS2)
case PROTOCOL_CHANNELS_AFHDS2A:
/* extmodulePulsesData.afhds2.init(INTERNAL_MODULE);
extmoduleSerialStart();*/
mixerSchedulerSetPeriod(INTERNAL_MODULE, 2 * 1000 /* us */);
resetPulsesAFHDS2();
intmoduleSerialStart(INTMODULE_USART_AFHDS2_BAUDRATE, true,
USART_Parity_No, USART_StopBits_1,
USART_WordLength_8b);
mixerSchedulerSetPeriod(INTERNAL_MODULE, AFHDS2_PERIOD);
break;
#endif
@@ -544,6 +548,19 @@ bool setupPulsesInternalModule(uint8_t protocol)
return true;
#endif
#if defined(AFHDS2)
case PROTOCOL_CHANNELS_AFHDS2A:
{
ModuleSyncStatus& status = getModuleSyncStatus(INTERNAL_MODULE);
mixerSchedulerSetPeriod(
INTERNAL_MODULE,
status.isValid() ? status.getAdjustedRefreshRate() : AFHDS2_PERIOD);
status.invalidate();
setupPulsesAFHDS2();
return true;
}
#endif
default:
return false;
}
+5
View File
@@ -28,6 +28,7 @@
#include "pxx2.h"
#include "multi.h"
#include "afhds3.h"
#include "afhds2.h"
#include "modules_helpers.h"
#include "ff.h"
@@ -266,6 +267,10 @@ union InternalModulePulsesData {
Pxx2Pulses pxx2;
#endif
#if defined(INTMODULE_USART) && defined(AFHDS2)
FlySkySerialPulsesData flysky;
#endif
#if defined(MULTIMODULE) //&& defined(INTMODULE_USART)
UartMultiPulses multi;
#endif
@@ -159,9 +159,11 @@ endif()
if(MULTIMODULE OR AFHDS3)
set(SRC ${SRC} telemetry/flysky_ibus.cpp)
endif()
if(AFHDS2)
add_definitions(-DAFHDS2)
set(SRC ${SRC} telemetry/flysky_nv14.cpp)
set(PULSES_SRC ${PULSES_SRC} flysky.cpp)
endif()
if(AFHDS3)
@@ -187,5 +187,13 @@ void intmoduleSendNextFrame()
intmoduleSendBuffer(intmodulePulsesData.multi.getData(), intmodulePulsesData.multi.getSize());
break;
#endif
#if defined(AFHDS2)
case PROTOCOL_CHANNELS_AFHDS2A: {
uint8_t* data = (uint8_t*)intmodulePulsesData.flysky.pulses;
uint16_t size = intmodulePulsesData.flysky.ptr - data;
intmoduleSendBuffer(data, size);
} break;
#endif
}
}
+3 -1
View File
@@ -97,7 +97,9 @@ if(NOT UNEXPECTED_SHUTDOWN)
endif()
set(AFHDS2 ON)
set(AFHDS3 ON)
# disable for now as it crashes on radio
#set(AFHDS3 ON)
include_directories(${RADIO_SRC_DIR}/fonts/colorlcd gui/${GUI_DIR} gui/${GUI_DIR}/layouts)
-1
View File
@@ -413,7 +413,6 @@
#define INTMODULE_USART_IRQHandler UART7_IRQHandler
#define INTMODULE_DMA_STREAM DMA1_Stream1
#define INTMODULE_DMA_STREAM_IRQ DMA1_Stream1_IRQn
#define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream7_IRQHandler
#define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF1
#define INTMODULE_DMA_CHANNEL DMA_Channel_5
+1
View File
@@ -72,6 +72,7 @@ bool isModuleSynchronous(uint8_t moduleIdx)
case PROTOCOL_CHANNELS_CROSSFIRE:
case PROTOCOL_CHANNELS_GHOST:
case PROTOCOL_CHANNELS_AFHDS3:
case PROTOCOL_CHANNELS_AFHDS2A:
case PROTOCOL_CHANNELS_NONE:
#if defined(MULTIMODULE)
+132 -75
View File
@@ -21,6 +21,46 @@
#include "opentx.h"
#include "flysky_nv14.h"
enum FlySkySensorType_E {
FLYSKY_SENSOR_RX_VOLTAGE=0,
FLYSKY_SENSOR_RX_SIGNAL,
FLYSKY_SENSOR_RX_RSSI,
FLYSKY_SENSOR_RX_NOISE,
FLYSKY_SENSOR_RX_SNR,
FLYSKY_SENSOR_TEMP,
FLYSKY_SENSOR_EXT_VOLTAGE,
FLYSKY_SENSOR_MOTO_RPM,
FLYSKY_SENSOR_PRESSURE,
FLYSKY_SENSOR_GPS
};
typedef struct FLYSKY_GPS_INFO_S {
uint8_t position_fix;
uint8_t satell_cnt;
uint8_t latitude[4];
uint8_t longtitude[4];
uint8_t altitude[4];
uint8_t g_speed[2];
uint8_t direction[2];
} gps_info_t;
typedef struct FLYSKY_SENSOR_DATA_S {
uint8_t sensor_type;
uint8_t sensor_id;
uint8_t voltage[2];
uint8_t signal;
uint8_t rssi[2];
uint8_t noise[2];
uint8_t snr[2];
uint8_t temp[2];
uint8_t ext_voltage[2];
uint8_t moto_rpm[2];
uint8_t pressure_value[2];
gps_info_t gps_info;
} rx_sensor_t;
#define FLYSKY_FIXED_RX_VOLTAGE (uint8_t)(FLYSKY_SENSOR_RX_VOLTAGE + (uint8_t)0xA0)
#define MIN_SNR 8
@@ -43,7 +83,6 @@ struct FlyskyNv14Sensor {
const bool issigned;
};
union nv14SensorData {
uint8_t UINT8;
uint16_t UINT16;
@@ -51,8 +90,6 @@ union nv14SensorData {
uint32_t UINT32;
};
const FlyskyNv14Sensor Nv14Sensor[]=
{
{FLYSKY_FIXED_RX_VOLTAGE, 0, STR_SENSOR_A3, UNIT_VOLTS, 2, 0, 2, false},
@@ -64,8 +101,8 @@ const FlyskyNv14Sensor Nv14Sensor[]=
{FLYSKY_SENSOR_TEMP, 0, STR_SENSOR_TEMP1, UNIT_CELSIUS, 1, 0, 2, true},
{FLYSKY_SENSOR_EXT_VOLTAGE,0, STR_SENSOR_A3, UNIT_VOLTS, 2, 0, 2, false},
{FLYSKY_SENSOR_MOTO_RPM, 0, STR_SENSOR_RPM, UNIT_RPMS, 0, 0, 2, false},
{FLYSKY_SENSOR_PRESURRE, 0, STR_SENSOR_PRES, UNIT_RAW, 1, 0, 2, false},
{FLYSKY_SENSOR_PRESURRE, 1, STR_SENSOR_ALT, UNIT_METERS, 0, 0, 2, true},
{FLYSKY_SENSOR_PRESSURE, 0, STR_SENSOR_PRES, UNIT_RAW, 1, 0, 2, false},
{FLYSKY_SENSOR_PRESSURE, 1, STR_SENSOR_ALT, UNIT_METERS, 0, 0, 2, true},
{FLYSKY_SENSOR_GPS, 1, STR_SENSOR_SATELLITES, UNIT_RAW, 0, 0, 1, false},
{FLYSKY_SENSOR_GPS, 2, STR_SENSOR_GPS, UNIT_GPS_LATITUDE, 0, 1, 4, true},
{FLYSKY_SENSOR_GPS, 3, STR_SENSOR_GPS, UNIT_GPS_LONGITUDE, 0, 5, 4, true},
@@ -77,25 +114,32 @@ const FlyskyNv14Sensor Nv14Sensor[]=
FlyskyNv14Sensor defaultNv14Sensor = {0, 0, "UNKNOWN", UNIT_RAW, 0, 0, 2, false};
const signed short tAltitude[225]=
{
20558, 20357, 20158, 19962, 19768, 19576, 19387, 19200, 19015, 18831, 18650, 18471, 18294, 18119, 17946, 17774,
17604, 17436, 17269, 17105, 16941, 16780, 16619, 16461, 16304, 16148, 15993, 15841, 15689, 15539, 15390, 15242,
15096, 14950, 14806, 14664, 14522, 14381, 14242, 14104, 13966, 13830, 13695, 13561, 13428, 13296, 13165, 13035,
12906, 12777, 12650, 12524, 12398, 12273, 12150, 12027, 11904, 11783, 11663, 11543, 11424, 11306, 11189, 11072,
10956, 10841, 10726, 10613, 10500, 10387, 10276, 10165, 10054, 9945, 9836, 9727, 9620, 9512, 9406, 9300,
9195, 9090, 8986, 8882, 8779, 8677, 8575, 8474, 8373, 8273, 8173, 8074, 7975, 7877, 7779, 7682,
7585, 7489, 7394, 7298, 7204, 7109, 7015, 6922, 6829, 6737, 6645, 6553, 6462, 6371, 6281, 6191,
6102, 6012, 5924, 5836, 5748, 5660, 5573, 5487, 5400, 5314, 5229, 5144, 5059, 4974, 4890, 4807,
4723, 4640, 4557, 4475, 4393, 4312, 4230, 4149, 4069, 3988, 3908, 3829, 3749, 3670, 3591, 3513,
3435, 3357, 3280, 3202, 3125, 3049, 2972, 2896, 2821, 2745, 2670, 2595, 2520, 2446, 2372, 2298,
2224, 2151, 2078, 2005, 1933, 1861, 1789, 1717, 1645, 1574, 1503, 1432, 1362, 1292, 1222, 1152,
1082, 1013, 944, 875, 806, 738, 670, 602, 534, 467, 399, 332, 265, 199, 132, 66,
0, -66, -131, -197, -262, -327, -392, -456, -521, -585, -649, -713, -776, -840, -903, -966,
-1029,-1091, -1154, -1216, -1278, -1340, -1402, -1463, -1525, -1586, -1647, -1708, -1769, -1829, -1889, -1950,
-2010
const signed short tAltitude[225] = {
20558, 20357, 20158, 19962, 19768, 19576, 19387, 19200, 19015, 18831, 18650,
18471, 18294, 18119, 17946, 17774, 17604, 17436, 17269, 17105, 16941, 16780,
16619, 16461, 16304, 16148, 15993, 15841, 15689, 15539, 15390, 15242, 15096,
14950, 14806, 14664, 14522, 14381, 14242, 14104, 13966, 13830, 13695, 13561,
13428, 13296, 13165, 13035, 12906, 12777, 12650, 12524, 12398, 12273, 12150,
12027, 11904, 11783, 11663, 11543, 11424, 11306, 11189, 11072, 10956, 10841,
10726, 10613, 10500, 10387, 10276, 10165, 10054, 9945, 9836, 9727, 9620,
9512, 9406, 9300, 9195, 9090, 8986, 8882, 8779, 8677, 8575, 8474,
8373, 8273, 8173, 8074, 7975, 7877, 7779, 7682, 7585, 7489, 7394,
7298, 7204, 7109, 7015, 6922, 6829, 6737, 6645, 6553, 6462, 6371,
6281, 6191, 6102, 6012, 5924, 5836, 5748, 5660, 5573, 5487, 5400,
5314, 5229, 5144, 5059, 4974, 4890, 4807, 4723, 4640, 4557, 4475,
4393, 4312, 4230, 4149, 4069, 3988, 3908, 3829, 3749, 3670, 3591,
3513, 3435, 3357, 3280, 3202, 3125, 3049, 2972, 2896, 2821, 2745,
2670, 2595, 2520, 2446, 2372, 2298, 2224, 2151, 2078, 2005, 1933,
1861, 1789, 1717, 1645, 1574, 1503, 1432, 1362, 1292, 1222, 1152,
1082, 1013, 944, 875, 806, 738, 670, 602, 534, 467, 399,
332, 265, 199, 132, 66, 0, -66, -131, -197, -262, -327,
-392, -456, -521, -585, -649, -713, -776, -840, -903, -966, -1029,
-1091, -1154, -1216, -1278, -1340, -1402, -1463, -1525, -1586, -1647, -1708,
-1769, -1829, -1889, -1950, -2010
};
signed short CalculateAltitude( unsigned int Pressure, unsigned int SeaLevelPressure )
signed short CalculateAltitude(unsigned int Pressure,
unsigned int SeaLevelPressure)
{
unsigned int Index;
signed int Altitude1;
@@ -103,91 +147,104 @@ signed short CalculateAltitude( unsigned int Pressure, unsigned int SeaLevelPres
unsigned int Decimal;
unsigned long Ratio;
Ratio = ( ( ( unsigned long long ) Pressure << 16 ) + ( SeaLevelPressure / 2 ) ) / SeaLevelPressure;
if( Ratio < ( ( 1 << 16 ) * 250 / 1000 ) )// 0.250 inclusive
{
Ratio = ( 1 << 16 ) * 250 / 1000;
}
else if( Ratio > ( 1 << 16 ) * 1125 / 1000 - 1 ) // 1.125 non-inclusive
{
Ratio = ( 1 << 16 ) * 1125 / 1000 - 1;
Ratio = (((unsigned long long)Pressure << 16) + (SeaLevelPressure / 2)) /
SeaLevelPressure;
if (Ratio < ((1 << 16) * 250 / 1000)) { // 0.250 inclusive
Ratio = (1 << 16) * 250 / 1000;
} else if (Ratio > (1 << 16) * 1125 / 1000 - 1) { // 1.125 non-inclusive
Ratio = (1 << 16) * 1125 / 1000 - 1;
}
Ratio -= ( 1 << 16 ) * 250 / 1000; // from 0.000 (inclusive) to 0.875 (non-inclusive)
// from 0.000 (inclusive) to 0.875 (non-inclusive)
Ratio -= (1 << 16) * 250 / 1000;
Index = Ratio >> 8;
Decimal = Ratio & ( ( 1 << 8 ) - 1 );
Decimal = Ratio & ((1 << 8) - 1);
Altitude1 = tAltitude[Index];
Altitude2 = Altitude1 - tAltitude[Index + 1];
Altitude1 = Altitude1 - ( Altitude2 * Decimal + ( 1 << 7 ) ) / ( 1 << 8 );
if( Altitude1 >= 0 )
{
return( ( Altitude1 + 1 ) / 2 );
}
else
{
return( ( Altitude1 - 1 ) / 2 );
Altitude1 = Altitude1 - (Altitude2 * Decimal + (1 << 7)) / (1 << 8);
if (Altitude1 >= 0) {
return ((Altitude1 + 1) / 2);
} else {
return ((Altitude1 - 1) / 2);
}
}
const FlyskyNv14Sensor* getFlyskyNv14Sensor(uint16_t id, uint8_t subId)
{
for(unsigned index = 0; index < *(&Nv14Sensor + 1) - Nv14Sensor; index++ ){
for (unsigned index = 0; index < *(&Nv14Sensor + 1) - Nv14Sensor; index++) {
if (Nv14Sensor[index].id == id && Nv14Sensor[index].subId == subId) {
return &Nv14Sensor[index];
}
}
return &defaultNv14Sensor;
return &defaultNv14Sensor;
}
void flySkyNv14SetDefault(int index, uint8_t id, uint8_t subId, uint8_t instance)
void flySkyNv14SetDefault(int index, uint8_t id, uint8_t subId,
uint8_t instance)
{
TelemetrySensor & telemetrySensor = g_model.telemetrySensors[index];
telemetrySensor.id = id;
telemetrySensor.subId = subId;
telemetrySensor.instance = instance;
const FlyskyNv14Sensor* sensor = getFlyskyNv14Sensor(id, subId);
telemetrySensor.init(sensor->name, sensor->unit, sensor->precision);
storageDirty(EE_MODEL);
TelemetrySensor& telemetrySensor = g_model.telemetrySensors[index];
telemetrySensor.id = id;
telemetrySensor.subId = subId;
telemetrySensor.instance = instance;
const FlyskyNv14Sensor* sensor = getFlyskyNv14Sensor(id, subId);
telemetrySensor.init(sensor->name, sensor->unit, sensor->precision);
storageDirty(EE_MODEL);
}
int32_t GetSensorValueFlySkyNv14(const FlyskyNv14Sensor* sensor, const uint8_t * data){
int32_t GetSensorValueFlySkyNv14(const FlyskyNv14Sensor* sensor,
const uint8_t* data)
{
int32_t value = 0;
const nv14SensorData* sensorData = reinterpret_cast<const nv14SensorData*>(data + sensor->offset);
if(sensor->bytes == 1) value = sensorData->UINT8;
else if(sensor->bytes == 2) value = sensor->issigned ? sensorData->INT16 : sensorData->UINT16;
else if(sensor->bytes == 4) value = sensorData->UINT32;
const nv14SensorData* sensorData =
reinterpret_cast<const nv14SensorData*>(data + sensor->offset);
if (sensor->bytes == 1)
value = sensorData->UINT8;
else if (sensor->bytes == 2)
value = sensor->issigned ? sensorData->INT16 : sensorData->UINT16;
else if (sensor->bytes == 4)
value = sensorData->UINT32;
if(sensor->id == FLYSKY_SENSOR_RX_RSSI) {
if(value < -200) value = -200;
#if defined (PCBNV14)
if(!g_model.rssiAlarms.flysky_telemetry)
if (sensor->id == FLYSKY_SENSOR_RX_RSSI) {
if (value < -200) value = -200;
#if defined(PCBNV14)
if (!g_model.rssiAlarms.flysky_telemetry)
#endif
{
value += 200;
value /= 2;
value += 200;
value /= 2;
}
TRACE("RSSI: %d", value);
telemetryData.rssi.set(value);
}
if(sensor->id == FLYSKY_SENSOR_PRESURRE && sensor->subId != 0){
if (sensor->id == FLYSKY_SENSOR_PRESSURE && sensor->subId != 0) {
value = CalculateAltitude(value, 101325);
value = (value+500)/1000;
value = (value + 500) / 1000;
}
return value;
}
void flySkyNv14ProcessTelemetryPacket(const uint8_t * ptr, uint8_t sensorID )
void flySkyNv14ProcessTelemetryPacket(uint8_t* ptr, uint8_t len)
{
uint8_t instnace = *ptr++;
if(sensorID == FLYSKY_SENSOR_RX_VOLTAGE) sensorID = FLYSKY_FIXED_RX_VOLTAGE;
uint8_t sensorType = *ptr++;
uint8_t sensorID = *ptr++;
TRACE("ID[%02X] Type[%02X] len=%d", ptr[1], ptr[0], len);
// remove unknown sensor (strange values)
if (sensorType == 0xEE) return;
if (sensorType == FLYSKY_SENSOR_RX_VOLTAGE)
sensorType = FLYSKY_FIXED_RX_VOLTAGE;
for (const FlyskyNv14Sensor sensor : Nv14Sensor) {
if (sensor.id == sensorID) {
int32_t value = GetSensorValueFlySkyNv14(&sensor, ptr);
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_NV14, sensor.id, sensor.subId, instnace, value, sensor.unit, sensor.precision);
}
if (sensor.id == sensorType) {
int32_t value = GetSensorValueFlySkyNv14(&sensor, ptr);
TRACE("[%02X] id=%02X(%s) subId=%02X value=%d",
sensorID, sensor.id, sensor.name, sensor.subId, value);
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_NV14, sensor.id, sensor.subId,
sensorID, value, sensor.unit, sensor.precision);
}
}
telemetryStreaming = TELEMETRY_TIMEOUT10ms;
telemetryStreaming = TELEMETRY_TIMEOUT10ms;
}
+1 -37
View File
@@ -21,43 +21,7 @@
#ifndef __FLYSKY_NV14_H__
#define __FLYSKY_NV14_H__
enum FlySkySensorType_E {
FLYSKY_SENSOR_RX_VOLTAGE,
FLYSKY_SENSOR_RX_SIGNAL,
FLYSKY_SENSOR_RX_RSSI,
FLYSKY_SENSOR_RX_NOISE,
FLYSKY_SENSOR_RX_SNR,
FLYSKY_SENSOR_TEMP,
FLYSKY_SENSOR_EXT_VOLTAGE,
FLYSKY_SENSOR_MOTO_RPM,
FLYSKY_SENSOR_PRESURRE,
FLYSKY_SENSOR_GPS
};
typedef struct FLYSKY_GPS_INFO_S {
uint8_t position_fix;
uint8_t satell_cnt;
uint8_t latitude[4];
uint8_t longtitude[4];
uint8_t altitude[4];
uint8_t g_speed[2];
uint8_t direction[2];
} gps_info_t;
typedef struct FLYSKY_SENSOR_DATA_S {
uint8_t sensor_type;
uint8_t sensor_id;
uint8_t voltage[2];
uint8_t signal;
uint8_t rssi[2];
uint8_t noise[2];
uint8_t snr[2];
uint8_t temp[2];
uint8_t ext_voltage[2];
uint8_t moto_rpm[2];
uint8_t pressure_value[2];
gps_info_t gps_info;
} rx_sensor_t;
void flySkyNv14SetDefault(int index, uint8_t id, uint8_t subId, uint8_t instance);
void flySkyNv14ProcessTelemetryPacket(const uint8_t * ptr, uint8_t SensorType );
void flySkyNv14ProcessTelemetryPacket(uint8_t * ptr, uint8_t len );
#endif
+18
View File
@@ -21,6 +21,7 @@
#include "opentx.h"
#include "multi.h"
#include "pulses/afhds3.h"
#include "pulses/flysky.h"
#include "mixer_scheduler.h"
#include "io/multi_protolist.h"
@@ -145,6 +146,18 @@ void telemetryWakeup()
#endif
#endif
#if defined(PCBNV14)
if (//!moduleUpdateActive(INTERNAL_MODULE) &&
moduleState[INTERNAL_MODULE].protocol == PROTOCOL_CHANNELS_AFHDS2A &&
intmoduleFifo.pop(data)) {
LOG_TELEMETRY_WRITE_START();
do {
processInternalFlySkyTelemetryData(data);
LOG_TELEMETRY_WRITE_BYTE(data);
} while (intmoduleFifo.pop(data));
}
#endif
#if defined(STM32)
if (telemetryGetByte(&data)) {
LOG_TELEMETRY_WRITE_START();
@@ -432,6 +445,11 @@ void ModuleSyncStatus::update(uint16_t newRefreshRate, int16_t newInputLag)
TRACE("[SYNC] update rate = %dus; lag = %dus",refreshRate,currentLag);
}
void ModuleSyncStatus::invalidate() {
//make invalid after use
currentLag = 0;
}
uint16_t ModuleSyncStatus::getAdjustedRefreshRate()
{
int16_t lag = currentLag;
+29 -41
View File
@@ -41,6 +41,8 @@
#include "flysky_ibus.h"
#endif
#include "pulses/modules_helpers.h"
extern uint8_t telemetryStreaming; // >0 (true) == data is streaming in. 0 = no data detected for some time
inline bool TELEMETRY_STREAMING()
@@ -115,79 +117,62 @@ void frskyDSetDefault(int index, uint16_t id);
extern uint8_t telemetryProtocol;
#if defined (MULTIMODULE)
#define IS_D16_MULTI(module) (((g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) && (g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16 || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_8CH || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_CLONED)) \
|| (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKYX2))
#define IS_R9_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY_R9)
#define IS_HOTT_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT)
#define IS_CONFIG_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_CONFIG)
#define IS_DSM_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2)
#define IS_RX_MULTI(module) ((g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_AFHDS2A_RX) || (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKYX_RX) \
|| (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_BAYANG_RX) || (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM_RX))
#if defined(HARDWARE_INTERNAL_MODULE)
#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (IS_D16_MULTI(INTERNAL_MODULE) || IS_D16_MULTI(EXTERNAL_MODULE) || IS_R9_MULTI(INTERNAL_MODULE) || IS_R9_MULTI(EXTERNAL_MODULE))))
#else
#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (IS_D16_MULTI(EXTERNAL_MODULE) || IS_R9_MULTI(EXTERNAL_MODULE))))
#endif
#else
#define IS_D16_MULTI(module) false
#define IS_R9_MULTI(module) false
#define IS_HOTT_MULTI(module) false
#define IS_CONFIG_MULTI(module) false
#define IS_DSM_MULTI(module) false
#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT)
#define IS_RX_MULTI(module) false
#endif
#define IS_SPEKTRUM_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_SPEKTRUM)
#if defined(PCBTARANIS) || defined(PCBHORUS)
inline bool isSportLineUsedByInternalModule()
inline const char* getRssiLabel()
{
return g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_XJT_PXX1;
}
#else
inline bool isSportLineUsedByInternalModule()
{
return false;
}
#if defined(MULTIMODULE)
if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE &&
(g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() ==
MODULE_SUBTYPE_MULTI_FS_AFHDS2A ||
g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol() ==
MODULE_SUBTYPE_MULTI_HOTT)) {
return "RQly";
}
#endif
#if defined(GHOST)
if (telemetryProtocol == PROTOCOL_TELEMETRY_GHOST) {
return "RQly";
}
#endif
return "RSSI";
}
inline uint8_t modelTelemetryProtocol()
{
bool sportUsed = isSportLineUsedByInternalModule();
#if defined(CROSSFIRE)
if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_CROSSFIRE) {
if (isModuleCrossfire(EXTERNAL_MODULE)) {
return PROTOCOL_TELEMETRY_CROSSFIRE;
}
#endif
#if defined(GHOST)
if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_GHOST) {
if (isModuleGhost(EXTERNAL_MODULE)) {
return PROTOCOL_TELEMETRY_GHOST;
}
#endif
if (!sportUsed && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_PPM) {
if (!sportUsed && isModulePPM(EXTERNAL_MODULE)) {
return g_model.telemetryProtocol;
}
#if defined(MULTIMODULE)
if (!sportUsed && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_MULTIMODULE) {
if (!sportUsed && isModuleMultimodule(EXTERNAL_MODULE)) {
return PROTOCOL_TELEMETRY_MULTIMODULE;
}
#if defined(INTERNAL_MODULE_MULTI)
if (g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_NONE) {
if (isModuleMultimodule(INTERNAL_MODULE) && isModuleNone(EXTERNAL_MODULE)) {
return PROTOCOL_TELEMETRY_MULTIMODULE;
}
#endif
#endif
#if defined(AFHDS3)
if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_AFHDS3) {
if (isModuleAFHDS3(EXTERNAL_MODULE)) {
return PROTOCOL_TELEMETRY_AFHDS3;
}
#endif
// default choice
return PROTOCOL_TELEMETRY_FRSKY_SPORT;
}
@@ -312,6 +297,9 @@ struct ModuleSyncStatus
// Set feedback from RF module
void update(uint16_t newRefreshRate, int16_t newInputLag);
//mark as timeouted
void invalidate();
// Get computed settings for scheduler
uint16_t getAdjustedRefreshRate();
@@ -26,6 +26,8 @@
#include "libopenui.h"
#endif
#include "telemetry/flysky_nv14.h"
TelemetryItem telemetryItems[MAX_TELEMETRY_SENSORS];
uint8_t allowNewSensors;
@@ -557,6 +559,12 @@ int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, ui
break;
#endif
#if defined(AFHDS2)
case PROTOCOL_TELEMETRY_FLYSKY_NV14:
flySkyNv14SetDefault(index, id, subId, instance);
break;
#endif
#if defined(MULTIMODULE)
case PROTOCOL_TELEMETRY_SPEKTRUM:
spektrumSetDefault(index, id, subId, instance);
+2
View File
@@ -75,6 +75,8 @@ ISTR(R9M_PXX2_RF_PROTOCOLS);
ISTR(DSM_PROTOCOLS);
ISTR(AFHDS3_PROTOCOLS);
ISTR(AFHDS3_POWERS);
ISTR(FLYSKY_PULSE_PROTO);
ISTR(FLYSKY_SERIAL_PROTO);
ISTR(CURVE_TYPES);
ISTR(VSENSORTYPES);
ISTR(VFORMULAS);
+3
View File
@@ -187,6 +187,9 @@ extern const char STR_AFHDS3_RX_FREQ[];
extern const char STR_AFHDS3_ACTUAL_POWER[];
extern const char STR_AFHDS3_POWER_SOURCE[];
extern const char STR_FLYSKY_PULSE_PROTO[];
extern const char STR_FLYSKY_SERIAL_PROTO[];
extern const char STR_CURVE_TYPES[];
extern const char STR_VSENSORTYPES[];
extern const char STR_VFORMULAS[];
+6
View File
@@ -176,6 +176,12 @@
#define LEN_AFHDS3_POWERS "\006"
#define TR_AFHDS3_POWERS "25 mW\0""100 mW""500 mW""1 W\0 ""2 W\0 "
#define LEN_FLYSKY_PULSE_PROTO "\x003"
#define TR_FLYSKY_PULSE_PROTO "PWM""PPM"
#define LEN_FLYSKY_SERIAL_PROTO "\x004"
#define TR_FLYSKY_SERIAL_PROTO "iBUS""SBUS"
#define LEN_PPM_POL "\001"
#define TR_PPM_POL "-""+"