static void mix_4WS(u8 action) { u8 val; if (action == MLA_CHG) { // change value switch (menu_set) { case 0: // channel number/off val = cm.channel_4WS; if (!val) val = 2; val = (u8)menu_change_val(val, 2, channels, 1, 1); if (val == 2) cm.channel_4WS = 0; else cm.channel_4WS = val; break; case 1: // mix value menu_4WS_mix = (s8)menu_change_val(menu_4WS_mix, -100, 100, MIX_FAST, 0); break; case 2: // crab/no-crab menu_4WS_crab ^= 1; } } else if (action == MLA_NEXT) { // select next value if (++menu_set > 2) menu_set = 0; if (!cm.channel_4WS) menu_set = 0; } // show value lcd_7seg(4); switch (menu_set) { case 0: // channel number/OFF if (!cm.channel_4WS) lcd_chars("OFF"); else lcd_char_num3(cm.channel_4WS); lcd_segment(LS_SYM_CHANNEL, LS_ON); break; case 1: // mix value lcd_char_num3(menu_4WS_mix); lcd_segment(LS_SYM_PERCENT, LS_ON); break; case 2: // crab/no-crab lcd_chars("CR"); lcd_char(LCHR3, (u8)(menu_4WS_crab + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); } }
// set trims static void sf_trim(u8 channel, u8 change) { s8 *addr = &cm.trim[channel]; if (change) *addr = (s8)menu_change_val(*addr, -TRIM_MAX, TRIM_MAX, TRIM_FAST, 0); if (channel == 0) lcd_char_num2_lbl(*addr, "LNR"); else lcd_char_num2_lbl(*addr, "FNB"); }
// set endpoints void sf_endpoint(u8 channel, u8 change) { u8 *addr = &cm.endpoint[channel][menu_adc_direction]; if (change) *addr = (u8)menu_change_val(*addr, 0, cg.endpoint_max, ENDPOINT_FAST, 0); lcd_segment(LS_SYM_PERCENT, LS_ON); lcd_char_num3(*addr); }
// set dualrate static void sf_dualrate(u8 channel, u8 change) { u8 *addr = &cm.dualrate[channel]; if (channel == 1 && menu_adc_direction) addr = &cm.dualrate[2]; if (change) *addr = (u8)menu_change_val(*addr, 0, 100, DUALRATE_FAST, 0); lcd_segment(LS_SYM_PERCENT, LS_ON); lcd_char_num3(*addr); }
// set subtrims static void sf_subtrim(u8 channel, u8 change) { s8 *addr = &cm.subtrim[channel]; if (change) *addr = (s8)menu_change_val(*addr, -SUBTRIM_MAX, SUBTRIM_MAX, SUBTRIM_FAST, 0); lcd_char_num3(*addr); }
// set expos static void sf_expo(u8 channel, u8 change) { s8 *addr = &cm.expo[channel]; if (channel == 1 && menu_adc_direction) addr = &cm.expo[2]; if (change) *addr = (s8)menu_change_val(*addr, -EXPO_MAX, EXPO_MAX, EXPO_FAST, 0); lcd_segment(LS_SYM_PERCENT, LS_ON); lcd_char_num3(*addr); }
static void menu_model_func(u8 action, u8 *model) { if (action == MCA_ID_CHG) *model = (u8)menu_change_val((s16)*model, 0, MIN(CONFIG_MODEL_MAX, 80) - 1, MODEL_FAST, 1); show_model_number(*model); lcd_chars(config_model_name(*model)); }
// set channel value, exclude 4WS and DIG channels // for channels 3..8 so add 2 to channel number static void sf_channel_val(u8 channel, u8 change) { s8 *addr = &menu_channel3_8[channel]; if (change && !(menu_channels_mixed & (u8)(1 << (channel + 2)))) *addr = (s8)menu_change_val(*addr, -100, 100, CHANNEL_FAST, 0); // show value lcd_7seg((u8)(channel + 2 + 1)); lcd_char_num3(*addr); }
static void mix_DIG(u8 action) { u8 val; if (action == MLA_CHG) { // change value switch (menu_set) { case 0: // channel number/off val = cm.channel_DIG; if (!val) val = 2; val = (u8)menu_change_val(val, 1, channels, 1, 1); if (val == 2) cm.channel_DIG = 0; else cm.channel_DIG = val; break; case 1: // mix value menu_DIG_mix = (s8)menu_change_val(menu_DIG_mix, -100, 100, MIX_FAST, 0); break; } } else if (action == MLA_NEXT) { // select next value if (++menu_set > 1) menu_set = 0; if (!cm.channel_DIG) menu_set = 0; } // show value lcd_7seg(L7_D); switch (menu_set) { case 0: // channel number/OFF if (!cm.channel_DIG) lcd_chars("OFF"); else lcd_char_num3(cm.channel_DIG); lcd_segment(LS_SYM_CHANNEL, LS_ON); break; case 1: // mix value lcd_char_num3(menu_DIG_mix); lcd_segment(LS_SYM_PERCENT, LS_ON); break; } }
static void gs_throttle_dead(u8 change) { u8 *addr = &cg.throttle_dead_zone; if (change == 0xff) { lcd_set(L7SEG, LB_EMPTY); return; } if (change) *addr = (u8)menu_change_val(*addr, 0, 50, 2, 0); lcd_7seg(2); lcd_char_num3(*addr); }
static void menu_abs_func(u8 action, void *p) { // change value if (action == MCA_SET_CHG) cm.abs_type = (u8)menu_change_val(cm.abs_type, 0, ABS_LABEL_SIZE-1, 1, 1); // show value lcd_segment(LS_SYM_CHANNEL, LS_ON); lcd_7seg(2); lcd_chars(abs_labels[cm.abs_type]); }
static void gs_long_press_delay(u8 change) { u8 *addr = &cg.long_press_delay; if (change == 0xff) { lcd_set(L7SEG, LB_EMPTY); return; } if (change) *addr = (u8)menu_change_val(*addr, 20, 200, 5, 0); lcd_7seg(L7_D); lcd_char_num3(*addr * 5); }
// set number of model channels static void menu_channels(u8 action) { // change value if (action == MLA_CHG) cm.channels = (u8)(menu_change_val(cm.channels + 1, 2, MAX_CHANNELS, 1, 0) - 1); // show value lcd_7seg(L7_C); lcd_segment(LS_SYM_CHANNEL, LS_ON); lcd_char_num3(cm.channels + 1); }
static void gs_battery_low(u8 change) { u8 *addr = &cg.battery_low; if (change == 0xff) { lcd_segment(LS_SYM_LOWPWR, LS_OFF); lcd_segment(LS_SYM_DOT, LS_OFF); lcd_segment(LS_SYM_VOLTS, LS_OFF); return; } if (change) *addr = (u8)menu_change_val(*addr, 60, 105, 2, 0); lcd_segment(LS_SYM_LOWPWR, LS_ON); lcd_segment(LS_SYM_DOT, LS_ON); lcd_segment(LS_SYM_VOLTS, LS_ON); lcd_char_num3(cg.battery_low); }
static void gs_inactivity_alarm(u8 change) { if (change == 0xff) { lcd_set(L7SEG, LB_EMPTY); return; } if (change) { cg.inactivity_alarm = (u8)menu_change_val(cg.inactivity_alarm, 0, 10, 1, 1); reset_inactivity_timer(); } lcd_7seg(L7_A); if (!cg.inactivity_alarm) lcd_chars("OFF"); else { bl_num2(cg.inactivity_alarm); lcd_char(LCHR3, 'M'); } }
// set servo speed static void sf_speed(u8 channel, u8 change) { u8 *addr = &cm.speed[channel]; u8 thfwdonly = (u8)(channel == 1 && menu_adc_direction ? 1 : 0); if (channel == 0 && menu_adc_direction) addr = &cm.stspd_return; if (change) { if (thfwdonly) // throttle forward only setting cm.thspd_onlyfwd ^= 1; else *addr = (u8)menu_change_val(*addr, 1, 100, SPEED_FAST, 0); } if (thfwdonly) lcd_chars(cm.thspd_onlyfwd ? "OFF" : "ON "); else { lcd_char_num3(*addr); lcd_segment(LS_SYM_PERCENT, LS_ON); } }
static void gs_endpoint_max(u8 change) { u8 *addr = &cg.endpoint_max; if (change == 0xff) { lcd_segment(LS_MENU_EPO, LS_OFF); lcd_segment(LS_SYM_PERCENT, LS_OFF); lcd_set(L7SEG, LB_EMPTY); return; } if (change) *addr = (u8)menu_change_val(*addr, 100, 150, 5, 0); lcd_segment(LS_SYM_PERCENT, LS_ON); lcd_segment(LS_MENU_EPO, LS_ON); lcd_char_num3(*addr); if (*addr > 120) { lcd_7seg(L7_D); lcd_set_blink(L7SEG, LB_SPC); } else lcd_set(L7SEG, LB_EMPTY); }
void menu_key_mapping_func(u8 action, void *p) { if (action == MCA_SET_CHG) { km_trim_key(1); } else if (action == MCA_SET_NEXT) { km_trim_key(2); } else if (action == MCA_ID_CHG) { while (1) { // select prev/next menu_id menu_id = (u8)menu_change_val(menu_id, 0, 3 * NUM_TRIMS + NUM_KEYS - 1, 1, 1); // 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[menu_id]); 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); } if (action != MCA_SET_NEXT && action != MCA_SET_CHG) km_trim_key(0); }
static void menu_channel_func(u8 action, menu_channel_t *p) { switch (action) { case MCA_INIT: menu_set_adc_force(menu_id, p->use_adc, p->forced_values); break; case MCA_SET_CHG: p->func(menu_id, 1); break; case MCA_ID_CHG: menu_id = (u8)menu_change_val(menu_id, 0, p->end_channel - 1, 1, 1); menu_set_adc_force(menu_id, p->use_adc, p->forced_values); break; case MCA_ADC_PRE: menu_set_adc_direction(menu_id); return; // show nothing at ADC_PRE case MCA_ADC_POST: // do nothing if left-right didn't changed if (p->last_direction == menu_adc_direction) return; // else flag it to show value menu_id_set = 1; // flag that new value is showed return; } // show value lcd_segment(LS_SYM_CHANNEL, LS_ON); if (action != MCA_SET_CHG) { // already showed lcd_7seg((u8)(menu_id + 1)); p->func(menu_id, 0); } if (menu_adc_wakeup) { // show arrow if (menu_adc_direction) lcd_segment(LS_SYM_RIGHT, LS_ON); else lcd_segment(LS_SYM_LEFT, LS_ON); } p->last_direction = menu_adc_direction; }
static void mix_MultiPosition(u8 action) { s8 val; if (action == MLA_CHG) { // change value if (menu_set == 0) { // channel number/off val = cm.channel_MP; if (!val) val = 2; else if (val == MP_DIG) val = (s8)(channels + 1); val = (u8)menu_change_val(val, 2, channels + 1, 1, 1); if (val == 2) cm.channel_MP = 0; else if (val == (s8)(channels + 1)) cm.channel_MP = MP_DIG; else cm.channel_MP = val; } else { // position value + END state (END not for first position) val = cm.multi_position[menu_set - 1]; if (val == MULTI_POSITION_END) val = -101; val = (s8)menu_change_val(val, menu_set == 1 ? -100 : -101, 100, CHANNEL_FAST, 0); if (val == -101) { // set all from this to END value memset(&cm.multi_position[menu_set - 1], (u8)MULTI_POSITION_END, NUM_MULTI_POSITION + 1 - menu_set); } else cm.multi_position[menu_set - 1] = val; } } else if (action == MLA_NEXT) { // select next value if (cm.channel_MP) { if (menu_set == 0) menu_set = 1; else if (cm.multi_position[menu_set - 1] == MULTI_POSITION_END || ++menu_set > NUM_MULTI_POSITION) menu_set = 0; } // allow forcing channel value if (menu_set && cm.channel_MP && cm.channel_MP <= channels) { menu_force_value_channel = cm.channel_MP; } else menu_force_value_channel = 0; } // show value lcd_7seg(L7_P); if (menu_set == 0) { // channel number/OFF if (!cm.channel_MP) lcd_chars("OFF"); else if (cm.channel_MP == MP_DIG) lcd_chars("DIG"); else lcd_char_num3(cm.channel_MP); lcd_segment(LS_SYM_CHANNEL, LS_ON); } else { // position value val = cm.multi_position[menu_set - 1]; if (val == MULTI_POSITION_END) { lcd_chars("END"); val = -100; } else lcd_char_num3(val); if (cm.channel_MP == MP_DIG) menu_DIG_mix = val; else menu_force_value = val * PPM(5); } }
static u8 menu_popup_et(u8 trim_id) { u16 delay_time; s16 val; u8 step; u16 buttons_state_last; u16 btn_l = ETB_L(trim_id); u16 btn_r = ETB_R(trim_id); u16 btn_lr = btn_l | btn_r; config_et_map_s *etm = &ck.et_map[trim_id]; #define SF_ROTATE etm->rotate et_functions_s *etf = &et_functions[etm->function]; u8 *mbs = &menu_buttons_state[NUM_KEYS + 2 * trim_id]; // read value RVAL(val); // remember buttons state buttons_state_last = buttons_state & ~btn_lr; // handle momentary keys // when something changed, show value for 5s while checking buttons // during initialize show nothing if (etm->buttons == ETB_MOMENTARY) { s16 *pv = &menu_buttons_previous_values[NUM_KEYS + 2 * trim_id]; u8 value_showed = 0; u8 state; while (1) { // set actual state of btn_lr to buttons_state_last buttons_state_last &= ~btn_lr; buttons_state_last |= buttons_state & btn_lr; // check buttons if (btns(btn_l)) { // left if (*mbs == MBS_LEFT) break; // already was left state = MBS_LEFT; *pv = val; // save previous value val = etm->reverse ? etf->max : etf->min; } else if (btns(btn_r)) { // right if (*mbs == MBS_RIGHT) break; // already was right state = MBS_RIGHT; *pv = val; // save previous value val = etm->reverse ? etf->min : etf->max; } else { // center if (*mbs == MBS_RELEASED) break; // already was center state = MBS_RELEASED; if (etm->previous_val) { if (*mbs != MBS_INITIALIZE) val = *pv; } else val = etf->reset; } AVAL(val); if (*mbs == MBS_INITIALIZE) { // show nothing when doing initialize *mbs = state; break; } *mbs = state; btnr(btn_lr); key_beep(); // if another button was pressed, leave this screen if (buttons) break; if (buttons_state != buttons_state_last) break; // show function id first time if (!value_showed) { value_showed = 1; menu_et_function_show_id(etf); } // show current value if (etf->show_func) etf->show_func(etf->name, val); else lcd_char_num3(val); lcd_update(); // sleep 5s, and if no button was changed during, end this screen delay_time = POPUP_DELAY * 200; while (delay_time && !(buttons & ~btn_lr) && (buttons_state == buttons_state_last)) delay_time = delay_menu(delay_time); if ((buttons_state & btn_lr) == (buttons_state_last & btn_lr)) break; } btnr(btn_lr); if (value_showed) lcd_menu(0); // set MENU off return value_showed; } // if button is not initialized, do it if (*mbs == MBS_INITIALIZE) { // set value to default only for non-config values (mixes, channels...) if (etf->flags & EF_NOCONFIG) { val = etf->reset; AVAL(val); } *mbs = MBS_RELEASED; } // return when key was not pressed if (!btn(btn_lr)) return 0; // convert steps step = steps_map[etm->step]; // show MENU and CHANNEL menu_et_function_show_id(etf); while (1) { u8 val_set_to_reset = 0; // check value left/right if (btnl_all(btn_lr)) { // both long keys together key_beep(); if (etf->long_func && etm->buttons == ETB_SPECIAL) // special handling etf->long_func(etf->name, &val, btn_l, btn_r); else { // reset to given reset value val = etf->reset; } AVAL(val); if (val == etf->reset) val_set_to_reset = 1; btnr(btn_lr); } else if (btn(btn_lr)) { if (!btns_all(btn_lr)) { // only one key is currently pressed key_beep(); if (etf->long_func && etm->buttons == ETB_SPECIAL && btnl(btn_lr)) // special handling etf->long_func(etf->name, &val, btn_l, btn_r); else if ((etm->buttons == ETB_LONG_RESET || etm->buttons == ETB_LONG_ENDVAL) && btnl(btn_lr)) { // handle long key press if (etm->buttons == ETB_LONG_RESET) { val = etf->reset; } else { // set side value if ((u8)(btn(btn_l) ? 1 : 0) ^ etm->reverse) val = etf->min; else val = etf->max; } } else { // handle short key press if ((u8)(btn(btn_l) ? 1 : 0) ^ etm->reverse) { val -= step; if (val < etf->min) { if (etm->rotate) val = etf->max; else val = etf->min; } if (etm->opposite_reset && val > etf->reset) val = etf->reset; } else { val += step; if (val > etf->max) { if (etm->rotate) val = etf->min; else val = etf->max; } if (etm->opposite_reset && val < etf->reset) val = etf->reset; } } AVAL(val); if (val == etf->reset) val_set_to_reset = 1; btnr(btn_lr); } else btnr_nolong(btn_lr); // keep long-presses for testing-both } else if (btn(BTN_ROT_ALL)) { s16 val2 = val; val = menu_change_val(val, etf->min, etf->max, etf->rot_fast_step, etm->rotate); // if encoder skipped reset value, set it to reset value if (val2 < etf->reset && val > etf->reset || val2 > etf->reset && val < etf->reset) val = etf->reset; AVAL(val); if (val == etf->reset) val_set_to_reset = 1; } btnr(BTN_ROT_ALL); // longer beep at value reset value if (val_set_to_reset) BEEP_RESET; // if another button was pressed, leave this screen if (buttons) break; if ((buttons_state & ~btn_lr) != buttons_state_last) break; // show current value if (etf->show_func) etf->show_func(etf->name, val); else lcd_char_num3(val); lcd_update(); // if reset value was reached, ignore rotate/btn_lr for some time delay_time = POPUP_DELAY * 200; if (val_set_to_reset) { u8 delay = RESET_VALUE_DELAY; while (delay && !(buttons & ~(btn_lr | BTN_ROT_ALL)) && ((buttons_state & ~btn_lr) == buttons_state_last)) delay = (u8)delay_menu(delay); btnr(BTN_ROT_ALL | btn_lr); delay_time -= RESET_VALUE_DELAY; } // sleep 5s, and if no button was changed during, end this screen while (delay_time && !buttons && ((buttons_state & ~btn_lr) == buttons_state_last)) delay_time = delay_menu(delay_time); if (!buttons) break; // timeouted without button press } btnr(btn_lr); // reset also long values // set MENU off lcd_menu(0); // save model config config_model_save(); return 1; }
// calibrate menu void menu_calibrate(u8 at_poweron) { u8 channel = 1; u16 last_val = 0xffff; u16 val; u8 seg; u8 bat_volts; u16 update_time = 0; u16 update_val = 0; menu_adc_wakeup = 1; // cleanup screen and disable possible low bat warning buzzer_off(); if (at_poweron) buzzer_on(30, 30, 2); else key_beep(); menu_battery_low = 0; // it will be set automatically again battery_low_shutup = 0; backlight_set_default(BACKLIGHT_MAX); backlight_on(); lcd_clear(); btnra(); // show intro text lcd_chars("CAL"); lcd_update(); delay_menu_always(2); // show channel number and not-yet calibrated values lcd_segment(LS_SYM_CHANNEL, LS_ON); lcd_7seg(channel); lcd_menu(LM_MODEL | LM_NAME | LM_REV | LM_TRIM | LM_DR | LM_EXP); lcd_set_blink(LMENU, LB_SPC); while (1) { // check keys if (btnl(BTN_BACK | BTN_ENTER)) break; if (btn(BTN_END | BTN_ROT_ALL)) { if (btn(BTN_END)) key_beep(); // change channel number channel = (u8)menu_change_val(channel, 1, 4, 1, 1); lcd_7seg(channel); lcd_update(); update_time = 0; } else if (btn(BTN_ENTER)) { // save calibrate value for channels 1 and 2 // select actual voltage for channel 4 if (channel == 1) { key_beep(); val = ADC_OVS(steering); if (val < CALIB_ST_LOW_MID) { cg.calib_steering_left = val; seg = LS_MENU_MODEL; } else if (val <= CALIB_ST_MID_HIGH) { cg.calib_steering_mid = val; seg = LS_MENU_NAME; } else { cg.calib_steering_right = val; seg = LS_MENU_REV; } lcd_segment(seg, LS_OFF); lcd_update(); } else if (channel == 2) { key_beep(); val = ADC_OVS(throttle); if (val < CALIB_TH_LOW_MID) { cg.calib_throttle_fwd = val; seg = LS_MENU_TRIM; } else if (val <= CALIB_TH_MID_HIGH) { cg.calib_throttle_mid = val; seg = LS_MENU_DR; } else { cg.calib_throttle_bck = val; seg = LS_MENU_EXP; } lcd_segment(seg, LS_OFF); // set corresponding LCD off lcd_update(); } else if (channel == 4) { key_beep(); // allow to set actual battery voltage lcd_segment(LS_SYM_DOT, LS_ON); lcd_segment(LS_SYM_VOLTS, LS_ON); bat_volts = (u8)(((u32)adc_battery * 100 + 300) / cg.battery_calib); lcd_char_num3(bat_volts); lcd_update(); while (1) { btnra(); stop(); if (btnl(BTN_BACK) || btn(BTN_ENTER | BTN_END)) break; if (btn(BTN_ROT_ALL)) { if (btn(BTN_ROT_L)) bat_volts--; else bat_volts++; lcd_char_num3(bat_volts); lcd_update(); } } key_beep(); lcd_segment(LS_SYM_DOT, LS_OFF); lcd_segment(LS_SYM_VOLTS, LS_OFF); last_val = 0xffff; // show ADC value if (!btn(BTN_END)) { // recalculate calibrate value for 10V cg.battery_calib = (u16)(((u32)adc_battery * 100 + 40) / bat_volts); if (btnl(BTN_BACK | BTN_ENTER)) break; } } } // show ADC value if other than last val switch (channel) { case 1: val = ADC_OVS(steering); break; case 2: val = ADC_OVS(throttle); break; case 3: val = ADC_OVS(ch3); break; case 4: val = adc_battery; break; default: // to eliminate compiler warning val = 0; } // only update display every 1s if (time_sec >= update_time) { update_time = time_sec + 1; update_val = val; } if (update_val != last_val) { last_val = update_val; lcd_char_num3(val); lcd_update(); } btnra(); stop(); } menu_adc_wakeup = 0; beep(60); lcd_menu(0); lcd_update(); config_global_save(); apply_global_config(); }
// 7seg: C b E 1l 1r 2l 2r 3l 3r dl dr // chars: // function // OFF -> function_long // 2STATE -> momentary // switch -> reverse -> prev_val -> function_long // momentary -> reverse -> prev_val // other -> function_long // // function_long (identified by symbol V) // OFF // 2STATE -> reverse -> prev_val // other static void km_key(u8 action) { config_key_map_s *km = &ck.key_map[menu_id - NUM_TRIMS]; u8 idx, new_idx = 0; if (action == 1) { // change value switch (menu_set) { case 0: // function // select new function, map through key_functions idx = menu_key_function_idx(km->function); while (1) { idx = (u8)menu_change_val(idx, 0, key_functions_max, 1, 1); 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 1: // 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 2: // reverse km->reverse ^= 1; break; case 3: // previous_val km->previous_val ^= 1; break; case 4: // function long // select new function, map through key_functions idx = menu_key_function_idx(km->function_long); while (1) { idx = (u8)menu_change_val(idx, 0, key_functions_max, 1, 1); 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 5: // reverse_long km->reverse_long ^= 1; break; case 6: // previous_val_long km->previous_val_long ^= 1; break; } } else if (action == 2) { // switch to next setting switch (menu_set) { case 0: if (menu_key_function_2state(km->function)) menu_set = 1; else menu_set = 4; break; case 1: menu_set = 2; break; case 2: menu_set = 3; break; case 3: if (km->momentary) menu_set = 0; else menu_set = 4; break; case 4: if (menu_key_function_2state(km->function_long)) menu_set = 5; else menu_set = 0; break; case 5: menu_set = 6; break; case 6: menu_set = 0; break; } } // show value of menu_set switch (menu_set) { case 0: // function lcd_chars(menu_key_function_name(km->function)); break; case 1: // momentary setting lcd_chars("MO"); lcd_char(LCHR3, (u8)(km->momentary + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); break; case 2: // reverse lcd_chars("RE"); lcd_char(LCHR3, (u8)(km->reverse + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); break; case 3: // previous_val lcd_chars("PV"); lcd_char(LCHR3, (u8)(km->previous_val + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); break; case 4: // function long lcd_chars(menu_key_function_name(km->function_long)); lcd_segment(LS_SYM_VOLTS, LS_ON); break; case 5: // reverse_long lcd_chars("RE"); lcd_char(LCHR3, (u8)(km->reverse_long + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); lcd_segment(LS_SYM_VOLTS, LS_ON); break; case 6: // previous_val_long lcd_chars("PV"); lcd_char(LCHR3, (u8)(km->previous_val_long + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); lcd_segment(LS_SYM_VOLTS, LS_ON); break; } }
// 7seg: 1 2 3 d // chars: // function // OFF // other -> buttons // MO -> reverse -> prev_val // NL/RP/RE/EN -> step -> reverse -> opp_reset -> rotate // id: V static void km_trim(u8 action) { config_et_map_s *etm = &ck.et_map[menu_id]; u8 idx, btn, new_idx = 0; if (action == 1) { // change value switch (menu_set) { case 0: // function // select new function, map through trim_functions if (!etm->is_trim) etm->function = 0; idx = menu_et_function_idx(etm->function); while (1) { idx = (u8)menu_change_val(idx, 0, trim_functions_max, 1, 1); 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 1: // buttons // show special ("SP") 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 2: // step etm->step = (u8)menu_change_val(etm->step, 0, STEPS_MAP_SIZE - 1, 1, 0); break; case 3: // reverse etm->reverse ^= 1; break; case 4: // opposite reset etm->opposite_reset ^= 1; break; case 5: // return to previous value etm->previous_val ^= 1; break; case 6: etm->rotate ^= 1; break; } } else if (action == 2) { // switch to next setting if (menu_set || etm->is_trim) { if (etm->buttons == ETB_MOMENTARY) { if (++menu_set > 5) menu_set = 0; else if (menu_set == 2) menu_set = 3; // skip "step" for momentary else if (menu_set == 4) menu_set = 5; // skip "opposite_reset" } else { if (++menu_set > 4) menu_set = 0; else if (menu_et_function_is_list(etm->function)) { if (menu_set == 2) { // skip "step" menu_set++; etm->step = 0; } else if (menu_set == 4) { // skip "opposite reset" menu_set = 6; etm->opposite_reset = 0; } } } } } // show value of menu_set switch (menu_set) { case 0: // function if (!etm->is_trim) lcd_chars("OFF"); else lcd_chars(menu_et_function_name(etm->function)); break; case 1: // buttons lcd_char(LCHR1, 'B'); lcd_chars2(trim_buttons[etm->buttons]); menu_blink &= (u8)~MCB_CHR1; break; case 2: // step lcd_char_num3(steps_map[etm->step]); lcd_segment(LS_SYM_VOLTS, LS_ON); break; case 3: // reverse lcd_chars("RE"); lcd_char(LCHR3, (u8)(etm->reverse + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); break; case 4: // opposite reset lcd_chars("OR"); lcd_char(LCHR3, (u8)(etm->opposite_reset + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); break; case 5: // previous val lcd_chars("PV"); lcd_char(LCHR3, (u8)(etm->previous_val + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); break; case 6: // rotate lcd_chars("RO"); lcd_char(LCHR3, (u8)(etm->rotate + '0')); menu_blink &= (u8)~(MCB_CHR1 | MCB_CHR2); break; } }