Files
edgetx-gx12/radio/src/pulses/modules_helpers.h
T
Raphael CoefficandMalte Langermann 2b100e0eb5 refact: ADC, switches and keys
Add "hardware_defs" target to dump hardware defines from hal.h per target

Fixed hal.h definitions for switches & ADC inputs

Tools to generate hardware definitions from current hal.h

generator: add support for EXTx and analog switches

WiP

Add generated header to hardware_defs target

Add support for ADC input direction and index per GPIO port

Incredible: it compiles

Removed StdPeriph ADC driver

Works on QX7

Works on TX16S (VBat missing)

Switch driver using generated switches for stm32 targets

Switch driver with generated switches for simu

Use switch names from switch driver

Fixed single conversion handling

Fixed horus VBat reading

Added switch name

Fix warnings about bitfield offsets and GCC 4.4

This is caused by bitfields that cross type boundaries. In this particular case, it happens as the bitfield is not defined the same in `rtc_backup.cpp`.

Switches has already been moved to generic driver

Jitter measurement for each sample, not just for oversampled values

Moved periph clock init to the ADC driver

ADC & GPIOs.

Add switchInit() to init pins

Fix NV14 CMake

Fix taranis target

Fix NV14 (again)

Model audio files: use new interface for switch index

Fix X9-lite

Fix simu headers

Fix getSwitchName()

Add support for ADC switches

Fix switch warning YAML

Test only switches which are defined

Conversions tests for QX7 only on QX7

Fix X12S

Fix function switch names

Enable ADC periph clock before initialising channels

NV14: offset inputs for the sticks & fix switches

WiP: get rid of VSRCRAW and some more

Simu shall use normal ADC driver

fix x7

fix nv14

Fix 9x nav

fix 212x64

fix xlite

fix x9e

fix simu lib

fix unit tests

fix x7 tests

PWM stick values should be written directly into adcValues

... just like FlySky sticks.

fix x12s

fix nv14

Add some support for SPI ADC (only unit tests)

Remove `jq` usage

fix generate_yaml.py for newer libclang

fix pot config

fix stick names

Some YAML generator improvements

Max 16 Pots on COLORLCD

Fix some source names

Use 10 bits for switches to prevent overflow

Removed horus constants for switches & ADC inputs

Fix unit tests

Fix curve edit

Fix libsimulator

Fix function switches (tpro)

Refine ADC & analog API

Moved hardware definitions scripts and templates into own dir

cleanup API refine

Fix unit tests

Mixer: apply calibration only on required inputs

Place ADC switches after all other ADC inputs

Fix X12S

Remove useless TR_POTS_VSRCRAW, TR_SW_VSRCRAW, and TR_VSRCRAW

Cleanup redundant generated YAML parsers

Fixes Boxer rebase

Add boxer to generate-hw-defs.sh

Obsolete LUA exports

Add boxer ADC_DIRECTION

Split generate_hw_defs.py into multiple files

Some cleanup (+ LUA switches)

Fix AXIS definitions

Fixed translation strings declarations

Some rebase fixes

Remove some useless StdPeriph drivers

fix: set pin mode to reset state on usart deinit

fix: use canonical names for calibration data

fix: ADC driver does not care about unconfigured inputs

fix X12S ADC

Add support for ADC conversion chaining

Better X12S ADC implem

Moved X12S ADC driver to HAL/LL

Improve ADC driver separation

Fixed taranis & nv14

Moved PWM gimbals to HAL/LL

Removed useless TR_EXTRA_VSRCRAW

Fixed include guards

Small fixes

Renamed control inputs

Moved internal and external module pulse driver def to boards

Move more things to the generic_stm32 board

Remove STR_VMIXTRIMS

Added analog labels

Generate main control names

Misuse labels / short labels for main controls

Backward compatibility: sliders and legacy names

New keys driver

Let's get rid of StdPeriph headers in simu

Add jinja2 to CI workflows

Use `grep` instead of `sed`

chore: add python jinja2 oto msys setup script

Removed more static definitions and use dynamic ones instead

Fixes X9E

Fix x7 nav too

