void user_loop(void) { char xdata str[32]; static unsigned char xdata adc_chn = 0; static char xdata turbo_on_last = -1; static unsigned long xdata last_read = 0; /* read one ADC channel */ adc_read(adc_chn, &user_data.adc[adc_chn]); /* convert voltage to pressure, see data sheets */ if (adc_chn == 0) user_data.hv_mbar = pow(10, 1.667 * user_data.adc[0] - 11.33); // PKR 251 if (adc_chn == 1) user_data.vv_mbar = pow(10, user_data.adc[1] - 5.5); // TPR 280 if (adc_chn == 5) user_data.hv_close = user_data.adc[5] > 5; // ADC as digital input if (adc_chn == 6) user_data.bv_open = user_data.adc[6] > 5; // ADC as digital input if (adc_chn == 7) user_data.bv_close = user_data.adc[7] > 5; // ADC as digital input adc_chn = (adc_chn + 1) % 8; /* read buttons and digital input */ sr_read(); /* read turbo pump parameters once each second */ if (time() > last_read + 100) { if (user_data.turbo_on != turbo_on_last) { tc600_write(10, 6, user_data.turbo_on ? 111111 : 0); turbo_on_last = user_data.turbo_on; } if (tc600_read(309, str)) { user_data.error &= ~ERR_TURBO_COMM; user_data.rot_speed = atoi(str); if (tc600_read(310, str)) user_data.tmp_current = atoi(str) / 100.0; if (tc600_read(303, str)) { if (atoi(str) != 0) { user_data.error |= ERR_TURBO; strcpy(turbo_err, str); } else { user_data.error &= ~ERR_TURBO; turbo_err[0] = 0; } } } else user_data.error |= ERR_TURBO_COMM; last_read = time(); } /* mangae menu on LCD display */ lcd_menu(); }
// show functions ID static void menu_et_function_show_id(et_functions_s *etf) { lcd_menu(etf->menu); if (etf->flags & EF_BLINK) lcd_set_blink(LMENU, LB_SPC); 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, (u8)(etf->flags & EF_PERCENT ? LS_ON : LS_OFF)); lcd_segment(LS_SYM_LEFT, (u8)(etf->flags & EF_LEFT ? LS_ON : LS_OFF)); lcd_segment(LS_SYM_RIGHT, (u8)(etf->flags & EF_RIGHT ? LS_ON : LS_OFF)); lcd_segment(LS_SYM_CHANNEL, (u8)(etf->flags & EF_NOCHANNEL ? LS_OFF : LS_ON)); lcd_7seg(etf->channel); }
// multi-position show and set value static void show_MP(u8 *name, s16 val) { u8 mp_id = (u8)(name[2] - '1'); s8 *multi_position; u8 channel_MP; u8 num_MP = config_get_MP(mp_id, &channel_MP, &multi_position); // show also selected channel/DIG if (channel_MP == MP_DIG) { lcd_7seg(L7_D); lcd_menu(LM_EPO); lcd_set_blink(LMENU, LB_SPC); lcd_segment(LS_SYM_CHANNEL, LS_OFF); lcd_segment(LS_SYM_PERCENT, LS_ON); } else { lcd_7seg(channel_MP); lcd_segment(LS_SYM_CHANNEL, LS_ON); } lcd_char_num3(multi_position[menu_MP_index[mp_id]]); }
// change val, temporary show new value (not always) // end when another key pressed static u8 menu_popup_key(u8 key_id) { u16 delay_time; u16 buttons_state_last; u16 btnx; config_key_map_s *km = &ck.key_map[key_id]; key_functions_s *kf; key_functions_s *kfl; u8 flags; u8 is_long = 0; u8 *mbs = &menu_buttons_state[key_id]; s16 *pv = &menu_buttons_previous_values[key_id]; // do nothing when both short and long set to OFF if (!km->function && !km->function_long) return 0; // prepare more variables kf = &key_functions[km->function]; btnx = key_buttons[key_id]; // remember buttons state buttons_state_last = buttons_state & ~btnx; // check momentary setting // when something changed, show value for 5s while checking buttons // during initialize show nothing if (km->function && (kf->flags & KF_2STATE) && km->momentary) { static @near u8 ch3_has_middle; // set to 1 if ch3 has middle state u8 state; // new button state u8 value_showed = 0; u16 btnx_orig = btnx; // for CH3 button add MIDDLE state also if (key_id == 0) btnx |= BTN_CH3_MID; while (1) { // set actual state of btnx to buttons_state_last buttons_state_last &= ~btnx; buttons_state_last |= buttons_state & btnx; // check button flags = FF_NONE; state = MBS_RELEASED; if (key_id == 0 && btns(BTN_CH3_MID)) { // special check for CH3 button middle flags |= FF_MID; state = MBS_MIDDLE; ch3_has_middle = 1; } else if (btns(btnx_orig)) { flags |= FF_ON; state = MBS_PRESSED; } if (km->reverse) flags |= FF_REVERSE; if (key_id == 0 && ch3_has_middle) flags |= FF_HAS_MID; if (km->previous_val) flags |= FF_PREVIOUS; // end if button state didn't changed if (state == *mbs) break; // end when initialize if (*mbs == MBS_INITIALIZE) { // call func when not previous_val if (!km->previous_val || state == MBS_PRESSED) kf->func(kf->name, kf->param, flags, pv); *mbs = state; break; } *mbs = state; btnr(btnx); key_beep(); // if value showing disabled, exit if (kf->flags & KF_NOSHOW) break; // 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_key_empty_id(); } // call function to set value and show it flags |= FF_SHOW; kf->func(kf->name, kf->param, flags, pv); lcd_update(); // sleep 5s, and if no button was changed during, end this screen delay_time = POPUP_DELAY * 200; while (delay_time && !(buttons & ~btnx) && (buttons_state == buttons_state_last)) delay_time = delay_menu(delay_time); if ((buttons_state & btnx) == (buttons_state_last & btnx)) break; } btnr(btnx); if (value_showed) lcd_menu(0); // set MENU off return value_showed; } // non-momentary key kfl = &key_functions[km->function_long]; // if button is not initialized, do it if (*mbs == MBS_INITIALIZE) { if (km->function && (kf->flags & KF_2STATE) && !km->previous_val) kf->func(kf->name, kf->param, (u8)(km->reverse ? FF_REVERSE : 0), pv); if (km->function_long && (kfl->flags & KF_2STATE) && !km->previous_val_long) kfl->func(kfl->name, kfl->param, (u8)(km->reverse_long ? FF_REVERSE : 0), pv); *mbs = 0; // both are OFF } // return when key was not pressed if (!btn(btnx)) return 0; // clear some lcd segments menu_key_empty_id(); while (1) { if (km->function_long && btnl(btnx)) { // long key press key_beep(); flags = 0; if (!(kfl->flags & KF_NOSHOW)) flags = FF_SHOW; if (kfl->flags & KF_2STATE) { // ON/OFF is only for 2-state if (*mbs & MBS_ON_LONG) { // is ON, switch to OFF *mbs &= (u8)~MBS_ON_LONG; } else { // is OFF, switch to ON *mbs |= MBS_ON_LONG; flags |= FF_ON; } if (km->reverse_long) flags |= FF_REVERSE; if (km->previous_val_long) flags |= FF_PREVIOUS; } kfl->func(kfl->name, kfl->param, flags, pv); // switch value if (kfl->flags & KF_NOSHOW) { btnr(btnx); return 0; } lcd_update(); is_long = 1; } else if (km->function && btn(btnx)) { // short key press key_beep(); flags = 0; if (!(kf->flags & KF_NOSHOW)) flags = FF_SHOW; if (kf->flags & KF_2STATE) { // ON/OFF is only for 2-state if (*mbs & MBS_ON) { // is ON, switch to OFF *mbs &= (u8)~MBS_ON; } else { // is OFF, switch to ON *mbs |= MBS_ON; flags |= FF_ON; } if (km->reverse) flags |= FF_REVERSE; if (km->previous_val) flags |= FF_PREVIOUS; } kf->func(kf->name, kf->param, flags, pv); // switch value if (kf->flags & KF_NOSHOW) { btnr(btnx); return 0; } lcd_update(); } else { // nothing to do btnr(btnx); return 0; } btnr(btnx); // if another button was pressed, leave this screen if (buttons) break; if ((buttons_state & ~btnx) != buttons_state_last) break; // sleep 5s, and if no button was changed during, end this screen delay_time = POPUP_DELAY * 200; while (delay_time && !buttons && ((buttons_state & ~btnx) == buttons_state_last)) delay_time = delay_menu(delay_time); if (!buttons) break; // timeouted without button press if (is_long) { // if long required but short pressed, end if (!btnl(btnx)) break; } else { // if short required, but long pressed with function_long // specified, end if (km->function_long && btnl(btnx)) break; } } // set MENU off lcd_menu(0); return 1; // popup was showed }
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; }
// choose from menu items static void select_menu(void) { u8 menu = LM_MODEL; lcd_menu(menu); main_screen(MS_NAME); // show model number and name while (1) { btnra(); menu_stop(); // Back/End key to end this menu if (btn(BTN_BACK | BTN_END)) break; // Enter key - goto submenu if (btn(BTN_ENTER)) { key_beep(); if (menu == LM_MODEL) { if (btnl(BTN_ENTER)) menu_model(1); else { menu_model(0); break; } } else if (menu == LM_NAME) { if (btnl(BTN_ENTER)) menu_channels_reset(); else menu_name(); } else if (menu == LM_REV) { if (btnl(BTN_ENTER)) menu_key_mapping(); else menu_reverse(); } else if (menu == LM_EPO) { if (btnl(BTN_ENTER)) menu_mix(); else menu_endpoint(); } else if (menu == LM_TRIM) { if (btnl(BTN_ENTER)) menu_subtrim(); else menu_trim(); } else if (menu == LM_DR) { if (btnl(BTN_ENTER)) menu_speed(); else menu_dualrate(); } else if (menu == LM_EXP) { if (btnl(BTN_ENTER)) menu_channel_value(); else menu_expo(); } else { if (btnl(BTN_ENTER)) break; else menu_abs(); } main_screen(MS_NAME); // show model number and name // exit when BACK if (btn(BTN_BACK)) break; } // rotate keys else if (btn(BTN_ROT_ALL)) { if (btn(BTN_ROT_R)) { menu >>= 1; if (!menu) menu = LM_MODEL; } else { menu <<= 1; if (!menu) menu = LM_ABS; } lcd_menu(menu); lcd_update(); } }
// 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(); }