static void gs_key_beep(u8 change) { if (change == 0xff) { lcd_set(L7SEG, LB_EMPTY); return; } if (change) cg.key_beep ^= 1; lcd_7seg(L7_B); if (cg.key_beep) lcd_chars("ON "); else lcd_chars("OFF"); }
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); } }
// change model name static void menu_name_func(u8 action, void *p) { u8 letter; if (action == MCA_SET_CHG) { // change letter letter = cm.name[menu_set]; if (btn(BTN_ROT_L)) { // lower if (letter == '0') letter = 'Z'; else if (letter == 'A') letter = '9'; else letter--; } else { // upper if (letter == '9') letter = 'A'; else if (letter == 'Z') letter = '0'; else letter++; } cm.name[menu_set] = letter; } else if (action == MCA_SET_NEXT) { // next char if (++menu_set > 2) menu_set = 0; } // show name menu_blink = (u8)(1 << menu_set); // blink only selected char lcd_segment(LS_SYM_MODELNO, LS_ON); lcd_chars(cm.name); }
// show main screen (model number and name/battery/...) static void main_screen(u8 item) { menu_adc_wakeup = 0; // chars is item dependent if (item == MS_NAME) { // model name lcd_segment(LS_SYM_CHANNEL, LS_OFF); lcd_segment(LS_SYM_DOT, LS_OFF); lcd_segment(LS_SYM_VOLTS, LS_OFF); show_model_number(cg.model); lcd_chars(cm.name); } else if (item == MS_BATTERY) { static u16 bat_val; static u16 bat_time; // battery voltage lcd_segment(LS_SYM_CHANNEL, LS_OFF); lcd_segment(LS_SYM_DOT, LS_ON); lcd_segment(LS_SYM_VOLTS, LS_ON); show_model_number(cg.model); // calculate voltage from current raw value and calib value if (time_sec >= bat_time) { bat_time = time_sec + 2; bat_val = (u16)(((u32)adc_battery * 100 + 300) / cg.battery_calib); } lcd_char_num3(bat_val); menu_adc_wakeup = 1; } else { // timers menu_timer_show((u8)(item - MS_TIMER0)); } lcd_update(); }
static void mix_brake_off(u8 action) { // change value if (action == MLA_CHG) cm.brake_off ^= 1; // show value lcd_7seg(L7_B); lcd_chars(cm.brake_off ? "CUT" : "OFF"); }
// show firmware version static void gs_firmware(u8 change) { if (change == 0xff) { lcd_set(L7SEG, LB_EMPTY); return; } lcd_7seg(L7_F); lcd_chars(VERSION); }
static void gs_reset_model_all(u8 change) { if (change == 0xff) { lcd_set(L7SEG, LB_EMPTY); if (gs_reset_flag) { gs_reset_flag = 0; cg.model = 0; config_global_save(); eeprom_empty_models(); menu_load_model(); } return; } if (change) gs_reset_flag ^= 1; lcd_7seg(L7_R); if (gs_reset_flag) lcd_chars("YES"); else lcd_chars("MOD"); }
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)); }
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]); }
void menu_key_test(void) { u8 i; u16 bit; // cleanup screen and disable possible low bat warning buzzer_off(); key_beep(); menu_battery_low = 0; // it will be set automatically again battery_low_shutup = 0; // do full screen blink lcd_set_full_on(); delay_menu_always(2); while (btns(BTN_ENTER)) stop(); // wait for release of ENTER lcd_clear(); button_autorepeat(0); // disable autorepeats btnra(); // show intro text lcd_chars("KEY"); lcd_update_stop(); // wait for key while (1) { if (btnl(BTN_BACK | BTN_ENTER)) break; for (i = 0, bit = 1; i < 16; i++, bit <<= 1) { if (btn(bit)) { key_beep(); lcd_chars(key_ids[i]); if (btnl(bit)) lcd_7seg(L7_L); else lcd_set(L7SEG, LB_EMPTY); lcd_update(); break; } } btnra(); stop(); } key_beep(); apply_model_config(); }
// write signed number, use labels for <0, =0, >0 (eg. "LNR") void lcd_char_num2_lbl(s8 num, u8 *labels) { // set label based on signum if (num == 0) chr[0] = labels[1]; else if (num > 0) chr[0] = labels[2]; else { num = (u8)-num; chr[0] = labels[0]; } lcd_num2char(num); lcd_chars(chr); }
// change 4WS crab/no-crab static void kf_4ws(u8 *id, u8 *param, u8 flags, s16 *prev_val) { if (flags & FF_ON) menu_4WS_crab = (u8)(flags & FF_REVERSE ? 0 : 1); else menu_4WS_crab = (u8)(flags & FF_REVERSE ? 1 : 0); if (flags & FF_SHOW) { lcd_7seg(4); lcd_chars(menu_4WS_crab ? "CRB" : "NOC"); } }
// change menu_brake bit static void kf_brake(u8 *id, u8 *param, u8 flags, s16 *prev_val) { if (flags & FF_ON) menu_brake = (u8)(flags & FF_REVERSE ? 0 : 1); else menu_brake = (u8)(flags & FF_REVERSE ? 1 : 0); if (flags & FF_SHOW) { lcd_7seg(L7_B); lcd_chars(menu_brake ? "BRK" : "OFF"); } }
static void gs_backlight_time(u8 change) { s8 i; u16 *addr = &cg.backlight_time; if (change == 0xff) { lcd_set(L7SEG, LB_EMPTY); return; } if (change) { if (btn(BTN_ROT_L)) { // find lower value for (i = BL_STEPS_SIZE - 1; i >= 0; i--) { if (bl_steps[i] >= *addr) continue; *addr = bl_steps[i]; break; } if (i < 0) *addr = bl_steps[BL_STEPS_SIZE - 1]; } else { // find upper value for (i = 0; i < BL_STEPS_SIZE; i++) { if (bl_steps[i] <= *addr) continue; *addr = bl_steps[i]; break; } if (i == BL_STEPS_SIZE) *addr = bl_steps[0]; } } lcd_7seg(L7_L); if (*addr < 60) { // seconds bl_num2((u8)*addr); lcd_char(LCHR3, 'S'); } else if (*addr < 3600) { // minutes bl_num2((u8)(*addr / 60)); lcd_char(LCHR3, 'M'); } else if (*addr != BACKLIGHT_MAX) { // hours bl_num2((u8)(*addr / 3600)); lcd_char(LCHR3, 'H'); } else { // max lcd_chars("MAX"); } }
// reset model to defaults static void menu_reset_model(u8 action) { // change value if (action == MLA_CHG) menu_tmp_flag ^= 1; // select next value, reset when flag is set else if (action == MLA_NEXT) { if (menu_tmp_flag) { menu_tmp_flag = 0; config_model_set_default(); buzzer_on(60, 0, 1); } } // show value lcd_7seg(L7_R); lcd_chars(menu_tmp_flag ? "YES" : "NO "); }
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 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; } }
// write unsigned number to 3 chars, max -199...1099 void lcd_char_num3(s16 num) { // check signum u8 sig = ' '; if (num < 0) { sig = '-'; num = -num; } chr[0] = (u8)('0' + num / 100); lcd_num2char((u8)(num % 100)); // if more than 999, go to special char 10 if (chr[0] > '9') chr[0] = LCHAR_ONE_ZERO; // remove leading spaces and add signum if (chr[0] == '0') { chr[0] = sig; if (chr[1] == '0') { chr[1] = sig; chr[0] = ' '; } } else if (sig == '-') chr[0] = LCHAR_MINUS_ONE; lcd_chars(chr); }
// 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; } }
// set reverse void sf_reverse(u8 channel, u8 change) { u8 bit = (u8)(1 << channel); if (change) cm.reverse ^= bit; if (cm.reverse & bit) lcd_chars("REV"); else lcd_chars("NOR"); }
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); } }