5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
23 #if defined(PCBTARANIS) || defined(PCBHORUS)
24 uint8_t switchToMix(uint8_t source
)
26 div_t qr
= div(source
-1, 3);
27 return qr
.quot
+MIXSRC_FIRST_SWITCH
;
30 uint8_t switchToMix(uint8_t source
)
35 return MIXSRC_FIRST_SWITCH
- 3 + source
;
39 int circularIncDec(int current
, int inc
, int min
, int max
, IsValueAvailable isValueAvailable
)
45 else if (current
> max
)
47 if (!isValueAvailable
|| isValueAvailable(current
))
53 bool isInputAvailable(int input
)
55 for (int i
=0; i
<MAX_EXPOS
; i
++) {
56 ExpoData
* expo
= expoAddress(i
);
57 if (!EXPO_VALID(expo
))
59 if (expo
->chn
== input
)
65 bool isRssiSensorAvailable(int sensor
)
70 TelemetrySensor
&telemSensor
= g_model
.telemetrySensors
[abs(sensor
) - 1];
71 return (telemSensor
.isAvailable() && telemSensor
.id
== RSSI_ID
);
75 bool isSensorAvailable(int sensor
)
80 return isTelemetryFieldAvailable(abs(sensor
) - 1);
83 bool isSensorUnit(int sensor
, uint8_t unit
)
85 if (sensor
<= 0 || sensor
> MAX_TELEMETRY_SENSORS
) {
89 return g_model
.telemetrySensors
[sensor
-1].unit
== unit
;
93 bool isCellsSensor(int sensor
)
95 return isSensorUnit(sensor
, UNIT_CELLS
);
98 bool isGPSSensor(int sensor
)
100 return isSensorUnit(sensor
, UNIT_GPS
);
103 bool isAltSensor(int sensor
)
105 return isSensorUnit(sensor
, UNIT_DIST
) || isSensorUnit(sensor
, UNIT_FEET
);
108 bool isVoltsSensor(int sensor
)
110 return isSensorUnit(sensor
, UNIT_VOLTS
) || isSensorUnit(sensor
, UNIT_CELLS
);
113 bool isCurrentSensor(int sensor
)
115 return isSensorUnit(sensor
, UNIT_AMPS
);
118 bool isTelemetryFieldAvailable(int index
)
120 TelemetrySensor
& sensor
= g_model
.telemetrySensors
[index
];
121 return sensor
.isAvailable();
124 bool isTelemetryFieldComparisonAvailable(int index
)
126 if (!isTelemetryFieldAvailable(index
))
129 TelemetrySensor
& sensor
= g_model
.telemetrySensors
[index
];
130 if (sensor
.unit
>= UNIT_DATETIME
)
135 bool isChannelUsed(int channel
)
137 for (int i
=0; i
<MAX_MIXERS
; ++i
) {
138 MixData
*md
= mixAddress(i
);
139 if (md
->srcRaw
== 0) return false;
140 if (md
->destCh
== channel
) return true;
141 if (md
->destCh
> channel
) return false;
146 int getChannelsUsed()
150 for (int i
=0; i
<MAX_MIXERS
; ++i
) {
151 MixData
*md
= mixAddress(i
);
152 if (md
->srcRaw
== 0) return result
;
153 if (md
->destCh
!= lastCh
) { ++result
; lastCh
= md
->destCh
; }
158 bool isSourceAvailable(int source
)
163 if (source
>= MIXSRC_FIRST_INPUT
&& source
<= MIXSRC_LAST_INPUT
) {
164 return isInputAvailable(source
- MIXSRC_FIRST_INPUT
);
167 #if defined(LUA_MODEL_SCRIPTS)
168 if (source
>= MIXSRC_FIRST_LUA
&& source
<= MIXSRC_LAST_LUA
) {
169 div_t qr
= div(source
- MIXSRC_FIRST_LUA
, MAX_SCRIPT_OUTPUTS
);
170 return (qr
.rem
<scriptInputsOutputs
[qr
.quot
].outputsCount
);
172 #elif defined(LUA_INPUTS)
173 if (source
>= MIXSRC_FIRST_LUA
&& source
<= MIXSRC_LAST_LUA
)
177 if (source
>= MIXSRC_FIRST_POT
&& source
<= MIXSRC_LAST_POT
) {
178 return IS_POT_SLIDER_AVAILABLE(POT1
+source
- MIXSRC_FIRST_POT
);
182 if (source
>= MIXSRC_MOUSE1
&& source
<= MIXSRC_MOUSE2
)
186 if (source
>= MIXSRC_FIRST_SWITCH
&& source
<= MIXSRC_LAST_SWITCH
) {
187 return SWITCH_EXISTS(source
- MIXSRC_FIRST_SWITCH
);
191 if (source
>= MIXSRC_CYC1
&& source
<= MIXSRC_CYC3
)
195 if (source
>= MIXSRC_FIRST_CH
&& source
<= MIXSRC_LAST_CH
) {
196 return isChannelUsed(source
- MIXSRC_FIRST_CH
);
199 if (source
>= MIXSRC_FIRST_LOGICAL_SWITCH
&& source
<= MIXSRC_LAST_LOGICAL_SWITCH
) {
200 LogicalSwitchData
* cs
= lswAddress(source
- MIXSRC_FIRST_LOGICAL_SWITCH
);
201 return (cs
->func
!= LS_FUNC_NONE
);
205 if (source
>= MIXSRC_GVAR1
&& source
<= MIXSRC_LAST_GVAR
)
209 if (source
>= MIXSRC_FIRST_RESERVE
&& source
<= MIXSRC_LAST_RESERVE
)
212 if (source
>= MIXSRC_FIRST_TELEM
&& source
<= MIXSRC_LAST_TELEM
) {
213 div_t qr
= div(source
- MIXSRC_FIRST_TELEM
, 3);
215 return isTelemetryFieldAvailable(qr
.quot
);
217 return isTelemetryFieldComparisonAvailable(qr
.quot
);
223 bool isSourceAvailableInGlobalFunctions(int source
)
225 if (source
>= MIXSRC_FIRST_TELEM
&& source
<= MIXSRC_LAST_TELEM
) {
228 return isSourceAvailable(source
);
231 bool isSourceAvailableInCustomSwitches(int source
)
233 bool result
= isSourceAvailable(source
);
235 if (result
&& source
>= MIXSRC_FIRST_TELEM
&& source
<= MIXSRC_LAST_TELEM
) {
236 div_t qr
= div(source
- MIXSRC_FIRST_TELEM
, 3);
237 result
= isTelemetryFieldComparisonAvailable(qr
.quot
);
243 bool isSourceAvailableInInputs(int source
)
245 if (source
>= MIXSRC_FIRST_POT
&& source
<= MIXSRC_LAST_POT
)
246 return IS_POT_SLIDER_AVAILABLE(POT1
+source
- MIXSRC_FIRST_POT
);
249 if (source
>= MIXSRC_MOUSE1
&& source
<= MIXSRC_MOUSE2
)
253 if (source
>= MIXSRC_Rud
&& source
<= MIXSRC_MAX
)
256 if (source
>= MIXSRC_FIRST_TRIM
&& source
<= MIXSRC_LAST_TRIM
)
259 if (source
>= MIXSRC_FIRST_SWITCH
&& source
<= MIXSRC_LAST_SWITCH
)
260 return SWITCH_EXISTS(source
- MIXSRC_FIRST_SWITCH
);
262 if (source
>= MIXSRC_FIRST_CH
&& source
<= MIXSRC_LAST_CH
)
265 if (source
>= MIXSRC_FIRST_LOGICAL_SWITCH
&& source
<= MIXSRC_LAST_LOGICAL_SWITCH
) {
266 LogicalSwitchData
* cs
= lswAddress(source
- MIXSRC_SW1
);
267 return (cs
->func
!= LS_FUNC_NONE
);
270 if (source
>= MIXSRC_FIRST_TRAINER
&& source
<= MIXSRC_LAST_TRAINER
)
273 if (source
>= MIXSRC_FIRST_TELEM
&& source
<= MIXSRC_LAST_TELEM
) {
274 div_t qr
= div(source
- MIXSRC_FIRST_TELEM
, 3);
275 return isTelemetryFieldAvailable(qr
.quot
) && isTelemetryFieldComparisonAvailable(qr
.quot
);
283 LogicalSwitchesContext
,
284 ModelCustomFunctionsContext
,
285 GeneralCustomFunctionsContext
,
290 bool isLogicalSwitchAvailable(int index
)
292 LogicalSwitchData
* lsw
= lswAddress(index
);
293 return (lsw
->func
!= LS_FUNC_NONE
);
296 bool isSwitchAvailable(int swtch
, SwitchContext context
)
298 bool negative
= false;
301 if (swtch
== -SWSRC_ON
|| swtch
== -SWSRC_ONE
) {
308 #if defined(PCBSKY9X)
309 if (swtch
>= SWSRC_FIRST_SWITCH
&& swtch
<= SWSRC_LAST_SWITCH
) {
314 if (swtch
>= SWSRC_FIRST_SWITCH
&& swtch
<= SWSRC_LAST_SWITCH
) {
315 div_t swinfo
= switchInfo(swtch
);
316 if (!SWITCH_EXISTS(swinfo
.quot
)) {
319 if (!IS_CONFIG_3POS(swinfo
.quot
)) {
323 if (swinfo
.rem
== 1) {
324 // mid position not available for 2POS switches
333 if (swtch
>= SWSRC_FIRST_MULTIPOS_SWITCH
&& swtch
<= SWSRC_LAST_MULTIPOS_SWITCH
) {
334 int index
= (swtch
- SWSRC_FIRST_MULTIPOS_SWITCH
) / XPOTS_MULTIPOS_COUNT
;
335 if (IS_POT_MULTIPOS(POT1
+index
)) {
336 StepsCalibData
* calib
= (StepsCalibData
*) &g_eeGeneral
.calib
[POT1
+index
];
337 return (calib
->count
>= ((swtch
- SWSRC_FIRST_MULTIPOS_SWITCH
) % XPOTS_MULTIPOS_COUNT
));
345 #if defined(PCBSKY9X) && defined(REVX)
346 if (swtch
== SWSRC_REa
) {
351 if (swtch
>= SWSRC_FIRST_LOGICAL_SWITCH
&& swtch
<= SWSRC_LAST_LOGICAL_SWITCH
) {
352 if (context
== GeneralCustomFunctionsContext
) {
355 else if (context
!= LogicalSwitchesContext
) {
356 return isLogicalSwitchAvailable(swtch
- SWSRC_FIRST_LOGICAL_SWITCH
);
360 if (context
!= ModelCustomFunctionsContext
&& context
!= GeneralCustomFunctionsContext
&& (swtch
== SWSRC_ON
|| swtch
== SWSRC_ONE
)) {
364 if (swtch
>= SWSRC_FIRST_FLIGHT_MODE
&& swtch
<= SWSRC_LAST_FLIGHT_MODE
) {
365 if (context
== MixesContext
|| context
== GeneralCustomFunctionsContext
) {
369 swtch
-= SWSRC_FIRST_FLIGHT_MODE
;
373 FlightModeData
* fm
= flightModeAddress(swtch
);
374 return (fm
->swtch
!= SWSRC_NONE
);
378 if (swtch
>= SWSRC_FIRST_SENSOR
&& swtch
<= SWSRC_LAST_SENSOR
) {
379 if (context
== GeneralCustomFunctionsContext
)
382 return isTelemetryFieldAvailable(swtch
- SWSRC_FIRST_SENSOR
);
388 bool isSwitchAvailableInLogicalSwitches(int swtch
)
390 return isSwitchAvailable(swtch
, LogicalSwitchesContext
);
393 bool isSwitchAvailableInCustomFunctions(int swtch
)
395 if (menuHandlers
[menuLevel
] == menuModelSpecialFunctions
)
396 return isSwitchAvailable(swtch
, ModelCustomFunctionsContext
);
398 return isSwitchAvailable(swtch
, GeneralCustomFunctionsContext
);
401 bool isSwitchAvailableInMixes(int swtch
)
403 return isSwitchAvailable(swtch
, MixesContext
);
406 #if defined(COLORLCD)
407 bool isSwitch2POSWarningStateAvailable(int state
)
409 return (state
!= 2); // two pos switch - middle state not available
411 #endif // #if defined(COLORLCD)
413 bool isSwitchAvailableInTimers(int swtch
)
416 if (swtch
< TMRMODE_COUNT
)
419 swtch
-= TMRMODE_COUNT
-1;
422 if (swtch
> -TMRMODE_COUNT
)
425 swtch
+= TMRMODE_COUNT
-1;
428 return isSwitchAvailable(swtch
, TimersContext
);
431 bool isThrottleSourceAvailable(int source
)
433 if (source
>= THROTTLE_SOURCE_FIRST_POT
&& source
< THROTTLE_SOURCE_FIRST_POT
+NUM_POTS
+NUM_SLIDERS
&& !IS_POT_SLIDER_AVAILABLE(POT1
+source
-THROTTLE_SOURCE_FIRST_POT
))
439 bool isLogicalSwitchFunctionAvailable(int function
)
441 return function
!= LS_FUNC_RANGE
;
444 bool isAssignableFunctionAvailable(int function
)
446 #if defined(OVERRIDE_CHANNEL_FUNCTION) || defined(GVARS)
447 bool modelFunctions
= (menuHandlers
[menuLevel
] == menuModelSpecialFunctions
);
451 case FUNC_OVERRIDE_CHANNEL
:
452 #if defined(OVERRIDE_CHANNEL_FUNCTION)
453 return modelFunctions
;
457 case FUNC_ADJUST_GVAR
:
459 return modelFunctions
;
467 #if !defined(DANGEROUS_MODULE_FUNCTIONS)
468 case FUNC_RANGECHECK
:
472 case FUNC_PLAY_SCRIPT
:
482 bool isSourceAvailableInGlobalResetSpecialFunction(int index
)
484 if (index
>= FUNC_RESET_PARAM_FIRST_TELEM
)
487 return isSourceAvailableInResetSpecialFunction(index
);
490 bool isSourceAvailableInResetSpecialFunction(int index
)
492 if (index
>= FUNC_RESET_PARAM_FIRST_TELEM
) {
493 TelemetrySensor
& telemetrySensor
= g_model
.telemetrySensors
[index
-FUNC_RESET_PARAM_FIRST_TELEM
];
494 return telemetrySensor
.isAvailable();
497 else if (index
== FUNC_RESET_TIMER3
) {
502 else if (index
== FUNC_RESET_TIMER2
) {
511 bool isR9MModeAvailable(int mode
)
513 #if defined(MODULE_PROTOCOL_FLEX)
516 return mode
<= MODULE_SUBTYPE_R9M_EU
;
521 bool isPxx2IsrmChannelsCountAllowed(int channels
)
523 if (g_model
.moduleData
[INTERNAL_MODULE
].subType
== MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16
&& channels
> 8)
525 return (channels
% 8 == 0);
528 bool isPxx2IsrmChannelsCountAllowed(int channels
)
534 bool isTrainerUsingModuleBay()
536 #if defined(PCBTARANIS)
537 if (TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE
<= g_model
.trainerData
.mode
&& g_model
.trainerData
.mode
<= TRAINER_MODE_MASTER_BATTERY_COMPARTMENT
)
543 bool isModuleUsingSport(uint8_t moduleBay
, uint8_t moduleType
)
545 switch (moduleType
) {
546 case MODULE_TYPE_NONE
:
547 case MODULE_TYPE_SBUS
:
548 case MODULE_TYPE_PPM
:
549 case MODULE_TYPE_DSM2
:
550 case MODULE_TYPE_MULTIMODULE
:
551 case MODULE_TYPE_ISRM_PXX2
:
552 case MODULE_TYPE_R9M_LITE_PXX2
:
553 case MODULE_TYPE_R9M_LITE_PRO_PXX2
:
556 case MODULE_TYPE_XJT_PXX1
:
557 // External XJT has a physical switch to disable S.PORT
558 case MODULE_TYPE_R9M_PXX1
:
559 // R9M telemetry is disabled by pulses (pxx1.cpp)
560 if (moduleBay
== EXTERNAL_MODULE
)
568 #if defined(HARDWARE_INTERNAL_MODULE)
569 bool isInternalModuleAvailable(int moduleType
)
571 if (moduleType
== MODULE_TYPE_NONE
)
574 #if defined(INTERNAL_MODULE_MULTI)
575 if (moduleType
== MODULE_TYPE_MULTIMODULE
)
581 if (moduleType
== MODULE_TYPE_XJT_PXX1
) {
582 #if defined(PXX1) && defined(INTERNAL_MODULE_PXX1)
583 return !isModuleUsingSport(EXTERNAL_MODULE
, g_model
.moduleData
[EXTERNAL_MODULE
].type
);
587 if (moduleType
== MODULE_TYPE_ISRM_PXX2
) {
588 #if defined(PXX2) && defined(INTERNAL_MODULE_PXX2)
593 if (moduleType
== MODULE_TYPE_PPM
) {
594 #if defined(PPM) && defined(INTERNAL_MODULE_PPM)
602 bool isExternalModuleAvailable(int moduleType
)
604 if (moduleType
== MODULE_TYPE_R9M_LITE_PRO_PXX1
)
607 #if !defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
608 if (isModuleTypeR9MLite(moduleType
) || moduleType
== MODULE_TYPE_XJT_LITE_PXX2
)
613 if (isModuleTypePXX1(moduleType
))
618 if (moduleType
== MODULE_TYPE_XJT_PXX1
)
622 #if !defined(HARDWARE_EXTERNAL_MODULE_SIZE_STD)
623 if (moduleType
== MODULE_TYPE_R9M_PXX1
|| moduleType
== MODULE_TYPE_R9M_PXX2
)
627 if (moduleType
== MODULE_TYPE_ISRM_PXX2
)
628 return false; // doesn't exist for now
630 #if !defined(PXX2) || !defined(EXTMODULE_USART)
631 if (moduleType
== MODULE_TYPE_XJT_LITE_PXX2
|| moduleType
== MODULE_TYPE_R9M_PXX2
|| moduleType
== MODULE_TYPE_R9M_LITE_PXX2
|| moduleType
== MODULE_TYPE_R9M_LITE_PRO_PXX2
) {
636 #if !defined(CROSSFIRE)
637 if (moduleType
== MODULE_TYPE_CROSSFIRE
)
642 if (moduleType
== MODULE_TYPE_DSM2
)
647 if (moduleType
== MODULE_TYPE_SBUS
)
651 #if !defined(MULTIMODULE)
652 if (moduleType
== MODULE_TYPE_MULTIMODULE
)
656 #if defined(HARDWARE_INTERNAL_MODULE)
657 if (isTrainerUsingModuleBay() || (isModuleUsingSport(EXTERNAL_MODULE
, moduleType
) && isModuleUsingSport(INTERNAL_MODULE
, g_model
.moduleData
[INTERNAL_MODULE
].type
)))
662 if (moduleType
== MODULE_TYPE_PPM
)
669 bool isRfProtocolAvailable(int protocol
)
671 #if defined(CROSSFIRE)
672 if (protocol
!= MODULE_SUBTYPE_PXX1_OFF
&& g_model
.moduleData
[EXTERNAL_MODULE
].type
== MODULE_TYPE_CROSSFIRE
) {
676 #if !defined(MODULE_PROTOCOL_D8)
677 if (protocol
== MODULE_SUBTYPE_PXX1_ACCST_D8
) {
681 #if defined(PCBTARANIS) || defined(PCBHORUS)
682 if (protocol
!= MODULE_SUBTYPE_PXX1_OFF
&& g_model
.moduleData
[EXTERNAL_MODULE
].type
== MODULE_TYPE_R9M_PXX1
) {
685 if (protocol
!= MODULE_SUBTYPE_PXX1_OFF
&& g_model
.moduleData
[EXTERNAL_MODULE
].type
== MODULE_TYPE_R9M_PXX2
) {
693 bool isTelemetryProtocolAvailable(int protocol
)
695 #if defined(PCBTARANIS)
696 if (protocol
== PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY
&& g_eeGeneral
.auxSerialMode
!= UART_MODE_TELEMETRY
) {
701 if (protocol
== PROTOCOL_TELEMETRY_CROSSFIRE
) {
705 #if !defined(MULTIMODULE)
706 if (protocol
== PROTOCOL_TELEMETRY_SPEKTRUM
|| protocol
== PROTOCOL_TELEMETRY_FLYSKY_IBUS
|| protocol
== PROTOCOL_TELEMETRY_MULTIMODULE
) {
711 #if defined(PCBHORUS)
712 if (protocol
== PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY
) {
720 bool isTrainerModeAvailable(int mode
)
722 #if defined(PCBTARANIS)
723 if (IS_EXTERNAL_MODULE_ENABLED() && (mode
== TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE
|| mode
== TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
))
727 #if defined(PCBTARANIS) && !defined(TRAINER_BATTERY_COMPARTMENT)
728 if (mode
== TRAINER_MODE_MASTER_BATTERY_COMPARTMENT
)
730 #elif defined(PCBTARANIS)
731 if (mode
== TRAINER_MODE_MASTER_BATTERY_COMPARTMENT
)
732 return g_eeGeneral
.auxSerialMode
== UART_MODE_SBUS_TRAINER
;
736 if (mode
== TRAINER_MODE_MASTER_BLUETOOTH
|| mode
== TRAINER_MODE_SLAVE_BLUETOOTH
)
738 #elif defined(BLUETOOTH)
739 if (g_eeGeneral
.bluetoothMode
!= BLUETOOTH_TRAINER
&& (mode
== TRAINER_MODE_MASTER_BLUETOOTH
|| mode
== TRAINER_MODE_SLAVE_BLUETOOTH
))
743 #if defined(PCBXLITE) && !defined(PCBXLITES)
744 if (mode
== TRAINER_MODE_MASTER_TRAINER_JACK
|| mode
== TRAINER_MODE_SLAVE
)
753 char filename
[sizeof(MODELS_PATH
)+1+sizeof(g_model
.header
.name
)+sizeof(TEXT_EXT
)] = MODELS_PATH
"/";
754 char *buf
= strcat_currentmodelname(&filename
[sizeof(MODELS_PATH
)]);
755 strcpy(buf
, TEXT_EXT
);
756 if (isFileAvailable(filename
)) {
761 buf
= strAppendFilename(&filename
[sizeof(MODELS_PATH
)], g_eeGeneral
.currModelFilename
, LEN_MODEL_FILENAME
);
762 strcpy(buf
, TEXT_EXT
);
763 if (isFileAvailable(filename
)) {
771 int getFirstAvailable(int min
, int max
, IsValueAvailable isValueAvailable
)
774 for (int i
= min
; i
<= max
; i
++) {
775 if (isValueAvailable(i
)) {
782 #if defined(MULTIMODULE)
784 // This maps OpenTX multi type with Pascal's Multi type
785 uint8_t convertMultiProtocol(uint8_t moduleIdx
, uint8_t type
)
788 // 15 for Multimodule is FrskyX or D16 which we map as a subprotocol of 3 (FrSky)
789 // all protos > frskyx are therefore also off by one
793 // 25 is again a FrSky protocol (FrskyV) so shift again
797 if (type
== MODULE_SUBTYPE_MULTI_FRSKY
) {
798 int subtype
= g_model
.moduleData
[moduleIdx
].subType
;
799 if (subtype
== MM_RF_FRSKY_SUBTYPE_D8
) {
803 else if (subtype
== MM_RF_FRSKY_SUBTYPE_V8
) {
814 // Third row is number of subtypes -1 (max valid subtype)
815 #define NO_SUBTYPE nullptr
817 // Table is designed to be shared with companion multi.cpp
819 // The subtype and options strings are only referenced here, so
820 // define them here to avoid duplication in all language files
821 // Also since these strings are ARM only and likely stay ARM only
822 // we don't need the special eeprom/flash string handling, just define them as
825 const char STR_SUBTYPE_FLYSKY
[] = "\004""Std\0""V9x9""V6x6""V912""CX20";
826 const char STR_SUBTYPE_HUBSAN
[] = "\004""H107""H301""H501";
827 const char STR_SUBTYPE_FRSKY
[] = "\007""D16\0 ""D8\0 ""D16 8ch""V8\0 ""LBT(EU)""LBT 8ch";
828 const char STR_SUBTYPE_HISKY
[] = "\005""Std\0 ""HK310";
829 const char STR_SUBTYPE_V2X2
[] = "\006""Std\0 ""JXD506";
830 const char STR_SUBTYPE_DSM
[] = "\006""2 22ms""2 11ms""X 22ms""X 11ms";
831 const char STR_SUBTYPE_DEVO
[] = "\004""8ch\0""10ch""12ch""6ch\0""7ch\0";
832 const char STR_SUBTYPE_YD717
[] = "\007""Std\0 ""SkyWlkr""Syma X4""XINXUN\0""NIHUI\0 ";
833 const char STR_SUBTYPE_KN
[] = "\006""WLtoys""FeiLun";
834 const char STR_SUBTYPE_SYMAX
[] = "\003""Std""X5C";
835 const char STR_SUBTYPE_SLT
[] = "\006""V1_6ch""V2_8ch""Q100\0 ""Q200\0 ""MR100\0";
836 const char STR_SUBTYPE_CX10
[] = "\007""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041";
837 const char STR_SUBTYPE_CG023
[] = "\005""Std\0 ""YD829";
838 const char STR_SUBTYPE_BAYANG
[] = "\007""Std\0 ""H8S3D\0 ""X16 AH\0""IRDrone""DHD D4";
839 const char STR_SUBTYPE_MT99
[] = "\006""MT99\0 ""H7\0 ""YZ\0 ""LS\0 ""FY805";
840 const char STR_SUBTYPE_MJXQ
[] = "\007""WLH08\0 ""X600\0 ""X800\0 ""H26D\0 ""E010\0 ""H26WH\0 ""Phoenix";
841 const char STR_SUBTYPE_FY326
[] = "\005""Std\0 ""FY319";
842 const char STR_SUBTYPE_HONTAI
[] = "\007""Std\0 ""JJRC X1""X5C1\0 ""FQ_951";
843 const char STR_SUBTYPE_AFHDS2A
[] = "\010""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS";
844 const char STR_SUBTYPE_Q2X2
[] = "\004""Q222""Q242""Q282";
845 const char STR_SUBTYPE_WK2x01
[] = "\006""WK2801""WK2401""W6_5_1""W6_6_1""W6_HeL""W6_HeI";
846 const char STR_SUBTYPE_Q303
[] = "\006""Std\0 ""CX35\0 ""CX10D\0""CX10WD";
847 const char STR_SUBTYPE_CABELL
[] = "\007""V3\0 ""V3 Telm""-\0 ""-\0 ""-\0 ""-\0 ""F-Safe\0""Unbind\0";
848 const char STR_SUBTYPE_H83D
[] = "\007""Std\0 ""H20H\0 ""H20Mini""H30Mini";
849 const char STR_SUBTYPE_CORONA
[] = "\005""V1\0 ""V2\0 ""FD V3";
850 const char STR_SUBTYPE_HITEC
[] = "\007""Optima\0""Opt Hub""Minima\0";
851 const char STR_SUBTYPE_BUGS_MINI
[] = "\006""Std\0 ""Bugs3H";
852 const char STR_SUBTYPE_TRAXXAS
[] = "\004""6519";
853 const char STR_SUBTYPE_E01X
[] = "\005""E012\0""E015\0""E016H";
854 const char STR_SUBTYPE_GD00X
[] = "\005""GD_V1""GD_V2";
855 const char STR_SUBTYPE_REDPINE
[] = "\004""Fast""Slow";
856 const char STR_SUBTYPE_POTENSIC
[] = "\003""A20";
857 const char STR_SUBTYPE_ZSX
[] = "\007""280JJRC";
858 const char STR_SUBTYPE_FLYZONE
[] = "\005""FZ410";
859 const char STR_SUBTYPE_FX816
[] = "\003""P38";
860 const char STR_SUBTYPE_ESKY150
[] = "\003""4CH""7CH";
862 const char* mm_options_strings::options
[] = {
874 const mm_protocol_definition multi_protocols
[] = {
875 // Protocol as defined in pulses\modules_constants.h, number of sub_protocols - 1, Failsafe supported, Disable channel mapping supported, Subtype string, Option type
876 {MODULE_SUBTYPE_MULTI_FLYSKY
, 4, false, true, STR_SUBTYPE_FLYSKY
, nullptr},
877 {MODULE_SUBTYPE_MULTI_HUBSAN
, 2, false, false, STR_SUBTYPE_HUBSAN
, STR_MULTI_VIDFREQ
},
878 {MODULE_SUBTYPE_MULTI_FRSKY
, 5, false, false, STR_SUBTYPE_FRSKY
, STR_MULTI_RFTUNE
},
879 {MODULE_SUBTYPE_MULTI_HISKY
, 1, false, true, STR_SUBTYPE_HISKY
, nullptr},
880 {MODULE_SUBTYPE_MULTI_V2X2
, 1, false, false, STR_SUBTYPE_V2X2
, nullptr},
881 {MODULE_SUBTYPE_MULTI_DSM2
, 3, false, true, STR_SUBTYPE_DSM
, STR_MULTI_MAX_THROW
},
882 {MODULE_SUBTYPE_MULTI_DEVO
, 4, false, true, STR_SUBTYPE_DEVO
, STR_MULTI_FIXEDID
},
883 {MODULE_SUBTYPE_MULTI_YD717
, 4, false, false, STR_SUBTYPE_YD717
, nullptr},
884 {MODULE_SUBTYPE_MULTI_KN
, 1, false, false, STR_SUBTYPE_KN
, nullptr},
885 {MODULE_SUBTYPE_MULTI_SYMAX
, 1, false, false, STR_SUBTYPE_SYMAX
, nullptr},
886 {MODULE_SUBTYPE_MULTI_SLT
, 4, false, true, STR_SUBTYPE_SLT
, nullptr},
887 {MODULE_SUBTYPE_MULTI_CX10
, 6, false, false, STR_SUBTYPE_CX10
, nullptr},
888 {MODULE_SUBTYPE_MULTI_CG023
, 1, false, false, STR_SUBTYPE_CG023
, nullptr},
889 {MODULE_SUBTYPE_MULTI_BAYANG
, 4, false, false, STR_SUBTYPE_BAYANG
, STR_MULTI_TELEMETRY
},
890 {MODULE_SUBTYPE_MULTI_MT99XX
, 4, false, false, STR_SUBTYPE_MT99
, nullptr},
891 {MODULE_SUBTYPE_MULTI_MJXQ
, 6, false, false, STR_SUBTYPE_MJXQ
, STR_MULTI_RFTUNE
},
892 {MODULE_SUBTYPE_MULTI_FY326
, 1, false, false, STR_SUBTYPE_FY326
, nullptr},
893 {MODULE_SUBTYPE_MULTI_SFHSS
, 0, true, true, NO_SUBTYPE
, STR_MULTI_RFTUNE
},
894 {MODULE_SUBTYPE_MULTI_HONTAI
, 3, false, false, STR_SUBTYPE_HONTAI
, nullptr},
895 {MODULE_SUBTYPE_MULTI_OLRS
, 0, false, false, NO_SUBTYPE
, STR_RFPOWER
},
896 {MODULE_SUBTYPE_MULTI_FS_AFHDS2A
, 3, true, true, STR_SUBTYPE_AFHDS2A
, STR_MULTI_SERVOFREQ
},
897 {MODULE_SUBTYPE_MULTI_Q2X2
, 2, false, false, STR_SUBTYPE_Q2X2
, nullptr},
898 {MODULE_SUBTYPE_MULTI_WK_2X01
, 5, false, true, STR_SUBTYPE_WK2x01
, nullptr},
899 {MODULE_SUBTYPE_MULTI_Q303
, 3, false, false, STR_SUBTYPE_Q303
, nullptr},
900 {MODULE_SUBTYPE_MULTI_CABELL
, 7, false, false, STR_SUBTYPE_CABELL
, STR_MULTI_OPTION
},
901 {MODULE_SUBTYPE_MULTI_H83D
, 3, false, false, STR_SUBTYPE_H83D
, nullptr},
902 {MODULE_SUBTYPE_MULTI_CORONA
, 2, false, false, STR_SUBTYPE_CORONA
, STR_MULTI_RFTUNE
},
903 {MODULE_SUBTYPE_MULTI_HITEC
, 2, false, false, STR_SUBTYPE_HITEC
, STR_MULTI_RFTUNE
},
904 {MODULE_SUBTYPE_MULTI_BUGS_MINI
, 1, false, false, STR_SUBTYPE_BUGS_MINI
, nullptr},
905 {MODULE_SUBTYPE_MULTI_TRAXXAS
, 0, false, false, STR_SUBTYPE_TRAXXAS
, nullptr},
906 {MODULE_SUBTYPE_MULTI_E01X
, 2, false, false, STR_SUBTYPE_E01X
, STR_MULTI_OPTION
},
907 {MODULE_SUBTYPE_MULTI_GD00X
, 1, false, false, STR_SUBTYPE_GD00X
, STR_MULTI_RFTUNE
},
908 {MODULE_SUBTYPE_MULTI_KF606
, 0, false, false, NO_SUBTYPE
, STR_MULTI_RFTUNE
},
909 {MODULE_SUBTYPE_MULTI_REDPINE
, 1, false, false, STR_SUBTYPE_REDPINE
, STR_MULTI_RFTUNE
},
910 {MODULE_SUBTYPE_MULTI_POTENSIC
, 0, false, false, STR_SUBTYPE_POTENSIC
, nullptr},
911 {MODULE_SUBTYPE_MULTI_ZSX
, 0, false, false, STR_SUBTYPE_ZSX
, nullptr},
912 {MODULE_SUBTYPE_MULTI_FLYZONE
, 0, false, false, STR_SUBTYPE_FLYZONE
, nullptr},
913 {MODULE_SUBTYPE_MULTI_FRSKYX_RX
, 0, false, false, NO_SUBTYPE
, STR_MULTI_RFTUNE
},
914 {MODULE_SUBTYPE_MULTI_ESky
, 0, false, true, NO_SUBTYPE
, nullptr},
915 {MODULE_SUBTYPE_MULTI_J6PRO
, 0, false, true, NO_SUBTYPE
, nullptr},
916 {MODULE_SUBTYPE_MULTI_ESKY150
, 1, false, false, STR_SUBTYPE_ESKY150
, nullptr},
917 {MODULE_SUBTYPE_MULTI_FX816
, 0, false, false, STR_SUBTYPE_FX816
, nullptr},
918 {MODULE_SUBTYPE_MULTI_HOTT
, 0, true, false, NO_SUBTYPE
, STR_MULTI_RFTUNE
},
919 {MM_RF_CUSTOM_SELECTED
, 7, true, true, NO_SUBTYPE
, STR_MULTI_OPTION
},
921 // Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff)
922 {0xfe, 0, false, true, NO_SUBTYPE
, nullptr}
927 const mm_protocol_definition
*getMultiProtocolDefinition (uint8_t protocol
)
929 const mm_protocol_definition
*pdef
;
930 for (pdef
= multi_protocols
; pdef
->protocol
!= 0xfe; pdef
++) {
931 if (pdef
->protocol
== protocol
)
934 // Return the empty last protocol
939 void editStickHardwareSettings(coord_t x
, coord_t y
, int idx
, event_t event
, LcdFlags flags
)
941 lcdDrawTextAtIndex(INDENT_WIDTH
, y
, STR_VSRCRAW
, idx
+1, 0);
942 if (ZEXIST(g_eeGeneral
.anaNames
[idx
]) || (flags
&& s_editMode
> 0))
943 editName(x
, y
, g_eeGeneral
.anaNames
[idx
], LEN_ANA_NAME
, event
, flags
);
945 lcdDrawMMM(x
, y
, flags
);