diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 6ace554bf..8af0b5df2 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -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); diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index 6347755c5..4e11a0b8c 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -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(); diff --git a/radio/src/gui/colorlcd/radio_version.cpp b/radio/src/gui/colorlcd/radio_version.cpp index 06255932d..b4540e815 100644 --- a/radio/src/gui/colorlcd/radio_version.cpp +++ b/radio/src/gui/colorlcd/radio_version.cpp @@ -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); diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 47bb95fc9..7ba89634b 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -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 diff --git a/radio/src/pulses/afhds2.h b/radio/src/pulses/afhds2.h index e6bab681b..ff421ef5a 100644 --- a/radio/src/pulses/afhds2.h +++ b/radio/src/pulses/afhds2.h @@ -27,6 +27,8 @@ #include #include +#define AFHDS2_PERIOD (2 * 1000) /* us */ + struct FlySkySerialPulsesData { uint8_t pulses[64]; uint8_t * ptr; diff --git a/radio/src/pulses/afhds3.cpp b/radio/src/pulses/afhds3.cpp index bafe7817c..9a1c176bc 100644 --- a/radio/src/pulses/afhds3.cpp +++ b/radio/src/pulses/afhds3.cpp @@ -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); diff --git a/radio/src/pulses/flysky.cpp b/radio/src/pulses/flysky.cpp new file mode 100644 index 000000000..d4b7b5c09 --- /dev/null +++ b/radio/src/pulses/flysky.cpp @@ -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(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(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(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(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(&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 +// } +// } diff --git a/radio/src/pulses/flysky.h b/radio/src/pulses/flysky.h new file mode 100644 index 000000000..0c35130cf --- /dev/null +++ b/radio/src/pulses/flysky.h @@ -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); diff --git a/radio/src/pulses/modules_constants.h b/radio/src/pulses/modules_constants.h index 4774c3dae..40a440cb4 100644 --- a/radio/src/pulses/modules_constants.h +++ b/radio/src/pulses/modules_constants.h @@ -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 }; diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index f9d91a5df..24101f103 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -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_ diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index 2a9a6e7f3..ea6f59d8d 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -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; } diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index 76d489737..d89cf724c 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -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 diff --git a/radio/src/targets/common/arm/CMakeLists.txt b/radio/src/targets/common/arm/CMakeLists.txt index df77ab664..3cca9e1ed 100644 --- a/radio/src/targets/common/arm/CMakeLists.txt +++ b/radio/src/targets/common/arm/CMakeLists.txt @@ -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) diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp index e918f174a..5f8eeb3a1 100755 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp @@ -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 } } diff --git a/radio/src/targets/nv14/CMakeLists.txt b/radio/src/targets/nv14/CMakeLists.txt index a3f7fb95a..db80a138c 100644 --- a/radio/src/targets/nv14/CMakeLists.txt +++ b/radio/src/targets/nv14/CMakeLists.txt @@ -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) diff --git a/radio/src/targets/nv14/hal.h b/radio/src/targets/nv14/hal.h index a074d0d2a..3a96c5c2e 100644 --- a/radio/src/targets/nv14/hal.h +++ b/radio/src/targets/nv14/hal.h @@ -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 diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp index e395b6832..735737e22 100644 --- a/radio/src/tasks.cpp +++ b/radio/src/tasks.cpp @@ -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) diff --git a/radio/src/telemetry/flysky_nv14.cpp b/radio/src/telemetry/flysky_nv14.cpp index 059abbbaf..62e392c4a 100644 --- a/radio/src/telemetry/flysky_nv14.cpp +++ b/radio/src/telemetry/flysky_nv14.cpp @@ -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(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(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; } - diff --git a/radio/src/telemetry/flysky_nv14.h b/radio/src/telemetry/flysky_nv14.h index f338e5e3e..35cc91c17 100644 --- a/radio/src/telemetry/flysky_nv14.h +++ b/radio/src/telemetry/flysky_nv14.h @@ -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 diff --git a/radio/src/telemetry/telemetry.cpp b/radio/src/telemetry/telemetry.cpp index 3487f5c14..d01fa8d7e 100644 --- a/radio/src/telemetry/telemetry.cpp +++ b/radio/src/telemetry/telemetry.cpp @@ -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; diff --git a/radio/src/telemetry/telemetry.h b/radio/src/telemetry/telemetry.h index e7063a0e7..aa93d28ae 100644 --- a/radio/src/telemetry/telemetry.h +++ b/radio/src/telemetry/telemetry.h @@ -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(); diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index 842312bf4..285c057f9 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -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); diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 1e81cd8d9..398ac4707 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -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); diff --git a/radio/src/translations.h b/radio/src/translations.h index 00b752045..ffb33e98e 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -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[]; diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index 29fa724ad..f502a45f9 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -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 "-""+"