Esempio n. 1
0
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();
}
Esempio n. 2
0
// 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);
}
Esempio n. 3
0
// 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]]);
}
Esempio n. 4
0
// 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
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
File: menu.c Progetto: Micha500/gt3b
// 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();
	}
    }
Esempio n. 7
0
// 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();
}