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 int circularIncDec(int current
, int inc
, int min
, int max
, IsValueAvailable isValueAvailable
)
29 else if (current
> max
)
31 if (!isValueAvailable
|| isValueAvailable(current
))
37 bool isInputAvailable(int input
)
39 for (int i
=0; i
<MAX_EXPOS
; i
++) {
40 ExpoData
* expo
= expoAddress(i
);
41 if (!EXPO_VALID(expo
))
43 if (expo
->chn
== input
)
49 bool isSensorAvailable(int sensor
)
54 return isTelemetryFieldAvailable(abs(sensor
) - 1);
57 bool isSensorUnit(int sensor
, uint8_t unit
)
59 if (sensor
<= 0 || sensor
> MAX_TELEMETRY_SENSORS
) {
63 return g_model
.telemetrySensors
[sensor
-1].unit
== unit
;
67 bool isCellsSensor(int sensor
)
69 return isSensorUnit(sensor
, UNIT_CELLS
);
72 bool isGPSSensor(int sensor
)
74 return isSensorUnit(sensor
, UNIT_GPS
);
77 bool isAltSensor(int sensor
)
79 return isSensorUnit(sensor
, UNIT_DIST
) || isSensorUnit(sensor
, UNIT_FEET
);
82 bool isVoltsSensor(int sensor
)
84 return isSensorUnit(sensor
, UNIT_VOLTS
) || isSensorUnit(sensor
, UNIT_CELLS
);
87 bool isCurrentSensor(int sensor
)
89 return isSensorUnit(sensor
, UNIT_AMPS
);
92 bool isTelemetryFieldAvailable(int index
)
94 TelemetrySensor
& sensor
= g_model
.telemetrySensors
[index
];
95 return sensor
.isAvailable();
98 bool isTelemetryFieldComparisonAvailable(int index
)
100 if (!isTelemetryFieldAvailable(index
))
103 TelemetrySensor
& sensor
= g_model
.telemetrySensors
[index
];
104 if (sensor
.unit
>= UNIT_DATETIME
)
109 bool isChannelUsed(int channel
)
111 for (int i
=0; i
<MAX_MIXERS
; ++i
) {
112 MixData
*md
= mixAddress(i
);
113 if (md
->srcRaw
== 0) return false;
114 if (md
->destCh
== channel
) return true;
115 if (md
->destCh
> channel
) return false;
120 int getChannelsUsed()
124 for (int i
=0; i
<MAX_MIXERS
; ++i
) {
125 MixData
*md
= mixAddress(i
);
126 if (md
->srcRaw
== 0) return result
;
127 if (md
->destCh
!= lastCh
) { ++result
; lastCh
= md
->destCh
; }
132 bool isSourceAvailable(int source
)
137 if (source
>=MIXSRC_FIRST_INPUT
&& source
<=MIXSRC_LAST_INPUT
) {
138 return isInputAvailable(source
- MIXSRC_FIRST_INPUT
);
141 #if defined(LUA_MODEL_SCRIPTS)
142 if (source
>=MIXSRC_FIRST_LUA
&& source
<=MIXSRC_LAST_LUA
) {
143 div_t qr
= div(source
-MIXSRC_FIRST_LUA
, MAX_SCRIPT_OUTPUTS
);
144 return (qr
.rem
<scriptInputsOutputs
[qr
.quot
].outputsCount
);
146 #elif defined(LUA_INPUTS)
147 if (source
>=MIXSRC_FIRST_LUA
&& source
<=MIXSRC_LAST_LUA
)
151 if (source
>=MIXSRC_FIRST_POT
&& source
<=MIXSRC_LAST_POT
) {
152 return IS_POT_SLIDER_AVAILABLE(POT1
+source
-MIXSRC_FIRST_POT
);
155 #if defined(PCBSKY9X) && defined(REVX)
156 if (source
== MIXSRC_REa
) {
162 if ((source
>=MIXSRC_S3
&& source
<=MIXSRC_S4
) || (source
>=MIXSRC_MOUSE1
&& source
<=MIXSRC_MOUSE2
))
166 if (source
>=MIXSRC_FIRST_SWITCH
&& source
<=MIXSRC_LAST_SWITCH
) {
167 return SWITCH_EXISTS(source
-MIXSRC_FIRST_SWITCH
);
171 if (source
>=MIXSRC_CYC1
&& source
<=MIXSRC_CYC3
)
175 if (source
>=MIXSRC_FIRST_CH
&& source
<=MIXSRC_LAST_CH
) {
176 return isChannelUsed(source
-MIXSRC_FIRST_CH
);
179 if (source
>=MIXSRC_FIRST_LOGICAL_SWITCH
&& source
<=MIXSRC_LAST_LOGICAL_SWITCH
) {
180 LogicalSwitchData
* cs
= lswAddress(source
-MIXSRC_FIRST_LOGICAL_SWITCH
);
181 return (cs
->func
!= LS_FUNC_NONE
);
185 if (source
>=MIXSRC_GVAR1
&& source
<=MIXSRC_LAST_GVAR
)
189 if (source
>=MIXSRC_FIRST_RESERVE
&& source
<=MIXSRC_LAST_RESERVE
)
192 if (source
>=MIXSRC_FIRST_TELEM
&& source
<=MIXSRC_LAST_TELEM
) {
193 div_t qr
= div(source
-MIXSRC_FIRST_TELEM
, 3);
195 return isTelemetryFieldAvailable(qr
.quot
);
197 return isTelemetryFieldComparisonAvailable(qr
.quot
);
203 bool isSourceAvailableInGlobalFunctions(int source
)
205 if (source
>=MIXSRC_FIRST_TELEM
&& source
<=MIXSRC_LAST_TELEM
) {
208 return isSourceAvailable(source
);
211 bool isSourceAvailableInCustomSwitches(int source
)
213 bool result
= isSourceAvailable(source
);
215 #if defined(TELEMETRY_FRSKY)
216 if (result
&& source
>=MIXSRC_FIRST_TELEM
&& source
<=MIXSRC_LAST_TELEM
) {
217 div_t qr
= div(source
-MIXSRC_FIRST_TELEM
, 3);
218 result
= isTelemetryFieldComparisonAvailable(qr
.quot
);
225 bool isInputSourceAvailable(int source
)
227 if (source
>=MIXSRC_FIRST_POT
&& source
<=MIXSRC_LAST_POT
) {
228 return IS_POT_SLIDER_AVAILABLE(POT1
+source
-MIXSRC_FIRST_POT
);
231 if (source
>=MIXSRC_Rud
&& source
<=MIXSRC_MAX
)
234 if (source
>=MIXSRC_FIRST_TRIM
&& source
<=MIXSRC_LAST_TRIM
)
237 if (source
>=MIXSRC_FIRST_SWITCH
&& source
<=MIXSRC_LAST_SWITCH
)
238 return SWITCH_EXISTS(source
-MIXSRC_FIRST_SWITCH
);
240 if (source
>=MIXSRC_FIRST_CH
&& source
<=MIXSRC_LAST_CH
)
243 if (source
>=MIXSRC_FIRST_LOGICAL_SWITCH
&& source
<=MIXSRC_LAST_LOGICAL_SWITCH
) {
244 LogicalSwitchData
* cs
= lswAddress(source
-MIXSRC_SW1
);
245 return (cs
->func
!= LS_FUNC_NONE
);
248 if (source
>=MIXSRC_FIRST_TRAINER
&& source
<=MIXSRC_LAST_TRAINER
)
251 if (source
>=MIXSRC_FIRST_TELEM
&& source
<=MIXSRC_LAST_TELEM
) {
252 div_t qr
= div(source
-MIXSRC_FIRST_TELEM
, 3);
253 return isTelemetryFieldAvailable(qr
.quot
) && isTelemetryFieldComparisonAvailable(qr
.quot
);
261 LogicalSwitchesContext
,
262 ModelCustomFunctionsContext
,
263 GeneralCustomFunctionsContext
,
268 bool isLogicalSwitchAvailable(int index
)
270 LogicalSwitchData
* lsw
= lswAddress(index
);
271 return (lsw
->func
!= LS_FUNC_NONE
);
274 bool isSwitchAvailable(int swtch
, SwitchContext context
)
276 bool negative
= false;
279 if (swtch
== -SWSRC_ON
|| swtch
== -SWSRC_ONE
) {
286 #if defined(PCBSKY9X)
287 if (swtch
>= SWSRC_FIRST_SWITCH
&& swtch
<= SWSRC_LAST_SWITCH
) {
292 if (swtch
>= SWSRC_FIRST_SWITCH
&& swtch
<= SWSRC_LAST_SWITCH
) {
293 div_t swinfo
= switchInfo(swtch
);
294 if (!SWITCH_EXISTS(swinfo
.quot
)) {
297 if (!IS_CONFIG_3POS(swinfo
.quot
)) {
301 if (swinfo
.rem
== 1) {
302 // mid position not available for 2POS switches
311 if (swtch
>= SWSRC_FIRST_MULTIPOS_SWITCH
&& swtch
<= SWSRC_LAST_MULTIPOS_SWITCH
) {
312 int index
= (swtch
- SWSRC_FIRST_MULTIPOS_SWITCH
) / XPOTS_MULTIPOS_COUNT
;
313 if (IS_POT_MULTIPOS(POT1
+index
)) {
314 StepsCalibData
* calib
= (StepsCalibData
*) &g_eeGeneral
.calib
[POT1
+index
];
315 return (calib
->count
>= ((swtch
- SWSRC_FIRST_MULTIPOS_SWITCH
) % XPOTS_MULTIPOS_COUNT
));
323 #if defined(PCBSKY9X) && defined(REVX)
324 if (swtch
== SWSRC_REa
) {
329 if (swtch
>= SWSRC_FIRST_LOGICAL_SWITCH
&& swtch
<= SWSRC_LAST_LOGICAL_SWITCH
) {
330 if (context
== GeneralCustomFunctionsContext
) {
333 else if (context
!= LogicalSwitchesContext
) {
334 return isLogicalSwitchAvailable(swtch
- SWSRC_FIRST_LOGICAL_SWITCH
);
338 if (context
!= ModelCustomFunctionsContext
&& context
!= GeneralCustomFunctionsContext
&& (swtch
== SWSRC_ON
|| swtch
== SWSRC_ONE
)) {
342 if (swtch
>= SWSRC_FIRST_FLIGHT_MODE
&& swtch
<= SWSRC_LAST_FLIGHT_MODE
) {
343 if (context
== MixesContext
|| context
== GeneralCustomFunctionsContext
) {
347 swtch
-= SWSRC_FIRST_FLIGHT_MODE
;
351 FlightModeData
* fm
= flightModeAddress(swtch
);
352 return (fm
->swtch
!= SWSRC_NONE
);
356 if (swtch
>= SWSRC_FIRST_SENSOR
&& swtch
<= SWSRC_LAST_SENSOR
) {
357 if (context
== GeneralCustomFunctionsContext
)
360 return isTelemetryFieldAvailable(swtch
- SWSRC_FIRST_SENSOR
);
366 bool isSwitchAvailableInLogicalSwitches(int swtch
)
368 return isSwitchAvailable(swtch
, LogicalSwitchesContext
);
371 bool isSwitchAvailableInCustomFunctions(int swtch
)
373 if (menuHandlers
[menuLevel
] == menuModelSpecialFunctions
)
374 return isSwitchAvailable(swtch
, ModelCustomFunctionsContext
);
376 return isSwitchAvailable(swtch
, GeneralCustomFunctionsContext
);
379 bool isSwitchAvailableInMixes(int swtch
)
381 return isSwitchAvailable(swtch
, MixesContext
);
384 #if defined(COLORLCD)
385 bool isSwitch2POSWarningStateAvailable(int state
)
387 return (state
!= 2); // two pos switch - middle state not available
389 #endif // #if defined(COLORLCD)
391 bool isSwitchAvailableInTimers(int swtch
)
394 if (swtch
< TMRMODE_COUNT
)
397 swtch
-= TMRMODE_COUNT
-1;
400 if (swtch
> -TMRMODE_COUNT
)
403 swtch
+= TMRMODE_COUNT
-1;
406 return isSwitchAvailable(swtch
, TimersContext
);
409 bool isThrottleSourceAvailable(int source
)
411 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
))
417 bool isLogicalSwitchFunctionAvailable(int function
)
419 return function
!= LS_FUNC_RANGE
;
422 bool isAssignableFunctionAvailable(int function
)
424 #if defined(OVERRIDE_CHANNEL_FUNCTION) || defined(GVARS)
425 bool modelFunctions
= (menuHandlers
[menuLevel
] == menuModelSpecialFunctions
);
429 case FUNC_OVERRIDE_CHANNEL
:
430 #if defined(OVERRIDE_CHANNEL_FUNCTION)
431 return modelFunctions
;
435 case FUNC_ADJUST_GVAR
:
437 return modelFunctions
;
445 #if !defined(DANGEROUS_MODULE_FUNCTIONS)
446 case FUNC_RANGECHECK
:
450 case FUNC_PLAY_SCRIPT
:
460 bool isSourceAvailableInGlobalResetSpecialFunction(int index
)
462 if (index
>= FUNC_RESET_PARAM_FIRST_TELEM
)
465 return isSourceAvailableInResetSpecialFunction(index
);
468 bool isSourceAvailableInResetSpecialFunction(int index
)
470 if (index
>= FUNC_RESET_PARAM_FIRST_TELEM
) {
471 TelemetrySensor
& telemetrySensor
= g_model
.telemetrySensors
[index
-FUNC_RESET_PARAM_FIRST_TELEM
];
472 return telemetrySensor
.isAvailable();
475 else if (index
== FUNC_RESET_TIMER3
) {
480 else if (index
== FUNC_RESET_TIMER2
) {
490 bool isModuleAvailable(int module
)
492 #if defined(CROSSFIRE)
493 if (module
== MODULE_TYPE_CROSSFIRE
&& g_model
.moduleData
[INTERNAL_MODULE
].type
!= MODULE_TYPE_NONE
) {
497 if (module
== MODULE_TYPE_CROSSFIRE
) {
502 if (module
== MODULE_TYPE_DSM2
) {
506 #if !defined(MULTIMODULE)
507 if (module
== MODULE_TYPE_MULTIMODULE
) {
514 bool isRfProtocolAvailable(int protocol
)
516 #if defined(CROSSFIRE)
517 if (protocol
!= RF_PROTO_OFF
&& g_model
.moduleData
[EXTERNAL_MODULE
].type
== MODULE_TYPE_CROSSFIRE
) {
521 #if defined(MODULE_D16_EU_ONLY_SUPPORT)
522 if (protocol
== RF_PROTO_D8
) {
529 bool isTelemetryProtocolAvailable(int protocol
)
531 #if defined(PCBTARANIS)
532 if (protocol
== PROTOCOL_FRSKY_D_SECONDARY
&& g_eeGeneral
.serial2Mode
!= UART_MODE_TELEMETRY
) {
537 if (protocol
== PROTOCOL_PULSES_CROSSFIRE
) {
541 #if !defined(MULTIMODULE)
542 if (protocol
== PROTOCOL_SPEKTRUM
|| protocol
== PROTOCOL_FLYSKY_IBUS
|| protocol
== PROTOCOL_MULTIMODULE
) {
547 #if defined(PCBHORUS)
548 if (protocol
== PROTOCOL_FRSKY_D_SECONDARY
) {
556 #if defined(PCBHORUS)
557 bool isTrainerModeAvailable(int mode
)
561 #elif defined(PCBX9E)
562 bool isTrainerModeAvailable(int mode
)
564 if (IS_EXTERNAL_MODULE_ENABLED() && (mode
== TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE
|| mode
== TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
))
566 #if defined(USEHORUSBT)
567 else if (mode
== TRAINER_MODE_MASTER_BATTERY_COMPARTMENT
)
569 else if (mode
== TRAINER_MODE_MASTER_BLUETOOTH
|| mode
== TRAINER_MODE_MASTER_BATTERY_COMPARTMENT
|| mode
== TRAINER_MODE_SLAVE_BLUETOOTH
)
576 bool isTrainerModeAvailable(int mode
)
578 if (IS_EXTERNAL_MODULE_ENABLED() && (mode
== TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE
|| mode
== TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
))
584 bool isTrainerModeAvailable(int mode
)
586 if (IS_EXTERNAL_MODULE_ENABLED() && (mode
== TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE
|| mode
== TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
))
588 else if (mode
== TRAINER_MODE_MASTER_BATTERY_COMPARTMENT
)
590 #if defined(BLUETOOTH)
591 else if (g_eeGeneral
.bluetoothMode
!= BLUETOOTH_TRAINER
&& (mode
== TRAINER_MODE_MASTER_BLUETOOTH
|| mode
== TRAINER_MODE_SLAVE_BLUETOOTH
))
597 #elif defined(PCBXLITE)
598 bool isTrainerModeAvailable(int mode
)
600 if ((g_eeGeneral
.bluetoothMode
== BLUETOOTH_TRAINER
&& (mode
== TRAINER_MODE_MASTER_BLUETOOTH
|| mode
== TRAINER_MODE_SLAVE_BLUETOOTH
)) || mode
== TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
)
609 char filename
[sizeof(MODELS_PATH
)+1+sizeof(g_model
.header
.name
)+sizeof(TEXT_EXT
)] = MODELS_PATH
"/";
610 char *buf
= strcat_currentmodelname(&filename
[sizeof(MODELS_PATH
)]);
611 strcpy(buf
, TEXT_EXT
);
612 if (isFileAvailable(filename
)) {
617 buf
= strAppendFilename(&filename
[sizeof(MODELS_PATH
)], g_eeGeneral
.currModelFilename
, LEN_MODEL_FILENAME
);
618 strcpy(buf
, TEXT_EXT
);
619 if (isFileAvailable(filename
)) {
627 int getFirstAvailable(int min
, int max
, IsValueAvailable isValueAvailable
)
630 for (int i
= min
; i
<= max
; i
++) {
631 if (isValueAvailable(i
)) {
638 #if defined(MULTIMODULE)
639 // Third row is number of subtypes -1 (max valid subtype)
640 #define NO_SUBTYPE nullptr
642 // Table is designed to be shared with companion multi.cpp
644 // The subtype and options strings are only referenced here, so
645 // define them here to avoid duplication in all language files
646 // Also since these strings are ARM only and likely stay ARM only
647 // we don't need the special eeprom/flash string handling, just define them as
650 const pm_char STR_SUBTYPE_FLYSKY
[] PROGMEM
= "\004""Std\0""V9x9""V6x6""V912""CX20";
652 const pm_char STR_SUBTYPE_AFHDS2A
[] PROGMEM
= "\010""PWM,IBUS""PPM,IBUS""PWM,SBUS""PPM,SBUS";
654 const pm_char STR_SUBTYPE_FRSKY
[] PROGMEM
= "\007""D16\0 ""D8\0 ""D16 8ch""V8\0 ""LBT(EU)""LBT 8ch";
656 const pm_char STR_SUBTYPE_HISKY
[] PROGMEM
= "\005""HiSky""HK310";
658 const pm_char STR_SUBTYPE_DSM
[] PROGMEM
= "\006""2 22ms""2 11ms""X 22ms""X 11ms";
660 const pm_char STR_SUBTYPE_YD717
[] PROGMEM
= "\007""YD717\0 ""SKYWLKR""Syma X2""XINXUN\0""NIHUI\0 ";
662 const pm_char STR_SUBTYPE_SYMAX
[] PROGMEM
= "\003""Std""5c\0";
664 const pm_char STR_SUBTYPE_SLT
[] PROGMEM
= "\005""SLT\0 ""Vista";
666 const pm_char STR_SUBTYPE_CX10
[] PROGMEM
= "\007""Green\0 ""Blue\0 ""DM007\0 ""-\0 ""JC3015a""JC3015b""MK33041""Q242\0 ";
668 const pm_char STR_SUBTYPE_CG023
[] PROGMEM
= "\005""CG023""YD829";
670 const pm_char STR_SUBTYPE_KN
[] PROGMEM
= "\006""WLtoys""FeiLun";
672 const pm_char STR_SUBTYPE_MT99
[] PROGMEM
= "\005""MT99\0""H7\0 ""YZ\0 ""LS\0 ""FY805";
674 const pm_char STR_SUBTYPE_MJXQ
[] PROGMEM
= "\005""WLH08""X600\0""X800\0""H26D\0""E010\0""H26WH";
676 const pm_char STR_SUBTYPE_HONTAI
[] PROGMEM
= "\007""Std\0 ""JJRC X1""X5C1cln";
678 const pm_char STR_SUBTYPE_Q2X2
[] PROGMEM
= "\004""Q222""Q242""Q282";
680 const pm_char STR_SUBTYPE_Q303
[] PROGMEM
= "\006""Q303\0 ""CX35\0 ""CX10D\0""CX10WD";
682 const pm_char STR_SUBTYPE_WK2x01
[] PROGMEM
= "\006""WK2801""WK2401""W6_5_1""W6_6_1""W6_Hel""W6_HeI";
684 const pm_char STR_SUBTYPE_V2X2
[] PROGMEM
= "\006""V2x2\0 ""JXD506";
686 const pm_char STR_SUBTYPE_BAYANG
[] PROGMEM
= "\007""Bayang\0""H8S3D\0 ""X16 AH\0 ""irdrone";
688 const pm_char STR_SUBTYPE_FY326
[] PROGMEM
= "\005""FY326""FY319";
690 const pm_char STR_SUBTYPE_CABELL
[] PROGMEM
= "\006""CAB_V3""C_TELM""-\0 ""-\0 ""-\0 ""-\0 ""F_SAFE""UNBIND";
692 const pm_char STR_SUBTYPE_H83D
[] PROGMEM
= "\006""H8_3D\0""H20H\0 ""H20Mini""H30Mini";
694 const mm_protocol_definition multi_protocols
[] = {
696 {MM_RF_PROTO_FLYSKY
, 4, false, STR_SUBTYPE_FLYSKY
, nullptr},
697 {MM_RF_PROTO_HUBSAN
, 0, false, NO_SUBTYPE
, STR_MULTI_VIDFREQ
},
698 {MM_RF_PROTO_FRSKY
, 5, false, STR_SUBTYPE_FRSKY
, STR_MULTI_RFTUNE
},
699 {MM_RF_PROTO_HISKY
, 1, false, STR_SUBTYPE_HISKY
, nullptr},
700 {MM_RF_PROTO_V2X2
, 1, false, STR_SUBTYPE_V2X2
, nullptr},
701 {MM_RF_PROTO_DSM2
, 3, false, STR_SUBTYPE_DSM
, nullptr},
702 {MM_RF_PROTO_YD717
, 4, false, STR_SUBTYPE_YD717
, nullptr},
703 {MM_RF_PROTO_KN
, 1, false, STR_SUBTYPE_KN
, nullptr},
704 {MM_RF_PROTO_SYMAX
, 1, false, STR_SUBTYPE_SYMAX
, nullptr},
705 {MM_RF_PROTO_SLT
, 1, false, STR_SUBTYPE_SLT
, nullptr},
706 {MM_RF_PROTO_CX10
, 7, false, STR_SUBTYPE_CX10
, nullptr},
707 {MM_RF_PROTO_CG023
, 1, false, STR_SUBTYPE_CG023
, nullptr},
708 {MM_RF_PROTO_BAYANG
, 3, false, STR_SUBTYPE_BAYANG
, STR_MULTI_TELEMETRY
},
709 {MM_RF_PROTO_MT99XX
, 4, false, STR_SUBTYPE_MT99
, nullptr},
710 {MM_RF_PROTO_MJXQ
, 5, false, STR_SUBTYPE_MJXQ
, nullptr},
711 {MM_RF_PROTO_FY326
, 1, false, STR_SUBTYPE_FY326
, nullptr},
712 {MM_RF_PROTO_SFHSS
, 0, true, NO_SUBTYPE
, STR_MULTI_RFTUNE
},
713 {MM_RF_PROTO_HONTAI
, 2, false, STR_SUBTYPE_HONTAI
, nullptr},
714 {MM_RF_PROTO_OLRS
, 0, false, NO_SUBTYPE
, STR_MULTI_RFPOWER
},
715 {MM_RF_PROTO_FS_AFHDS2A
, 3, true, STR_SUBTYPE_AFHDS2A
, STR_MULTI_SERVOFREQ
},
716 {MM_RF_PROTO_Q2X2
, 2, false, STR_SUBTYPE_Q2X2
, nullptr},
717 {MM_RF_PROTO_WK_2X01
, 5, false, STR_SUBTYPE_WK2x01
, nullptr},
718 {MM_RF_PROTO_Q303
, 3, false, STR_SUBTYPE_Q303
, nullptr},
719 {MM_RF_PROTO_CABELL
, 7, false, STR_SUBTYPE_CABELL
, STR_MULTI_OPTION
},
720 {MM_RF_PROTO_H83D
, 3, false, STR_SUBTYPE_H83D
, nullptr},
721 {MM_RF_CUSTOM_SELECTED
, 7, true, NO_SUBTYPE
, STR_MULTI_OPTION
},
723 // Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff)
724 {0xfe, 0, false, NO_SUBTYPE
, nullptr}
729 const mm_protocol_definition
*getMultiProtocolDefinition (uint8_t protocol
)
731 const mm_protocol_definition
*pdef
;
732 for (pdef
= multi_protocols
; pdef
->protocol
!= 0xfe; pdef
++) {
733 if (pdef
->protocol
== protocol
)
736 // Return the empty last protocol
741 void editStickHardwareSettings(coord_t x
, coord_t y
, int idx
, event_t event
, LcdFlags flags
)
743 lcdDrawTextAtIndex(INDENT_WIDTH
, y
, STR_VSRCRAW
, idx
+1, 0);
744 if (ZEXIST(g_eeGeneral
.anaNames
[idx
]) || (flags
&& s_editMode
> 0))
745 editName(x
, y
, g_eeGeneral
.anaNames
[idx
], LEN_ANA_NAME
, event
, flags
);
747 lcdDrawMMM(x
, y
, flags
);