Files
edgetx-gx12/radio/src/pulses/modules_helpers.h
T
2019-07-19 09:31:30 +02:00

555 lines
13 KiB
C++

/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _MODULES_H_
#define _MODULES_H_
#include "bitfield.h"
#include "definitions.h"
#include "telemetry/telemetry.h"
#if defined(MULTIMODULE)
#include "telemetry/multi.h"
#endif
#define CROSSFIRE_CHANNELS_COUNT 16
#if defined(MULTIMODULE)
inline bool isModuleMultimodule(uint8_t idx)
{
return idx == EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_MULTIMODULE;
}
inline bool isModuleMultimoduleDSM2(uint8_t idx)
{
return isModuleMultimodule(idx) && g_model.moduleData[idx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2;
}
#else
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 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 isModuleISRM(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_ISRM_PXX2;
}
inline bool isModuleISRMD16(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_ISRM_PXX2 && g_model.moduleData[idx].subType == MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16;
}
inline bool isModuleD16(uint8_t idx)
{
return isModuleXJTD16(idx) || isModuleISRMD16(idx);
}
inline bool isModuleISRMAccess(uint8_t idx)
{
return g_model.moduleData[idx].type == MODULE_TYPE_ISRM_PXX2 && g_model.moduleData[idx].subType == MODULE_SUBTYPE_ISRM_PXX2_ACCESS;
}
#if defined(CROSSFIRE)
inline bool isModuleCrossfire(uint8_t idx)
{
return idx == EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_CROSSFIRE;
}
#else
inline bool isModuleCrossfire(uint8_t idx)
{
return false;
}
#endif
#if defined(PCBSKY9X)
inline bool isExtraModule(uint8_t idx)
{
return idx == EXTRA_MODULE;
}
#else
inline bool isExtraModule(uint8_t)
{
return false;
}
#endif
#if defined(INTERNAL_MODULE_PPM)
inline bool isModulePPM(uint8_t idx)
{
return (idx == INTERNAL_MODULE && g_model.moduleData[INTERNAL_MODULE].type == MODULE_TYPE_PPM) ||
(idx == EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_PPM);
}
#else
inline bool isModulePPM(uint8_t idx)
{
return isExtraModule(idx) ||
(idx == EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_PPM);
}
#endif
inline bool isModuleTypeR9MNonAccess(uint8_t type)
{
return type == MODULE_TYPE_R9M_PXX1 || type == MODULE_TYPE_R9M_LITE_PXX1 || type == MODULE_TYPE_R9M_LITE_PRO_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_PXX1 || 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 isModulePXX2(uint8_t idx)
{
return isModuleISRM(idx) || isModuleR9MAccess(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;
}
}
#if defined(DSM2)
inline bool isModuleDSM2(uint8_t idx)
{
return idx == EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_DSM2;
}
#else
inline bool isModuleDSM2(uint8_t idx)
{
return false;
}
#endif
#if defined(SBUS)
inline bool isModuleSBUS(uint8_t idx)
{
return idx == EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_SBUS;
}
#else
inline bool isModuleSBUS(uint8_t idx)
{
return false;
}
#endif
// order is the same as in enum Protocols in myeeprom.h (none, ppm, pxx, pxx2, dsm, crossfire, multi, r9m, r9m2, sbus)
static const int8_t maxChannelsModules[] = { 0, 8, 8, 16, -2, 8, 4, 8, 16, 8}; // relative to 8!
static const int8_t maxChannelsXJT[] = { 0, 8, 0, 4 }; // relative to 8!
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 idx)
{
if (isExtraModule(idx)) {
return MAX_EXTRA_MODULE_CHANNELS_M8;
}
else if (isModuleXJT(idx)) {
return maxChannelsXJT[1 + g_model.moduleData[idx].subType];
}
else if (isModuleR9M(idx)) {
if (isModuleR9M_LBT(idx)) {
if (isModuleR9MLite(idx))
return g_model.moduleData[idx].pxx.power == R9M_LITE_LBT_POWER_25_8CH ? 0 : 8;
else
return g_model.moduleData[idx].pxx.power == R9M_LBT_POWER_25_8CH ? 0 : 8;
}
else {
return 8; // always 16 channels in FCC / FLEX
}
}
else {
return maxChannelsModules[g_model.moduleData[idx].type];
}
}
inline int8_t defaultModuleChannels_M8(uint8_t idx)
{
if (isModulePPM(idx))
return 0; // 8 channels
else if (isModuleDSM2(idx))
return 0; // 8 channels
else if (isModuleMultimoduleDSM2(idx))
return -1; // 7 channels
else if (isModuleXJTD8(idx))
return 0; // 8 channels
else if (isModuleXJTLR12(idx))
return 4; // 12 channels
else if (isModulePXX2(idx))
return 8; // 16 channels
else
return maxModuleChannels_M8(idx);
}
inline int8_t sentModuleChannels(uint8_t idx)
{
if (isModuleCrossfire(idx))
return CROSSFIRE_CHANNELS_COUNT;
else if (isModuleMultimodule(idx) && !isModuleMultimoduleDSM2(idx))
return 16;
else
return 8 + g_model.moduleData[idx].channelsCount;
}
enum {
MODULE_OPTION_EXTERNAL_ANTENNA,
MODULE_OPTION_POWER,
MODULE_OPTION_SPECTRUM_ANALYSER,
MODULE_OPTION_POWER_METER,
};
/* Options order:
* - External antenna (0x01)
* - Power (0x02)
* - Spektrum analyser (0x04)
* - Power meter (0x08)
*/
static const uint8_t moduleOptions[] = {
#if defined(SIMU)
0b11111111, // None = display all options on SIMU
#else
0b00000000, // None = no option available on unknown modules
#endif
0b11110001, // XJT
0b11110001, // ISRM
0b11111101, // ISRM-PRO
0b11110101, // ISRM-S
0b11110010, // R9M
0b11110010, // R9MLite
0b11110110, // R9MLite-PRO
0b11110100, // ISRM-N
};
inline uint8_t getPXX2ModuleOptions(uint8_t modelId)
{
if (modelId < DIM(moduleOptions))
return moduleOptions[modelId];
else
return moduleOptions[0];
}
inline bool isModuleOptionAvailable(uint8_t modelId, uint8_t option)
{
return getPXX2ModuleOptions(modelId) & (1 << option);
}
enum {
RECEIVER_OPTION_OTA,
};
/* Options order:
* - OTA (0x01)
*/
static const uint8_t receiverOptions[] = {
#if defined(SIMU)
0b11111111, // None = display all options on SIMU
#else
0b00000000, // None = display all options on SIMU
#endif
0b11111110, // X8R
0b11111110, // RX8R
0b11111110, // RX8R-PRO
0b11111110, // RX6R
0b11111110, // RX4R
0b11111110, // G-RX8
0b11111110, // G-RX6
0b11111110, // X6R
0b11111110, // X4R
0b11111110, // X4R-SB
0b11111110, // XSR
0b11111110, // XSR-M
0b11111110, // RXSR
0b11111110, // S6R
0b11111110, // S8R
0b11111110, // XM
0b11111110, // XM+
0b11111110, // XMR
0b11111110, // R9
0b11111110, // R9-SLIM
0b11111110, // R9-SLIM+
0b11111110, // R9-MINI
0b11111110, // R9-MM
0b11111110, // R9-STAB
0b11111111, // R9-MINI+OTA
0b11111111, // R9-MM+OTA
};
enum ModuleCapabilities {
MODULE_CAPABILITY_COUNT
};
enum ReceiverCapabilities {
RECEIVER_CAPABILITY_FPORT,
RECEIVER_CAPABILITY_COUNT
};
inline uint8_t getPXX2ReceiverOptions(uint8_t modelId)
{
if (modelId < DIM(receiverOptions))
return receiverOptions[modelId];
else
return receiverOptions[0];
}
inline bool isReceiverOptionAvailable(uint8_t modelId, uint8_t option)
{
return getPXX2ReceiverOptions(modelId) & (1 << option);
}
inline bool isDefaultModelRegistrationID()
{
return memcmp(g_model.modelRegistrationID, g_eeGeneral.ownerRegistrationID, PXX2_LEN_REGISTRATION_ID) == 0;
}
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;
return false;
}
inline bool isModuleFailsafeAvailable(uint8_t idx)
{
#if defined(PXX2)
if (isModuleISRM(idx))
return true;
#endif
if (isModuleXJT(idx))
return g_model.moduleData[idx].subType == MODULE_SUBTYPE_PXX1_ACCST_D16;
#if defined(MULTIMODULE)
if (isModuleMultimodule(idx))
return multiModuleStatus.isValid() && multiModuleStatus.supportsFailsafe();
#endif
if (isModuleR9M(idx))
return true;
return false;
}
inline bool isModuleBindRangeAvailable(uint8_t moduleIdx)
{
return isModulePXX2(moduleIdx) || isModulePXX1(moduleIdx) || isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx);
}
inline uint8_t getMaxRxNum(uint8_t idx)
{
if (isModuleDSM2(idx))
return 20;
#if defined(MULTIMODULE)
if (isModuleMultimodule(idx))
return g_model.moduleData[idx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_OLRS ? 4 : 15;
#endif
return 63;
}
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;
}
}
inline bool isTelemAllowedOnBind(uint8_t moduleIndex)
{
#if defined(HARDWARE_INTERNAL_MODULE)
if (moduleIndex == INTERNAL_MODULE)
return isSportLineUsedByInternalModule();
if (isSportLineUsedByInternalModule())
return false;
#endif
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 || g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_R9M_LITE_PRO_PXX1) {
if (isModuleR9M_LBT(EXTERNAL_MODULE))
return g_model.moduleData[EXTERNAL_MODULE].pxx.power < R9M_LBT_POWER_200_16CH_NOTELEM;
else
return true;
}
return true;
}
#endif // _MODULES_H_