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 // TODO find why we need this (for REGISTER at least)
25 #define EVT_BUTTON_PRESSED() EVT_KEY_FIRST(KEY_ENTER)
27 #define EVT_BUTTON_PRESSED() EVT_KEY_BREAK(KEY_ENTER)
32 #if defined(PCBTARANIS)
33 uint8_t getSwitchWarningsCount()
36 for (int i
=0; i
<NUM_SWITCHES
; ++i
) {
37 if (SWITCH_WARNING_ALLOWED(i
)) {
45 enum MenuModelSetupItems
{
46 ITEM_MODEL_SETUP_NAME
,
47 ITEM_MODEL_SETUP_TIMER1
,
48 ITEM_MODEL_SETUP_TIMER1_NAME
,
49 ITEM_MODEL_SETUP_TIMER1_PERSISTENT
,
50 ITEM_MODEL_SETUP_TIMER1_MINUTE_BEEP
,
51 ITEM_MODEL_SETUP_TIMER1_COUNTDOWN_BEEP
,
52 ITEM_MODEL_SETUP_TIMER2
,
53 ITEM_MODEL_SETUP_TIMER2_NAME
,
54 ITEM_MODEL_SETUP_TIMER2_PERSISTENT
,
55 ITEM_MODEL_SETUP_TIMER2_MINUTE_BEEP
,
56 ITEM_MODEL_SETUP_TIMER2_COUNTDOWN_BEEP
,
57 ITEM_MODEL_SETUP_TIMER3
,
58 ITEM_MODEL_SETUP_TIMER3_NAME
,
59 ITEM_MODEL_SETUP_TIMER3_PERSISTENT
,
60 ITEM_MODEL_SETUP_TIMER3_MINUTE_BEEP
,
61 ITEM_MODEL_SETUP_TIMER3_COUNTDOWN_BEEP
,
62 ITEM_MODEL_SETUP_EXTENDED_LIMITS
,
63 ITEM_MODEL_SETUP_EXTENDED_TRIMS
,
64 ITEM_MODEL_SETUP_DISPLAY_TRIMS
,
65 ITEM_MODEL_SETUP_TRIM_INC
,
66 ITEM_MODEL_SETUP_THROTTLE_REVERSED
,
67 ITEM_MODEL_SETUP_THROTTLE_TRACE
,
68 ITEM_MODEL_SETUP_THROTTLE_TRIM
,
69 ITEM_MODEL_SETUP_PREFLIGHT_LABEL
,
70 ITEM_MODEL_SETUP_CHECKLIST_DISPLAY
,
71 ITEM_MODEL_SETUP_THROTTLE_WARNING
,
72 ITEM_MODEL_SETUP_SWITCHES_WARNING1
,
73 #if defined(PCBTARANIS)
74 ITEM_MODEL_SETUP_SWITCHES_WARNING2
,
75 ITEM_MODEL_SETUP_POTS_WARNING
,
77 ITEM_MODEL_SETUP_BEEP_CENTER
,
78 ITEM_MODEL_SETUP_USE_GLOBAL_FUNCTIONS
,
81 ITEM_MODEL_SETUP_REGISTRATION_ID
,
84 #if defined(HARDWARE_INTERNAL_MODULE)
85 ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL
,
86 ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE
,
87 ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS
,
88 ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND
,
89 ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM
,
90 #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
91 ITEM_MODEL_SETUP_INTERNAL_MODULE_ANTENNA
,
93 ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE
,
94 ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE
,
95 ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS
,
96 ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1
,
97 ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2
,
98 ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_3
,
101 ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL
,
102 ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE
,
103 #if defined(MULTIMODULE)
104 ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE
,
106 #if defined(MULTIMODULE)
107 ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS
,
108 ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS
,
110 ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS
,
111 ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND
,
112 ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM
,
113 #if defined(PCBSKY9X) && defined(REVX)
114 ITEM_MODEL_SETUP_EXTERNAL_MODULE_OUTPUT_TYPE
,
116 ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER
,
117 ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS
,
118 #if defined(MULTIMODULE)
119 ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND
,
120 ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM
,
121 ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING
,
123 ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE
,
124 ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_REGISTER_RANGE
,
125 ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_OPTIONS
,
126 ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1
,
127 ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_2
,
128 ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_3
,
130 #if defined(PCBSKY9X)
131 ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL
,
132 ITEM_MODEL_SETUP_EXTRA_MODULE_CHANNELS
,
133 ITEM_MODEL_SETUP_EXTRA_MODULE_BIND
,
136 #if defined(PCBTARANIS)
137 ITEM_MODEL_SETUP_TRAINER_LABEL
,
138 ITEM_MODEL_SETUP_TRAINER_MODE
,
139 #if defined(BLUETOOTH)
140 ITEM_MODEL_SETUP_TRAINER_BLUETOOTH
,
142 ITEM_MODEL_SETUP_TRAINER_CHANNELS
,
143 ITEM_MODEL_SETUP_TRAINER_PPM_PARAMS
,
145 ITEM_MODEL_SETUP_LINES_COUNT
148 #define MODEL_SETUP_2ND_COLUMN (LCD_W-11*FW)
149 #define MODEL_SETUP_BIND_OFS 2*FW+1
150 #define MODEL_SETUP_RANGE_OFS 4*FW+3
151 #define MODEL_SETUP_SET_FAILSAFE_OFS 7*FW-2
153 #define IF_PXX2_MODULE(module, xxx) (isModulePXX2(module) ? (uint8_t)(xxx) : HIDDEN_ROW)
154 #define IF_NOT_PXX2_MODULE(module, xxx) (isModulePXX2(module) ? HIDDEN_ROW : (uint8_t)(xxx))
155 #define IF_ACCESS_MODULE_RF(module, xxx) (isModuleRFAccess(module) ? (uint8_t)(xxx) : HIDDEN_ROW)
156 #define IF_NOT_ACCESS_MODULE_RF(module, xxx) (isModuleRFAccess(module) ? HIDDEN_ROW : (uint8_t)(xxx))
159 #define REGISTRATION_ID_ROWS uint8_t((isDefaultModelRegistrationID() || (warningText && popupFunc == runPopupRegister)) ? HIDDEN_ROW : READONLY_ROW),
161 #define REGISTRATION_ID_ROWS
164 #if defined(HARDWARE_INTERNAL_MODULE)
165 #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL ? EXTERNAL_MODULE : INTERNAL_MODULE)
166 #define CURRENT_RECEIVER_EDITED(k) (k - (k >= ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL ? ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1 : ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1))
167 #elif defined(PCBSKY9X)
168 #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL ? EXTRA_MODULE : EXTERNAL_MODULE)
170 #define CURRENT_MODULE_EDITED(k) (EXTERNAL_MODULE)
171 #define CURRENT_RECEIVER_EDITED(k) (k - ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1)
174 #define MAX_SWITCH_PER_LINE (getSwitchWarningsCount() > 5 ? 4 : 5)
175 #if defined(PCBXLITE)
176 #define SW_WARN_ROWS uint8_t(NAVIGATION_LINE_BY_LINE|getSwitchWarningsCount()), uint8_t(getSwitchWarningsCount() > 4 ? TITLE_ROW : HIDDEN_ROW) // X-Lite needs an additional column for full line selection (<])
178 #define SW_WARN_ROWS uint8_t(NAVIGATION_LINE_BY_LINE|(getSwitchWarningsCount()-1)), uint8_t(getSwitchWarningsCount() > MAX_SWITCH_PER_LINE ? TITLE_ROW : HIDDEN_ROW)
181 #if defined(INTERNAL_MODULE_PXX1)
182 #define INTERNAL_MODULE_TYPE_ROWS ((isModuleXJT(INTERNAL_MODULE) || isModulePXX2(INTERNAL_MODULE)) ? (uint8_t)1 : (uint8_t)0) // Module type + RF protocols
184 #define INTERNAL_MODULE_TYPE_ROWS (0) // Module type + RF protocols
187 #if defined(PCBSKY9X) && defined(REVX)
188 #define OUTPUT_TYPE_ROW (isModulePPM(EXTERNAL_MODULE) ? (uint8_t)0 : HIDDEN_ROW),
189 #elif defined(PCBSKY9X)
190 #define OUTPUT_TYPE_ROW
193 inline uint8_t EXTERNAL_MODULE_TYPE_ROW()
195 if (isModuleXJT(EXTERNAL_MODULE
) || isModuleR9MNonAccess(EXTERNAL_MODULE
) || isModuleDSM2(EXTERNAL_MODULE
))
197 #if defined(MULTIMODULE)
198 else if (isModuleMultimodule(EXTERNAL_MODULE
)) {
206 #define POT_WARN_ROWS ((g_model.potsWarnMode) ? (uint8_t)(NUM_POTS+NUM_SLIDERS) : (uint8_t)0)
207 #define TIMER_ROWS 2, 0, 0, 0, 0
209 #if defined(PCBSKY9X)
210 #define EXTRA_MODULE_ROWS LABEL(ExtraModule), 1, 2,
212 #define EXTRA_MODULE_ROWS
215 #define TRAINER_CHANNELS_ROW (IS_SLAVE_TRAINER() ? (IS_BLUETOOTH_TRAINER() ? (uint8_t)0 : (uint8_t)1) : HIDDEN_ROW)
216 #define TRAINER_PPM_PARAMS_ROW (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)2 : HIDDEN_ROW)
217 #define TRAINER_BLUETOOTH_M_ROW ((bluetooth.distantAddr[0] == '\0' || bluetooth.state == BLUETOOTH_STATE_CONNECTED) ? (uint8_t)0 : (uint8_t)1)
218 #define TRAINER_BLUETOOTH_S_ROW (bluetooth.distantAddr[0] == '\0' ? HIDDEN_ROW : LABEL())
219 #define IF_BT_TRAINER_ON(x) (g_eeGeneral.bluetoothMode == BLUETOOTH_TRAINER ? (uint8_t)(x) : HIDDEN_ROW)
221 #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
222 #define EXTERNAL_ANTENNA_ROW ((isModuleXJT(INTERNAL_MODULE) && g_eeGeneral.antennaMode == ANTENNA_MODE_PER_MODEL) ? (uint8_t)0 : HIDDEN_ROW),
223 void onModelAntennaSwitchConfirm(const char * result
)
225 if (result
== STR_OK
) {
226 // Switch to external antenna confirmation
227 g_model
.moduleData
[INTERNAL_MODULE
].pxx
.antennaMode
= ANTENNA_MODE_EXTERNAL
;
228 globalData
.externalAntennaEnabled
= true;
229 storageDirty(EE_MODEL
);
232 reusableBuffer
.moduleSetup
.antennaMode
= g_model
.moduleData
[INTERNAL_MODULE
].pxx
.antennaMode
;
236 #define EXTERNAL_ANTENNA_ROW
239 #if defined(PCBX7) || defined(PCBX9LITE)
240 #if defined(BLUETOOTH)
241 #define TRAINER_BLUETOOTH_ROW (g_model.trainerData.mode == TRAINER_MODE_MASTER_BLUETOOTH ? TRAINER_BLUETOOTH_M_ROW : (g_model.trainerData.mode == TRAINER_MODE_SLAVE_BLUETOOTH ? TRAINER_BLUETOOTH_S_ROW : HIDDEN_ROW)),
243 #define TRAINER_BLUETOOTH_ROW
245 #define TRAINER_PPM_PARAMS_ROW (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)2 : HIDDEN_ROW)
246 #define TRAINER_ROWS LABEL(Trainer), 0, TRAINER_BLUETOOTH_ROW TRAINER_CHANNELS_ROW, TRAINER_PPM_PARAMS_ROW
247 #elif defined(PCBXLITES)
248 #define TRAINER_BLUETOOTH_ROW (g_model.trainerData.mode == TRAINER_MODE_MASTER_BLUETOOTH ? TRAINER_BLUETOOTH_M_ROW : (g_model.trainerData.mode == TRAINER_MODE_SLAVE_BLUETOOTH ? TRAINER_BLUETOOTH_S_ROW : HIDDEN_ROW))
249 #define TRAINER_PPM_PARAMS_ROW (g_model.trainerData.mode == TRAINER_MODE_SLAVE ? (uint8_t)2 : HIDDEN_ROW)
250 #define TRAINER_ROWS LABEL(Trainer), 0, IF_BT_TRAINER_ON(TRAINER_BLUETOOTH_ROW), TRAINER_CHANNELS_ROW, TRAINER_PPM_PARAMS_ROW
251 #elif defined(PCBXLITE)
252 #define TRAINER_BLUETOOTH_ROW (g_model.trainerData.mode == TRAINER_MODE_MASTER_BLUETOOTH ? TRAINER_BLUETOOTH_M_ROW : (g_model.trainerData.mode == TRAINER_MODE_SLAVE_BLUETOOTH ? TRAINER_BLUETOOTH_S_ROW : HIDDEN_ROW))
253 #define TRAINER_ROWS IF_BT_TRAINER_ON(LABEL(Trainer)), IF_BT_TRAINER_ON(0), IF_BT_TRAINER_ON(TRAINER_BLUETOOTH_ROW), IF_BT_TRAINER_ON(TRAINER_CHANNELS_ROW), HIDDEN_ROW /* xlite has only BT trainer, so never PPM */
258 #if defined(BLUETOOTH)
259 void onBluetoothConnectMenu(const char * result
)
261 if (result
!= STR_EXIT
) {
262 uint8_t index
= (result
- reusableBuffer
.moduleSetup
.bt
.devices
[0]) / sizeof(reusableBuffer
.moduleSetup
.bt
.devices
[0]);
263 strncpy(bluetooth
.distantAddr
, reusableBuffer
.moduleSetup
.bt
.devices
[index
], LEN_BLUETOOTH_ADDR
);
264 bluetooth
.state
= BLUETOOTH_STATE_BIND_REQUESTED
;
267 reusableBuffer
.moduleSetup
.bt
.devicesCount
= 0;
268 bluetooth
.state
= BLUETOOTH_STATE_DISCOVER_END
;
273 #include "common/stdlcd/model_setup_pxx1.cpp"
276 #include "common/stdlcd/model_setup_pxx2.cpp"
279 #if defined(HARDWARE_INTERNAL_MODULE)
280 #define INTERNAL_MODULE_ROWS \
281 LABEL(InternalModule), \
282 INTERNAL_MODULE_TYPE_ROWS, \
283 MODULE_CHANNELS_ROWS(INTERNAL_MODULE), \
284 IF_NOT_ACCESS_MODULE_RF(INTERNAL_MODULE, IF_INTERNAL_MODULE_ON(isModuleRxNumAvailable(INTERNAL_MODULE) ? (uint8_t)2 : (uint8_t)1)), \
285 IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* RxNum */ \
286 EXTERNAL_ANTENNA_ROW \
287 IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE)), /* Failsafe */ \
288 IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 1), /* Range check and Register buttons */ \
289 IF_PXX2_MODULE(INTERNAL_MODULE, 0), /* Module options */ \
290 IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 1 */ \
291 IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 2 */ \
292 IF_ACCESS_MODULE_RF(INTERNAL_MODULE, 0), /* Receiver 3 */
294 #define INTERNAL_MODULE_ROWS
297 void menuModelSetup(event_t event
)
299 int8_t old_editMode
= s_editMode
;
301 #if defined(PCBTARANIS)
302 int8_t old_posHorz
= menuHorizontalPosition
;
310 0, // Extended limits
314 0, // Throttle reverse
315 0, // Throttle trace source
318 LABEL(PreflightCheck
),
320 0, // Throttle warning
321 SW_WARN_ROWS
, // Switch warning
322 POT_WARN_ROWS
, // Pot warning
324 NUM_STICKS
+ NUM_POTS
+ NUM_SLIDERS
- 1, // Center beeps
325 0, // Global functions
331 LABEL(ExternalModule
),
332 EXTERNAL_MODULE_TYPE_ROW(),
333 MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE
)
334 MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE
)
335 MODULE_CHANNELS_ROWS(EXTERNAL_MODULE
),
336 IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE
, MODULE_BIND_ROWS(EXTERNAL_MODULE
)), // line reused for PPM: PPM settings
337 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 0), // RxNum
338 MODULE_POWER_ROW(EXTERNAL_MODULE
),
339 IF_NOT_PXX2_MODULE(EXTERNAL_MODULE
, MODULE_OPTION_ROW(EXTERNAL_MODULE
)),
340 MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE
)
341 FAILSAFE_ROWS(EXTERNAL_MODULE
),
342 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 1), // Range check and Register buttons
343 IF_PXX2_MODULE(EXTERNAL_MODULE
, 0), // Module options
344 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 0), // Receiver 1
345 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 0), // Receiver 2
346 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 0), // Receiver 3
357 0, // Extended limits
361 0, // Throttle reverse
362 0, // Throttle trace source
365 LABEL(PreflightCheck
),
367 0, // Throttle warning
368 NUM_SWITCHES
-1, // Switch warning
370 NUM_STICKS
+NUM_POTS
+NUM_SLIDERS
-1, // Center beeps
371 0, // Global functions
373 LABEL(ExternalModule
),
374 EXTERNAL_MODULE_TYPE_ROW(),
375 MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE
)
376 MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE
)
377 MODULE_CHANNELS_ROWS(EXTERNAL_MODULE
),
378 IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE
, MODULE_BIND_ROWS(EXTERNAL_MODULE
)), // line reused for PPM: PPM settings
379 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 0), // RxNum
380 MODULE_POWER_ROW(EXTERNAL_MODULE
),
381 IF_NOT_PXX2_MODULE(EXTERNAL_MODULE
, MODULE_OPTION_ROW(EXTERNAL_MODULE
)),
382 MULTIMODULE_MODULE_ROWS(EXTERNAL_MODULE
)
383 FAILSAFE_ROWS(EXTERNAL_MODULE
),
384 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 1), // Range check and Register buttons
385 IF_PXX2_MODULE(EXTERNAL_MODULE
, 0), // Module options
386 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 0), // Receiver 1
387 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 0), // Receiver 2
388 IF_ACCESS_MODULE_RF(EXTERNAL_MODULE
, 0), // Receiver 3
395 MENU_CHECK(menuTabModel
, MENU_MODEL_SETUP
, HEADER_LINE
+ ITEM_MODEL_SETUP_LINES_COUNT
);
396 title(STR_MENUSETUP
);
398 if (event
== EVT_ENTRY
|| event
== EVT_ENTRY_UP
) {
399 memclear(&reusableBuffer
.moduleSetup
, sizeof(reusableBuffer
.moduleSetup
));
400 reusableBuffer
.moduleSetup
.r9mPower
= g_model
.moduleData
[EXTERNAL_MODULE
].pxx
.power
;
401 reusableBuffer
.moduleSetup
.previousType
= g_model
.moduleData
[EXTERNAL_MODULE
].type
;
402 reusableBuffer
.moduleSetup
.newType
= g_model
.moduleData
[EXTERNAL_MODULE
].type
;
403 #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
404 reusableBuffer
.moduleSetup
.antennaMode
= g_model
.moduleData
[INTERNAL_MODULE
].pxx
.antennaMode
;
408 #if (defined(DSM2) || defined(PXX))
410 moduleState
[0].mode
= 0;
412 moduleState
[1].mode
= 0;
417 uint8_t sub
= menuVerticalPosition
- HEADER_LINE
;
419 for (uint8_t i
=0; i
<NUM_BODY_LINES
; ++i
) {
420 coord_t y
= MENU_HEADER_HEIGHT
+ 1 + i
*FH
;
421 uint8_t k
= i
+ menuVerticalOffset
;
422 for (int j
=0; j
<=k
; j
++) {
423 if (mstate_tab
[j
+HEADER_LINE
] == HIDDEN_ROW
) {
424 if (++k
>= (int)DIM(mstate_tab
)) {
430 LcdFlags blink
= ((s_editMode
>0) ? BLINK
|INVERS
: INVERS
);
431 LcdFlags attr
= (sub
== k
? blink
: 0);
434 case ITEM_MODEL_SETUP_NAME
:
435 editSingleName(MODEL_SETUP_2ND_COLUMN
, y
, STR_MODELNAME
, g_model
.header
.name
, sizeof(g_model
.header
.name
), event
, attr
);
436 memcpy(modelHeaders
[g_eeGeneral
.currModel
].name
, g_model
.header
.name
, sizeof(g_model
.header
.name
));
439 case ITEM_MODEL_SETUP_TIMER1
:
440 case ITEM_MODEL_SETUP_TIMER2
:
441 case ITEM_MODEL_SETUP_TIMER3
:
443 unsigned int timerIdx
= (k
>=ITEM_MODEL_SETUP_TIMER3
? 2 : (k
>=ITEM_MODEL_SETUP_TIMER2
? 1 : 0));
444 TimerData
* timer
= &g_model
.timers
[timerIdx
];
445 drawStringWithIndex(0*FW
, y
, STR_TIMER
, timerIdx
+1);
446 drawTimerMode(MODEL_SETUP_2ND_COLUMN
, y
, timer
->mode
, menuHorizontalPosition
==0 ? attr
: 0);
447 drawTimer(MODEL_SETUP_2ND_COLUMN
+5*FW
-2+5*FWNUM
+1, y
, timer
->start
, RIGHT
| (menuHorizontalPosition
==1 ? attr
: 0), menuHorizontalPosition
==2 ? attr
: 0);
448 if (attr
&& s_editMode
> 0) {
449 div_t qr
= div(timer
->start
, 60);
450 switch (menuHorizontalPosition
) {
453 swsrc_t timerMode
= timer
->mode
;
455 timerMode
-= TMRMODE_COUNT
-1;
456 CHECK_INCDEC_MODELVAR_CHECK(event
, timerMode
, -TMRMODE_COUNT
-SWSRC_LAST
+1, TMRMODE_COUNT
+SWSRC_LAST
-1, isSwitchAvailableInTimers
);
458 timerMode
+= TMRMODE_COUNT
-1;
459 timer
->mode
= timerMode
;
460 #if defined(AUTOSWITCH)
462 int8_t val
= timer
->mode
- (TMRMODE_COUNT
-1);
463 int8_t switchVal
= checkIncDecMovedSwitch(val
);
464 if (val
!= switchVal
) {
465 timer
->mode
= switchVal
+ (TMRMODE_COUNT
-1);
466 storageDirty(EE_MODEL
);
473 CHECK_INCDEC_MODELVAR_ZERO(event
, qr
.quot
, 539); // 8:59
474 timer
->start
= qr
.rem
+ qr
.quot
*60;
477 qr
.rem
-= checkIncDecModel(event
, qr
.rem
+2, 1, 62)-2;
478 timer
->start
-= qr
.rem
;
479 if ((int16_t)timer
->start
< 0) timer
->start
=0;
480 if ((int16_t)timer
->start
> 5999) timer
->start
=32399; // 8:59:59
487 case ITEM_MODEL_SETUP_TIMER1_NAME
:
488 case ITEM_MODEL_SETUP_TIMER2_NAME
:
489 case ITEM_MODEL_SETUP_TIMER3_NAME
:
491 TimerData
* timer
= &g_model
.timers
[k
>=ITEM_MODEL_SETUP_TIMER3
? 2 : (k
>=ITEM_MODEL_SETUP_TIMER2
? 1 : 0)];
492 editSingleName(MODEL_SETUP_2ND_COLUMN
, y
, INDENT TR_NAME
, timer
->name
, sizeof(timer
->name
), event
, attr
);
496 case ITEM_MODEL_SETUP_TIMER1_MINUTE_BEEP
:
497 case ITEM_MODEL_SETUP_TIMER2_MINUTE_BEEP
:
498 case ITEM_MODEL_SETUP_TIMER3_MINUTE_BEEP
:
500 TimerData
* timer
= &g_model
.timers
[k
>=ITEM_MODEL_SETUP_TIMER3
? 2 : (k
>=ITEM_MODEL_SETUP_TIMER2
? 1 : 0)];
501 timer
->minuteBeep
= editCheckBox(timer
->minuteBeep
, MODEL_SETUP_2ND_COLUMN
, y
, INDENT TR_MINUTEBEEP
, attr
, event
);
505 case ITEM_MODEL_SETUP_TIMER1_COUNTDOWN_BEEP
:
506 case ITEM_MODEL_SETUP_TIMER2_COUNTDOWN_BEEP
:
507 case ITEM_MODEL_SETUP_TIMER3_COUNTDOWN_BEEP
:
509 TimerData
* timer
= &g_model
.timers
[k
>=ITEM_MODEL_SETUP_TIMER3
? 2 : (k
>=ITEM_MODEL_SETUP_TIMER2
? 1 : 0)];
510 timer
->countdownBeep
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_BEEPCOUNTDOWN
, STR_VBEEPCOUNTDOWN
, timer
->countdownBeep
, COUNTDOWN_SILENT
, COUNTDOWN_COUNT
-1, attr
, event
);
514 case ITEM_MODEL_SETUP_TIMER1_PERSISTENT
:
515 case ITEM_MODEL_SETUP_TIMER2_PERSISTENT
:
516 case ITEM_MODEL_SETUP_TIMER3_PERSISTENT
:
518 TimerData
* timer
= &g_model
.timers
[k
>=ITEM_MODEL_SETUP_TIMER3
? 2 : (k
>=ITEM_MODEL_SETUP_TIMER2
? 1 : 0)];
519 timer
->persistent
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_PERSISTENT
, STR_VPERSISTENT
, timer
->persistent
, 0, 2, attr
, event
);
523 case ITEM_MODEL_SETUP_EXTENDED_LIMITS
:
524 ON_OFF_MENU_ITEM(g_model
.extendedLimits
, MODEL_SETUP_2ND_COLUMN
, y
, STR_ELIMITS
, attr
, event
);
527 case ITEM_MODEL_SETUP_EXTENDED_TRIMS
:
528 ON_OFF_MENU_ITEM(g_model
.extendedTrims
, MODEL_SETUP_2ND_COLUMN
, y
, STR_ETRIMS
, menuHorizontalPosition
<=0 ? attr
: 0, event
==EVT_KEY_BREAK(KEY_ENTER
) ? event
: 0);
529 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+4*FW
, y
, STR_RESET_BTN
, (menuHorizontalPosition
>0 && !NO_HIGHLIGHT()) ? attr
: 0);
530 if (attr
&& menuHorizontalPosition
>0) {
532 if (event
==EVT_KEY_LONG(KEY_ENTER
)) {
533 START_NO_HIGHLIGHT();
534 for (uint8_t i
=0; i
<MAX_FLIGHT_MODES
; i
++) {
535 memclear(&g_model
.flightModeData
[i
], TRIMS_ARRAY_SIZE
);
537 storageDirty(EE_MODEL
);
543 case ITEM_MODEL_SETUP_DISPLAY_TRIMS
:
544 g_model
.displayTrims
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_DISPLAY_TRIMS
, STR_VDISPLAYTRIMS
, g_model
.displayTrims
, 0, 2, attr
, event
);
547 case ITEM_MODEL_SETUP_TRIM_INC
:
548 g_model
.trimInc
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_TRIMINC
, STR_VTRIMINC
, g_model
.trimInc
, -2, 2, attr
, event
);
551 case ITEM_MODEL_SETUP_THROTTLE_REVERSED
:
552 ON_OFF_MENU_ITEM(g_model
.throttleReversed
, MODEL_SETUP_2ND_COLUMN
, y
, STR_THROTTLEREVERSE
, attr
, event
) ;
555 case ITEM_MODEL_SETUP_THROTTLE_TRACE
:
557 lcdDrawTextAlignedLeft(y
, STR_TTRACE
);
558 if (attr
) CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.thrTraceSrc
, NUM_POTS
+NUM_SLIDERS
+MAX_OUTPUT_CHANNELS
);
559 uint8_t idx
= g_model
.thrTraceSrc
+ MIXSRC_Thr
;
560 if (idx
> MIXSRC_Thr
)
562 if (idx
>= MIXSRC_FIRST_POT
+NUM_POTS
+NUM_SLIDERS
)
563 idx
+= MIXSRC_CH1
- MIXSRC_FIRST_POT
- NUM_POTS
- NUM_SLIDERS
;
564 drawSource(MODEL_SETUP_2ND_COLUMN
, y
, idx
, attr
);
568 case ITEM_MODEL_SETUP_THROTTLE_TRIM
:
569 ON_OFF_MENU_ITEM(g_model
.thrTrim
, MODEL_SETUP_2ND_COLUMN
, y
, STR_TTRIM
, attr
, event
);
572 case ITEM_MODEL_SETUP_PREFLIGHT_LABEL
:
573 lcdDrawTextAlignedLeft(y
, STR_PREFLIGHT
);
576 case ITEM_MODEL_SETUP_CHECKLIST_DISPLAY
:
577 ON_OFF_MENU_ITEM(g_model
.displayChecklist
, MODEL_SETUP_2ND_COLUMN
, y
, STR_CHECKLIST
, attr
, event
);
580 case ITEM_MODEL_SETUP_THROTTLE_WARNING
:
581 g_model
.disableThrottleWarning
= !editCheckBox(!g_model
.disableThrottleWarning
, MODEL_SETUP_2ND_COLUMN
, y
, STR_THROTTLEWARNING
, attr
, event
);
584 #if defined(PCBTARANIS)
585 case ITEM_MODEL_SETUP_SWITCHES_WARNING2
:
587 if (CURSOR_MOVED_LEFT(event
))
588 menuVerticalOffset
--;
590 menuVerticalOffset
++;
595 case ITEM_MODEL_SETUP_SWITCHES_WARNING1
:
596 #if defined(PCBTARANIS)
598 #define FIRSTSW_STR STR_VSRCRAW+(MIXSRC_FIRST_SWITCH-MIXSRC_Rud+1)*length
599 uint8_t switchWarningsCount
= getSwitchWarningsCount();
600 uint8_t length
= STR_VSRCRAW
[0];
601 horzpos_t l_posHorz
= menuHorizontalPosition
;
603 if (i
>=NUM_BODY_LINES
-2 && getSwitchWarningsCount() > MAX_SWITCH_PER_LINE
*(NUM_BODY_LINES
-i
)) {
604 if (CURSOR_MOVED_LEFT(event
))
605 menuVerticalOffset
--;
607 menuVerticalOffset
++;
611 swarnstate_t states
= g_model
.switchWarningState
;
614 lcdDrawTextAlignedLeft(y
, STR_SWITCHWARNING
);
615 #if defined(PCBXLITE)
616 lcdDrawText(LCD_W
, y
, "<]", RIGHT
);
618 if (menuHorizontalPosition
> switchWarningsCount
)
619 menuHorizontalPosition
= switchWarningsCount
;
621 if (attr
&& menuHorizontalPosition
== switchWarningsCount
) {
628 case EVT_KEY_BREAK(KEY_ENTER
):
631 case EVT_KEY_LONG(KEY_ENTER
):
632 if (menuHorizontalPosition
< 0 || menuHorizontalPosition
>= switchWarningsCount
) {
633 START_NO_HIGHLIGHT();
635 g_model
.switchWarningState
= switches_states
;
637 storageDirty(EE_MODEL
);
646 for (int i
= 0; i
< NUM_SWITCHES
; i
++) {
647 if (SWITCH_WARNING_ALLOWED(i
)) {
648 div_t qr
= div(current
, MAX_SWITCH_PER_LINE
);
649 if (!READ_ONLY() && event
==EVT_KEY_BREAK(KEY_ENTER
) && attr
&& l_posHorz
== current
&& old_posHorz
>= 0) {
650 g_model
.switchWarningEnable
^= (1 << i
);
651 storageDirty(EE_MODEL
);
652 #if defined(PCBXLITE)
656 uint8_t swactive
= !(g_model
.switchWarningEnable
& (1<<i
));
657 c
= "\300-\301"[states
& 0x03];
658 // lcdDrawChar(MODEL_SETUP_2ND_COLUMN+qr.rem*(2*FW+1), y+FH*qr.quot, 'A'+i, attr && (menuHorizontalPosition==current) ? INVERS : 0);
659 lcdDrawSizedText(MODEL_SETUP_2ND_COLUMN
+ qr
.rem
*((2*FW
)+1), y
+FH
*qr
.quot
, FIRSTSW_STR
+(i
*length
)+3, 1, attr
&& (menuHorizontalPosition
==current
) ? INVERS
: 0);
660 if (swactive
) lcdDrawChar(lcdNextPos
, y
+FH
*qr
.quot
, c
);
665 if (attr
&& ((menuHorizontalPosition
< 0) || menuHorizontalPosition
>= switchWarningsCount
)) {
666 lcdDrawFilledRect(MODEL_SETUP_2ND_COLUMN
-1, y
-1, 8*(2*FW
+1), 1+FH
*((current
+4)/5));
670 lcdDrawTextAlignedLeft(y
, STR_SWITCHWARNING
);
671 swarnstate_t states
= g_model
.switchWarningState
;
677 case EVT_KEY_BREAK(KEY_ENTER
):
678 if (menuHorizontalPosition
< NUM_SWITCHES
-1) {
679 g_model
.switchWarningEnable
^= (1 << menuHorizontalPosition
);
680 storageDirty(EE_MODEL
);
684 case EVT_KEY_LONG(KEY_ENTER
):
685 if (menuHorizontalPosition
== NUM_SWITCHES
-1) {
686 START_NO_HIGHLIGHT();
688 g_model
.switchWarningState
= switches_states
;
690 storageDirty(EE_MODEL
);
698 for (uint8_t i
=0; i
<NUM_SWITCHES
-1/*not on TRN switch*/; i
++) {
699 uint8_t swactive
= !(g_model
.switchWarningEnable
& 1 << i
);
703 c
= '0'+(states
& 0x03);
707 if ((states
& 0x01) && swactive
)
709 c
= *(STR_VSWITCHES
- 2 + 9 + (3*(i
+1)));
712 if (attr
&& (menuHorizontalPosition
== i
)) {
713 attr
= BLINK
| INVERS
;
715 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+i
*FW
, y
, (swactive
) ? c
: '-', attr
);
716 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+(NUM_SWITCHES
*FW
), y
, "<]", (menuHorizontalPosition
== NUM_SWITCHES
-1 && !NO_HIGHLIGHT()) ? attr
: 0);
722 #if defined(PCBTARANIS)
723 case ITEM_MODEL_SETUP_POTS_WARNING
:
724 lcdDrawTextAlignedLeft(y
, STR_POTWARNING
);
725 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, "\004""OFF\0""Man\0""Auto", g_model
.potsWarnMode
, (menuHorizontalPosition
== 0) ? attr
: 0);
726 if (attr
&& (menuHorizontalPosition
== 0)) {
727 CHECK_INCDEC_MODELVAR(event
, g_model
.potsWarnMode
, POTS_WARN_OFF
, POTS_WARN_AUTO
);
728 storageDirty(EE_MODEL
);
732 if (menuHorizontalPosition
> 0) s_editMode
= 0;
733 if (!READ_ONLY() && menuHorizontalPosition
> 0) {
735 case EVT_KEY_LONG(KEY_ENTER
):
737 if (g_model
.potsWarnMode
== POTS_WARN_MANUAL
) {
738 SAVE_POT_POSITION(menuHorizontalPosition
-1);
740 storageDirty(EE_MODEL
);
743 case EVT_KEY_BREAK(KEY_ENTER
):
744 g_model
.potsWarnEnabled
^= (1 << (menuHorizontalPosition
-1));
745 storageDirty(EE_MODEL
);
750 if (g_model
.potsWarnMode
) {
751 coord_t x
= MODEL_SETUP_2ND_COLUMN
+28;
752 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; ++i
) {
753 if (i
<NUM_XPOTS
&& !IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
754 if (attr
&& (menuHorizontalPosition
==i
+1)) REPEAT_LAST_CURSOR_MOVE();
757 LcdFlags flags
= ((menuHorizontalPosition
==i
+1) && attr
) ? BLINK
: 0;
758 if ((!attr
|| menuHorizontalPosition
>= 0) && !(g_model
.potsWarnEnabled
& (1 << i
))) {
762 // TODO add a new function
763 lcdDrawSizedText(x
, y
, STR_VSRCRAW
+2+STR_VSRCRAW
[0]*(NUM_STICKS
+1+i
), STR_VSRCRAW
[0]-1, flags
& ~ZCHAR
);
771 case ITEM_MODEL_SETUP_BEEP_CENTER
:
772 lcdDrawTextAlignedLeft(y
, STR_BEEPCTR
);
773 for (uint8_t i
=0; i
<NUM_STICKS
+NUM_POTS
+NUM_SLIDERS
; i
++) {
774 // TODO flash saving, \001 not needed in STR_RETA123
775 coord_t x
= MODEL_SETUP_2ND_COLUMN
+i
*FW
;
776 lcdDrawTextAtIndex(x
, y
, STR_RETA123
, i
, ((menuHorizontalPosition
==i
) && attr
) ? BLINK
|INVERS
: (((g_model
.beepANACenter
& ((BeepANACenter
)1<<i
)) || (attr
&& CURSOR_ON_LINE())) ? INVERS
: 0 ) );
779 if (event
== EVT_KEY_BREAK(KEY_ENTER
)) {
780 if (READ_ONLY_UNLOCKED()) {
782 g_model
.beepANACenter
^= ((BeepANACenter
)1<<menuHorizontalPosition
);
783 storageDirty(EE_MODEL
);
789 case ITEM_MODEL_SETUP_USE_GLOBAL_FUNCTIONS
:
790 lcdDrawTextAlignedLeft(y
, STR_USE_GLOBAL_FUNCS
);
791 drawCheckBox(MODEL_SETUP_2ND_COLUMN
, y
, !g_model
.noGlobalFunctions
, attr
);
792 if (attr
) g_model
.noGlobalFunctions
= !checkIncDecModel(event
, !g_model
.noGlobalFunctions
, 0, 1);
795 #if defined(HARDWARE_INTERNAL_MODULE)
796 case ITEM_MODEL_SETUP_INTERNAL_MODULE_LABEL
:
797 lcdDrawTextAlignedLeft(y
, STR_INTERNALRF
);
800 case ITEM_MODEL_SETUP_INTERNAL_MODULE_TYPE
:
802 lcdDrawTextAlignedLeft(y
, INDENT TR_MODE
);
803 #if defined(INTERNAL_MODULE_PXX1)
804 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_INTERNAL_MODULE_PROTOCOLS
, g_model
.moduleData
[INTERNAL_MODULE
].type
, menuHorizontalPosition
==0 ? attr
: 0);
805 if (isModuleXJT(INTERNAL_MODULE
))
806 lcdDrawTextAtIndex(lcdNextPos
+ 3, y
, STR_XJT_ACCST_RF_PROTOCOLS
, 1+g_model
.moduleData
[INTERNAL_MODULE
].subType
, menuHorizontalPosition
==1 ? attr
: 0);
807 else if (isModuleISRM(INTERNAL_MODULE
))
808 lcdDrawTextAtIndex(lcdNextPos
+ 3, y
, STR_ISRM_RF_PROTOCOLS
, g_model
.moduleData
[INTERNAL_MODULE
].subType
, menuHorizontalPosition
==1 ? attr
: 0);
810 if (menuHorizontalPosition
== 0) {
811 uint8_t moduleType
= checkIncDec(event
, g_model
.moduleData
[INTERNAL_MODULE
].type
, MODULE_TYPE_NONE
, MODULE_TYPE_MAX
, EE_MODEL
, isInternalModuleAvailable
);
812 if (checkIncDec_Ret
) {
813 setModuleType(INTERNAL_MODULE
, moduleType
);
816 else if (isModuleXJT(INTERNAL_MODULE
)) {
817 g_model
.moduleData
[INTERNAL_MODULE
].subType
= checkIncDec(event
, g_model
.moduleData
[INTERNAL_MODULE
].subType
, 0, MODULE_SUBTYPE_PXX1_LAST
, EE_MODEL
, isRfProtocolAvailable
);
818 if (checkIncDec_Ret
) {
819 g_model
.moduleData
[0].type
= MODULE_TYPE_XJT_PXX1
;
820 g_model
.moduleData
[0].channelsStart
= 0;
821 g_model
.moduleData
[0].channelsCount
= defaultModuleChannels_M8(INTERNAL_MODULE
);
824 else if (isModulePXX2(INTERNAL_MODULE
)) {
825 g_model
.moduleData
[INTERNAL_MODULE
].subType
= checkIncDec(event
, g_model
.moduleData
[INTERNAL_MODULE
].subType
, 0, MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16
, EE_MODEL
, isRfProtocolAvailable
);
830 if (g_model
.moduleData
[INTERNAL_MODULE
].type
== MODULE_TYPE_ISRM_PXX2
) {
831 index
= 1 + g_model
.moduleData
[INTERNAL_MODULE
].subType
;
833 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_ISRM_RF_PROTOCOLS
, index
, attr
);
835 index
= checkIncDec(event
, index
, 0, MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16
+ 1 /* because of --- */, EE_MODEL
);
836 if (checkIncDec_Ret
) {
837 memclear(&g_model
.moduleData
[INTERNAL_MODULE
], sizeof(ModuleData
));
839 g_model
.moduleData
[INTERNAL_MODULE
].type
= MODULE_TYPE_ISRM_PXX2
;
840 g_model
.moduleData
[INTERNAL_MODULE
].subType
= index
- 1;
841 g_model
.moduleData
[INTERNAL_MODULE
].channelsCount
= defaultModuleChannels_M8(INTERNAL_MODULE
);
850 #if defined(PCBSKY9X)
851 case ITEM_MODEL_SETUP_EXTRA_MODULE_LABEL
:
852 lcdDrawTextAlignedLeft(y
, "RF Port 2 (PPM)");
856 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_LABEL
:
857 lcdDrawTextAlignedLeft(y
, STR_EXTERNALRF
);
860 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE
:
861 lcdDrawTextAlignedLeft(y
, INDENT TR_MODE
);
862 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_EXTERNAL_MODULE_PROTOCOLS
, reusableBuffer
.moduleSetup
.newType
, menuHorizontalPosition
==0 ? attr
: 0);
863 if (isModuleXJT(EXTERNAL_MODULE
))
864 lcdDrawTextAtIndex(lcdNextPos
+ 3, y
, STR_XJT_ACCST_RF_PROTOCOLS
, 1+g_model
.moduleData
[EXTERNAL_MODULE
].subType
, menuHorizontalPosition
==1 ? attr
: 0);
865 else if (isModuleDSM2(EXTERNAL_MODULE
))
866 lcdDrawTextAtIndex(lcdNextPos
+ 3, y
, STR_DSM_PROTOCOLS
, g_model
.moduleData
[EXTERNAL_MODULE
].rfProtocol
, menuHorizontalPosition
==1 ? attr
: 0);
867 else if (isModuleR9MNonAccess(EXTERNAL_MODULE
))
868 lcdDrawTextAtIndex(lcdNextPos
+ 3, y
, STR_R9M_REGION
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, (menuHorizontalPosition
==1 ? attr
: 0));
869 #if defined(MULTIMODULE)
870 else if (isModuleMultimodule(EXTERNAL_MODULE
)) {
871 int multi_rfProto
= g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol();
872 lcdDrawMultiProtocolString(lcdNextPos
+ 3, y
, EXTERNAL_MODULE
, multi_rfProto
, menuHorizontalPosition
== 1 ? attr
: 0);
875 if (attr
&& menuHorizontalPosition
== 0) {
876 if (s_editMode
> 0) {
877 g_model
.moduleData
[EXTERNAL_MODULE
].type
= MODULE_TYPE_NONE
;
879 else if (reusableBuffer
.moduleSetup
.newType
!= reusableBuffer
.moduleSetup
.previousType
) {
880 g_model
.moduleData
[EXTERNAL_MODULE
].type
= reusableBuffer
.moduleSetup
.newType
;
881 reusableBuffer
.moduleSetup
.previousType
= reusableBuffer
.moduleSetup
.newType
;
882 setModuleType(EXTERNAL_MODULE
, g_model
.moduleData
[EXTERNAL_MODULE
].type
);
884 else if (g_model
.moduleData
[EXTERNAL_MODULE
].type
== MODULE_TYPE_NONE
) {
885 g_model
.moduleData
[EXTERNAL_MODULE
].type
= reusableBuffer
.moduleSetup
.newType
;
889 if (s_editMode
> 0) {
890 switch (menuHorizontalPosition
) {
892 reusableBuffer
.moduleSetup
.newType
= checkIncDec(event
, reusableBuffer
.moduleSetup
.newType
, MODULE_TYPE_NONE
, MODULE_TYPE_MAX
, EE_MODEL
, isExternalModuleAvailable
);
896 if (isModuleDSM2(EXTERNAL_MODULE
)) {
897 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[EXTERNAL_MODULE
].rfProtocol
, DSM2_PROTO_LP45
, DSM2_PROTO_DSMX
);
899 else if (isModuleR9MNonAccess(EXTERNAL_MODULE
)) {
900 g_model
.moduleData
[EXTERNAL_MODULE
].subType
= checkIncDec(event
,
901 g_model
.moduleData
[EXTERNAL_MODULE
].subType
,
902 MODULE_SUBTYPE_R9M_FCC
,
903 MODULE_SUBTYPE_R9M_LAST
,
906 if (checkIncDec_Ret
) {
907 g_model
.moduleData
[EXTERNAL_MODULE
].pxx
.power
= 0;
908 g_model
.moduleData
[EXTERNAL_MODULE
].channelsStart
= 0;
909 g_model
.moduleData
[EXTERNAL_MODULE
].channelsCount
= defaultModuleChannels_M8(EXTERNAL_MODULE
);
913 #if defined(MULTIMODULE)
914 else if (isModuleMultimodule(EXTERNAL_MODULE
)) {
915 int multiRfProto
= g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol();
916 CHECK_INCDEC_MODELVAR_CHECK(event
, multiRfProto
, MODULE_SUBTYPE_MULTI_FIRST
, MULTI_MAX_PROTOCOLS
, isMultiProtocolSelectable
);
917 if (checkIncDec_Ret
) {
918 g_model
.moduleData
[EXTERNAL_MODULE
].setMultiProtocol(multiRfProto
);
919 g_model
.moduleData
[EXTERNAL_MODULE
].subType
= 0;
920 // Sensible default for DSM2 (same as for ppm): 7ch@22ms + Autodetect settings enabled
921 if (g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2
) {
922 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.autoBindMode
= 1;
925 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.autoBindMode
= 0;
927 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.optionValue
= 0;
932 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, 0, MODULE_SUBTYPE_PXX1_LAST
);
935 if (checkIncDec_Ret
) {
936 g_model
.moduleData
[EXTERNAL_MODULE
].channelsStart
= 0;
937 g_model
.moduleData
[EXTERNAL_MODULE
].channelsCount
= defaultModuleChannels_M8(EXTERNAL_MODULE
);
942 else if (old_editMode
> 0) {
943 if (isModuleR9MNonAccess(EXTERNAL_MODULE
)) {
944 if (g_model
.moduleData
[EXTERNAL_MODULE
].subType
> MODULE_SUBTYPE_R9M_EU
) {
945 POPUP_WARNING(STR_MODULE_PROTOCOL_FLEX_WARN_LINE1
);
946 SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2
, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2
) - 1, 0);
949 else if (g_model
.moduleData
[EXTERNAL_MODULE
].subType
== MODULE_SUBTYPE_R9M_EU
) {
950 POPUP_WARNING(STR_MODULE_PROTOCOL_EU_WARN_LINE1
);
951 SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2
, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2
) - 1, 0);
954 POPUP_WARNING(STR_MODULE_PROTOCOL_FCC_WARN_LINE1
);
955 SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2
, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2
) - 1, 0);
964 #if defined(MULTIMODULE)
965 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SUBTYPE
:
967 lcdDrawTextAlignedLeft(y
, STR_SUBTYPE
);
968 lcdDrawMultiSubProtocolString(MODEL_SETUP_2ND_COLUMN
, y
, EXTERNAL_MODULE
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, attr
);
969 if (attr
&& s_editMode
> 0) {
970 switch (menuHorizontalPosition
) {
972 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, 0, getMaxMultiSubtype(EXTERNAL_MODULE
));
981 #if defined(PCBTARANIS)
982 case ITEM_MODEL_SETUP_TRAINER_LABEL
:
983 lcdDrawTextAlignedLeft(y
, STR_TRAINER
);
986 case ITEM_MODEL_SETUP_TRAINER_MODE
:
987 lcdDrawTextAlignedLeft(y
, INDENT TR_MODE
);
988 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_VTRAINERMODES
, g_model
.trainerData
.mode
, attr
);
990 g_model
.trainerData
.mode
= checkIncDec(event
, g_model
.trainerData
.mode
, 0, TRAINER_MODE_MAX(), EE_MODEL
, isTrainerModeAvailable
);
991 #if defined(BLUETOOTH)
992 if (checkIncDec_Ret
) {
993 bluetooth
.state
= BLUETOOTH_STATE_OFF
;
994 bluetooth
.distantAddr
[0] = '\0';
1001 #if defined(PCBTARANIS) && defined(BLUETOOTH)
1002 case ITEM_MODEL_SETUP_TRAINER_BLUETOOTH
:
1003 if (g_model
.trainerData
.mode
== TRAINER_MODE_MASTER_BLUETOOTH
) {
1007 if (bluetooth
.distantAddr
[0]) {
1008 lcdDrawText(INDENT_WIDTH
, y
+1, bluetooth
.distantAddr
, TINSIZE
);
1009 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, BUTTON(TR_CLEAR
), attr
);
1010 if (attr
&& event
== EVT_KEY_BREAK(KEY_ENTER
)) {
1011 bluetooth
.state
= BLUETOOTH_STATE_CLEAR_REQUESTED
;
1012 memclear(bluetooth
.distantAddr
, sizeof(bluetooth
.distantAddr
));
1016 lcdDrawText(INDENT_WIDTH
, y
, "---");
1017 if (bluetooth
.state
< BLUETOOTH_STATE_IDLE
)
1018 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_BUTTON_INIT
, attr
);
1020 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, BUTTON(TR_DISCOVER
), attr
);
1021 if (attr
&& event
== EVT_KEY_BREAK(KEY_ENTER
)) {
1022 if (bluetooth
.state
< BLUETOOTH_STATE_IDLE
) {
1023 bluetooth
.state
= BLUETOOTH_STATE_OFF
;
1026 reusableBuffer
.moduleSetup
.bt
.devicesCount
= 0;
1027 bluetooth
.state
= BLUETOOTH_STATE_DISCOVER_REQUESTED
;
1031 if (bluetooth
.state
== BLUETOOTH_STATE_DISCOVER_START
&& reusableBuffer
.moduleSetup
.bt
.devicesCount
> 0) {
1032 popupMenuItemsCount
= min
<uint8_t>(reusableBuffer
.moduleSetup
.bt
.devicesCount
, MAX_BLUETOOTH_DISTANT_ADDR
);
1033 for (uint8_t i
=0; i
<popupMenuItemsCount
; i
++) {
1034 popupMenuItems
[i
] = reusableBuffer
.moduleSetup
.bt
.devices
[i
];
1036 popupMenuTitle
= STR_BT_SELECT_DEVICE
;
1037 POPUP_MENU_START(onBluetoothConnectMenu
);
1042 if (bluetooth
.distantAddr
[0])
1043 lcdDrawText(INDENT_WIDTH
, y
+1, bluetooth
.distantAddr
, TINSIZE
);
1045 lcdDrawText(INDENT_WIDTH
, y
, "---");
1046 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, bluetooth
.state
== BLUETOOTH_STATE_CONNECTED
? STR_CONNECTED
: STR_NOT_CONNECTED
);
1051 #if defined(PCBTARANIS)
1052 case ITEM_MODEL_SETUP_TRAINER_CHANNELS
:
1053 lcdDrawTextAlignedLeft(y
, STR_CHANNELRANGE
);
1054 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_CH
, menuHorizontalPosition
==0 ? attr
: 0);
1055 lcdDrawNumber(lcdLastRightPos
, y
, g_model
.trainerData
.channelsStart
+1, LEFT
| (menuHorizontalPosition
==0 ? attr
: 0));
1056 lcdDrawChar(lcdLastRightPos
, y
, '-');
1057 lcdDrawNumber(lcdLastRightPos
+ FW
+1, y
, g_model
.trainerData
.channelsStart
+ 8 + g_model
.trainerData
.channelsCount
, LEFT
| (menuHorizontalPosition
==1 ? attr
: 0));
1058 if (attr
&& s_editMode
> 0) {
1059 switch (menuHorizontalPosition
) {
1061 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.trainerData
.channelsStart
, 32-8-g_model
.trainerData
.channelsCount
);
1064 CHECK_INCDEC_MODELVAR(event
, g_model
.trainerData
.channelsCount
, -4, min
<int8_t>(MAX_TRAINER_CHANNELS_M8
, 32-8-g_model
.trainerData
.channelsStart
));
1071 #if defined(HARDWARE_INTERNAL_MODULE)
1072 case ITEM_MODEL_SETUP_INTERNAL_MODULE_CHANNELS
:
1074 #if defined(PCBSKY9X)
1075 case ITEM_MODEL_SETUP_EXTRA_MODULE_CHANNELS
:
1077 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS
:
1079 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1080 ModuleData
& moduleData
= g_model
.moduleData
[moduleIdx
];
1081 lcdDrawTextAlignedLeft(y
, STR_CHANNELRANGE
);
1082 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_CH
, menuHorizontalPosition
==0 ? attr
: 0);
1083 lcdDrawNumber(lcdLastRightPos
, y
, moduleData
.channelsStart
+1, LEFT
| (menuHorizontalPosition
==0 ? attr
: 0));
1084 lcdDrawChar(lcdLastRightPos
, y
, '-');
1085 lcdDrawNumber(lcdLastRightPos
+ FW
+1, y
, moduleData
.channelsStart
+sentModuleChannels(moduleIdx
), LEFT
| (menuHorizontalPosition
==1 ? attr
: 0));
1086 const char * delay
= getModuleDelay(moduleIdx
);
1088 lcdDrawText(lcdLastRightPos
+4, y
, delay
, SMLSIZE
);
1089 if (attr
&& s_editMode
> 0) {
1090 switch (menuHorizontalPosition
) {
1092 CHECK_INCDEC_MODELVAR_ZERO(event
, moduleData
.channelsStart
, 32-8-moduleData
.channelsCount
);
1095 CHECK_INCDEC_MODELVAR_CHECK(event
, moduleData
.channelsCount
, -4, min
<int8_t>(maxModuleChannels_M8(moduleIdx
), 32-8-moduleData
.channelsStart
), moduleData
.type
== MODULE_TYPE_ISRM_PXX2
? isPxx2IsrmChannelsCountAllowed
: nullptr);
1096 if (checkIncDec_Ret
&& moduleData
.type
== MODULE_TYPE_PPM
) {
1097 setDefaultPpmFrameLength(moduleIdx
);
1105 #if defined(PCBX7) || defined(PCBX9LITE) || defined(PCBXLITE)
1106 case ITEM_MODEL_SETUP_TRAINER_PPM_PARAMS
:
1107 lcdDrawTextAlignedLeft(y
, STR_PPMFRAME
);
1108 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+3*FW
, y
, STR_MS
);
1109 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, (int16_t)g_model
.trainerData
.frameLength
*5 + 225, (menuHorizontalPosition
<=0 ? attr
: 0) | PREC1
|LEFT
);
1110 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, 'u');
1111 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, (g_model
.trainerData
.delay
*50)+300, RIGHT
| ((CURSOR_ON_LINE() || menuHorizontalPosition
==1) ? attr
: 0));
1112 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+10*FW
, y
, g_model
.trainerData
.pulsePol
? '+' : '-', (CURSOR_ON_LINE() || menuHorizontalPosition
==2) ? attr
: 0);
1113 if (attr
&& s_editMode
> 0) {
1114 switch (menuHorizontalPosition
) {
1116 CHECK_INCDEC_MODELVAR(event
, g_model
.trainerData
.frameLength
, -20, 35);
1119 CHECK_INCDEC_MODELVAR(event
, g_model
.trainerData
.delay
, -4, 10);
1122 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.trainerData
.pulsePol
, 1);
1130 case ITEM_MODEL_SETUP_REGISTRATION_ID
:
1131 lcdDrawTextAlignedLeft(y
, STR_REG_ID
);
1132 if (isDefaultModelRegistrationID())
1133 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_PXX2_DEFAULT
);
1135 lcdDrawSizedText(MODEL_SETUP_2ND_COLUMN
, y
, g_model
.modelRegistrationID
, PXX2_LEN_REGISTRATION_ID
, ZCHAR
);
1138 case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM
:
1139 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM
:
1141 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1142 lcdDrawText(INDENT_WIDTH
, y
, STR_RECEIVER_NUM
);
1143 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, g_model
.header
.modelId
[moduleIdx
], attr
| LEADING0
| LEFT
, 2);
1145 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.header
.modelId
[moduleIdx
], getMaxRxNum(moduleIdx
));
1146 if (checkIncDec_Ret
) {
1147 modelHeaders
[g_eeGeneral
.currModel
].modelId
[moduleIdx
] = g_model
.header
.modelId
[moduleIdx
];
1153 case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_REGISTER_RANGE
:
1154 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_REGISTER_RANGE
:
1156 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1157 lcdDrawTextAlignedLeft(y
, INDENT TR_MODULE
);
1158 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, BUTTON(TR_REGISTER
), (menuHorizontalPosition
== 0 ? attr
: 0));
1159 lcdDrawText(lcdLastRightPos
+ 3, y
, STR_MODULE_RANGE
, (menuHorizontalPosition
== 1 ? attr
: 0));
1161 if (moduleState
[moduleIdx
].mode
== MODULE_MODE_NORMAL
&& s_editMode
> 0) {
1162 if (menuHorizontalPosition
== 0 && event
== EVT_BUTTON_PRESSED()) {
1163 startRegisterDialog(moduleIdx
);
1165 else if (menuHorizontalPosition
== 1) {
1166 moduleState
[moduleIdx
].mode
= MODULE_MODE_RANGECHECK
;
1169 if (s_editMode
== 0 && !warningText
) {
1170 moduleState
[moduleIdx
].mode
= MODULE_MODE_NORMAL
;
1172 if (moduleState
[moduleIdx
].mode
== MODULE_MODE_NORMAL
) {
1173 // REGISTER finished
1180 case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_OPTIONS
:
1181 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_OPTIONS
:
1182 lcdDrawText(INDENT_WIDTH
, y
, STR_OPTIONS
);
1183 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_SET
, attr
);
1184 if (event
== EVT_KEY_BREAK(KEY_ENTER
) && attr
) {
1185 g_moduleIdx
= CURRENT_MODULE_EDITED(k
);
1186 pushMenu(menuModelModuleOptions
);
1190 case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_1
:
1191 case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_2
:
1192 case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_RECEIVER_3
:
1193 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_1
:
1194 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_2
:
1195 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_RECEIVER_3
:
1196 modelSetupModulePxx2ReceiverLine(CURRENT_MODULE_EDITED(k
), CURRENT_RECEIVER_EDITED(k
), y
, event
, attr
);
1200 #if defined(PCBSKY9X)
1201 case ITEM_MODEL_SETUP_EXTRA_MODULE_BIND
:
1203 #if defined(HARDWARE_INTERNAL_MODULE)
1204 case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND
:
1206 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND
:
1208 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1209 ModuleData
& moduleData
= g_model
.moduleData
[moduleIdx
];
1210 if (isModulePPM(moduleIdx
)) {
1211 lcdDrawTextAlignedLeft(y
, STR_PPMFRAME
);
1212 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+3*FW
, y
, STR_MS
);
1213 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, (int16_t)moduleData
.ppm
.frameLength
*5 + 225, (menuHorizontalPosition
<=0 ? attr
: 0) | PREC1
|LEFT
);
1214 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, 'u');
1215 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, (moduleData
.ppm
.delay
*50)+300, RIGHT
| ((CURSOR_ON_LINE() || menuHorizontalPosition
==1) ? attr
: 0));
1216 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+10*FW
, y
, moduleData
.ppm
.pulsePol
? '+' : '-', (CURSOR_ON_LINE() || menuHorizontalPosition
==2) ? attr
: 0);
1217 if (attr
&& s_editMode
> 0) {
1218 switch (menuHorizontalPosition
) {
1220 CHECK_INCDEC_MODELVAR(event
, moduleData
.ppm
.frameLength
, -20, 35);
1223 CHECK_INCDEC_MODELVAR(event
, moduleData
.ppm
.delay
, -4, 10);
1226 CHECK_INCDEC_MODELVAR_ZERO(event
, moduleData
.ppm
.pulsePol
, 1);
1231 else if (isModuleSBUS(moduleIdx
)) {
1232 lcdDrawTextAlignedLeft(y
, STR_REFRESHRATE
);
1233 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, (int16_t)moduleData
.ppm
.frameLength
*5 + 225, (menuHorizontalPosition
<=0 ? attr
: 0) | PREC1
|LEFT
);
1234 lcdDrawText(lcdLastRightPos
, y
, STR_MS
);
1235 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+5*FW
+2, y
, moduleData
.sbus
.noninverted
? STR_NOT_INVERTED
: STR_NORMAL
, (CURSOR_ON_LINE() || menuHorizontalPosition
==1) ? attr
: 0);
1237 if (attr
&& s_editMode
>0) {
1238 switch (menuHorizontalPosition
) {
1240 CHECK_INCDEC_MODELVAR(event
, moduleData
.ppm
.frameLength
, -33, 35);
1243 CHECK_INCDEC_MODELVAR_ZERO(event
, moduleData
.sbus
.noninverted
, 1);
1249 horzpos_t l_posHorz
= menuHorizontalPosition
;
1250 coord_t xOffsetBind
= MODEL_SETUP_BIND_OFS
;
1251 if (!isModuleRxNumAvailable(moduleIdx
)) {
1253 lcdDrawText(INDENT_WIDTH
, y
, STR_RECEIVER
);
1254 if (attr
) l_posHorz
+= 1;
1257 lcdDrawText(INDENT_WIDTH
, y
, STR_RECEIVER_NUM
);
1259 if (isModuleBindRangeAvailable(moduleIdx
)) {
1261 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, g_model
.header
.modelId
[moduleIdx
], (l_posHorz
==0 ? attr
: 0) | LEADING0
|LEFT
, 2);
1262 if (attr
&& l_posHorz
== 0) {
1263 if (s_editMode
> 0) {
1264 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.header
.modelId
[moduleIdx
], getMaxRxNum(moduleIdx
));
1265 if (checkIncDec_Ret
) {
1266 modelHeaders
[g_eeGeneral
.currModel
].modelId
[moduleIdx
] = g_model
.header
.modelId
[moduleIdx
];
1268 else if (event
== EVT_KEY_LONG(KEY_ENTER
)) {
1270 uint8_t newVal
= findNextUnusedModelId(g_eeGeneral
.currModel
, moduleIdx
);
1271 if (newVal
!= g_model
.header
.modelId
[moduleIdx
]) {
1272 modelHeaders
[g_eeGeneral
.currModel
].modelId
[moduleIdx
] = g_model
.header
.modelId
[moduleIdx
] = newVal
;
1273 storageDirty(EE_MODEL
);
1278 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+xOffsetBind
, y
, STR_MODULE_BIND
, l_posHorz
==1 ? attr
: 0);
1279 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+MODEL_SETUP_RANGE_OFS
+xOffsetBind
, y
, STR_MODULE_RANGE
, l_posHorz
==2 ? attr
: 0);
1280 uint8_t newFlag
= 0;
1281 #if defined(MULTIMODULE)
1282 if (getMultiBindStatus(moduleIdx
) == MULTI_BIND_FINISHED
) {
1283 setMultiBindStatus(moduleIdx
, MULTI_NORMAL_OPERATION
);
1287 #if defined(PCBTARANIS)
1288 if (attr
&& l_posHorz
> 0) {
1289 if (s_editMode
> 0) {
1290 if (l_posHorz
== 1) {
1291 if (isModuleR9MNonAccess(moduleIdx
) || isModuleD16(moduleIdx
)) {
1292 #if defined(PCBXLITE)
1293 if (EVT_KEY_MASK(event
) == KEY_ENTER
) {
1294 #elif defined(NAVIGATION_9X)
1295 if (event
== EVT_KEY_FIRST(KEY_ENTER
)) {
1297 if (event
== EVT_KEY_BREAK(KEY_ENTER
)) {
1300 startBindMenu(moduleIdx
);
1303 if (moduleState
[moduleIdx
].mode
== MODULE_MODE_BIND
) {
1304 newFlag
= MODULE_MODE_BIND
;
1307 if (!popupMenuItemsCount
) {
1308 s_editMode
= 0; // this is when popup is exited before a choice is made
1313 newFlag
= MODULE_MODE_BIND
;
1316 else if (l_posHorz
== 2) {
1317 newFlag
= MODULE_MODE_RANGECHECK
;
1322 if (attr
&& l_posHorz
>0 && s_editMode
>0) {
1324 newFlag
= MODULE_MODE_BIND
;
1325 else if (l_posHorz
== 2)
1326 newFlag
= MODULE_MODE_RANGECHECK
;
1329 moduleState
[moduleIdx
].mode
= newFlag
;
1331 #if defined(MULTIMODULE)
1332 if (newFlag
== MODULE_MODE_BIND
) {
1333 setMultiBindStatus(moduleIdx
, MULTI_BIND_INITIATED
);
1342 #if defined(PCBSKY9X) && defined(REVX)
1343 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_OUTPUT_TYPE
:
1345 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1346 ModuleData
& moduleData
= g_model
.moduleData
[moduleIdx
];
1347 moduleData
.ppm
.outputType
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_OUTPUT_TYPE
, STR_VOUTPUT_TYPE
, moduleData
.ppm
.outputType
, 0, 1, attr
, event
);
1352 #if defined(HARDWARE_INTERNAL_MODULE)
1353 case ITEM_MODEL_SETUP_INTERNAL_MODULE_FAILSAFE
:
1355 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_FAILSAFE
: {
1356 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1357 ModuleData
&moduleData
= g_model
.moduleData
[moduleIdx
];
1358 lcdDrawTextAlignedLeft(y
, STR_FAILSAFE
);
1359 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_VFAILSAFE
, moduleData
.failsafeMode
, menuHorizontalPosition
== 0 ? attr
: 0);
1360 if (moduleData
.failsafeMode
== FAILSAFE_CUSTOM
)
1361 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+ MODEL_SETUP_SET_FAILSAFE_OFS
, y
, STR_SET
, menuHorizontalPosition
== 1 ? attr
: 0);
1363 if (moduleData
.failsafeMode
!= FAILSAFE_CUSTOM
)
1364 menuHorizontalPosition
= 0;
1365 if (menuHorizontalPosition
== 0) {
1366 if (s_editMode
> 0) {
1367 CHECK_INCDEC_MODELVAR_ZERO(event
, moduleData
.failsafeMode
, isModuleR9M(moduleIdx
) ? FAILSAFE_NOPULSES
: FAILSAFE_LAST
);
1368 if (checkIncDec_Ret
)
1369 SEND_FAILSAFE_NOW(moduleIdx
);
1372 else if (menuHorizontalPosition
== 1) {
1374 if (moduleData
.failsafeMode
== FAILSAFE_CUSTOM
) {
1375 if (event
== EVT_KEY_LONG(KEY_ENTER
)) {
1377 setCustomFailsafe(moduleIdx
);
1378 storageDirty(EE_MODEL
);
1380 SEND_FAILSAFE_NOW(moduleIdx
);
1382 else if (event
== EVT_KEY_BREAK(KEY_ENTER
) && attr
) {
1383 g_moduleIdx
= moduleIdx
;
1384 pushMenu(menuModelFailsafe
);
1389 lcdDrawSolidFilledRect(MODEL_SETUP_2ND_COLUMN
, y
, LCD_W
- MODEL_SETUP_2ND_COLUMN
, 8);
1395 #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
1396 case ITEM_MODEL_SETUP_INTERNAL_MODULE_ANTENNA
:
1397 reusableBuffer
.moduleSetup
.antennaMode
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, INDENT TR_ANTENNA
, STR_ANTENNA_MODES
,
1398 reusableBuffer
.moduleSetup
.antennaMode
== ANTENNA_MODE_PER_MODEL
? ANTENNA_MODE_INTERNAL
: reusableBuffer
.moduleSetup
.antennaMode
,
1399 ANTENNA_MODE_INTERNAL
, ANTENNA_MODE_EXTERNAL
, attr
, event
,
1400 [](int value
) { return value
!= ANTENNA_MODE_PER_MODEL
; });
1401 if (event
&& !s_editMode
&& reusableBuffer
.moduleSetup
.antennaMode
!= g_model
.moduleData
[INTERNAL_MODULE
].pxx
.antennaMode
) {
1402 if (reusableBuffer
.moduleSetup
.antennaMode
== ANTENNA_MODE_EXTERNAL
&& !isExternalAntennaEnabled()) {
1403 POPUP_CONFIRMATION(STR_ANTENNACONFIRM1
, onModelAntennaSwitchConfirm
);
1404 SET_WARNING_INFO(STR_ANTENNACONFIRM2
, sizeof(TR_ANTENNACONFIRM2
), 0);
1407 g_model
.moduleData
[INTERNAL_MODULE
].pxx
.antennaMode
= reusableBuffer
.moduleSetup
.antennaMode
;
1408 checkExternalAntenna();
1414 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_OPTIONS
:
1416 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1417 #if defined(MULTIMODULE)
1418 if (isModuleMultimodule(moduleIdx
)) {
1419 int optionValue
= g_model
.moduleData
[moduleIdx
].multi
.optionValue
;
1421 const uint8_t multi_proto
= g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol();
1422 if (multi_proto
< MODULE_SUBTYPE_MULTI_LAST
) {
1423 const mm_protocol_definition
* pdef
= getMultiProtocolDefinition(multi_proto
);
1424 if (pdef
->optionsstr
) {
1425 lcdDrawText(INDENT_WIDTH
, y
, pdef
->optionsstr
);
1426 if (attr
&& pdef
->optionsstr
== STR_MULTI_RFTUNE
) {
1427 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+ 23, y
, "RSSI(", LEFT
);
1428 lcdDrawNumber(lcdLastRightPos
, y
, TELEMETRY_RSSI(), LEFT
);
1429 lcdDrawText(lcdLastRightPos
, y
, ")", LEFT
);
1434 MultiModuleStatus
&status
= getMultiModuleStatus(moduleIdx
);
1435 lcdDrawText(INDENT_WIDTH
, y
, mm_options_strings::options
[status
.optionDisp
]);
1436 if (attr
&& status
.optionDisp
== 2) {
1437 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+ 23, y
, "RSSI(", LEFT
);
1438 lcdDrawNumber(lcdLastRightPos
, y
, TELEMETRY_RSSI(), LEFT
);
1439 lcdDrawText(lcdLastRightPos
, y
, ")", LEFT
);
1443 if (multi_proto
== MODULE_SUBTYPE_MULTI_FS_AFHDS2A
)
1444 optionValue
= 50 + 5 * optionValue
;
1446 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, optionValue
, LEFT
| attr
);
1448 if (multi_proto
== MODULE_SUBTYPE_MULTI_FS_AFHDS2A
) {
1449 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[moduleIdx
].multi
.optionValue
, 0, 70);
1451 else if (multi_proto
== MODULE_SUBTYPE_MULTI_OLRS
) {
1452 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[moduleIdx
].multi
.optionValue
, -1, 7);
1455 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[moduleIdx
].multi
.optionValue
, -128, 127);
1460 if (isModuleR9MNonAccess(moduleIdx
)) {
1461 lcdDrawTextAlignedLeft(y
, STR_MODULE_TELEMETRY
);
1462 if (isSportLineUsedByInternalModule())
1463 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_DISABLE_INTERNAL
);
1465 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_MODULE_TELEM_ON
);
1467 else if (isModuleSBUS(moduleIdx
)) {
1468 lcdDrawTextAlignedLeft(y
, STR_WARN_BATTVOLTAGE
);
1469 putsVolts(lcdLastRightPos
, y
, getBatteryVoltage(), attr
| PREC2
| LEFT
);
1474 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_POWER
:
1476 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1477 auto & module
= g_model
.moduleData
[moduleIdx
];
1478 // Lite FCC / Lite FLEX / Lite Pro Flex
1479 if (isModuleTypeR9MNonAccess(module
.type
)) {
1480 lcdDrawTextAlignedLeft(y
, STR_RFPOWER
);
1481 if (isModuleR9M_FCC_VARIANT(moduleIdx
)) {
1482 // FCC and FLEX modes ...
1483 if (isModuleTypeR9MLiteNonPro(module
.type
)) { // R9M lite FCC has only one power value, so displayed for info only
1484 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_R9M_LITE_FCC_POWER_VALUES
, 0, LEFT
);
1486 REPEAT_LAST_CURSOR_MOVE();
1490 module
.pxx
.power
= min
<uint8_t>(module
.pxx
.power
, R9M_FCC_POWER_MAX
); // Sanitize
1491 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_R9M_FCC_POWER_VALUES
, module
.pxx
.power
, LEFT
| attr
);
1493 CHECK_INCDEC_MODELVAR_ZERO(event
, module
.pxx
.power
, R9M_FCC_POWER_MAX
);
1494 if (s_editMode
== 0 && reusableBuffer
.moduleSetup
.r9mPower
!= module
.pxx
.power
&& module
.channelsCount
> maxModuleChannels_M8(moduleIdx
)) {
1495 module
.channelsStart
= 0;
1496 module
.channelsCount
= maxModuleChannels_M8(moduleIdx
);
1503 if (isModuleTypeR9MLiteNonPro(module
.type
)) {
1504 // R9M Lite in EU-LBT mode ...
1505 module
.pxx
.power
= min
<uint8_t>(module
.pxx
.power
, R9M_LITE_LBT_POWER_MAX
); // Sanitize
1506 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_R9M_LITE_LBT_POWER_VALUES
, module
.pxx
.power
, LEFT
| attr
);
1508 CHECK_INCDEC_MODELVAR_ZERO(event
, module
.pxx
.power
, R9M_LITE_LBT_POWER_MAX
);
1509 if (s_editMode
== 0 && reusableBuffer
.moduleSetup
.r9mPower
!= module
.pxx
.power
) {
1510 module
.channelsStart
= 0;
1511 if (module
.channelsCount
> maxModuleChannels_M8(moduleIdx
))
1512 module
.channelsCount
= maxModuleChannels_M8(moduleIdx
);
1513 if (reusableBuffer
.moduleSetup
.r9mPower
+ module
.pxx
.power
< 5) { // switching between mode 2 and 3 does not require rebind
1514 POPUP_WARNING(STR_REBIND
);
1516 reusableBuffer
.moduleSetup
.r9mPower
= module
.pxx
.power
;
1521 // R9M (full size) or R9M Lite Pro in EU-LBT mode ...
1522 module
.pxx
.power
= min((uint8_t) module
.pxx
.power
, (uint8_t) R9M_LBT_POWER_MAX
); // Sanitize
1523 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_R9M_LBT_POWER_VALUES
, module
.pxx
.power
, LEFT
| attr
);
1525 CHECK_INCDEC_MODELVAR_ZERO(event
, module
.pxx
.power
, R9M_LBT_POWER_MAX
);
1526 if (s_editMode
== 0 && reusableBuffer
.moduleSetup
.r9mPower
!= module
.pxx
.power
) {
1527 module
.channelsStart
= 0;
1528 if (module
.channelsCount
> maxModuleChannels_M8(moduleIdx
))
1529 module
.channelsCount
= maxModuleChannels_M8(moduleIdx
);
1530 if (reusableBuffer
.moduleSetup
.r9mPower
+ module
.pxx
.power
< 5) { //switching between mode 2 and 3 does not require rebind
1531 POPUP_WARNING(STR_REBIND
);
1533 reusableBuffer
.moduleSetup
.r9mPower
= module
.pxx
.power
;
1539 #if defined(MULTIMODULE)
1540 else if (isModuleMultimodule(moduleIdx
)) {
1541 module
.multi
.lowPowerMode
= editCheckBox(module
.multi
.lowPowerMode
, MODEL_SETUP_2ND_COLUMN
, y
, STR_MULTI_LOWPOWER
, attr
, event
);
1548 #if defined(MULTIMODULE)
1549 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AUTOBIND
:
1550 if (g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2
)
1551 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.autoBindMode
= editCheckBox(g_model
.moduleData
[EXTERNAL_MODULE
].multi
.autoBindMode
, MODEL_SETUP_2ND_COLUMN
, y
, STR_MULTI_DSM_AUTODTECT
, attr
, event
);
1553 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.autoBindMode
= editCheckBox(g_model
.moduleData
[EXTERNAL_MODULE
].multi
.autoBindMode
, MODEL_SETUP_2ND_COLUMN
, y
, STR_MULTI_AUTOBIND
, attr
, event
);
1556 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_TELEM
:
1557 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.disableTelemetry
= editCheckBox(g_model
.moduleData
[EXTERNAL_MODULE
].multi
.disableTelemetry
, MODEL_SETUP_2ND_COLUMN
, y
, INDENT TR_DISABLE_TELEM
, attr
, event
);
1560 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DISABLE_MAPPING
:
1561 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.disableMapping
= editCheckBox(g_model
.moduleData
[EXTERNAL_MODULE
].multi
.disableMapping
, MODEL_SETUP_2ND_COLUMN
, y
, INDENT TR_DISABLE_CH_MAP
, attr
, event
);
1564 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS
: {
1565 lcdDrawTextAlignedLeft(y
, STR_MODULE_STATUS
);
1567 char statusText
[64];
1568 getMultiModuleStatus(EXTERNAL_MODULE
).getStatusString(statusText
);
1569 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, statusText
);
1573 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS
: {
1574 lcdDrawTextAlignedLeft(y
, STR_MODULE_SYNC
);
1576 char statusText
[64];
1577 getMultiSyncStatus(EXTERNAL_MODULE
).getRefreshString(statusText
);
1578 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, statusText
);
1584 case ITEM_MODEL_SETUP_PPM2_PROTOCOL
:
1585 lcdDrawTextAlignedLeft(y
, "Port2");
1586 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_VPROTOS
, 0, 0);
1587 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+4*FW
+3, y
, STR_CH
, menuHorizontalPosition
<=0 ? attr
: 0);
1588 lcdDrawNumber(lcdLastRightPos
, y
, g_model
.moduleData
[1].channelsStart
+1, LEFT
| (menuHorizontalPosition
<=0 ? attr
: 0));
1589 lcdDrawChar(lcdLastRightPos
, y
, '-');
1590 lcdDrawNumber(lcdLastRightPos
+ FW
+1, y
, g_model
.moduleData
[1].channelsStart
+8+g_model
.moduleData
[1].channelsCount
, LEFT
| (menuHorizontalPosition
!=0 ? attr
: 0));
1591 if (attr
&& s_editMode
> 0) {
1592 switch (menuHorizontalPosition
) {
1594 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.moduleData
[1].channelsStart
, 32-8-g_model
.moduleData
[1].channelsCount
);
1595 setDefaultPpmFrameLength(1);
1598 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[1].channelsCount
, -4, min
<int8_t>(8, 32-8-g_model
.moduleData
[1].channelsStart
));
1599 setDefaultPpmFrameLength(1);
1605 case ITEM_MODEL_SETUP_PPM2_PARAMS
:
1606 lcdDrawTextAlignedLeft(y
, STR_PPMFRAME
);
1607 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+3*FW
, y
, STR_MS
);
1608 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, (int16_t)g_model
.moduleData
[1].ppmFrameLength
*5 + 225, (menuHorizontalPosition
<=0 ? attr
: 0) | PREC1
| LEFT
);
1609 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, 'u');
1610 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, (g_model
.moduleData
[1].ppmDelay
*50)+300, RIGHT
| ((menuHorizontalPosition
< 0 || menuHorizontalPosition
==1) ? attr
: 0));
1611 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+10*FW
, y
, g_model
.moduleData
[1].ppmPulsePol
? '+' : '-', (menuHorizontalPosition
< 0 || menuHorizontalPosition
==2) ? attr
: 0);
1612 if (attr
&& s_editMode
> 0) {
1613 switch (menuHorizontalPosition
) {
1615 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[1].ppmFrameLength
, -20, 35);
1618 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[1].ppmDelay
, -4, 10);
1621 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.moduleData
[1].ppmPulsePol
, 1);
1632 if (isModuleInRangeCheckMode()) {
1633 showMessageBox("RSSI: ");
1634 lcdDrawNumber(WARNING_LINE_X
, 5*FH
, TELEMETRY_RSSI(), BOLD
);
1638 // some field just finished being edited
1639 if (old_editMode
> 0 && s_editMode
== 0) {
1640 switch(menuVerticalPosition
) {
1641 #if defined(HARDWARE_INTERNAL_MODULE)
1642 case ITEM_MODEL_SETUP_INTERNAL_MODULE_NOT_ACCESS_BIND
:
1643 case ITEM_MODEL_SETUP_INTERNAL_MODULE_PXX2_MODEL_NUM
:
1644 if (menuHorizontalPosition
== 0)
1645 checkModelIdUnique(g_eeGeneral
.currModel
, INTERNAL_MODULE
);
1648 #if defined(PCBSKY9X)
1649 case ITEM_MODEL_SETUP_EXTRA_MODULE_BIND
:
1650 if (menuHorizontalPosition
== 0)
1651 checkModelIdUnique(g_eeGeneral
.currModel
, EXTRA_MODULE
);
1654 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_BIND
:
1655 case ITEM_MODEL_SETUP_EXTERNAL_MODULE_PXX2_MODEL_NUM
:
1656 if (menuHorizontalPosition
== 0)
1657 checkModelIdUnique(g_eeGeneral
.currModel
, EXTERNAL_MODULE
);