212 switch display

Fix default sliders

Removed NUM_STICKS

212 switch display working nicely

Surface radio 'stick' replacements

fix: switch, trim & rotary pin init

Remove old key drivers

Removed VKEYS

Removed ETX_FOURCC

Fixed SURFACE_NAME

Removed TR_VSWITCHES & TR_TRIMS_SWITCHES

Fix xpot switches

Store calibrated analogs in physical order

Use getSourceString in drawSource

Implement missing YAML read/write

Fix isSourceAvailableInInputs()

Fix isSourceAvailable()

Some surface fixes

Fix CLI debug

Ported colour UI of analog diagnostics to new ADC API

Small fixes

Better input mapping

Minor tpro fixes

Fix trims available

Remove TX mode choice on surface radio

Rename surface controls

Channel order alignement

Fix throttle warning

Fix checkTrims()

Fix pot config casting issue

Fix IS_SWITCH_FS()

Fixed input mapping

Fix fswitch auto-switch

Fixed storing / reading function switches in YAML

Fix enableVBatBridge() / disableVBatBridge()

Fix interesting mode conversion

Fix sources issues

Fix special funnction list

Proper function switch handling

128 GUI improvements

Fix compilation

Boxer cosmetics

128 hardware screen cosmetic

Fix TX12 switches

More switches fixes

Simplify CPU type handling

Fix flash size

Fixed page-up / page-down in libopenui
2023-06-25 14:32:39 +02:00

844 lines
22 KiB
C++

