-
Notifications
You must be signed in to change notification settings - Fork 75
/
menu_common.c
375 lines (310 loc) · 9.98 KB
/
menu_common.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
/*
menu_mix - handle menus for mix settings
Copyright (C) 2011 Pavel Semerad
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "menu.h"
#include "config.h"
#include "ppm.h"
#include "input.h"
#include "lcd.h"
#include "buzzer.h"
// variables to be used in CALC task
s8 menu_channel3_8[MAX_CHANNELS - 2]; // values -100..100 for channels >=3
u8 menu_channels_mixed; // channel with 1 here will not be set from
// menu_channel3_8
s8 menu_4WS_mix; // mix -100..100
_Bool menu_4WS_crab; // when 1, crab steering
s8 menu_DIG_mix; // mix -100..100
u8 menu_MP_index[MP_COUNT]; // index of MultiPosition channels
_Bool menu_brake; // when 1, full brake is applied
// battery low flag
_Bool menu_battery_low;
// raw battery ADC value for check to battery low
u16 battery_low_raw;
// set menu_channels_mixed to ignore them from menu_channel3_8
void set_menu_channels_mixed(void) {
menu_channels_mixed = 0;
if (cm.channel_4WS)
menu_channels_mixed |= (u8)(1 << (u8)(cm.channel_4WS - 1));
if (cm.channel_DIG)
menu_channels_mixed |= (u8)(1 << (u8)(cm.channel_DIG - 1));
if (cm.channel_brake)
menu_channels_mixed |= (u8)(1 << (u8)(cm.channel_brake - 1));
}
// apply model settings to variables
void apply_model_config(void) {
u8 i, autorepeat = 0;
// set number of channels for this model
ppm_set_channels((u8)(cm.channels + 1));
set_menu_channels_mixed();
// set autorepeat
for (i = 0; i < 4; i++) {
if (!ck.et_map[i].is_trim) continue; // trim is off, skip
if (ck.et_map[i].buttons == ETB_AUTORPT)
autorepeat |= (u8)((u8)et_buttons[i][0] | (u8)et_buttons[i][1]);
}
button_autorepeat(autorepeat);
}
// load model config from eeprom and set model settings
void menu_load_model(void) {
u8 i;
// load config
config_model_read();
// set values of channels >= 3 to default left state,
// for channels mapped to some trims/keys, it will next be set
// to corresponding centre/reset value
for (i = 0; i < MAX_CHANNELS - 2; i++)
menu_channel3_8[i] = -100;
// set 4WS, DIG, MP to defaults
menu_4WS_mix = 0;
menu_4WS_crab = 0;
menu_DIG_mix = 0;
memset(menu_MP_index, 0, sizeof(menu_MP_index));
if (cm.channel_MP0 && cm.channel_MP0 != MP_DIG)
menu_channel3_8[cm.channel_MP0 - 3] = cm.multi_position0[0];
if (cm.channel_MP1 && cm.channel_MP1 != MP_DIG)
menu_channel3_8[cm.channel_MP1 - 3] = cm.multi_position1[0];
if (cm.channel_MP2 && cm.channel_MP2 != MP_DIG)
menu_channel3_8[cm.channel_MP2 - 3] = cm.multi_position2[0];
if (cm.channel_MP3 && cm.channel_MP3 != MP_DIG)
menu_channel3_8[cm.channel_MP3 - 3] = cm.multi_position3[0];
menu_brake = 0;
// set state of buttons to do initialize
menu_buttons_initialize();
// apply config to radio setting
apply_model_config();
}
// apply global setting to variables
void apply_global_config(void) {
backlight_set_default(cg.backlight_time);
backlight_on();
// compute raw value for battery low voltage
battery_low_raw = (u16)(((u32)cg.battery_calib * cg.battery_low + 50) / 100);
}
// menu stop - checks low battery
_Bool battery_low_shutup;
void menu_stop(void) {
static _Bool battery_low_on;
stop();
// low_bat is disabled in calibrate, key-test and global menus,
// check it by buzzer_running
if (menu_battery_low && !buzzer_running && !battery_low_shutup)
battery_low_on = 0;
if (battery_low_on == menu_battery_low) return; // no change
// battery low status changed
if (menu_battery_low) {
// battery low firstly
battery_low_on = 1;
lcd_segment(LS_SYM_LOWPWR, LS_ON);
lcd_segment_blink(LS_SYM_LOWPWR, LB_SPC);
buzzer_on(40, 160, BUZZER_MAX);
}
else {
// battery low now OK
battery_low_on = 0;
lcd_segment(LS_SYM_LOWPWR, LS_OFF);
buzzer_off();
}
lcd_update();
}
// change value based on state of rotate encoder
s16 menu_change_val(s16 val, s16 min, s16 max, u8 amount_fast, u8 rotate) {
u8 amount = 1;
if (btn(BTN_ROT_L)) {
// left
if (btnl(BTN_ROT_L)) amount = amount_fast;
val -= amount;
if (val < min)
if (rotate) val = max;
else val = min;
}
else {
// right
if (btnl(BTN_ROT_R)) amount = amount_fast;
val += amount;
if (val > max)
if (rotate) val = min;
else val = max;
}
return val;
}
// clear all symbols
void menu_clear_symbols(void) {
lcd_segment(LS_SYM_MODELNO, LS_OFF);
lcd_segment(LS_SYM_DOT, LS_OFF);
lcd_segment(LS_SYM_VOLTS, LS_OFF);
lcd_segment(LS_SYM_PERCENT, LS_OFF);
lcd_segment(LS_SYM_LEFT, LS_OFF);
lcd_segment(LS_SYM_RIGHT, LS_OFF);
lcd_segment(LS_SYM_CHANNEL, LS_OFF);
}
// common menu, select item at 7SEG and then set params at CHR3
u8 menu_set; // menu is in: 0 = menu_id, 1..X = menu setting 1..X
u8 menu_id; // id of selected menu
_Bool menu_id_set; // 0 = in menu-id, 1 = in menu-setting
u8 menu_blink; // what of chars should blink
static void func_init(u8 flags) {
// blink all
menu_blink = 0xff;
// clear display symbols
menu_clear_symbols();
if (flags & MCF_LOWPWR) lcd_segment(LS_SYM_LOWPWR, LS_OFF);
}
void menu_common(menu_common_t func, void *params, u8 flags) {
menu_id_set = flags & MCF_SET_ONLY ? 1 : 0;
menu_set = 0; // now in menu_id
menu_id = 0; // first menu item
// init and show setting
func_init(flags);
func(MCA_INIT, params);
if (menu_id_set) {
lcd_chars_blink_mask(LB_SPC, menu_blink);
}
else {
if (menu_blink & MCB_7SEG) lcd_set_blink(L7SEG, LB_SPC);
}
lcd_update();
while (1) {
// remove button flags and wait for wakeup
btnra();
if (flags & MCF_STOP) stop();
else menu_stop();
// end this menu with defined buttons
if (btn(BTN_BACK | BTN_END) || btnl(BTN_ENTER)) break;
if ((flags & MCF_ENTER) && btn(BTN_ENTER)) break;
// if menu ADC was activated, call func to read for example left-right pos
if (menu_adc_wakeup) func(MCA_ADC_PRE, params);
// rotate encoder changed, change menu-id or value
if (btn(BTN_ROT_ALL)) {
if (menu_id_set) {
func_init(flags);
func(MCA_SET_CHG, params);
lcd_chars_blink_mask(LB_SPC, menu_blink);
}
else {
// change menu-id
// reset some variables
menu_adc_wakeup = 0;
menu_force_value_channel = 0;
// select new menu id and show it
func_init(flags);
func(MCA_ID_CHG, params); // do own change based on BTN_ROT
if (menu_blink & MCB_7SEG) lcd_set_blink(L7SEG, LB_SPC);
}
lcd_update();
}
// ENTER pressed, switch between menu settings
else if (btn(BTN_ENTER)) {
// switch menu_id/menu-setting0/menu-setting1/...
key_beep();
if (flags & MCF_SWITCH) {
// switch will be done by function
func_init(flags);
func(MCA_SWITCH, params);
if (menu_set == 255) break; // exit menu when requested
// blinking
if (menu_id_set) {
lcd_chars_blink_mask(LB_SPC, menu_blink);
lcd_set_blink(L7SEG, LB_OFF);
}
else {
if (menu_blink & MCB_7SEG) lcd_set_blink(L7SEG, LB_SPC);
lcd_chars_blink(LB_OFF);
}
lcd_update();
}
else if (menu_id_set) {
// select next menu setting
func_init(flags);
func(MCA_SET_NEXT, params);
if (menu_set == 255) break; // exit menu when requested
if (menu_set || (flags & MCF_SET_ONLY)) {
// some > 0 menu setting
lcd_chars_blink_mask(LB_SPC, menu_blink);
}
else {
// rotated back to setting 0, switch to menu selection
menu_id_set = 0;
if (menu_blink & MCB_7SEG) lcd_set_blink(L7SEG, LB_SPC);
lcd_chars_blink(LB_OFF);
}
lcd_update();
}
else {
// switch to first menu setting
menu_id_set = 1;
// menu setting values is already showed
lcd_set_blink(L7SEG, LB_OFF);
lcd_chars_blink_mask(LB_SPC, menu_blink);
}
}
// if menu ADC was activated, call func to check if to show for example
// other value when left-right position changed
if (menu_adc_wakeup) {
u8 mis = menu_id_set; // save value
menu_id_set = 0; // func will set it to 1 when show call needed
func(MCA_ADC_POST, params);
if (menu_id_set) {
menu_id_set = mis;
// show changed value
func_init(flags);
func(MCA_SHOW, params);
if (menu_id_set) {
lcd_chars_blink_mask(LB_SPC, menu_blink);
}
else {
if (menu_blink & MCB_7SEG) lcd_set_blink(L7SEG, LB_SPC);
}
lcd_update();
}
else menu_id_set = mis;
}
}
// call to select next value which can do some action (such as reset)
if (menu_id_set && menu_set != 255) func(MCA_SET_NEXT, params);
// cleanup display
func_init(flags);
// reset variables
menu_adc_wakeup = 0;
menu_force_value_channel = 0;
key_beep();
}
// common list menu, given by list of functions, one for each menu item
typedef struct {
menu_list_t *funcs;
u8 nitems;
} menu_list_params_t;
static void menu_list_func(u8 action, menu_list_params_t *p) {
menu_list_t func = p->funcs[menu_id];
switch (action) {
case MCA_SET_CHG:
func(MLA_CHG);
return; // value already showed
case MCA_SET_NEXT:
func(MLA_NEXT);
return; // value already showed
case MCA_ID_CHG:
menu_id = (u8)menu_change_val(menu_id, 0, p->nitems - 1, 1, 1);
func = p->funcs[menu_id];
break;
}
// show value
func(MLA_SHOW);
}
void menu_list(menu_list_t *menu_funcs, u8 menu_nitems, u8 flags) {
menu_list_params_t params;
params.funcs = menu_funcs;
params.nitems = menu_nitems;
menu_common(menu_list_func, ¶ms, (u8)(flags & (MCF_STOP | MCF_LOWPWR)));
}