Files
gt3b/menu_key.c
2012-04-19 21:21:58 +02:00

482 lines
12 KiB
C

/*
menu_key - handle key_mapping menu
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 "calc.h"
#include "timer.h"
#include "ppm.h"
#include "lcd.h"
#include "buzzer.h"
#include "input.h"
// set mapping of keys
// key_id is: 4 trims, 3 buttons, 8 individual buttons of trims
// individual buttons of trims are available only when corresponding trim
// is off
#define TRIM_FUNCTIONS_SIZE 128
@near static u8 trim_functions[TRIM_FUNCTIONS_SIZE];
@near static u8 trim_functions_max;
static const u8 trim_buttons[][4] = {
"NOL", "RPT", "MOM", "RES", "END", "SPC"
};
#define TRIM_BUTTONS_SIZE (sizeof(trim_buttons) / 4)
// 7seg: 1 2 3 d
// chars:
// function
// OFF (NOR/REV) (NOO/ORS) (NPV/PRV) (NOR/ROT)
// other -> buttons
// MOM -> reverse -> prev_val
// NOL/RPT/RES/END -> step -> reverse -> opp_reset -> rotate
// id: % % V V V blink % blink % V blink
static u8 km_trim(u8 trim_id, u8 val_id, u8 action) {
config_et_map_s *etm = &ck.et_map[trim_id];
u8 id = val_id;
u8 idx, btn, new_idx = 0;
if (action == 1) {
// change value
switch (id) {
case 1:
// function
// select new function, map through trim_functions
if (!etm->is_trim) etm->function = 0;
idx = menu_et_function_idx(etm->function);
while (1) {
if (btn(BTN_ROT_L)) {
if (idx) idx--;
else idx = trim_functions_max;
}
else {
if (++idx > trim_functions_max) idx = 0;
}
new_idx = trim_functions[idx];
if (!new_idx) continue; // empty slot
new_idx--; // was one more
if (menu_et_function_is_allowed(new_idx)) break; // we have it
}
// set values to defaults
((u16 *)etm)[0] = 0;
((u16 *)etm)[1] = 0;
etm->function = new_idx;
if (etm->function)
etm->is_trim = etm->is_trim2 = 1;
break;
case 2:
// buttons
// show special ("SPC") only when selected function has it
if (menu_et_function_long_special(etm->function))
idx = 1;
else idx = 2;
btn = etm->buttons;
btn = (u8)menu_change_val(btn, 0, TRIM_BUTTONS_SIZE - idx,
1, 1);
// skip MOMentary for list functions
if (btn == ETB_MOMENTARY &&
menu_et_function_is_list(etm->function)) {
if (etm->buttons < ETB_MOMENTARY) btn++;
else btn--;
}
etm->buttons = btn;
break;
case 3:
// step
etm->step = (u8)menu_change_val(etm->step, 0,
STEPS_MAP_SIZE - 1, 1, 0);
break;
case 4:
// reverse
etm->reverse ^= 1;
break;
case 5:
// opposite reset
etm->opposite_reset ^= 1;
break;
case 6:
// return to previous value
etm->previous_val ^= 1;
break;
case 7:
etm->rotate ^= 1;
break;
}
}
else if (action == 2) {
// switch to next setting
if (id != 1 || etm->is_trim) {
if (etm->buttons == ETB_MOMENTARY) {
if (++id > 6) id = 1;
else if (id == 3) id = 4; // skip "step" for momentary
else if (id == 5) id = 6; // skip "opposite_reset"
}
else {
if (++id > 5) id = 1;
else if (menu_et_function_is_list(etm->function)) {
if (id == 3) {
// skip "step"
id++;
etm->step = 0;
}
else if (id == 5) {
// skip "opposite reset"
id = 7;
etm->opposite_reset = 0;
}
}
}
}
}
// show value of val_id
switch (id) {
case 1:
if (!etm->is_trim) lcd_chars("OFF");
else lcd_chars(menu_et_function_name(etm->function));
lcd_segment(LS_SYM_PERCENT, LS_OFF);
lcd_segment(LS_SYM_VOLTS, LS_OFF);
break;
case 2:
lcd_chars(trim_buttons[etm->buttons]);
lcd_segment(LS_SYM_PERCENT, LS_ON);
lcd_segment(LS_SYM_VOLTS, LS_OFF);
break;
case 3:
lcd_char_num3(steps_map[etm->step]);
lcd_segment(LS_SYM_PERCENT, LS_ON);
lcd_segment(LS_SYM_VOLTS, LS_ON);
break;
case 4:
lcd_chars(etm->reverse ? "REV" : "NOR");
lcd_segment(LS_SYM_PERCENT, LS_OFF);
lcd_segment(LS_SYM_VOLTS, LS_ON);
break;
case 5:
lcd_chars(etm->opposite_reset ? "ORS" : "NOO");
lcd_segment(LS_SYM_PERCENT, LS_OFF);
lcd_segment(LS_SYM_VOLTS, LS_ON);
lcd_segment_blink(LS_SYM_VOLTS, LB_SPC);
break;
case 6:
lcd_chars(etm->previous_val ? "PRV" : "NPV");
lcd_segment(LS_SYM_PERCENT, LS_ON);
lcd_segment(LS_SYM_VOLTS, LS_OFF);
lcd_segment_blink(LS_SYM_PERCENT, LB_SPC);
break;
case 7:
lcd_chars(etm->rotate ? "ROT" : "NOR");
lcd_segment(LS_SYM_PERCENT, LS_ON);
lcd_segment(LS_SYM_VOLTS, LS_ON);
lcd_segment_blink(LS_SYM_PERCENT, LB_SPC);
lcd_segment_blink(LS_SYM_VOLTS, LB_SPC);
break;
}
return id;
}
#define KEY_FUNCTIONS_SIZE 32
@near static u8 key_functions[KEY_FUNCTIONS_SIZE];
@near static u8 key_functions_max;
// 7seg: C b E 1l 1r 2l 2r 3l 3r dl dr
// chars:
// function
// OFF -> function_long
// 2STATE -> momentary (%)
// SWI -> reverse (V) -> prev_val (% blink) -> function_long
// MOM -> reverse (V) -> prev_val (% blink)
// (NOR/REV) (NPV/PRV)
// other -> function_long
//
// function_long (% V)
// OFF
// 2STATE -> reverse (V) -> prev_val (% blink)
// (NOR/REV) (NPV/PRV)
// other
static u8 km_key(u8 key_id, u8 val_id, u8 action) {
config_key_map_s *km = &ck.key_map[key_id];
u8 id = val_id;
u8 idx, new_idx = 0;
if (action == 1) {
// change value
switch (id) {
case 1:
// function
// select new function, map through key_functions
idx = menu_key_function_idx(km->function);
while (1) {
if (btn(BTN_ROT_L)) {
if (idx) idx--;
else idx = key_functions_max;
}
else {
if (++idx > key_functions_max) idx = 0;
}
new_idx = key_functions[idx];
if (!new_idx) continue; // empty slot
new_idx--; // was one more
if (menu_key_function_is_allowed(new_idx)) break; // we have it
}
// set values to defaults
if (km->momentary) *(u16 *)km = 0; // was momentary, zero all
else {
// zero only no-long function parameters
km->reverse = 0;
km->previous_val = 0;
}
km->function = new_idx;
break;
case 2:
// momentary setting
km->momentary ^= 1;
// after change momentary, reset long setting
km->function_long = 0;
km->reverse_long = 0;
km->previous_val_long = 0;
break;
case 3:
// reverse
km->reverse ^= 1;
break;
case 4:
// previous_val
km->previous_val ^= 1;
break;
case 5:
// function long
// select new function, map through key_functions
idx = menu_key_function_idx(km->function_long);
while (1) {
if (btn(BTN_ROT_L)) {
if (idx) idx--;
else idx = key_functions_max;
}
else {
if (++idx > key_functions_max) idx = 0;
}
new_idx = key_functions[idx];
if (!new_idx) continue; // empty slot
new_idx--; // was one more
if (menu_key_function_is_allowed(new_idx)) break; // we have it
}
// set values to defaults
km->reverse_long = 0;
km->previous_val_long = 0;
km->function_long = new_idx;
break;
case 6:
// reverse_long
km->reverse_long ^= 1;
break;
case 7:
// previous_val_long
km->previous_val_long ^= 1;
break;
}
}
else if (action == 2) {
// switch to next setting
switch (id) {
case 1:
if (menu_key_function_2state(km->function)) id = 2;
else id = 5;
break;
case 2:
id = 3;
break;
case 3:
id = 4;
break;
case 4:
if (km->momentary) id = 1;
else id = 5;
break;
case 5:
if (menu_key_function_2state(km->function_long)) id = 6;
else id = 1;
break;
case 6:
id = 7;
break;
case 7:
id = 1;
break;
}
}
// show value of val_id
switch (id) {
case 1:
// function
lcd_chars(menu_key_function_name(km->function));
lcd_segment(LS_SYM_PERCENT, LS_OFF);
lcd_segment(LS_SYM_VOLTS, LS_OFF);
break;
case 2:
// momentary setting
lcd_chars(km->momentary ? "MOM" : "SWI");
lcd_segment(LS_SYM_PERCENT, LS_ON);
lcd_segment(LS_SYM_VOLTS, LS_OFF);
break;
case 3:
// reverse
lcd_chars(km->reverse ? "REV" : "NOR");
lcd_segment(LS_SYM_PERCENT, LS_OFF);
lcd_segment(LS_SYM_VOLTS, LS_ON);
break;
case 4:
// previous_val
lcd_chars(km->previous_val ? "PRV" : "NPV");
lcd_segment(LS_SYM_PERCENT, LS_ON);
lcd_segment(LS_SYM_VOLTS, LS_OFF);
lcd_segment_blink(LS_SYM_PERCENT, LB_SPC);
break;
case 5:
// function long
lcd_chars(menu_key_function_name(km->function_long));
lcd_segment(LS_SYM_PERCENT, LS_ON);
lcd_segment(LS_SYM_VOLTS, LS_ON);
break;
case 6:
// reverse_long
lcd_chars(km->reverse_long ? "REV" : "NOR");
lcd_segment(LS_SYM_PERCENT, LS_OFF);
lcd_segment(LS_SYM_VOLTS, LS_ON);
break;
case 7:
// previous_val_long
lcd_chars(km->previous_val_long ? "PRV" : "NPV");
lcd_segment(LS_SYM_PERCENT, LS_ON);
lcd_segment(LS_SYM_VOLTS, LS_OFF);
lcd_segment_blink(LS_SYM_PERCENT, LB_SPC);
break;
}
return id;
}
static u8 km_trim_key(u8 key_id, u8 val_id, u8 action) {
if (key_id < NUM_TRIMS) return km_trim(key_id, val_id, action);
else return km_key((u8)(key_id - NUM_TRIMS), val_id, action);
}
static const u8 key_ids[] = {
1, 2, 3, L7_D, L7_C, L7_B, L7_E
};
void menu_key_mapping_func(u8 action, void *p) {
if (action == MCA_SET_CHG) {
km_trim_key(menu_id, (u8)(menu_set + 1), 1);
return; // value already showed
}
else if (action == MCA_SET_NEXT) {
menu_set = (u8)(km_trim_key(menu_id, (u8)(menu_set + 1), 2) - 1);
return; // value already showed
}
else if (action == MCA_ID_CHG) {
while (1) {
// select prev/next menu_id
if (btn(BTN_ROT_L)) {
if (menu_id) menu_id--;
else menu_id = 3 * NUM_TRIMS + NUM_KEYS - 1;
}
else {
if (++menu_id >= 3 * NUM_TRIMS + NUM_KEYS) menu_id = 0;
}
// trims and 3keys (CH3/BACK/END) always
if (menu_id < NUM_TRIMS + NUM_KEYS) break;
// check trim keys and use them only when corresponding
// trim is off
if (ck.key_map[menu_id - NUM_TRIMS].is_trim) continue;
break;
}
}
// show value
if (menu_id < NUM_TRIMS + NUM_KEYS)
// standard trims and buttons
lcd_7seg(key_ids[0]);
else {
// trims as buttons, use arrows to show them
lcd_7seg(key_ids[(u8)((u8)(menu_id - NUM_TRIMS - NUM_KEYS) >> 1)]);
if ((u8)(menu_id - NUM_TRIMS - NUM_KEYS) & 1)
// right trim key
lcd_segment(LS_SYM_RIGHT, LS_ON);
else
// left trim key
lcd_segment(LS_SYM_LEFT, LS_ON);
}
km_trim_key(menu_id, (u8)(menu_set + 1), 0);
}
void menu_key_mapping(void) {
lcd_set_blink(LMENU, LB_SPC);
menu_common(menu_key_mapping_func, NULL, MCF_ID_CHG);
lcd_set_blink(LMENU, LB_OFF);
config_model_save();
apply_model_config();
menu_buttons_initialize();
}
// prepare sorted functions for mapping keys
void menu_key_mapping_prepare(void) {
u8 i;
s8 n;
// electronic trims
for (i = 0; i < TRIM_FUNCTIONS_SIZE; i++) {
n = menu_et_function_idx(i);
if (n < 0) break; // last
if (n > trim_functions_max) trim_functions_max = n;
trim_functions[n] = (u8)(i + 1); // + 1 to be able to find non-empty
}
// keys
for (i = 0; i < KEY_FUNCTIONS_SIZE; i++) {
n = menu_key_function_idx(i);
if (n < 0) break; // last
if (n > key_functions_max) key_functions_max = n;
key_functions[n] = (u8)(i + 1); // + 1 to be able to find non-empty
}
}