/*
* 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.
*/
#ifndef _MODULES_HELPERS_H_
#define _MODULES_HELPERS_H_
#include "libopenui/src/bitfield.h"
#include "definitions.h"
#include "opentx_helpers.h"
#include "storage/storage.h"
#include "globals.h"
#include "MultiProtoDefs.h"
#if defined(MULTIMODULE)
#include "telemetry/multi.h"
#endif
#if defined(PCBNV14)
extern uint32_t NV14internalModuleFwVersion;
#endif
#if defined(AFHDS3)
#include "pulses/afhds3_module.h"
#endif
#define CROSSFIRE_CHANNELS_COUNT 16
#define GHOST_CHANNELS_COUNT 16
#define IS_NATIVE_FRSKY_PROTOCOL(module) \
((moduleState[module].protocol == PROTOCOL_CHANNELS_PXX1) || \
(moduleState[module].protocol == PROTOCOL_CHANNELS_PXX2))
#if defined (MULTIMODULE)
#define IS_D16_MULTI(module) \
((g_model.moduleData[module].multi.rfProtocol == MODULE_SUBTYPE_MULTI_FRSKYX) || \
(g_model.moduleData[module].multi.rfProtocol == MODULE_SUBTYPE_MULTI_FRSKYX2))
#define IS_R9_MULTI(module) \
(g_model.moduleData[module].multi.rfProtocol == \
MODULE_SUBTYPE_MULTI_FRSKY_R9)
#define IS_HOTT_MULTI(module) \
(g_model.moduleData[module].multi.rfProtocol == MODULE_SUBTYPE_MULTI_HOTT)
#define IS_CONFIG_MULTI(module) \
(g_model.moduleData[module].multi.rfProtocol == MODULE_SUBTYPE_MULTI_CONFIG)
#define IS_DSM_MULTI(module) \
(g_model.moduleData[module].multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2)
#define IS_RX_MULTI(module) \
((g_model.moduleData[module].multi.rfProtocol == \
MODULE_SUBTYPE_MULTI_AFHDS2A_RX) || \
(g_model.moduleData[module].multi.rfProtocol == \
MODULE_SUBTYPE_MULTI_FRSKYX_RX) || \
(g_model.moduleData[module].multi.rfProtocol == \
MODULE_SUBTYPE_MULTI_BAYANG_RX) || \
(g_model.moduleData[module].multi.rfProtocol == \
MODULE_SUBTYPE_MULTI_DSM_RX))
// When using packed, the pointer in here end up not being aligned, which clang and gcc complain about
// Keep the order of the fields that the so that the size stays small
struct mm_options_strings {
static const char* const options[];
};
const uint8_t getMaxMultiOptions();
struct mm_protocol_definition {
uint8_t protocol;
uint8_t maxSubtype;
bool failsafe;
bool disable_ch_mapping;
const char* const* subTypeString;
const char* optionsstr;
};
const mm_protocol_definition *getMultiProtocolDefinition (uint8_t protocol);
inline uint8_t getMaxMultiSubtype(uint8_t moduleIdx)
{
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
uint8_t max_pdef = 0;
auto proto = g_model.moduleData[moduleIdx].multi.rfProtocol;
const mm_protocol_definition *pdef = getMultiProtocolDefinition(proto);
if (pdef) {
max_pdef = pdef->maxSubtype;
}
uint8_t max_status = 0;
if (status.isValid()) {
max_status = (status.protocolSubNbr == 0 ? 0 : status.protocolSubNbr - 1);
}
return max(max_status, max_pdef);
}
inline bool isModuleMultimodule(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_MULTIMODULE;
}
inline bool isModuleMultimoduleDSM2(uint8_t idx)
{
return isModuleMultimodule(idx) &&
g_model.moduleData[idx].multi.rfProtocol ==
MODULE_SUBTYPE_MULTI_DSM2;
}
inline void resetMultiProtocolsOptions(uint8_t moduleIdx)
{
if (!isModuleMultimodule(moduleIdx))
return;
// Sensible default for DSM2 (same as for ppm): 7ch@22ms + Autodetect settings enabled
if (g_model.moduleData[moduleIdx].multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2) {
g_model.moduleData[moduleIdx].multi.autoBindMode = 1;
}
else {
g_model.moduleData[moduleIdx].multi.autoBindMode = 0;
}
g_model.moduleData[moduleIdx].multi.optionValue = 0;
g_model.moduleData[moduleIdx].multi.disableTelemetry = 0;
g_model.moduleData[moduleIdx].multi.disableMapping = 0;
g_model.moduleData[moduleIdx].multi.lowPowerMode = 0;
g_model.moduleData[moduleIdx].failsafeMode = FAILSAFE_NOT_SET;
g_model.header.modelId[moduleIdx] = 0;
}
#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_RX_MULTI(module) false
inline bool isModuleMultimodule(uint8_t)
{
return false;
}
inline bool isModuleMultimoduleDSM2(uint8_t)
{
return false;
}
#endif
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);
}
inline bool isModuleXJTD8(uint8_t idx)
{
return isModuleXJT(idx) && g_model.moduleData[idx].subType == MODULE_SUBTYPE_PXX1_ACCST_D8;
}
inline bool isModuleXJTLR12(uint8_t idx)
{
return isModuleXJT(idx) && g_model.moduleData[idx].subType == MODULE_SUBTYPE_PXX1_ACCST_LR12;
}
inline bool isModuleXJTD16(uint8_t idx)
{
return isModuleXJT(idx) && g_model.moduleData[idx].subType == MODULE_SUBTYPE_PXX1_ACCST_D16;
}
inline bool isModuleTypeISRM(uint8_t type)
{
return type == MODULE_TYPE_ISRM_PXX2;
}
inline bool isModuleISRM(uint8_t idx)
{
return isModuleTypeISRM(g_model.moduleData[idx].type);
}
inline bool isModuleISRMD16(uint8_t idx)
{
return isModuleISRM(idx) &&
g_model.moduleData[idx].subType == MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16;
}
inline bool isModuleD16(uint8_t idx)
{
return isModuleXJTD16(idx) || isModuleISRMD16(idx) || IS_D16_MULTI(idx);
}
inline bool isModuleISRMAccess(uint8_t idx)
{
return isModuleISRM(idx) &&
g_model.moduleData[idx].subType == MODULE_SUBTYPE_ISRM_PXX2_ACCESS;
}
#if defined(CROSSFIRE)
inline bool isModuleCrossfire(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_CROSSFIRE;
}
inline bool isInternalModuleCrossfire()
{
return g_eeGeneral.internalModule == MODULE_TYPE_CROSSFIRE;
}
#else
inline bool isModuleCrossfire(uint8_t idx)
{
return false;
}
inline bool isInternalModuleCrossfire()
{
return false;
}
#endif
#if defined(GHOST)
inline bool isModuleGhost(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_GHOST;
}
#else
inline bool isModuleGhost(uint8_t idx)
{
return false;
}
#endif
inline bool isExtraModule(uint8_t)
{
return false;
}
inline bool isModuleTypePPM(uint8_t type)
{
return type == MODULE_TYPE_PPM;
}
inline bool isModulePPM(uint8_t moduleIdx)
{
return isModuleTypePPM(g_model.moduleData[moduleIdx].type);
}
inline bool isModuleTypeR9MNonAccess(uint8_t type)
{
return type == MODULE_TYPE_R9M_PXX1 || type == MODULE_TYPE_R9M_LITE_PXX1;
}
inline bool isModuleR9MNonAccess(uint8_t idx)
{
return isModuleTypeR9MNonAccess(g_model.moduleData[idx].type);
}
inline bool isModuleTypeR9MAccess(uint8_t type)
{
return type == MODULE_TYPE_R9M_PXX2 || type == MODULE_TYPE_R9M_LITE_PXX2 || type == MODULE_TYPE_R9M_LITE_PRO_PXX2;
}
inline bool isModuleR9MAccess(uint8_t idx)
{
return isModuleTypeR9MAccess(g_model.moduleData[idx].type);
}
inline bool isModuleTypeR9M(uint8_t type)
{
return isModuleTypeR9MNonAccess(type) || isModuleTypeR9MAccess(type);
}
inline bool isModuleR9M(uint8_t idx)
{
return isModuleTypeR9M(g_model.moduleData[idx].type);
}
inline bool isModuleTypeR9MLiteNonPro(uint8_t type)
{
return type == MODULE_TYPE_R9M_LITE_PXX1 || type == MODULE_TYPE_R9M_LITE_PXX2;
}
inline bool isModuleR9MLiteNonPro(uint8_t idx)
{
return isModuleTypeR9MLiteNonPro(g_model.moduleData[idx].type);
}
inline bool isModuleTypeR9MLitePro(uint8_t type)
{
return type == MODULE_TYPE_R9M_LITE_PRO_PXX2;
}
inline bool isModuleTypeR9MLite(uint8_t type)
{
return isModuleTypeR9MLiteNonPro(type) || isModuleTypeR9MLitePro(type);
}
inline bool isModuleR9MLite(uint8_t idx)
{
return isModuleTypeR9MLite(g_model.moduleData[idx].type);
}
inline bool isModuleR9M_FCC(uint8_t idx)
{
return isModuleR9MNonAccess(idx) && g_model.moduleData[idx].subType == MODULE_SUBTYPE_R9M_FCC;
}
inline bool isModuleTypeLite(uint8_t type)
{
return isModuleTypeR9MLite(type) || type == MODULE_TYPE_XJT_LITE_PXX2;
}
inline bool isModuleR9M_LBT(uint8_t idx)
{
return isModuleR9MNonAccess(idx) && g_model.moduleData[idx].subType == MODULE_SUBTYPE_R9M_EU;
}
inline bool isModuleR9M_FCC_VARIANT(uint8_t idx)
{
return isModuleR9MNonAccess(idx) && g_model.moduleData[idx].subType != MODULE_SUBTYPE_R9M_EU;
}
inline bool isModuleR9M_EUPLUS(uint8_t idx)
{
return isModuleR9MNonAccess(idx) && g_model.moduleData[idx].subType == MODULE_SUBTYPE_R9M_EUPLUS;
}
inline bool isModuleR9M_AU_PLUS(uint8_t idx)
{
return isModuleR9MNonAccess(idx) && g_model.moduleData[idx].subType == MODULE_SUBTYPE_R9M_AUPLUS;
}
inline bool isModuleTypePXX1(uint8_t type)
{
return isModuleTypeXJT(type) || isModuleTypeR9MNonAccess(type);
}
inline bool isModulePXX1(uint8_t idx)
{
return isModuleTypePXX1(g_model.moduleData[idx].type);
}
inline bool isModuleXJTLite(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_XJT_LITE_PXX2;
}
inline bool isModulePXX2(uint8_t idx)
{
return isModuleISRM(idx) || isModuleR9MAccess(idx) || isModuleXJTLite(idx);
}
inline bool isModuleRFAccess(uint8_t idx)
{
if (isModuleISRM(idx)) {
return g_model.moduleData[idx].subType == MODULE_SUBTYPE_ISRM_PXX2_ACCESS;
}
else if (isModuleR9MAccess(idx)) {
return true;
}
else {
return false;
}
}
inline bool isModuleDSM2(uint8_t moduleIdx)
{
return g_model.moduleData[moduleIdx].type == MODULE_TYPE_DSM2;
}
inline bool isModuleSBUS(uint8_t moduleIdx)
{
return g_model.moduleData[moduleIdx].type == MODULE_TYPE_SBUS;
}
inline bool isModuleFlySky(uint8_t idx)
{
return
(g_model.moduleData[idx].type == MODULE_TYPE_FLYSKY);
}
inline bool isModuleAFHDS2A(uint8_t idx)
{
return isModuleFlySky(idx)
&& (g_model.moduleData[idx].subType == FLYSKY_SUBTYPE_AFHDS2A);
}
inline bool isModuleAFHDS3(uint8_t idx)
{
return isModuleFlySky(idx)
&& (g_model.moduleData[idx].subType == FLYSKY_SUBTYPE_AFHDS3);
}
inline bool isModuleDSMP(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_LEMON_DSMP;
}
// See enum ModuleType in modules_constant.h
// relative to 8!
static const int8_t maxChannelsModules_M8[] = {
0, // MODULE_TYPE_NONE
8, // MODULE_TYPE_PPM
0, // MODULE_TYPE_XJT_PXX1: index NOT USED
16,// MODULE_TYPE_ISRM_PXX2
-2,// MODULE_TYPE_DSM2
CROSSFIRE_CHANNELS_COUNT - 8, // MODULE_TYPE_CROSSFIRE
8, // MODULE_TYPE_MULTIMODULE
0, // MODULE_TYPE_R9M_PXX1: index NOT USED
0, // MODULE_TYPE_R9M_PXX2: index NOT USED
0, // MODULE_TYPE_R9M_LITE_PXX1: index NOT USED
0, // MODULE_TYPE_R9M_LITE_PXX2: index NOT USED
GHOST_CHANNELS_COUNT - 8, // MODULE_TYPE_GHOST
0, // MODULE_TYPE_R9M_LITE_PRO_PXX2: index NOT USED
8, // MODULE_TYPE_SBUS
0, // MODULE_TYPE_XJT_LITE_PXX2: index NOT USED
6, // MODULE_TYPE_FLYSKY: 14 channels for AFHDS2A, AFHDS3 special cased
4, // MODULE_TYPE_LEMON_DSMP: 12 channels for DSMX
};
static_assert(MODULE_TYPE_COUNT == sizeof(maxChannelsModules_M8),
"MODULE_TYPE_COUNT != sizeof(maxChannelsModules_M8)");
// See enum ModuleSubtypePXX1 in modules_constant.h
// relative to 8!
static const int8_t maxChannelsXJT_M8[] = {
0, // MODULE_SUBTYPE_PXX1_OFF
8, // MODULE_SUBTYPE_PXX1_ACCST_D16
0, // MODULE_SUBTYPE_PXX1_ACCST_D8
4 // MODULE_SUBTYPE_PXX1_ACCST_LR12
};
// MODULE_SUBTYPE_PXX1_OFF == -1
static_assert(MODULE_SUBTYPE_PXX1_LAST + 2 == sizeof(maxChannelsXJT_M8),
"MODULE_SUBTYPE_PXX1_LAST + 2 != sizeof(maxChannelsXJT_M8)");
constexpr int8_t MAX_TRAINER_CHANNELS_M8 = MAX_TRAINER_CHANNELS - 8;
constexpr int8_t MAX_EXTRA_MODULE_CHANNELS_M8 = 8; // only 16ch PPM
inline int8_t maxModuleChannels_M8(uint8_t moduleIdx)
{
if (isExtraModule(moduleIdx)) {
return MAX_EXTRA_MODULE_CHANNELS_M8;
} else if (isModuleXJT(moduleIdx)) {
return maxChannelsXJT_M8[1 + g_model.moduleData[moduleIdx].subType];
} else if (isModuleISRMD16(moduleIdx)) {
return maxChannelsXJT_M8[MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16];
} else if (isModuleR9M(moduleIdx)) {
if (isModuleR9M_LBT(moduleIdx)) {
if (isModuleR9MLite(moduleIdx))
return g_model.moduleData[moduleIdx].pxx.power ==
R9M_LITE_LBT_POWER_25_8CH
? 0
: 8;
else
return g_model.moduleData[moduleIdx].pxx.power == R9M_LBT_POWER_25_8CH
? 0
: 8;
} else {
return 8; // always 16 channels in FCC / FLEX
}
} else if (isModuleAFHDS3(moduleIdx)) {
return 10;
} else if (isModuleMultimoduleDSM2(moduleIdx)) {
return 4; // 12 channels
} else if (isModuleDSMP(moduleIdx) &&
(g_model.moduleData[moduleIdx].dsmp.flags != 0)) {
return g_model.moduleData[moduleIdx].channelsCount;
} else {
return maxChannelsModules_M8[g_model.moduleData[moduleIdx].type];
}
}
inline int8_t maxModuleChannels(uint8_t moduleIdx)
{
return maxModuleChannels_M8(moduleIdx) + 8;
}
inline int8_t minModuleChannels(uint8_t idx)
{
if (isModuleCrossfire(idx))
return CROSSFIRE_CHANNELS_COUNT;
else if (isModuleGhost(idx))
return GHOST_CHANNELS_COUNT;
else if (isModuleSBUS(idx))
return 16;
else if (isModuleDSMP(idx))
return maxModuleChannels(idx);
else
return 1;
}
inline int8_t defaultModuleChannels_M8(uint8_t idx)
{
if (isModulePPM(idx))
return 0; // 8 channels
else
return maxModuleChannels_M8(idx);
}
inline uint8_t sentModulePXXChannels(uint8_t idx)
{
return 8 + g_model.moduleData[idx].channelsCount;
}
inline int8_t sentModuleChannels(uint8_t idx)
{
if (isModuleCrossfire(idx))
return CROSSFIRE_CHANNELS_COUNT;
else if (isModuleGhost(idx))
return GHOST_CHANNELS_COUNT;
else if (isModuleMultimodule(idx) && !isModuleMultimoduleDSM2(idx))
return 16;
else if (isModuleSBUS(idx))
return 16;
else
return sentModulePXXChannels(idx);
}
inline bool isDefaultModelRegistrationID()
{
return memcmp(g_model.modelRegistrationID, g_eeGeneral.ownerRegistrationID, PXX2_LEN_REGISTRATION_ID) == 0;
}
inline bool isModuleRxNumAvailable(uint8_t moduleIdx)
{
if (isModuleXJT(moduleIdx))
return g_model.moduleData[moduleIdx].subType != MODULE_SUBTYPE_PXX1_ACCST_D8;
if (isModuleR9M(moduleIdx))
return true;
if (isModuleDSM2(moduleIdx))
return true;
if (isModuleISRM(moduleIdx))
return true;
if (isModuleMultimodule(moduleIdx))
return true;
if (isModuleCrossfire(moduleIdx))
return true;
return false;
}
inline bool isModuleModelIndexAvailable(uint8_t idx)
{
if (isModuleXJT(idx))
return g_model.moduleData[idx].subType != MODULE_SUBTYPE_PXX1_ACCST_D8;
if (isModuleR9M(idx))
return true;
if (isModuleDSM2(idx))
return true;
if (isModuleISRM(idx))
return true;
if (isModuleMultimodule(idx))
return true;
if (isModuleCrossfire(idx))
return true;
if (isModuleAFHDS3(idx))
return true;
return false;
}
inline bool isModuleFailsafeAvailable(uint8_t moduleIdx)
{
#if defined(PXX2)
if (isModuleISRM(moduleIdx))
return true;
#endif
if (isModuleXJT(moduleIdx))
return g_model.moduleData[moduleIdx].subType == MODULE_SUBTYPE_PXX1_ACCST_D16;
#if defined(MULTIMODULE)
if (isModuleMultimodule(moduleIdx)) {
MultiModuleStatus &status = getMultiModuleStatus(moduleIdx);
if (status.isValid()) {
return status.supportsFailsafe();
}
else {
auto proto = g_model.moduleData[moduleIdx].multi.rfProtocol;
const mm_protocol_definition * pdef = getMultiProtocolDefinition(proto);
if (pdef) return pdef->failsafe;
return false;
}
}
#endif
#if defined(AFHDS3) || defined(AFHDS2)
if (isModuleFlySky(moduleIdx))
return true;
#endif
if (isModuleR9M(moduleIdx))
return true;
return false;
}
inline bool isModuleBindRangeAvailable(uint8_t moduleIdx)
{
return isModulePXX2(moduleIdx) || isModulePXX1(moduleIdx) ||
isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx) ||
isModuleFlySky(moduleIdx) || isModuleDSMP(moduleIdx);
}
inline uint32_t getNV14RfFwVersion()
{
#if defined(PCBNV14)
return NV14internalModuleFwVersion;
#else
return 0;
#endif
}
inline bool isModuleRangeAvailable(uint8_t moduleIdx)
{
bool ret = isModuleBindRangeAvailable(moduleIdx) && !IS_RX_MULTI(moduleIdx);
#if defined(PCBNV14)
ret = ret &&
(!isModuleFlySky(moduleIdx) || NV14internalModuleFwVersion >= 0x1000E);
#else
ret = ret && (!isModuleFlySky(moduleIdx));
#endif
return ret;
}
constexpr uint8_t MAX_RXNUM = 63;
inline uint8_t getMaxRxNum(uint8_t idx)
{
if (isModuleDSM2(idx))
return 20;
#if defined(MULTIMODULE)
if (isModuleMultimodule(idx)) {
switch (g_model.moduleData[idx].multi.rfProtocol) {
case MODULE_SUBTYPE_MULTI_OLRS:
return MODULE_SUBTYPE_MULTI_OLRS_RXNUM;
case MODULE_SUBTYPE_MULTI_BUGS:
return MODULE_SUBTYPE_MULTI_BUGS_RXNUM;
case MODULE_SUBTYPE_MULTI_BUGS_MINI:
return MODULE_SUBTYPE_MULTI_BUGS_MINI_RXNUM;
}
}
#endif
#if defined(AFHDS3)
if (isModuleAFHDS3(idx)) return AFHDS3_MAX_MODEL_ID;
#endif
return MAX_RXNUM;
}
inline const char * getModuleDelay(uint8_t idx)
{
if (isModuleISRMAccess(idx))
return sentModuleChannels(idx) > 16 ? "(21ms)" : (sentModuleChannels(idx) > 8 ? "(14ms)" : "(7ms)");
if (isModuleXJTD16(idx) || isModuleR9MNonAccess(idx))
return sentModuleChannels(idx) > 8 ? "(18ms)" : "(9ms)";
return nullptr;
}
inline bool isBindCh9To16Allowed(uint8_t moduleIndex)
{
if (g_model.moduleData[moduleIndex].channelsCount <= 0) {
return false;
}
if (isModuleR9M_LBT(moduleIndex)) {
if (isModuleR9MLite(moduleIndex))
return g_model.moduleData[moduleIndex].pxx.power != R9M_LBT_POWER_25_8CH;
else
return g_model.moduleData[moduleIndex].pxx.power != R9M_LITE_LBT_POWER_25_8CH;
}
else {
return true;
}
}
#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)
if (moduleIndex == INTERNAL_MODULE)
return true;
if (isSportLineUsedByInternalModule())
return false;
#endif
#if defined(HARDWARE_EXTERNAL_MODULE)
if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_R9M_LITE_PXX1) {
if (isModuleR9M_LBT(EXTERNAL_MODULE))
return g_model.moduleData[EXTERNAL_MODULE].pxx.power < R9M_LITE_LBT_POWER_100_16CH_NOTELEM;
else
return true;
}
if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_R9M_PXX1) {
if (isModuleR9M_LBT(EXTERNAL_MODULE))
return g_model.moduleData[EXTERNAL_MODULE].pxx.power < R9M_LBT_POWER_200_16CH_NOTELEM;
else
return true;
}
#endif
return true;
}
inline bool isPXX2ReceiverUsed(uint8_t moduleIdx, uint8_t receiverIdx)
{
return g_model.moduleData[moduleIdx].pxx2.receivers & (1 << receiverIdx);
}
inline void setPXX2ReceiverUsed(uint8_t moduleIdx, uint8_t receiverIdx)
{
g_model.moduleData[moduleIdx].pxx2.receivers |= (1 << receiverIdx);
storageDirty(EE_MODEL);
}
inline bool isPXX2ReceiverEmpty(uint8_t moduleIdx, uint8_t receiverIdx)
{
return is_memclear(g_model.moduleData[moduleIdx].pxx2.receiverName[receiverIdx], PXX2_LEN_RX_NAME);
}
inline void removePXX2Receiver(uint8_t moduleIdx, uint8_t receiverIdx)
{
memclear(g_model.moduleData[moduleIdx].pxx2.receiverName[receiverIdx], PXX2_LEN_RX_NAME);
g_model.moduleData[moduleIdx].pxx2.receivers &= ~(1 << receiverIdx);
storageDirty(EE_MODEL);
}
inline void removePXX2ReceiverIfEmpty(uint8_t moduleIdx, uint8_t receiverIdx)
{
if (isPXX2ReceiverEmpty(moduleIdx, receiverIdx)) {
removePXX2Receiver(moduleIdx, receiverIdx);
}
}
inline void setDefaultPpmFrameLength(uint8_t moduleIdx)
{
// channelsCount + 8 ???
g_model.moduleData[moduleIdx].ppm.frameLength =
4 * max<int>(0, g_model.moduleData[moduleIdx].channelsCount);
}
inline void setDefaultPpmFrameLengthTrainer()
{
g_model.trainerData.frameLength =
4 * max<int>(0, g_model.trainerData.channelsCount);
}
inline void resetAccessAuthenticationCount()
{
// the module will reset on mode switch, we need to reset the authentication counter
globalData.authenticationCount = 0;
}
inline void resetAfhdsOptions(uint8_t moduleIdx)
{
#if defined(AFHDS3)
auto & data = g_model.moduleData[moduleIdx];
data.subType = FLYSKY_SUBTYPE_AFHDS3;
data.afhds3.emi = 2; // FCC
data.afhds3.telemetry = 1;
data.afhds3.phyMode = 0;
#elif defined(AFHDS2)
auto & data = g_model.moduleData[moduleIdx];
data.subType = FLYSKY_SUBTYPE_AFHDS2A;
data.flysky.setDefault();
#endif
}
inline void setModuleType(uint8_t moduleIdx, uint8_t moduleType)
{
ModuleData & moduleData = g_model.moduleData[moduleIdx];
memclear(&moduleData, sizeof(ModuleData));
moduleData.type = moduleType;
moduleData.channelsCount = defaultModuleChannels_M8(moduleIdx);
if (moduleData.type == MODULE_TYPE_SBUS)
moduleData.sbus.refreshRate = -31;
else if (moduleData.type == MODULE_TYPE_PPM)
setDefaultPpmFrameLength(moduleIdx);
else if (moduleData.type == MODULE_TYPE_FLYSKY) {
resetAfhdsOptions(moduleIdx);
}
else
resetAccessAuthenticationCount();
}
extern bool isExternalAntennaEnabled();
#endif // _MODULES_HELPERS_H_