diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt index 8466fdccf..bc1d9a0af 100644 --- a/radio/src/gui/colorlcd/CMakeLists.txt +++ b/radio/src/gui/colorlcd/CMakeLists.txt @@ -140,6 +140,9 @@ endif() if(AFHDS2 OR AFHDS3) add_gui_src(flysky_settings.cpp) + if(AFHDS3) + add_gui_src(afhds3_options.cpp) + endif() endif() if(MULTIMODULE) diff --git a/radio/src/gui/colorlcd/afhds3_options.cpp b/radio/src/gui/colorlcd/afhds3_options.cpp new file mode 100644 index 000000000..c2199135e --- /dev/null +++ b/radio/src/gui/colorlcd/afhds3_options.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "afhds3_options.h" +#include "opentx.h" + +//#include "checkbox.h" + +static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; + +#define SET_DIRTY() + +static const char* _analog_outputs[] = { "PWM", "PPM" }; +static const char* _bus_types[] = { "iBUS", "iBUS2", "SBUS" }; +static const char* _v1_bus_types[] = { "PWM", "PPM", "SBUS", "iBUS IN", "iBUS OUT" }; + +AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP) +{ + cfg = afhds3::getConfig(moduleIdx); + + std::string title = + moduleIdx == INTERNAL_MODULE ? STR_INTERNALRF : STR_EXTERNALRF; + title += "\nAFHDS3"; + + header.setTitle(title); + + auto form = new FormGroup(&body, rect_t{}); + form->setFlexLayout(); + form->padAll(lv_dpx(8)); + + FlexGridLayout grid(col_dsc, row_dsc, 2); + + if (cfg->version == 0) { + auto vCfg = &cfg->v0; + + auto line = form->newLine(&grid); + new StaticText(line, rect_t{}, "PWM frequency"); + new NumberEdit(line, rect_t{}, 50, 400, GET_SET_DEFAULT(vCfg->PWMFrequency.Frequency)); + + line = form->newLine(&grid); + new StaticText(line, rect_t{}, "PWM sychronized"); + new CheckBox(line, rect_t{}, GET_SET_DEFAULT(vCfg->PWMFrequency.Synchronized)); + + line = form->newLine(&grid); + new StaticText(line, rect_t{}, "Analog output"); + new Choice(line, rect_t{}, _analog_outputs, + afhds3::SES_ANALOG_OUTPUT_PWM, afhds3::SES_ANALOG_OUTPUT_PPM, + GET_SET_DEFAULT(vCfg->AnalogOutput)); + + line = form->newLine(&grid); + new StaticText(line, rect_t{}, "External bus type"); + new Choice(line, rect_t{}, _bus_types, + afhds3::EB_BT_IBUS1, afhds3::EB_BT_SBUS1, + GET_SET_DEFAULT(vCfg->ExternalBusType)); + + } else { + auto vCfg = &cfg->v1; + + auto line = form->newLine(&grid); + new StaticText(line, rect_t{}, "PWM frequency"); + new NumberEdit(line, rect_t{}, 50, 400, + GET_DEFAULT(vCfg->PWMFrequenciesV1.PWMFrequencies[0]), + [=](int16_t newVal) { + for (uint8_t i = 0; i < SES_NB_MAX_CHANNELS; i++) { + vCfg->PWMFrequenciesV1.PWMFrequencies[i] = newVal; + } + }); + + line = form->newLine(&grid); + new StaticText(line, rect_t{}, "PWM sychronized"); + new CheckBox( + line, rect_t{}, GET_DEFAULT(vCfg->PWMFrequenciesV1.Synchronized), + [=](uint8_t newVal) { + vCfg->PWMFrequenciesV1.Synchronized = newVal ? 0xFFFFFFFF : 0; + }); + + for (uint8_t i = 0; i < SES_NPT_NB_MAX_PORTS; i++) { + line = form->newLine(&grid); + + std::string portName = "NP"; + portName += 'A' + i; + + new StaticText(line, rect_t{}, portName.c_str()); + new Choice(line, rect_t{}, _v1_bus_types, afhds3::SES_NPT_PWM, + afhds3::SES_NPT_IBUS1_OUT, + GET_SET_DEFAULT(vCfg->NewPortTypes[i])); + } + } +} diff --git a/radio/src/gui/colorlcd/afhds3_options.h b/radio/src/gui/colorlcd/afhds3_options.h new file mode 100644 index 000000000..3a7497b59 --- /dev/null +++ b/radio/src/gui/colorlcd/afhds3_options.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 + +#include "page.h" +#include "pulses/afhds3_config.h" + +class AFHDS3_Options : public Page +{ + afhds3::Config_u* cfg; + + public: + AFHDS3_Options(uint8_t moduleIdx); +}; diff --git a/radio/src/gui/colorlcd/flysky_settings.cpp b/radio/src/gui/colorlcd/flysky_settings.cpp index 58ed89ee0..6adc75686 100644 --- a/radio/src/gui/colorlcd/flysky_settings.cpp +++ b/radio/src/gui/colorlcd/flysky_settings.cpp @@ -22,6 +22,10 @@ #include "flysky_settings.h" #include "opentx.h" +#if defined(AFHDS3) +#include "afhds3_options.h" +#endif + #include "pulses/flysky.h" #include "pulses/afhds3.h" @@ -132,50 +136,23 @@ void FlySkySettings::update() new StaticText(line, rect_t{}, STR_TYPE, 0, COLOR_THEME_PRIMARY1); auto box = new FormGroup(line, rect_t{}); - box->setFlexLayout(LV_FLEX_FLOW_ROW); - - new Choice(box, rect_t{}, _afhds3_region, 1, afhds3::LNK_ES_FCC, - GET_SET_DEFAULT(md->afhds3.emi)); + box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP); + lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); new Choice(box, rect_t{}, _afhds3_phy_mode, 0, afhds3::PHYMODE_MAX, GET_SET_DEFAULT(md->afhds3.phyMode)); - // // Power source - // line = newLine(&grid); - // new StaticText(line, rect_t{}, STR_AFHDS3_POWER_SOURCE, 0, - // COLOR_THEME_PRIMARY1); - // new DynamicText(line, rect_t{}, [=] { - // char msg[64] = ""; - // getModuleSyncStatusString(moduleIdx, msg); - // return std::string(msg); - // }); + new Choice(box, rect_t{}, _afhds3_region, + afhds3::LNK_ES_CE, afhds3::LNK_ES_FCC, + GET_SET_DEFAULT(md->afhds3.emi)); - // // RX Freq - // line = newLine(&grid); - // new StaticText(line, rect_t{}, STR_AFHDS3_RX_FREQ, 0, COLOR_THEME_PRIMARY1); - // auto edit = new NumberEdit(line, rect_t{}, AFHDS3_MIN_FREQ, AFHDS3_MAX_FREQ, - // GET_DEFAULT(md->afhds3.rxFreq())); - // edit->setSetValueHandler( - // [=](int32_t newValue) { md->afhds3.setRxFreq((uint16_t)newValue); }); - // edit->setSuffix(STR_HZ); - - // // Module actual power - // line = newLine(&grid); - // new StaticText(line, rect_t{}, STR_AFHDS3_ACTUAL_POWER, 0, - // COLOR_THEME_PRIMARY1); - // new DynamicText(line, rect_t{}, [=] { - // char msg[64] = ""; - // getStringAtIndex(msg, STR_AFHDS3_POWERS, actualAfhdsRunPower(moduleIdx)); - // return std::string(msg); - // }); - - // // Module power - // line = newLine(&grid); - // new StaticText(line, rect_t{}, STR_RF_POWER, 0, COLOR_THEME_PRIMARY1); - // new Choice(line, rect_t{}, STR_AFHDS3_POWERS, - // afhds3::RUN_POWER::RUN_POWER_FIRST, - // afhds3::RUN_POWER::RUN_POWER_LAST, - // GET_SET_DEFAULT(md->afhds3.runPower)); + uint8_t module = moduleIdx; + new TextButton(box, rect_t{}, STR_MODULE_OPTIONS, + [=]() { + afhds3::applyModelConfig(module); + new AFHDS3_Options(module); + return 0; + }); } #endif } diff --git a/radio/src/mixer_scheduler.h b/radio/src/mixer_scheduler.h index 98d4177bf..07d4c979b 100644 --- a/radio/src/mixer_scheduler.h +++ b/radio/src/mixer_scheduler.h @@ -64,7 +64,7 @@ void mixerSchedulerISRTrigger(); #define mixerSchedulerStart() #define mixerSchedulerStop() #define mixerSchedulerResetTimer() -#define mixerSchedulerSetPeriod(m,p) +#define mixerSchedulerSetPeriod(m,p) ((void)(p)) #define mixerSchedulerClearTrigger() #define mixerSchedulerEnableTrigger() diff --git a/radio/src/pulses/afhds3.cpp b/radio/src/pulses/afhds3.cpp index a418b3f40..65ddff730 100644 --- a/radio/src/pulses/afhds3.cpp +++ b/radio/src/pulses/afhds3.cpp @@ -21,11 +21,12 @@ #include "afhds3.h" #include "afhds3_transport.h" +#include "afhds3_config.h" + #include "pulses.h" #include "../debug.h" #include "../definitions.h" -// #include #include "telemetry/telemetry.h" #include "mixer_scheduler.h" @@ -62,24 +63,24 @@ static uint8_t _phyMode_channels[] = { 12, // ROUTINE_LORA_12CH }; -enum COMMAND_DIRECTION -{ - RADIO_TO_MODULE = 0, - MODULE_TO_RADIO = 1 -}; +// enum COMMAND_DIRECTION +// { +// RADIO_TO_MODULE = 0, +// MODULE_TO_RADIO = 1 +// }; -enum DATA_TYPE -{ - READY_DT, // 8 bytes 0x01 Not ready 0x02 Ready - STATE_DT, // See MODULE_STATE - MODE_DT, - MOD_CONFIG_DT, - CHANNELS_DT, - TELEMETRY_DT, - MODULE_POWER_DT, - MODULE_VERSION_DT, - EMPTY_DT, -}; +// enum DATA_TYPE +// { +// READY_DT, // 8 bytes 0x01 Not ready 0x02 Ready +// STATE_DT, // See MODULE_STATE +// MODE_DT, +// MOD_CONFIG_DT, +// CHANNELS_DT, +// TELEMETRY_DT, +// MODULE_POWER_DT, +// MODULE_VERSION_DT, +// EMPTY_DT, +// }; //enum used by command response -> translate to ModuleState enum MODULE_READY_E @@ -122,135 +123,6 @@ enum CMD_RESULT SUCCESS = 0x02, }; -enum BIND_POWER -{ - MIN_16dBm = 0x00, - BIND_POWER_FIRST = MIN_16dBm, - MIN_5dBm = 0x01, - MIN_0dbm = 0x02, - PLUS_5dBm = 0x03, - PLUS_14dBm = 0x04, - BIND_POWER_LAST = PLUS_14dBm, -}; - -// enum EMI_STANDARD -// { -// FCC = 0x00, -// CE = 0x01 -// }; - -enum TELEMETRY -{ - TELEMETRY_DISABLED = 0x00, - TELEMETRY_ENABLED = 0x01 -}; - -enum PULSE_MODE -{ - PWM_MODE = 0x00, - PPM_MODE = 0x01, -}; - -enum SERIAL_MODE -{ - IBUS = 0x00, - SBUS_MODE = 0x02 -}; - -// Old format for FRM302 -// PACK(struct Config_s { -// uint8_t bindPower; -// uint8_t runPower; -// uint8_t emiStandard; -// uint8_t telemetry; -// uint16_t pwmFreq; -// uint8_t pulseMode; -// uint8_t serialMode; -// uint8_t channelCount; -// uint16_t failSafeTimout; -// int16_t failSafeMode[AFHDS3_MAX_CHANNELS]; -// }); - -PACK(struct sSES_PWMFrequencyV0 { - uint16_t Frequency : 15; // From 50 to 400Hz - uint16_t Synchronized : 1; // 1=Synchronize the PWM output to the RF cycle - // (lower latency but unstable frequency) -}); - -enum eSES_PA_SetAnalogOutput { - SES_ANALOG_OUTPUT_PWM = 0, - SES_ANALOG_OUTPUT_PPM -}; - -enum eEB_BusType { - EB_BT_IBUS1=0, - EB_BT_IBUS2, - EB_BT_SBUS1 -}; - -// 48 bytes -PACK(struct sDATA_ConfigV0 { - uint8_t Version; // =0 - uint8_t EMIStandard; // eLNK_EMIStandard - uint8_t IsTwoWay; - uint8_t PhyMode; // eDATA_PHYMODE - uint8_t SignalStrengthRCChannelNb; // 0xFF if not used, 0`18 - uint16_t FailsafeTimeout; // in unit of ms - int16_t FailSafe[AFHDS3_MAX_CHANNELS]; - uint8_t FailsafeOutputMode; //TRUE Or FALSE - sSES_PWMFrequencyV0 PWMFrequency; - uint8_t AnalogOutput; // eSES_PA_SetAnalogOutput - uint8_t ExternalBusType; // eEB_BusType -}); - -#define SES_NB_MAX_CHANNELS (32) -#define SES_NPT_NB_MAX_PORTS (4) - -enum eSES_NewPortType { - SES_NPT_PWM, - SES_NPT_PPM, - SES_NPT_SBUS, - SES_NPT_IBUS1_IN, - SES_NPT_IBUS1_OUT, - SES_NPT_IBUS2, - SES_NPT_IBUS2_HUB_PORT, - SES_NPT_WSTX, - SES_NPT_WSRX, - SES_NPT_NONE=0xFF -}; - -PACK(struct sSES_PWMFrequenciesAPPV1 { - // One unsigned short per - // channel, From 50 to 400Hz, - // 1:1000Hz,2:833Hz - uint16_t PWMFrequencies[SES_NB_MAX_CHANNELS]; - - // 1 bit per channel, 32 channels total - uint32_t Synchronized; -}); - -// 116 bytes -PACK(struct sDATA_ConfigV1 { - uint8_t Version; // =1 - uint8_t EMIStandard; // eLNK_EMIStandard - uint8_t IsTwoWay; - uint8_t PhyMode; // eDATA_PHYMODE - uint8_t SignalStrengthRCChannelNb; // 0xFF if not used , 0`18 - uint16_t FailsafeTimeout; // in unit of ms - int16_t FailSafe[AFHDS3_MAX_CHANNELS]; - uint8_t FailsafeOutputMode; // TRUE Or FALSE - uint8_t NewPortTypes[SES_NPT_NB_MAX_PORTS]; // eSES_NewPortType - sSES_PWMFrequenciesAPPV1 PWMFrequenciesV1; -}); - -union Config_u -{ - uint8_t version; - sDATA_ConfigV0 v0; - sDATA_ConfigV1 v1; - uint8_t buffer[sizeof(sDATA_ConfigV1)]; -}; - enum CHANNELS_DATA_MODE { CHANNELS = 0x01, @@ -349,9 +221,13 @@ class ProtoState */ void stop(); + Config_u* getConfig() { return &cfg; } + + void applyConfigFromModel(); + protected: - void setConfigFromModel(); + void resetConfig(uint8_t version); private: //friendship declaration - use for passing telemetry @@ -391,6 +267,7 @@ class ProtoState ModuleState state; bool modelIDSet; + uint8_t modelID; /** * Command count used for counting actual number of commands sent in run mode @@ -438,7 +315,7 @@ static const char* const moduleStateText[] = static const COMMAND periodicRequestCommands[] = { COMMAND::MODULE_STATE, - COMMAND::MODULE_GET_CONFIG, + // COMMAND::MODULE_GET_CONFIG, COMMAND::VIRTUAL_FAILSAFE }; @@ -513,7 +390,7 @@ void ProtoState::setupFrame() if (moduleMode == ::ModuleSettingsMode::MODULE_MODE_BIND) { if (state != STATE_BINDING) { TRACE("AFHDS3 [BIND]"); - setConfigFromModel(); + applyConfigFromModel(); trsp.sendFrame(COMMAND::MODULE_SET_CONFIG, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, cfg.buffer, @@ -542,10 +419,19 @@ void ProtoState::setupFrame() return; } else { modelIDSet = true; + modelID = g_model.header.modelId[module_index]; trsp.sendFrame(COMMAND::MODEL_ID, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, &g_model.header.modelId[module_index], 1); + + // always fetch config after setting model ID + trsp.enqueue(COMMAND::MODULE_GET_CONFIG, FRAME_TYPE::REQUEST_GET_DATA); return; } + } else if (modelID != g_model.header.modelId[module_index]) { + modelIDSet = false; + auto mode = (uint8_t)MODULE_MODE_E::STANDBY; + trsp.sendFrame(COMMAND::MODULE_MODE, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, &mode, 1); + return; } if (this->state == ModuleState::STATE_STANDBY) { @@ -873,64 +759,58 @@ void ProtoState::stop() trsp.sendFrame(COMMAND::MODULE_MODE, FRAME_TYPE::REQUEST_SET_EXPECT_DATA, &mode, 1); } -void ProtoState::setConfigFromModel() +void ProtoState::resetConfig(uint8_t version) { - if (moduleData->afhds3.phyMode < ROUTINE_FLCR1_18CH) { - cfg.version = 0; + memclear(&cfg, sizeof(cfg)); + cfg.version = version; + + if (cfg.version == 1) { + cfg.v1.SignalStrengthRCChannelNb = 0xFF; + cfg.v1.FailsafeTimeout = 500; + for (int i = 0; i < SES_NB_MAX_CHANNELS; i++) + cfg.v1.PWMFrequenciesV1.PWMFrequencies[i] = 50; } else { - cfg.version = 1; + cfg.v0.SignalStrengthRCChannelNb = 0xFF; + cfg.v0.FailsafeTimeout = 500; + cfg.v0.PWMFrequency.Frequency = 50; + } +} + +void ProtoState::applyConfigFromModel() +{ + uint8_t version = 0; + if (moduleData->afhds3.phyMode >= ROUTINE_FLCR1_18CH) { + version = 1; + } + + if (version != cfg.version) { + resetConfig(version); } if (cfg.version == 1) { cfg.v1.EMIStandard = moduleData->afhds3.emi; cfg.v1.IsTwoWay = moduleData->afhds3.telemetry; cfg.v1.PhyMode = moduleData->afhds3.phyMode; - cfg.v1.SignalStrengthRCChannelNb = 0xFF; // Failsafe - cfg.v1.FailsafeTimeout = 500; setFailSafe(cfg.v1.FailSafe); - if (moduleData->failsafeMode != FAILSAFE_NOPULSES) { cfg.v1.FailsafeOutputMode = true; } else { cfg.v1.FailsafeOutputMode = false; } - - // Serial output - memclear(&cfg.v1.NewPortTypes, sizeof(cfg.v1.NewPortTypes)); - - // PWM settings - for (int i = 0; i < SES_NB_MAX_CHANNELS; i++) - cfg.v1.PWMFrequenciesV1.PWMFrequencies[i] = 50; - - cfg.v1.PWMFrequenciesV1.Synchronized = 0; - } else { cfg.v0.EMIStandard = moduleData->afhds3.emi; cfg.v0.IsTwoWay = moduleData->afhds3.telemetry; cfg.v0.PhyMode = moduleData->afhds3.phyMode; - cfg.v0.SignalStrengthRCChannelNb = 0xFF; // Failsafe - cfg.v0.FailsafeTimeout = 500; setFailSafe(cfg.v0.FailSafe); - if (moduleData->failsafeMode != FAILSAFE_NOPULSES) { cfg.v0.FailsafeOutputMode = true; } else { cfg.v0.FailsafeOutputMode = false; } - - // PWM settings - cfg.v0.PWMFrequency.Frequency = 50; - cfg.v0.PWMFrequency.Synchronized = 0; - - // PWM/PPM - cfg.v0.AnalogOutput = 0; - - // iBUS/SBUS - cfg.v0.ExternalBusType = EB_BT_IBUS1; } } @@ -969,6 +849,18 @@ uint8_t ProtoState::setFailSafe(int16_t* target) return (uint8_t) (AFHDS3_MAX_CHANNELS); } +Config_u* getConfig(uint8_t module) +{ + auto p_state = &protoState[module]; + return p_state->getConfig(); +} + +void applyModelConfig(uint8_t module) +{ + auto p_state = &protoState[module]; + p_state->applyConfigFromModel(); +} + static void* initExternal(uint8_t module) { #if defined(AFHDS3_EXT_UART) diff --git a/radio/src/pulses/afhds3.h b/radio/src/pulses/afhds3.h index b035df0f3..146477332 100644 --- a/radio/src/pulses/afhds3.h +++ b/radio/src/pulses/afhds3.h @@ -36,7 +36,6 @@ #define AFHDS3_MIN_FREQ 50 #define AFHDS3_MAX_FREQ 400 -#define AFHDS3_MAX_CHANNELS 18 #define AFHDS3_FAILSAFE_MIN -15000 #define AFHDS3_FAILSAFE_MAX 15000 diff --git a/radio/src/pulses/afhds3_config.h b/radio/src/pulses/afhds3_config.h new file mode 100644 index 000000000..2bcad0003 --- /dev/null +++ b/radio/src/pulses/afhds3_config.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * 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 AFHDS3_MAX_CHANNELS 18 + +namespace afhds3 +{ + +PACK(struct sSES_PWMFrequencyV0 { + uint16_t Frequency : 15; // From 50 to 400Hz + uint16_t Synchronized : 1; // 1=Synchronize the PWM output to the RF cycle + // (lower latency but unstable frequency) +}); + +enum eSES_PA_SetAnalogOutput { + SES_ANALOG_OUTPUT_PWM = 0, + SES_ANALOG_OUTPUT_PPM +}; + +enum eEB_BusType { + EB_BT_IBUS1=0, + EB_BT_IBUS2, + EB_BT_SBUS1 +}; + +// 48 bytes +PACK(struct sDATA_ConfigV0 { + uint8_t Version; // =0 + uint8_t EMIStandard; // eLNK_EMIStandard + uint8_t IsTwoWay; + uint8_t PhyMode; // eDATA_PHYMODE + uint8_t SignalStrengthRCChannelNb; // 0xFF if not used, 0`18 + uint16_t FailsafeTimeout; // in unit of ms + int16_t FailSafe[AFHDS3_MAX_CHANNELS]; + uint8_t FailsafeOutputMode; //TRUE Or FALSE + sSES_PWMFrequencyV0 PWMFrequency; + uint8_t AnalogOutput; // eSES_PA_SetAnalogOutput + uint8_t ExternalBusType; // eEB_BusType +}); + +#define SES_NB_MAX_CHANNELS (32) +#define SES_NPT_NB_MAX_PORTS (4) + +enum eSES_NewPortType { + SES_NPT_PWM, + SES_NPT_PPM, + SES_NPT_SBUS, + SES_NPT_IBUS1_IN, + SES_NPT_IBUS1_OUT, + SES_NPT_IBUS2, + SES_NPT_IBUS2_HUB_PORT, + SES_NPT_WSTX, + SES_NPT_WSRX, + SES_NPT_NONE=0xFF +}; + +PACK(struct sSES_PWMFrequenciesAPPV1 { + // One unsigned short per + // channel, From 50 to 400Hz, + // 1:1000Hz,2:833Hz + uint16_t PWMFrequencies[SES_NB_MAX_CHANNELS]; + + // 1 bit per channel, 32 channels total + uint32_t Synchronized; +}); + +// 116 bytes +PACK(struct sDATA_ConfigV1 { + uint8_t Version; // =1 + uint8_t EMIStandard; // eLNK_EMIStandard + uint8_t IsTwoWay; + uint8_t PhyMode; // eDATA_PHYMODE + uint8_t SignalStrengthRCChannelNb; // 0xFF if not used , 0`18 + uint16_t FailsafeTimeout; // in unit of ms + int16_t FailSafe[AFHDS3_MAX_CHANNELS]; + uint8_t FailsafeOutputMode; // TRUE Or FALSE + uint8_t NewPortTypes[SES_NPT_NB_MAX_PORTS]; // eSES_NewPortType + sSES_PWMFrequenciesAPPV1 PWMFrequenciesV1; +}); + +union Config_u +{ + uint8_t version; + sDATA_ConfigV0 v0; + sDATA_ConfigV1 v1; + uint8_t buffer[sizeof(sDATA_ConfigV1)]; +}; + +Config_u* getConfig(uint8_t moduleIdx); +void applyModelConfig(uint8_t moduleIdx); + +};