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.
25 void menuModelFailsafe(event_t event
);
28 enum MenuModelSetupItems
{
31 CASE_CPUARM(ITEM_MODEL_TIMER1_NAME
)
32 CASE_PERSISTENT_TIMERS(ITEM_MODEL_TIMER1_PERSISTENT
)
33 ITEM_MODEL_TIMER1_MINUTE_BEEP
,
34 ITEM_MODEL_TIMER1_COUNTDOWN_BEEP
,
36 CASE_CPUARM(ITEM_MODEL_TIMER2_NAME
)
37 CASE_PERSISTENT_TIMERS(ITEM_MODEL_TIMER2_PERSISTENT
)
38 ITEM_MODEL_TIMER2_MINUTE_BEEP
,
39 ITEM_MODEL_TIMER2_COUNTDOWN_BEEP
,
40 CASE_CPUARM(ITEM_MODEL_TIMER3
)
41 CASE_CPUARM(ITEM_MODEL_TIMER3_NAME
)
42 CASE_CPUARM(ITEM_MODEL_TIMER3_PERSISTENT
)
43 CASE_CPUARM(ITEM_MODEL_TIMER3_MINUTE_BEEP
)
44 CASE_CPUARM(ITEM_MODEL_TIMER3_COUNTDOWN_BEEP
)
45 ITEM_MODEL_EXTENDED_LIMITS
,
46 ITEM_MODEL_EXTENDED_TRIMS
,
47 CASE_CPUARM(ITEM_MODEL_DISPLAY_TRIMS
)
49 ITEM_MODEL_THROTTLE_REVERSED
,
50 ITEM_MODEL_THROTTLE_TRACE
,
51 ITEM_MODEL_THROTTLE_TRIM
,
52 CASE_CPUARM(ITEM_MODEL_PREFLIGHT_LABEL
)
53 CASE_CPUARM(ITEM_MODEL_CHECKLIST_DISPLAY
)
54 ITEM_MODEL_THROTTLE_WARNING
,
55 ITEM_MODEL_SWITCHES_WARNING
,
57 ITEM_MODEL_POTS_WARNING
,
59 ITEM_MODEL_BEEP_CENTER
,
60 CASE_CPUARM(ITEM_MODEL_USE_GLOBAL_FUNCTIONS
)
62 ITEM_MODEL_INTERNAL_MODULE_LABEL
,
63 ITEM_MODEL_INTERNAL_MODULE_MODE
,
64 ITEM_MODEL_INTERNAL_MODULE_CHANNELS
,
65 ITEM_MODEL_INTERNAL_MODULE_BIND
,
66 ITEM_MODEL_INTERNAL_MODULE_FAILSAFE
,
69 ITEM_MODEL_EXTERNAL_MODULE_LABEL
,
70 ITEM_MODEL_EXTERNAL_MODULE_MODE
,
71 #if defined(MULTIMODULE)
72 ITEM_MODEL_EXTERNAL_MODULE_SUBTYPE
,
73 ITEM_MODEL_EXTERNAL_MODULE_STATUS
,
74 ITEM_MODEL_EXTERNAL_MODULE_SYNCSTATUS
,
76 ITEM_MODEL_EXTERNAL_MODULE_CHANNELS
,
77 ITEM_MODEL_EXTERNAL_MODULE_BIND
,
78 #if defined(PCBSKY9X) && defined(REVX)
79 ITEM_MODEL_EXTERNAL_MODULE_OUTPUT_TYPE
,
81 ITEM_MODEL_EXTERNAL_MODULE_FAILSAFE
,
82 ITEM_MODEL_EXTERNAL_MODULE_OPTIONS
,
83 #if defined(MULTIMODULE)
84 ITEM_MODEL_EXTERNAL_MODULE_AUTOBIND
,
86 ITEM_MODEL_EXTERNAL_MODULE_POWER
,
87 #if defined(PCBSKY9X) && !defined(REVA)
88 ITEM_MODEL_EXTRA_MODULE_LABEL
,
89 ITEM_MODEL_EXTRA_MODULE_CHANNELS
,
90 ITEM_MODEL_EXTRA_MODULE_BIND
,
93 ITEM_MODEL_PPM1_PROTOCOL
,
94 ITEM_MODEL_PPM1_PARAMS
,
97 ITEM_MODEL_TRAINER_LABEL
,
98 ITEM_MODEL_TRAINER_MODE
,
99 #if defined(BLUETOOTH)
100 ITEM_MODEL_TRAINER_BLUETOOTH
,
102 ITEM_MODEL_TRAINER_CHANNELS
,
103 ITEM_MODEL_TRAINER_PARAMS
,
108 #if defined(PCBSKY9X)
109 #define FIELD_PROTOCOL_MAX 2
111 #define FIELD_PROTOCOL_MAX 1
114 #define MODEL_SETUP_2ND_COLUMN (LCD_W-11*FW)
115 #define MODEL_SETUP_BIND_OFS 2*FW+1
116 #define MODEL_SETUP_RANGE_OFS 4*FW+3
117 #define MODEL_SETUP_SET_FAILSAFE_OFS 7*FW-2
120 #define CURRENT_MODULE_EDITED(k) (k>=ITEM_MODEL_TRAINER_LABEL ? TRAINER_MODULE : (k>=ITEM_MODEL_EXTERNAL_MODULE_LABEL ? EXTERNAL_MODULE : INTERNAL_MODULE))
121 #elif defined(PCBSKY9X) && !defined(REVA)
122 #define CURRENT_MODULE_EDITED(k) (k>=ITEM_MODEL_EXTRA_MODULE_LABEL ? EXTRA_MODULE : EXTERNAL_MODULE)
124 #define CURRENT_MODULE_EDITED(k) (EXTERNAL_MODULE)
129 #if !defined(TARANIS_INTERNAL_PPM)
130 #define INTERNAL_MODULE_MODE_ROWS 0 // (OFF / RF protocols)
132 #define INTERNAL_MODULE_MODE_ROWS (IS_MODULE_XJT(INTERNAL_MODULE) ? (uint8_t)1 : (uint8_t)0) // Module type + RF protocols
134 #define IF_INTERNAL_MODULE_ON(x) (IS_INTERNAL_MODULE_ENABLED()? (uint8_t)(x) : HIDDEN_ROW )
135 #define IF_EXTERNAL_MODULE_ON(x) (IS_EXTERNAL_MODULE_ENABLED()? (uint8_t)(x) : HIDDEN_ROW)
136 #define INTERNAL_MODULE_CHANNELS_ROWS IF_INTERNAL_MODULE_ON(1)
137 #define EXTERNAL_MODULE_BIND_ROWS() ((IS_MODULE_XJT(EXTERNAL_MODULE) && IS_D8_RX(EXTERNAL_MODULE)) || IS_MODULE_SBUS(EXTERNAL_MODULE)) ? (uint8_t)1 : (IS_MODULE_PPM(EXTERNAL_MODULE) || IS_MODULE_PXX(EXTERNAL_MODULE) || IS_MODULE_DSM2(EXTERNAL_MODULE) || IS_MODULE_MULTIMODULE(EXTERNAL_MODULE)) ? (uint8_t)2 : HIDDEN_ROW
139 #if defined(PCBSKY9X) && defined(REVX)
140 #define OUTPUT_TYPE_ROWS() (IS_MODULE_PPM(EXTERNAL_MODULE) ? (uint8_t)0 : HIDDEN_ROW) ,
142 #define OUTPUT_TYPE_ROWS()
144 #define PORT_CHANNELS_ROWS(x) (x==EXTERNAL_MODULE ? EXTERNAL_MODULE_CHANNELS_ROWS : 0)
146 #define EXTERNAL_MODULE_MODE_ROWS (IS_MODULE_PXX(EXTERNAL_MODULE) || IS_MODULE_DSM2(EXTERNAL_MODULE) || IS_MODULE_MULTIMODULE(EXTERNAL_MODULE)) ? (uint8_t)1 : (uint8_t)0
148 #define CURSOR_ON_CELL (true)
149 #define MODEL_SETUP_MAX_LINES (HEADER_LINE+ITEM_MODEL_SETUP_MAX)
150 #define POT_WARN_ITEMS() ((g_model.nPotsToWarn >> 6) ? (uint8_t)NUM_POTS+NUM_SLIDERS : (uint8_t)0)
151 #define TIMER_ROWS 2, 0, CASE_PERSISTENT_TIMERS(0) 0, 0
152 #if defined(PCBSKY9X) && !defined(REVA)
153 #define EXTRA_MODULE_ROWS LABEL(ExtraModule), 1, 2,
155 #define EXTRA_MODULE_ROWS
159 #if defined(BLUETOOTH)
160 #define TRAINER_BLUETOOTH_M_ROW ((bluetoothDistantAddr[0] == '\0' || bluetoothState == BLUETOOTH_STATE_CONNECTED) ? (uint8_t)0 : (uint8_t)1)
161 #define TRAINER_BLUETOOTH_S_ROW (bluetoothDistantAddr[0] == '\0' ? HIDDEN_ROW : LABEL())
162 #define TRAINER_BLUETOOTH_ROW (g_model.trainerMode == TRAINER_MODE_MASTER_BLUETOOTH ? TRAINER_BLUETOOTH_M_ROW : (g_model.trainerMode == TRAINER_MODE_SLAVE_BLUETOOTH ? TRAINER_BLUETOOTH_S_ROW : HIDDEN_ROW)),
164 #define TRAINER_BLUETOOTH_ROW
166 #define TRAINER_CHANNELS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)1 : HIDDEN_ROW)
167 #define TRAINER_PARAMS_ROW (IS_SLAVE_TRAINER() ? (uint8_t)2 : HIDDEN_ROW)
168 #define TRAINER_ROWS LABEL(Trainer), 0, TRAINER_BLUETOOTH_ROW TRAINER_CHANNELS_ROW, TRAINER_PARAMS_ROW
173 #elif defined(CPUM64)
174 #define CURSOR_ON_CELL (true)
175 #define MODEL_SETUP_MAX_LINES ((IS_PPM_PROTOCOL(protocol)||IS_DSM2_PROTOCOL(protocol)||IS_PXX_PROTOCOL(protocol)) ? HEADER_LINE+ITEM_MODEL_SETUP_MAX : HEADER_LINE+ITEM_MODEL_SETUP_MAX-1)
177 #define CURSOR_ON_CELL (true)
178 #define MODEL_SETUP_MAX_LINES ((IS_PPM_PROTOCOL(protocol)||IS_DSM2_PROTOCOL(protocol)||IS_PXX_PROTOCOL(protocol)) ? HEADER_LINE+ITEM_MODEL_SETUP_MAX : HEADER_LINE+ITEM_MODEL_SETUP_MAX-1)
181 #if defined(PCBTARANIS)
182 void onBindMenu(const char * result
)
184 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(menuVerticalPosition
);
186 if (result
== STR_BINDING_25MW_CH1_8_TELEM_OFF
) {
187 g_model
.moduleData
[moduleIdx
].pxx
.power
= R9M_LBT_POWER_25
;
188 g_model
.moduleData
[moduleIdx
].pxx
.receiver_telem_off
= true;
189 g_model
.moduleData
[moduleIdx
].pxx
.receiver_channel_9_16
= false;
191 else if (result
== STR_BINDING_25MW_CH1_8_TELEM_ON
) {
192 g_model
.moduleData
[moduleIdx
].pxx
.power
= R9M_LBT_POWER_25
;
193 g_model
.moduleData
[moduleIdx
].pxx
.receiver_telem_off
= false;
194 g_model
.moduleData
[moduleIdx
].pxx
.receiver_channel_9_16
= false;
196 else if (result
== STR_BINDING_500MW_CH1_8_TELEM_OFF
) {
197 g_model
.moduleData
[moduleIdx
].pxx
.power
= R9M_LBT_POWER_500
;
198 g_model
.moduleData
[moduleIdx
].pxx
.receiver_telem_off
= true;
199 g_model
.moduleData
[moduleIdx
].pxx
.receiver_channel_9_16
= false;
201 else if (result
== STR_BINDING_500MW_CH9_16_TELEM_OFF
) {
202 g_model
.moduleData
[moduleIdx
].pxx
.power
= R9M_LBT_POWER_500
;
203 g_model
.moduleData
[moduleIdx
].pxx
.receiver_telem_off
= true;
204 g_model
.moduleData
[moduleIdx
].pxx
.receiver_channel_9_16
= true;
206 else if (result
== STR_BINDING_1_8_TELEM_ON
) {
207 g_model
.moduleData
[moduleIdx
].pxx
.receiver_telem_off
= false;
208 g_model
.moduleData
[moduleIdx
].pxx
.receiver_channel_9_16
= false;
210 else if (result
== STR_BINDING_1_8_TELEM_OFF
) {
211 g_model
.moduleData
[moduleIdx
].pxx
.receiver_telem_off
= true;
212 g_model
.moduleData
[moduleIdx
].pxx
.receiver_channel_9_16
= false;
214 else if (result
== STR_BINDING_9_16_TELEM_ON
) {
215 g_model
.moduleData
[moduleIdx
].pxx
.receiver_telem_off
= false;
216 g_model
.moduleData
[moduleIdx
].pxx
.receiver_channel_9_16
= true;
218 else if (result
== STR_BINDING_9_16_TELEM_OFF
) {
219 g_model
.moduleData
[moduleIdx
].pxx
.receiver_telem_off
= true;
220 g_model
.moduleData
[moduleIdx
].pxx
.receiver_channel_9_16
= true;
226 moduleFlag
[moduleIdx
] = MODULE_BIND
;
231 void menuModelSetup(event_t event
)
234 MENU_TAB({ HEADER_LINE_COLUMNS
0, TIMER_ROWS
, TIMER_ROWS
, TIMER_ROWS
, 0, 1, 0, 0, 0, 0, 0, CASE_CPUARM(LABEL(PreflightCheck
)) CASE_CPUARM(0) 0, NUM_SWITCHES
-1, NUM_POTS
, NUM_STICKS
+NUM_POTS
+NUM_SLIDERS
+NUM_ROTARY_ENCODERS
-1, 0,
235 LABEL(InternalModule
),
236 INTERNAL_MODULE_MODE_ROWS
,
237 INTERNAL_MODULE_CHANNELS_ROWS
,
238 IF_INTERNAL_MODULE_ON(HAS_RF_PROTOCOL_MODELINDEX(g_model
.moduleData
[INTERNAL_MODULE
].rfProtocol
) ? (uint8_t)2 : (uint8_t)1),
239 IF_INTERNAL_MODULE_ON(FAILSAFE_ROWS(INTERNAL_MODULE
)),
240 LABEL(ExternalModule
),
241 EXTERNAL_MODULE_MODE_ROWS
,
242 MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE
)
243 MULTIMODULE_STATUS_ROWS
244 EXTERNAL_MODULE_CHANNELS_ROWS
,
245 EXTERNAL_MODULE_BIND_ROWS(),
247 FAILSAFE_ROWS(EXTERNAL_MODULE
),
248 EXTERNAL_MODULE_OPTION_ROW
,
249 MULTIMODULE_MODULE_ROWS
250 EXTERNAL_MODULE_POWER_ROW
,
253 #elif defined(CPUARM)
254 MENU_TAB({ HEADER_LINE_COLUMNS
0, TIMER_ROWS
, TIMER_ROWS
, TIMER_ROWS
, 0, 1, 0, 0, 0, 0, 0, CASE_CPUARM(LABEL(PreflightCheck
)) CASE_CPUARM(0) 0, NUM_SWITCHES
-1, NUM_STICKS
+NUM_POTS
+NUM_SLIDERS
+NUM_ROTARY_ENCODERS
-1, 0,
255 LABEL(ExternalModule
),
256 EXTERNAL_MODULE_MODE_ROWS
,
257 MULTIMODULE_SUBTYPE_ROWS(EXTERNAL_MODULE
)
258 MULTIMODULE_STATUS_ROWS
259 EXTERNAL_MODULE_CHANNELS_ROWS
,
260 EXTERNAL_MODULE_BIND_ROWS(),
262 FAILSAFE_ROWS(EXTERNAL_MODULE
),
263 EXTERNAL_MODULE_OPTION_ROW
,
264 MULTIMODULE_MODULE_ROWS
265 EXTERNAL_MODULE_POWER_ROW
,
268 #elif defined(CPUM64)
269 uint8_t protocol
= g_model
.protocol
;
270 MENU_TAB({ HEADER_LINE_COLUMNS
0, 2, CASE_PERSISTENT_TIMERS(0) 0, 0, 2, CASE_PERSISTENT_TIMERS(0) 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, NUM_STICKS
+NUM_POTS
+NUM_SLIDERS
+NUM_ROTARY_ENCODERS
-1, FIELD_PROTOCOL_MAX
, 2 });
272 uint8_t protocol
= g_model
.protocol
;
273 MENU_TAB({ HEADER_LINE_COLUMNS
0, 2, CASE_PERSISTENT_TIMERS(0) 0, 0, 2, CASE_PERSISTENT_TIMERS(0) 0, 0, 0, 1, 0, 0, 0, 0, 0, NUM_SWITCHES
, NUM_STICKS
+NUM_POTS
+NUM_SLIDERS
+NUM_ROTARY_ENCODERS
-1, FIELD_PROTOCOL_MAX
, 2, CASE_PCBSKY9X(1) CASE_PCBSKY9X(2) });
276 MENU_CHECK(menuTabModel
, MENU_MODEL_SETUP
, MODEL_SETUP_MAX_LINES
);
278 #if defined(CPUARM) && (defined(DSM2) || defined(PXX))
287 TITLE(STR_MENUSETUP
);
289 uint8_t sub
= menuVerticalPosition
- HEADER_LINE
;
290 int8_t editMode
= s_editMode
;
292 for (uint8_t i
=0; i
<NUM_BODY_LINES
; ++i
) {
293 coord_t y
= MENU_HEADER_HEIGHT
+ 1 + i
*FH
;
294 uint8_t k
= i
+menuVerticalOffset
;
296 for (int j
=0; j
<=k
; j
++) {
297 if (mstate_tab
[j
+HEADER_LINE
] == HIDDEN_ROW
) {
298 if (++k
>= (int)DIM(mstate_tab
)) {
305 LcdFlags blink
= ((editMode
>0) ? BLINK
|INVERS
: INVERS
);
306 LcdFlags attr
= (sub
== k
? blink
: 0);
309 case ITEM_MODEL_NAME
:
310 editSingleName(MODEL_SETUP_2ND_COLUMN
, y
, STR_MODELNAME
, g_model
.header
.name
, sizeof(g_model
.header
.name
), event
, attr
);
312 memcpy(modelHeaders
[g_eeGeneral
.currModel
].name
, g_model
.header
.name
, sizeof(g_model
.header
.name
));
317 case ITEM_MODEL_TIMER1
:
318 case ITEM_MODEL_TIMER2
:
319 case ITEM_MODEL_TIMER3
:
321 unsigned int timerIdx
= (k
>=ITEM_MODEL_TIMER3
? 2 : (k
>=ITEM_MODEL_TIMER2
? 1 : 0));
322 TimerData
* timer
= &g_model
.timers
[timerIdx
];
323 drawStringWithIndex(0*FW
, y
, STR_TIMER
, timerIdx
+1);
324 drawTimerMode(MODEL_SETUP_2ND_COLUMN
, y
, timer
->mode
, menuHorizontalPosition
==0 ? attr
: 0);
325 drawTimer(MODEL_SETUP_2ND_COLUMN
+5*FW
-2+5*FWNUM
+1, y
, timer
->start
, RIGHT
| (menuHorizontalPosition
==1 ? attr
: 0), menuHorizontalPosition
==2 ? attr
: 0);
326 if (attr
&& (editMode
>0 || p1valdiff
)) {
327 div_t qr
= div(timer
->start
, 60);
328 switch (menuHorizontalPosition
) {
331 int8_t timerMode
= timer
->mode
;
332 if (timerMode
< 0) timerMode
-= TMRMODE_COUNT
-1;
333 CHECK_INCDEC_MODELVAR_CHECK(event
, timerMode
, -TMRMODE_COUNT
-SWSRC_LAST
+1, TMRMODE_COUNT
+SWSRC_LAST
-1, isSwitchAvailableInTimers
);
334 if (timerMode
< 0) timerMode
+= TMRMODE_COUNT
-1;
335 timer
->mode
= timerMode
;
336 #if defined(AUTOSWITCH)
338 int8_t val
= timer
->mode
- (TMRMODE_COUNT
-1);
339 int8_t switchVal
= checkIncDecMovedSwitch(val
);
340 if (val
!= switchVal
) {
341 timer
->mode
= switchVal
+ (TMRMODE_COUNT
-1);
342 storageDirty(EE_MODEL
);
349 CHECK_INCDEC_MODELVAR_ZERO(event
, qr
.quot
, 539); // 8:59
350 timer
->start
= qr
.rem
+ qr
.quot
*60;
353 qr
.rem
-= checkIncDecModel(event
, qr
.rem
+2, 1, 62)-2;
354 timer
->start
-= qr
.rem
;
355 if ((int16_t)timer
->start
< 0) timer
->start
=0;
356 if ((int16_t)timer
->start
> 5999) timer
->start
=32399; // 8:59:59
363 case ITEM_MODEL_TIMER1_NAME
:
364 case ITEM_MODEL_TIMER2_NAME
:
365 case ITEM_MODEL_TIMER3_NAME
:
367 TimerData
* timer
= &g_model
.timers
[k
>=ITEM_MODEL_TIMER3
? 2 : (k
>=ITEM_MODEL_TIMER2
? 1 : 0)];
368 editSingleName(MODEL_SETUP_2ND_COLUMN
, y
, STR_TIMER_NAME
, timer
->name
, sizeof(timer
->name
), event
, attr
);
372 case ITEM_MODEL_TIMER1_MINUTE_BEEP
:
373 case ITEM_MODEL_TIMER2_MINUTE_BEEP
:
374 case ITEM_MODEL_TIMER3_MINUTE_BEEP
:
376 TimerData
* timer
= &g_model
.timers
[k
>=ITEM_MODEL_TIMER3
? 2 : (k
>=ITEM_MODEL_TIMER2
? 1 : 0)];
377 timer
->minuteBeep
= editCheckBox(timer
->minuteBeep
, MODEL_SETUP_2ND_COLUMN
, y
, STR_MINUTEBEEP
, attr
, event
);
381 case ITEM_MODEL_TIMER1_COUNTDOWN_BEEP
:
382 case ITEM_MODEL_TIMER2_COUNTDOWN_BEEP
:
383 case ITEM_MODEL_TIMER3_COUNTDOWN_BEEP
:
385 TimerData
* timer
= &g_model
.timers
[k
>=ITEM_MODEL_TIMER3
? 2 : (k
>=ITEM_MODEL_TIMER2
? 1 : 0)];
386 timer
->countdownBeep
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_BEEPCOUNTDOWN
, STR_VBEEPCOUNTDOWN
, timer
->countdownBeep
, COUNTDOWN_SILENT
, COUNTDOWN_COUNT
-1, attr
, event
);
390 case ITEM_MODEL_TIMER1_PERSISTENT
:
391 case ITEM_MODEL_TIMER2_PERSISTENT
:
392 case ITEM_MODEL_TIMER3_PERSISTENT
:
394 TimerData
* timer
= &g_model
.timers
[k
>=ITEM_MODEL_TIMER3
? 2 : (k
>=ITEM_MODEL_TIMER2
? 1 : 0)];
395 timer
->persistent
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_PERSISTENT
, STR_VPERSISTENT
, timer
->persistent
, 0, 2, attr
, event
);
399 case ITEM_MODEL_TIMER1
:
400 case ITEM_MODEL_TIMER2
:
401 case ITEM_MODEL_TIMER1_MINUTE_BEEP
:
402 case ITEM_MODEL_TIMER2_MINUTE_BEEP
:
403 case ITEM_MODEL_TIMER1_COUNTDOWN_BEEP
:
404 case ITEM_MODEL_TIMER2_COUNTDOWN_BEEP
:
406 TimerData
*timer
= &g_model
.timers
[k
>=ITEM_MODEL_TIMER2
? 1 : 0];
407 if (k
==ITEM_MODEL_TIMER1_MINUTE_BEEP
|| k
==ITEM_MODEL_TIMER2_MINUTE_BEEP
) {
408 timer
->minuteBeep
= editCheckBox(timer
->minuteBeep
, MODEL_SETUP_2ND_COLUMN
, y
, STR_MINUTEBEEP
, attr
, event
);
410 else if (k
==ITEM_MODEL_TIMER1_COUNTDOWN_BEEP
|| k
==ITEM_MODEL_TIMER2_COUNTDOWN_BEEP
) {
411 timer
->countdownBeep
= editCheckBox(timer
->countdownBeep
, MODEL_SETUP_2ND_COLUMN
, y
, STR_BEEPCOUNTDOWN
, attr
, event
);
414 drawStringWithIndex(0*FW
, y
, STR_TIMER
, k
>=ITEM_MODEL_TIMER2
? 2 : 1);
415 drawTimerMode(MODEL_SETUP_2ND_COLUMN
, y
, timer
->mode
, menuHorizontalPosition
==0 ? attr
: 0);
416 drawTimer(MODEL_SETUP_2ND_COLUMN
+5*FW
-2+5*FWNUM
+1, y
, timer
->start
, menuHorizontalPosition
==1 ? attr
: 0, menuHorizontalPosition
==2 ? attr
: 0);
417 if (attr
&& (editMode
>0 || p1valdiff
)) {
418 div_t qr
= div(timer
->start
, 60);
419 switch (menuHorizontalPosition
) {
421 CHECK_INCDEC_MODELVAR_CHECK(event
, timer
->mode
, SWSRC_FIRST
, TMRMODE_COUNT
+SWSRC_LAST
-1/*SWSRC_None removed*/, isSwitchAvailableInTimers
);
424 CHECK_INCDEC_MODELVAR_ZERO(event
, qr
.quot
, 59);
425 timer
->start
= qr
.rem
+ qr
.quot
*60;
428 qr
.rem
-= checkIncDecModel(event
, qr
.rem
+2, 1, 62) - 2;
429 if ((int16_t)timer
->start
>= qr
.rem
) {
430 timer
->start
-= qr
.rem
;
432 if ((int16_t)timer
->start
> 3599) {
433 timer
->start
= 3599; // 59:59
442 #if defined(CPUM2560)
443 case ITEM_MODEL_TIMER1_PERSISTENT
:
444 case ITEM_MODEL_TIMER2_PERSISTENT
:
446 TimerData
&timer
= g_model
.timers
[k
==ITEM_MODEL_TIMER2_PERSISTENT
];
447 timer
.persistent
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_PERSISTENT
, STR_VPERSISTENT
, timer
.persistent
, 0, 2, attr
, event
);
453 case ITEM_MODEL_EXTENDED_LIMITS
:
454 ON_OFF_MENU_ITEM(g_model
.extendedLimits
, MODEL_SETUP_2ND_COLUMN
, y
, STR_ELIMITS
, attr
, event
);
457 case ITEM_MODEL_EXTENDED_TRIMS
:
459 ON_OFF_MENU_ITEM(g_model
.extendedTrims
, MODEL_SETUP_2ND_COLUMN
, y
, STR_ETRIMS
, attr
, event
);
461 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);
462 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+4*FW
, y
, STR_RESET_BTN
, (menuHorizontalPosition
>0 && !NO_HIGHLIGHT()) ? attr
: 0);
463 if (attr
&& menuHorizontalPosition
>0) {
465 if (event
==EVT_KEY_LONG(KEY_ENTER
)) {
466 START_NO_HIGHLIGHT();
467 for (uint8_t i
=0; i
<MAX_FLIGHT_MODES
; i
++) {
468 memclear(&g_model
.flightModeData
[i
], TRIMS_ARRAY_SIZE
);
470 storageDirty(EE_MODEL
);
478 case ITEM_MODEL_DISPLAY_TRIMS
:
479 g_model
.displayTrims
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_DISPLAY_TRIMS
, STR_VDISPLAYTRIMS
, g_model
.displayTrims
, 0, 2, attr
, event
);
483 case ITEM_MODEL_TRIM_INC
:
484 g_model
.trimInc
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_TRIMINC
, STR_VTRIMINC
, g_model
.trimInc
, -2, 2, attr
, event
);
487 case ITEM_MODEL_THROTTLE_REVERSED
:
488 ON_OFF_MENU_ITEM(g_model
.throttleReversed
, MODEL_SETUP_2ND_COLUMN
, y
, STR_THROTTLEREVERSE
, attr
, event
) ;
491 case ITEM_MODEL_THROTTLE_TRACE
:
493 lcdDrawTextAlignedLeft(y
, STR_TTRACE
);
494 if (attr
) CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.thrTraceSrc
, NUM_POTS
+NUM_SLIDERS
+MAX_OUTPUT_CHANNELS
);
495 uint8_t idx
= g_model
.thrTraceSrc
+ MIXSRC_Thr
;
496 if (idx
> MIXSRC_Thr
)
498 if (idx
>= MIXSRC_FIRST_POT
+NUM_POTS
+NUM_SLIDERS
)
499 idx
+= MIXSRC_CH1
- MIXSRC_FIRST_POT
- NUM_POTS
- NUM_SLIDERS
;
500 drawSource(MODEL_SETUP_2ND_COLUMN
, y
, idx
, attr
);
504 case ITEM_MODEL_THROTTLE_TRIM
:
505 ON_OFF_MENU_ITEM(g_model
.thrTrim
, MODEL_SETUP_2ND_COLUMN
, y
, STR_TTRIM
, attr
, event
);
509 case ITEM_MODEL_PREFLIGHT_LABEL
:
510 lcdDrawTextAlignedLeft(y
, STR_PREFLIGHT
);
513 case ITEM_MODEL_CHECKLIST_DISPLAY
:
514 ON_OFF_MENU_ITEM(g_model
.displayChecklist
, MODEL_SETUP_2ND_COLUMN
, y
, STR_CHECKLIST
, attr
, event
);
518 case ITEM_MODEL_THROTTLE_WARNING
:
519 g_model
.disableThrottleWarning
= !editCheckBox(!g_model
.disableThrottleWarning
, MODEL_SETUP_2ND_COLUMN
, y
, STR_THROTTLEWARNING
, attr
, event
);
522 case ITEM_MODEL_SWITCHES_WARNING
:
524 lcdDrawTextAlignedLeft(y
, STR_SWITCHWARNING
);
525 swarnstate_t states
= g_model
.switchWarningState
;
531 CASE_EVT_ROTARY_BREAK
532 case EVT_KEY_BREAK(KEY_ENTER
):
534 g_model
.switchWarningEnable
^= (1 << menuHorizontalPosition
);
535 storageDirty(EE_MODEL
);
538 if (menuHorizontalPosition
< NUM_SWITCHES
) {
539 g_model
.switchWarningEnable
^= (1 << (menuHorizontalPosition
-1));
541 if (menuHorizontalPosition
< NUM_SWITCHES
-1) {
542 g_model
.switchWarningEnable
^= (1 << menuHorizontalPosition
);
544 storageDirty(EE_MODEL
);
549 case EVT_KEY_LONG(KEY_ENTER
):
552 g_model
.switchWarningState
= switches_states
;
554 storageDirty(EE_MODEL
);
556 if (attr
&& menuHorizontalPosition
== 0) {
558 g_model
.switchWarningState
= switches_states
;
560 storageDirty(EE_MODEL
);
563 if (menuHorizontalPosition
== NUM_SWITCHES
-1) {
564 START_NO_HIGHLIGHT();
566 g_model
.switchWarningState
= switches_states
;
568 storageDirty(EE_MODEL
);
576 LcdFlags line
= attr
;
579 for (int i
=0; i
<NUM_SWITCHES
-1; i
++) {
580 if (SWITCH_WARNING_ALLOWED(i
)) {
581 div_t qr
= div(current
, 8);
582 uint8_t swactive
= !(g_model
.switchWarningEnable
& (1<<i
));
583 c
= "\300-\301"[states
& 0x03];
584 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+qr
.rem
*(2*FW
), y
, (i
< 4 ? 'A'+i
: 'B'+i
), line
&& (menuHorizontalPosition
-1==current
) ? INVERS
: 0);
585 if (swactive
) lcdDrawChar(lcdNextPos
, y
, c
);
590 if (attr
&& menuHorizontalPosition
== 0) {
591 lcdDrawFilledRect(MODEL_SETUP_2ND_COLUMN
-1, y
-1, (NUM_SWITCHES
-1)*(2*FW
), 1+FH
*((current
+7)/8));
594 for (uint8_t i
=0; i
<NUM_SWITCHES
-1/*not on TRN switch*/; i
++) {
595 uint8_t swactive
= !(g_model
.switchWarningEnable
& 1 << i
);
599 c
= '0'+(states
& 0x03);
603 if ((states
& 0x01) && swactive
)
605 c
= pgm_read_byte(STR_VSWITCHES
- 2 + 9 + (3*(i
+1)));
608 if (line
&& (menuHorizontalPosition
== i
)) {
609 attr
= BLINK
| INVERS
;
612 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+i
*FW
, y
, (swactive
) ? c
: '-', attr
);
614 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+i
*FW
, y
, (swactive
|| (attr
& BLINK
)) ? c
: '-', attr
);
617 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+(NUM_SWITCHES
*FW
), y
, PSTR("<]"), (menuHorizontalPosition
== NUM_SWITCHES
-1 && !NO_HIGHLIGHT()) ? line
: 0);
624 case ITEM_MODEL_POTS_WARNING
:
625 lcdDrawTextAlignedLeft(y
, STR_POTWARNING
);
626 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, PSTR("\004""OFF\0""Man\0""Auto"), g_model
.potsWarnMode
, (menuHorizontalPosition
== 0) ? attr
: 0);
627 if (attr
&& (menuHorizontalPosition
== 0)) {
628 CHECK_INCDEC_MODELVAR(event
, g_model
.potsWarnMode
, POTS_WARN_OFF
, POTS_WARN_AUTO
);
629 storageDirty(EE_MODEL
);
633 if (menuHorizontalPosition
> 0) s_editMode
= 0;
634 if (!READ_ONLY() && menuHorizontalPosition
> 0) {
636 case EVT_KEY_LONG(KEY_ENTER
):
638 if (g_model
.potsWarnMode
== POTS_WARN_MANUAL
) {
639 SAVE_POT_POSITION(menuHorizontalPosition
-1);
641 storageDirty(EE_MODEL
);
644 case EVT_KEY_BREAK(KEY_ENTER
):
645 g_model
.potsWarnEnabled
^= (1 << (menuHorizontalPosition
-1));
646 storageDirty(EE_MODEL
);
651 if (g_model
.potsWarnMode
) {
652 coord_t x
= MODEL_SETUP_2ND_COLUMN
+28;
653 for (int i
=0; i
<NUM_POTS
+NUM_SLIDERS
; ++i
) {
654 if (i
<NUM_XPOTS
&& !IS_POT_SLIDER_AVAILABLE(POT1
+i
)) {
655 if (attr
&& (menuHorizontalPosition
==i
+1)) REPEAT_LAST_CURSOR_MOVE();
658 LcdFlags flags
= ((menuHorizontalPosition
==i
+1) && attr
) ? BLINK
: 0;
659 if ((!attr
|| menuHorizontalPosition
>= 0) && !(g_model
.potsWarnEnabled
& (1 << i
))) {
663 // TODO add a new function
664 lcdDrawSizedText(x
, y
, STR_VSRCRAW
+2+STR_VSRCRAW
[0]*(NUM_STICKS
+1+i
), STR_VSRCRAW
[0]-1, flags
& ~ZCHAR
);
672 case ITEM_MODEL_BEEP_CENTER
:
673 lcdDrawTextAlignedLeft(y
, STR_BEEPCTR
);
674 for (uint8_t i
=0; i
<NUM_STICKS
+NUM_POTS
+NUM_SLIDERS
+NUM_ROTARY_ENCODERS
; i
++) {
675 // TODO flash saving, \001 not needed in STR_RETA123
676 coord_t x
= MODEL_SETUP_2ND_COLUMN
+i
*FW
;
677 lcdDrawTextAtIndex(x
, y
, STR_RETA123
, i
, ((menuHorizontalPosition
==i
) && attr
) ? BLINK
|INVERS
: (((g_model
.beepANACenter
& ((BeepANACenter
)1<<i
)) || (attr
&& CURSOR_ON_LINE())) ? INVERS
: 0 ) );
679 if (attr
&& CURSOR_ON_CELL
) {
680 if (event
==EVT_KEY_BREAK(KEY_ENTER
) || p1valdiff
) {
681 if (READ_ONLY_UNLOCKED()) {
683 g_model
.beepANACenter
^= ((BeepANACenter
)1<<menuHorizontalPosition
);
684 storageDirty(EE_MODEL
);
691 case ITEM_MODEL_USE_GLOBAL_FUNCTIONS
:
692 lcdDrawTextAlignedLeft(y
, STR_USE_GLOBAL_FUNCS
);
693 drawCheckBox(MODEL_SETUP_2ND_COLUMN
, y
, !g_model
.noGlobalFunctions
, attr
);
694 if (attr
) g_model
.noGlobalFunctions
= !checkIncDecModel(event
, !g_model
.noGlobalFunctions
, 0, 1);
699 case ITEM_MODEL_INTERNAL_MODULE_LABEL
:
700 lcdDrawTextAlignedLeft(y
, TR_INTERNALRF
);
703 case ITEM_MODEL_INTERNAL_MODULE_MODE
:
704 lcdDrawTextAlignedLeft(y
, STR_MODE
);
705 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_XJT_PROTOCOLS
, 1+g_model
.moduleData
[0].rfProtocol
, attr
);
707 g_model
.moduleData
[INTERNAL_MODULE
].rfProtocol
= checkIncDec(event
, g_model
.moduleData
[INTERNAL_MODULE
].rfProtocol
, RF_PROTO_OFF
, RF_PROTO_LAST
, EE_MODEL
, isRfProtocolAvailable
);
708 if (checkIncDec_Ret
) {
709 g_model
.moduleData
[0].type
= MODULE_TYPE_XJT
;
710 g_model
.moduleData
[0].channelsStart
= 0;
711 g_model
.moduleData
[0].channelsCount
= DEFAULT_CHANNELS(INTERNAL_MODULE
);
712 if (g_model
.moduleData
[INTERNAL_MODULE
].rfProtocol
== RF_PROTO_OFF
)
713 g_model
.moduleData
[INTERNAL_MODULE
].type
= MODULE_TYPE_NONE
;
719 #if defined(PCBSKY9X)
720 case ITEM_MODEL_EXTRA_MODULE_LABEL
:
721 lcdDrawTextAlignedLeft(y
, "RF Port 2 (PPM)");
726 case ITEM_MODEL_EXTERNAL_MODULE_LABEL
:
727 lcdDrawTextAlignedLeft(y
, TR_EXTERNALRF
);
730 case ITEM_MODEL_EXTERNAL_MODULE_MODE
:
731 lcdDrawTextAlignedLeft(y
, STR_MODE
);
732 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_TARANIS_PROTOCOLS
, g_model
.moduleData
[EXTERNAL_MODULE
].type
, menuHorizontalPosition
==0 ? attr
: 0);
733 if (IS_MODULE_XJT(EXTERNAL_MODULE
))
734 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
+5*FW
, y
, STR_XJT_PROTOCOLS
, 1+g_model
.moduleData
[EXTERNAL_MODULE
].rfProtocol
, menuHorizontalPosition
==1 ? attr
: 0);
735 else if (IS_MODULE_DSM2(EXTERNAL_MODULE
))
736 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
+5*FW
, y
, STR_DSM_PROTOCOLS
, g_model
.moduleData
[EXTERNAL_MODULE
].rfProtocol
, menuHorizontalPosition
==1 ? attr
: 0);
737 else if (IS_MODULE_R9M(EXTERNAL_MODULE
))
738 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
+5*FW
, y
, STR_R9M_MODES
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, (menuHorizontalPosition
==1 ? attr
: 0));
739 #if defined(MULTIMODULE)
740 else if (IS_MODULE_MULTIMODULE(EXTERNAL_MODULE
)) {
741 int multi_rfProto
= g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol(false);
742 if (g_model
.moduleData
[EXTERNAL_MODULE
].multi
.customProto
)
743 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+5*FW
, y
, STR_MULTI_CUSTOM
, menuHorizontalPosition
==1 ? attr
: 0);
745 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
+5*FW
, y
, STR_MULTI_PROTOCOLS
, multi_rfProto
, menuHorizontalPosition
==1 ? attr
: 0);
748 if (attr
&& (editMode
>0 || p1valdiff
)) {
749 switch (menuHorizontalPosition
) {
751 g_model
.moduleData
[EXTERNAL_MODULE
].type
= checkIncDec(event
, g_model
.moduleData
[EXTERNAL_MODULE
].type
, MODULE_TYPE_NONE
, IS_TRAINER_EXTERNAL_MODULE() ? MODULE_TYPE_NONE
: MODULE_TYPE_COUNT
-1, EE_MODEL
, isModuleAvailable
);
752 if (checkIncDec_Ret
) {
753 g_model
.moduleData
[EXTERNAL_MODULE
].rfProtocol
= 0;
754 g_model
.moduleData
[EXTERNAL_MODULE
].channelsStart
= 0;
755 g_model
.moduleData
[EXTERNAL_MODULE
].channelsCount
= DEFAULT_CHANNELS(EXTERNAL_MODULE
);
756 if (IS_MODULE_SBUS(EXTERNAL_MODULE
))
757 g_model
.moduleData
[EXTERNAL_MODULE
].sbus
.refreshRate
= -31;
761 if (IS_MODULE_DSM2(EXTERNAL_MODULE
))
762 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[EXTERNAL_MODULE
].rfProtocol
, DSM2_PROTO_LP45
, DSM2_PROTO_DSMX
);
763 else if (IS_MODULE_R9M(EXTERNAL_MODULE
))
764 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, MODULE_SUBTYPE_R9M_FCC
, MODULE_SUBTYPE_R9M_LBT
);
765 #if defined(MULTIMODULE)
766 else if (IS_MODULE_MULTIMODULE(EXTERNAL_MODULE
)) {
767 int multiRfProto
= g_model
.moduleData
[EXTERNAL_MODULE
].multi
.customProto
== 1 ? MM_RF_PROTO_CUSTOM
: g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol(false);
768 CHECK_INCDEC_MODELVAR(event
, multiRfProto
, MM_RF_PROTO_FIRST
, MM_RF_PROTO_LAST
);
769 if (checkIncDec_Ret
) {
770 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.customProto
= (multiRfProto
== MM_RF_PROTO_CUSTOM
);
771 if (!g_model
.moduleData
[EXTERNAL_MODULE
].multi
.customProto
)
772 g_model
.moduleData
[EXTERNAL_MODULE
].setMultiProtocol(multiRfProto
);
773 g_model
.moduleData
[EXTERNAL_MODULE
].subType
= 0;
774 // Sensible default for DSM2 (same as for ppm): 7ch@22ms + Autodetect settings enabled
775 if (g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol(true) == MM_RF_PROTO_DSM2
) {
776 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.autoBindMode
= 1;
779 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.autoBindMode
= 0;
781 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.optionValue
= 0;
786 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[EXTERNAL_MODULE
].rfProtocol
, RF_PROTO_X16
, RF_PROTO_LAST
);
788 if (checkIncDec_Ret
) {
789 g_model
.moduleData
[EXTERNAL_MODULE
].channelsStart
= 0;
790 g_model
.moduleData
[EXTERNAL_MODULE
].channelsCount
= DEFAULT_CHANNELS(EXTERNAL_MODULE
);
797 #if defined(MULTIMODULE)
798 case ITEM_MODEL_EXTERNAL_MODULE_SUBTYPE
:
800 lcdDrawTextAlignedLeft(y
, STR_SUBTYPE
);
801 uint8_t multi_rfProto
= g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol(true);
802 const mm_protocol_definition
* pdef
= getMultiProtocolDefinition(multi_rfProto
);
804 if (multi_rfProto
== MM_RF_CUSTOM_SELECTED
) {
805 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
+ 3 * FW
, y
, g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol(false), RIGHT
| (menuHorizontalPosition
== 0 ? attr
: 0), 2);
806 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
+ 5 * FW
, y
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, RIGHT
| (menuHorizontalPosition
== 1 ? attr
: 0), 2);
809 if (pdef
->subTypeString
!= nullptr)
810 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, pdef
->subTypeString
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, attr
);
812 if (attr
&& (editMode
> 0 || p1valdiff
)) {
813 switch (menuHorizontalPosition
) {
815 if (multi_rfProto
== MM_RF_CUSTOM_SELECTED
)
816 g_model
.moduleData
[EXTERNAL_MODULE
].setMultiProtocol(checkIncDec(event
, g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol(false), 0, 63, EE_MODEL
));
817 else if (pdef
->maxSubtype
> 0)
818 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, 0, pdef
->maxSubtype
);
821 // Custom protocol, third column is subtype
822 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[EXTERNAL_MODULE
].subType
, 0, 7);
831 case ITEM_MODEL_TRAINER_LABEL
:
832 lcdDrawTextAlignedLeft(y
, STR_TRAINER
);
835 case ITEM_MODEL_TRAINER_MODE
:
836 lcdDrawTextAlignedLeft(y
, STR_MODE
);
837 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_VTRAINERMODES
, g_model
.trainerMode
, attr
);
839 g_model
.trainerMode
= checkIncDec(event
, g_model
.trainerMode
, 0, TRAINER_MODE_MAX(), EE_MODEL
, isTrainerModeAvailable
);
840 #if defined(BLUETOOTH)
841 if (checkIncDec_Ret
) {
842 bluetoothState
= BLUETOOTH_STATE_OFF
;
843 bluetoothDistantAddr
[0] = 0;
850 #if defined(PCBX7) && defined(BLUETOOTH)
851 case ITEM_MODEL_TRAINER_BLUETOOTH
:
852 if (g_model
.trainerMode
== TRAINER_MODE_MASTER_BLUETOOTH
) {
856 if (bluetoothDistantAddr
[0]) {
857 lcdDrawText(INDENT_WIDTH
, y
+1, bluetoothDistantAddr
, TINSIZE
);
858 if (bluetoothState
!= BLUETOOTH_STATE_CONNECTED
) {
859 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, BUTTON("Bind"), menuHorizontalPosition
== 0 ? attr
: 0);
860 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+5*FW
, y
, BUTTON("Clear"), menuHorizontalPosition
== 1 ? attr
: 0);
863 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, BUTTON("Clear"), attr
);
865 if (attr
&& event
== EVT_KEY_FIRST(KEY_ENTER
)) {
866 if (bluetoothState
== BLUETOOTH_STATE_CONNECTED
|| menuHorizontalPosition
== 1) {
867 bluetoothState
= BLUETOOTH_STATE_OFF
;
868 bluetoothDistantAddr
[0] = 0;
871 bluetoothState
= BLUETOOTH_STATE_BIND_REQUESTED
;
876 lcdDrawText(INDENT_WIDTH
, y
, "---");
877 if (bluetoothState
< BLUETOOTH_STATE_IDLE
)
878 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, BUTTON("Init"), attr
);
880 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, BUTTON("Discover"), attr
);
881 if (attr
&& event
== EVT_KEY_FIRST(KEY_ENTER
)) {
882 if (bluetoothState
< BLUETOOTH_STATE_IDLE
)
883 bluetoothState
= BLUETOOTH_STATE_OFF
;
885 bluetoothState
= BLUETOOTH_STATE_DISCOVER_REQUESTED
;
890 if (bluetoothDistantAddr
[0])
891 lcdDrawText(INDENT_WIDTH
, y
+1, bluetoothDistantAddr
, TINSIZE
);
893 lcdDrawText(INDENT_WIDTH
, y
, "---");
894 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, bluetoothState
== BLUETOOTH_STATE_CONNECTED
? "Connected" : "!Connected");
900 case ITEM_MODEL_TRAINER_CHANNELS
:
901 case ITEM_MODEL_INTERNAL_MODULE_CHANNELS
:
903 #if defined(PCBSKY9X)
904 case ITEM_MODEL_EXTRA_MODULE_CHANNELS
:
907 case ITEM_MODEL_EXTERNAL_MODULE_CHANNELS
:
909 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
910 ModuleData
& moduleData
= g_model
.moduleData
[moduleIdx
];
911 lcdDrawTextAlignedLeft(y
, STR_CHANNELRANGE
);
912 if ((int8_t)PORT_CHANNELS_ROWS(moduleIdx
) >= 0) {
913 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_CH
, menuHorizontalPosition
==0 ? attr
: 0);
914 lcdDrawNumber(lcdLastRightPos
, y
, moduleData
.channelsStart
+1, LEFT
| (menuHorizontalPosition
==0 ? attr
: 0));
915 lcdDrawChar(lcdLastRightPos
, y
, '-');
916 lcdDrawNumber(lcdLastRightPos
+ FW
+1, y
, moduleData
.channelsStart
+NUM_CHANNELS(moduleIdx
), LEFT
| (menuHorizontalPosition
==1 ? attr
: 0));
917 if (attr
&& (editMode
>0 || p1valdiff
)) {
918 switch (menuHorizontalPosition
) {
920 CHECK_INCDEC_MODELVAR_ZERO(event
, moduleData
.channelsStart
, 32-8-moduleData
.channelsCount
);
923 CHECK_INCDEC_MODELVAR(event
, moduleData
.channelsCount
, -4, min
<int8_t>(MAX_CHANNELS(moduleIdx
), 32-8-moduleData
.channelsStart
));
924 if ((k
== ITEM_MODEL_EXTERNAL_MODULE_CHANNELS
&& g_model
.moduleData
[EXTERNAL_MODULE
].type
== MODULE_TYPE_PPM
)) {
925 SET_DEFAULT_PPM_FRAME_LENGTH(moduleIdx
);
936 case ITEM_MODEL_TRAINER_PARAMS
:
937 case ITEM_MODEL_INTERNAL_MODULE_BIND
:
939 #if defined(PCBSKY9X)
940 case ITEM_MODEL_EXTRA_MODULE_BIND
:
943 case ITEM_MODEL_EXTERNAL_MODULE_BIND
:
945 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
946 ModuleData
& moduleData
= g_model
.moduleData
[moduleIdx
];
947 if (IS_MODULE_PPM(moduleIdx
)) {
948 lcdDrawTextAlignedLeft(y
, STR_PPMFRAME
);
949 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+3*FW
, y
, STR_MS
);
950 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, (int16_t)moduleData
.ppm
.frameLength
*5 + 225, (menuHorizontalPosition
<=0 ? attr
: 0) | PREC1
|LEFT
);
951 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, 'u');
952 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, (moduleData
.ppm
.delay
*50)+300, RIGHT
| ((CURSOR_ON_LINE() || menuHorizontalPosition
==1) ? attr
: 0));
953 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+10*FW
, y
, moduleData
.ppm
.pulsePol
? '+' : '-', (CURSOR_ON_LINE() || menuHorizontalPosition
==2) ? attr
: 0);
954 if (attr
&& (editMode
>0 || p1valdiff
)) {
955 switch (menuHorizontalPosition
) {
957 CHECK_INCDEC_MODELVAR(event
, moduleData
.ppm
.frameLength
, -20, 35);
960 CHECK_INCDEC_MODELVAR(event
, moduleData
.ppm
.delay
, -4, 10);
963 CHECK_INCDEC_MODELVAR_ZERO(event
, moduleData
.ppm
.pulsePol
, 1);
968 else if (IS_MODULE_SBUS(moduleIdx
)) {
969 lcdDrawTextAlignedLeft(y
, STR_REFRESHRATE
);
970 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, (int16_t)moduleData
.ppm
.frameLength
*5 + 225, (menuHorizontalPosition
<=0 ? attr
: 0) | PREC1
|LEFT
);
971 lcdDrawText(lcdLastRightPos
, y
, STR_MS
);
972 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+5*FW
+2, y
, moduleData
.sbus
.noninverted
? "no inv" : "normal", (CURSOR_ON_LINE() || menuHorizontalPosition
==1) ? attr
: 0);
974 if (attr
&& s_editMode
>0) {
975 switch (menuHorizontalPosition
) {
977 CHECK_INCDEC_MODELVAR(event
, moduleData
.ppm
.frameLength
, -33, 35);
980 CHECK_INCDEC_MODELVAR_ZERO(event
, moduleData
.sbus
.noninverted
, 1);
986 horzpos_t l_posHorz
= menuHorizontalPosition
;
987 coord_t xOffsetBind
= MODEL_SETUP_BIND_OFS
;
988 if (IS_MODULE_XJT(moduleIdx
) && IS_D8_RX(moduleIdx
)) {
990 lcdDrawTextAlignedLeft(y
, STR_RECEIVER
);
991 if (attr
) l_posHorz
+= 1;
994 lcdDrawTextAlignedLeft(y
, STR_RECEIVER_NUM
);
996 if (IS_MODULE_PXX(moduleIdx
) || IS_MODULE_DSM2(moduleIdx
) || IS_MODULE_MULTIMODULE(moduleIdx
)) {
997 if (xOffsetBind
) lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, g_model
.header
.modelId
[moduleIdx
], (l_posHorz
==0 ? attr
: 0) | LEADING0
|LEFT
, 2);
998 if (attr
&& l_posHorz
==0) {
999 if (editMode
>0 || p1valdiff
) {
1000 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.header
.modelId
[moduleIdx
], MAX_RX_NUM(moduleIdx
));
1001 if (checkIncDec_Ret
) {
1002 modelHeaders
[g_eeGeneral
.currModel
].modelId
[moduleIdx
] = g_model
.header
.modelId
[moduleIdx
];
1005 if (editMode
==0 && event
==EVT_KEY_BREAK(KEY_ENTER
)) {
1006 checkModelIdUnique(g_eeGeneral
.currModel
, moduleIdx
);
1009 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+xOffsetBind
, y
, STR_MODULE_BIND
, l_posHorz
==1 ? attr
: 0);
1010 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+MODEL_SETUP_RANGE_OFS
+xOffsetBind
, y
, STR_MODULE_RANGE
, l_posHorz
==2 ? attr
: 0);
1011 uint8_t newFlag
= 0;
1012 #if defined(MULTIMODULE)
1013 if (multiBindStatus
== MULTI_BIND_FINISHED
) {
1014 multiBindStatus
= MULTI_NORMAL_OPERATION
;
1018 #if defined(PCBTARANIS)
1019 if (attr
&& l_posHorz
> 0) {
1020 if (s_editMode
> 0) {
1021 if (l_posHorz
== 1) {
1022 if (IS_MODULE_R9M(moduleIdx
) || (IS_MODULE_XJT(moduleIdx
) && g_model
.moduleData
[moduleIdx
].rfProtocol
== RF_PROTO_X16
)) {
1023 if (event
== EVT_KEY_BREAK(KEY_ENTER
)) {
1024 uint8_t default_selection
;
1025 if (IS_MODULE_R9M_LBT(moduleIdx
)) {
1026 POPUP_MENU_ADD_ITEM(STR_BINDING_25MW_CH1_8_TELEM_OFF
);
1027 POPUP_MENU_ADD_ITEM(STR_BINDING_25MW_CH1_8_TELEM_ON
);
1028 POPUP_MENU_ADD_ITEM(STR_BINDING_500MW_CH1_8_TELEM_OFF
);
1029 POPUP_MENU_ADD_ITEM(STR_BINDING_500MW_CH9_16_TELEM_OFF
);
1030 default_selection
= 2;
1033 POPUP_MENU_ADD_ITEM(STR_BINDING_1_8_TELEM_ON
);
1034 POPUP_MENU_ADD_ITEM(STR_BINDING_1_8_TELEM_OFF
);
1035 POPUP_MENU_ADD_ITEM(STR_BINDING_9_16_TELEM_ON
);
1036 POPUP_MENU_ADD_ITEM(STR_BINDING_9_16_TELEM_OFF
);
1037 default_selection
= g_model
.moduleData
[INTERNAL_MODULE
].pxx
.receiver_telem_off
+ (g_model
.moduleData
[INTERNAL_MODULE
].pxx
.receiver_channel_9_16
<< 1);
1039 POPUP_MENU_SELECT_ITEM(default_selection
);
1040 POPUP_MENU_START(onBindMenu
);
1043 if (moduleFlag
[moduleIdx
] == MODULE_BIND
) {
1044 newFlag
= MODULE_BIND
;
1047 if (!popupMenuNoItems
) {
1048 s_editMode
= 0; // this is when popup is exited before a choice is made
1053 newFlag
= MODULE_BIND
;
1056 else if (l_posHorz
== 2) {
1057 newFlag
= MODULE_RANGECHECK
;
1062 if (attr
&& l_posHorz
>0 && s_editMode
>0) {
1064 newFlag
= MODULE_BIND
;
1065 else if (l_posHorz
== 2)
1066 newFlag
= MODULE_RANGECHECK
;
1069 moduleFlag
[moduleIdx
] = newFlag
;
1071 #if defined(MULTIMODULE)
1072 if (newFlag
== MODULE_BIND
) {
1073 multiBindStatus
= MULTI_BIND_INITIATED
;
1083 #if defined(PCBSKY9X) && defined(REVX)
1084 case ITEM_MODEL_EXTERNAL_MODULE_OUTPUT_TYPE
:
1086 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1087 ModuleData
& moduleData
= g_model
.moduleData
[moduleIdx
];
1088 moduleData
.ppm
.outputType
= editChoice(MODEL_SETUP_2ND_COLUMN
, y
, STR_OUTPUT_TYPE
, STR_VOUTPUT_TYPE
, moduleData
.ppm
.outputType
, 0, 1, attr
, event
);
1094 case ITEM_MODEL_INTERNAL_MODULE_FAILSAFE
:
1097 case ITEM_MODEL_EXTERNAL_MODULE_FAILSAFE
: {
1098 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1099 ModuleData
&moduleData
= g_model
.moduleData
[moduleIdx
];
1100 lcdDrawTextAlignedLeft(y
, STR_FAILSAFE
);
1101 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_VFAILSAFE
, moduleData
.failsafeMode
, menuHorizontalPosition
== 0 ? attr
: 0);
1102 if (moduleData
.failsafeMode
== FAILSAFE_CUSTOM
)
1103 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+ MODEL_SETUP_SET_FAILSAFE_OFS
, y
, STR_SET
, menuHorizontalPosition
== 1 ? attr
: 0);
1105 if (moduleData
.failsafeMode
!= FAILSAFE_CUSTOM
)
1106 menuHorizontalPosition
= 0;
1107 if (menuHorizontalPosition
== 0) {
1108 if (editMode
> 0 || p1valdiff
) {
1109 CHECK_INCDEC_MODELVAR_ZERO(event
, moduleData
.failsafeMode
, FAILSAFE_LAST
);
1110 if (checkIncDec_Ret
) SEND_FAILSAFE_NOW(moduleIdx
);
1112 } else if (menuHorizontalPosition
== 1) {
1114 if (moduleData
.failsafeMode
== FAILSAFE_CUSTOM
&& event
== EVT_KEY_FIRST(KEY_ENTER
)) {
1115 g_moduleIdx
= moduleIdx
;
1116 pushMenu(menuModelFailsafe
);
1119 lcdDrawSolidFilledRect(MODEL_SETUP_2ND_COLUMN
, y
, LCD_W
- MODEL_SETUP_2ND_COLUMN
, 8);
1125 case ITEM_MODEL_EXTERNAL_MODULE_OPTIONS
:
1127 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1128 #if defined(MULTIMODULE)
1129 if (IS_MODULE_MULTIMODULE(moduleIdx
)) {
1130 int optionValue
= g_model
.moduleData
[moduleIdx
].multi
.optionValue
;
1132 const uint8_t multi_proto
= g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol(true);
1133 const mm_protocol_definition
* pdef
= getMultiProtocolDefinition(multi_proto
);
1134 if (pdef
->optionsstr
)
1135 lcdDrawTextAlignedLeft(y
, pdef
->optionsstr
);
1137 if (multi_proto
== MM_RF_PROTO_FS_AFHDS2A
)
1138 optionValue
= 50 + 5 * optionValue
;
1140 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, optionValue
, LEFT
| attr
);
1142 if (multi_proto
== MM_RF_PROTO_FS_AFHDS2A
) {
1143 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[moduleIdx
].multi
.optionValue
, 0, 70);
1145 else if (multi_proto
== MM_RF_PROTO_OLRS
) {
1146 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[moduleIdx
].multi
.optionValue
, -1, 7);
1149 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[moduleIdx
].multi
.optionValue
, -128, 127);
1154 if (IS_MODULE_R9M_FCC(moduleIdx
)) {
1155 if (IS_TELEMETRY_INTERNAL_MODULE()) {
1156 lcdDrawTextAlignedLeft(y
, STR_MODULE_TELEMETRY
);
1157 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_DISABLE_INTERNAL
);
1160 g_model
.moduleData
[moduleIdx
].pxx
.sport_out
= editCheckBox(g_model
.moduleData
[EXTERNAL_MODULE
].pxx
.sport_out
, MODEL_SETUP_2ND_COLUMN
, y
, STR_MODULE_TELEMETRY
, attr
, event
);
1163 else if (IS_MODULE_R9M_LBT(moduleIdx
)) {
1164 if (IS_TELEMETRY_INTERNAL_MODULE()) {
1165 lcdDrawTextAlignedLeft(y
, STR_MODULE_TELEMETRY
);
1166 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_DISABLE_INTERNAL
);
1169 lcdDrawTextAlignedLeft(y
, STR_MODULE_TELEMETRY
);
1170 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, STR_BINDING_OPTION
);
1173 else if (IS_MODULE_SBUS(moduleIdx
)) {
1174 lcdDrawTextAlignedLeft(y
, STR_WARN_BATTVOLTAGE
);
1175 putsVolts(lcdLastRightPos
, y
, getBatteryVoltage(), attr
| PREC2
| LEFT
);
1180 case ITEM_MODEL_EXTERNAL_MODULE_POWER
:
1182 uint8_t moduleIdx
= CURRENT_MODULE_EDITED(k
);
1183 if (IS_MODULE_R9M_FCC(moduleIdx
)) {
1184 // Power selection is only available on R9M FCC
1185 lcdDrawTextAlignedLeft(y
, TR_MULTI_RFPOWER
);
1186 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_R9M_FCC_POWER_VALUES
, g_model
.moduleData
[moduleIdx
].pxx
.power
, LEFT
| attr
);
1188 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[moduleIdx
].pxx
.power
, 0, R9M_FCC_POWER_MAX
);
1190 #if defined(MULTIMODULE)
1191 else if (IS_MODULE_MULTIMODULE(moduleIdx
)) {
1192 g_model
.moduleData
[EXTERNAL_MODULE
].multi
.lowPowerMode
= editCheckBox(g_model
.moduleData
[EXTERNAL_MODULE
].multi
.lowPowerMode
, MODEL_SETUP_2ND_COLUMN
, y
, STR_MULTI_LOWPOWER
, attr
, event
);
1199 #if defined(MULTIMODULE)
1200 case ITEM_MODEL_EXTERNAL_MODULE_AUTOBIND
:
1201 if (g_model
.moduleData
[EXTERNAL_MODULE
].getMultiProtocol(true) == MM_RF_PROTO_DSM2
)
1202 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
);
1204 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
);
1207 case ITEM_MODEL_EXTERNAL_MODULE_STATUS
: {
1208 lcdDrawTextAlignedLeft(y
, STR_MODULE_STATUS
);
1210 char statusText
[64];
1211 multiModuleStatus
.getStatusString(statusText
);
1212 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, statusText
);
1216 case ITEM_MODEL_EXTERNAL_MODULE_SYNCSTATUS
: {
1217 lcdDrawTextAlignedLeft(y
, STR_MODULE_SYNC
);
1219 char statusText
[64];
1220 multiSyncStatus
.getRefreshString(statusText
);
1221 lcdDrawText(MODEL_SETUP_2ND_COLUMN
, y
, statusText
);
1227 #if !defined(CPUARM)
1228 case ITEM_MODEL_PPM1_PROTOCOL
:
1229 lcdDrawTextAlignedLeft(y
, NO_INDENT(STR_PROTO
));
1230 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_VPROTOS
, protocol
, menuHorizontalPosition
<=0 ? attr
: 0);
1231 if (IS_PPM_PROTOCOL(protocol
)) {
1232 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
+7*FW
, y
, STR_NCHANNELS
, g_model
.ppmNCH
+2, menuHorizontalPosition
!=0 ? attr
: 0);
1234 else if (menuHorizontalPosition
>0 && attr
) {
1235 MOVE_CURSOR_FROM_HERE();
1237 if (attr
&& (editMode
>0 || p1valdiff
|| (!IS_PPM_PROTOCOL(protocol
) && !IS_DSM2_PROTOCOL(protocol
)))) {
1238 switch (menuHorizontalPosition
) {
1240 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.protocol
, PROTO_MAX
-1);
1243 CHECK_INCDEC_MODELVAR(event
, g_model
.ppmNCH
, -2, 4);
1244 g_model
.ppmFrameLength
= g_model
.ppmNCH
* 8;
1252 case ITEM_MODEL_PPM2_PROTOCOL
:
1253 lcdDrawTextAlignedLeft(y
, PSTR("Port2"));
1254 lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN
, y
, STR_VPROTOS
, 0, 0);
1255 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+4*FW
+3, y
, STR_CH
, menuHorizontalPosition
<=0 ? attr
: 0);
1256 lcdDrawNumber(lcdLastRightPos
, y
, g_model
.moduleData
[1].channelsStart
+1, LEFT
| (menuHorizontalPosition
<=0 ? attr
: 0));
1257 lcdDrawChar(lcdLastRightPos
, y
, '-');
1258 lcdDrawNumber(lcdLastRightPos
+ FW
+1, y
, g_model
.moduleData
[1].channelsStart
+8+g_model
.moduleData
[1].channelsCount
, LEFT
| (menuHorizontalPosition
!=0 ? attr
: 0));
1259 if (attr
&& (editMode
>0 || p1valdiff
)) {
1260 switch (menuHorizontalPosition
) {
1262 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.moduleData
[1].channelsStart
, 32-8-g_model
.moduleData
[1].channelsCount
);
1263 SET_DEFAULT_PPM_FRAME_LENGTH(1);
1266 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[1].channelsCount
, -4, min
<int8_t>(8, 32-8-g_model
.moduleData
[1].channelsStart
));
1267 SET_DEFAULT_PPM_FRAME_LENGTH(1);
1273 case ITEM_MODEL_PPM2_PARAMS
:
1274 lcdDrawTextAlignedLeft(y
, STR_PPMFRAME
);
1275 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+3*FW
, y
, STR_MS
);
1276 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, (int16_t)g_model
.moduleData
[1].ppmFrameLength
*5 + 225, (menuHorizontalPosition
<=0 ? attr
: 0) | PREC1
| LEFT
);
1277 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, 'u');
1278 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, (g_model
.moduleData
[1].ppmDelay
*50)+300, RIGHT
| ((menuHorizontalPosition
< 0 || menuHorizontalPosition
==1) ? attr
: 0));
1279 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+10*FW
, y
, g_model
.moduleData
[1].ppmPulsePol
? '+' : '-', (menuHorizontalPosition
< 0 || menuHorizontalPosition
==2) ? attr
: 0);
1280 if (attr
&& (editMode
>0 || p1valdiff
)) {
1281 switch (menuHorizontalPosition
) {
1283 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[1].ppmFrameLength
, -20, 35);
1286 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[1].ppmDelay
, -4, 10);
1289 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.moduleData
[1].ppmPulsePol
, 1);
1296 #if !defined(CPUARM)
1297 case ITEM_MODEL_PPM1_PARAMS
:
1298 if (IS_PPM_PROTOCOL(protocol
)) {
1299 lcdDrawTextAlignedLeft(y
, STR_PPMFRAME
);
1300 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+3*FW
, y
, STR_MS
);
1301 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, (int16_t)g_model
.ppmFrameLength
*5 + 225, (menuHorizontalPosition
<=0 ? attr
: 0) | PREC1
|LEFT
);
1302 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, 'u');
1303 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
+8*FW
+2, y
, (g_model
.ppmDelay
*50)+300, (CURSOR_ON_LINE() || menuHorizontalPosition
==1) ? attr
: 0);
1304 lcdDrawChar(MODEL_SETUP_2ND_COLUMN
+10*FW
, y
, g_model
.pulsePol
? '+' : '-', (CURSOR_ON_LINE() || menuHorizontalPosition
==2) ? attr
: 0);
1305 if (attr
&& (editMode
>0 || p1valdiff
)) {
1306 switch (menuHorizontalPosition
) {
1308 CHECK_INCDEC_MODELVAR(event
, g_model
.ppmFrameLength
, -20, 35);
1311 CHECK_INCDEC_MODELVAR(event
, g_model
.ppmDelay
, -4, 10);
1314 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.pulsePol
, 1);
1319 #if defined(DSM2) || defined(PXX)
1320 else if (IS_DSM2_PROTOCOL(protocol
) || IS_PXX_PROTOCOL(protocol
)) {
1321 if (attr
&& menuHorizontalPosition
> 1) {
1322 REPEAT_LAST_CURSOR_MOVE(); // limit 3 column row to 2 colums (Rx_Num and RANGE fields)
1324 lcdDrawTextAlignedLeft(y
, STR_RECEIVER_NUM
);
1325 lcdDrawNumber(MODEL_SETUP_2ND_COLUMN
, y
, g_model
.header
.modelId
[0], (menuHorizontalPosition
<=0 ? attr
: 0) | LEADING0
|LEFT
, 2);
1326 if (attr
&& (menuHorizontalPosition
==0 && (editMode
>0 || p1valdiff
))) {
1327 CHECK_INCDEC_MODELVAR_ZERO(event
, g_model
.header
.modelId
[0], 99);
1330 if (protocol
== PROTO_PXX
) {
1331 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+4*FW
, y
, STR_SYNCMENU
, menuHorizontalPosition
!=0 ? attr
: 0);
1332 uint8_t newFlag
= 0;
1333 if (attr
&& menuHorizontalPosition
>0 && editMode
>0) {
1335 newFlag
= MODULE_BIND
;
1337 moduleFlag
[0] = newFlag
;
1341 if (IS_DSM2_PROTOCOL(protocol
)) {
1342 lcdDrawText(MODEL_SETUP_2ND_COLUMN
+4*FW
, y
, STR_MODULE_RANGE
, menuHorizontalPosition
!=0 ? attr
: 0);
1343 moduleFlag
[0] = (attr
&& menuHorizontalPosition
>0 && editMode
>0) ? MODULE_RANGECHECK
: 0; // [MENU] key toggles range check mode
1353 #if defined(CPUARM) && defined(PXX)
1354 if (IS_RANGECHECK_ENABLE()) {
1355 showMessageBox("RSSI: ");
1356 lcdDrawNumber(16+4*FW
, 5*FH
, TELEMETRY_RSSI(), BOLD
);
1362 void menuModelFailsafe(event_t event
)
1364 uint8_t ch
= 8 * (menuVerticalPosition
/ 8);
1365 const uint8_t channelStart
= g_model
.moduleData
[g_moduleIdx
].channelsStart
;
1366 const int lim
= (g_model
.extendedLimits
? (512 * LIMIT_EXT_PERCENT
/ 100) : 512) * 2;
1367 uint8_t wbar
= LCD_W
- FW
* 4 - FWNUM
* 4;
1368 #if defined(PPM_UNIT_PERCENT_PREC1)
1372 if (event
== EVT_KEY_LONG(KEY_ENTER
)) {
1376 g_model
.moduleData
[g_moduleIdx
].failsafeChannels
[menuVerticalPosition
] = channelOutputs
[menuVerticalPosition
+channelStart
];
1377 storageDirty(EE_MODEL
);
1380 SEND_FAILSAFE_NOW(g_moduleIdx
);
1383 int16_t & failsafe
= g_model
.moduleData
[g_moduleIdx
].failsafeChannels
[menuVerticalPosition
];
1384 if (failsafe
< FAILSAFE_CHANNEL_HOLD
)
1385 failsafe
= FAILSAFE_CHANNEL_HOLD
;
1386 else if (failsafe
== FAILSAFE_CHANNEL_HOLD
)
1387 failsafe
= FAILSAFE_CHANNEL_NOPULSE
;
1390 storageDirty(EE_MODEL
);
1392 SEND_FAILSAFE_NOW(g_moduleIdx
);
1396 SIMPLE_SUBMENU_NOTITLE(NUM_CHANNELS(g_moduleIdx
));
1398 lcdDrawTextAlignedCenter(0, FAILSAFESET
);
1401 const coord_t x
= 1;
1404 for (uint8_t line
=0; line
<8; line
++) {
1405 const coord_t y
= 9+line
*7;
1406 const int32_t channelValue
= channelOutputs
[ch
+channelStart
];
1407 int32_t failsafeValue
= g_model
.moduleData
[g_moduleIdx
].failsafeChannels
[ch
];
1410 putsChn(x
+1, y
, ch
+1, SMLSIZE
);
1413 LcdFlags flags
= TINSIZE
;
1414 if (menuVerticalPosition
== ch
) {
1417 if (failsafeValue
== FAILSAFE_CHANNEL_HOLD
|| failsafeValue
== FAILSAFE_CHANNEL_NOPULSE
) {
1422 CHECK_INCDEC_MODELVAR(event
, g_model
.moduleData
[g_moduleIdx
].failsafeChannels
[ch
], -lim
, +lim
);
1427 uint8_t xValue
= x
+LCD_W
-4-wbar
;
1428 if (failsafeValue
== FAILSAFE_CHANNEL_HOLD
) {
1429 lcdDrawText(xValue
, y
, STR_HOLD
, RIGHT
|flags
);
1432 else if (failsafeValue
== FAILSAFE_CHANNEL_NOPULSE
) {
1433 lcdDrawText(xValue
, y
, STR_NONE
, RIGHT
|flags
);
1437 #if defined(PPM_UNIT_US)
1438 lcdDrawNumber(xValue
, y
, PPM_CH_CENTER(ch
)+failsafeValue
/2, RIGHT
|flags
);
1439 #elif defined(PPM_UNIT_PERCENT_PREC1)
1440 lcdDrawNumber(xValue
, y
, calcRESXto1000(failsafeValue
), RIGHT
|PREC1
|flags
);
1442 lcdDrawNumber(xValue
, y
, calcRESXto1000(failsafeValue
)/10, RIGHT
|flags
);
1447 #if !defined(PCBX7) // X7 LCD doesn't like too many horizontal lines
1448 lcdDrawRect(x
+LCD_W
-3-wbar
, y
, wbar
+1, 6);
1450 const uint8_t lenChannel
= limit
<uint8_t>(1, (abs(channelValue
) * wbar
/2 + lim
/2) / lim
, wbar
/2);
1451 const uint8_t lenFailsafe
= limit
<uint8_t>(1, (abs(failsafeValue
) * wbar
/2 + lim
/2) / lim
, wbar
/2);
1452 const coord_t xChannel
= (channelValue
>0) ? x
+LCD_W
-3-wbar
/2 : x
+LCD_W
-2-wbar
/2-lenChannel
;
1453 const coord_t xFailsafe
= (failsafeValue
>0) ? x
+LCD_W
-3-wbar
/2 : x
+LCD_W
-2-wbar
/2-lenFailsafe
;
1454 lcdDrawHorizontalLine(xChannel
, y
+1, lenChannel
, DOTTED
, 0);
1455 lcdDrawHorizontalLine(xChannel
, y
+2, lenChannel
, DOTTED
, 0);
1456 lcdDrawSolidHorizontalLine(xFailsafe
, y
+3, lenFailsafe
);
1457 lcdDrawSolidHorizontalLine(xFailsafe
, y
+4, lenFailsafe
);
1459 if (++ch
>= NUM_CHANNELS(g_moduleIdx
))