/*! ******************************************************************************* * main program ******************************************************************************/ int main(void) { //! initalization init(); task=0; //! Enable interrupts sei(); /* check EEPROM layout */ if (EEPROM_read((uint16_t)&ee_layout)!=EE_LAYOUT) { LCD_PrintStringID(LCD_STRING_EEPr,LCD_MODE_ON); task_lcd_update(); for(;;) {;} //fatal error, stop startup } COM_init(); // We should do the following once here to have valid data from the start /*! **************************************************************************** * main loop ***************************************************************************/ for (;;){ // go to sleep with ADC conversion start asm volatile ("cli"); if ( ! task && ((ASSR & (_BV(OCR2UB)|_BV(TCN2UB)|_BV(TCR2UB))) == 0) // ATmega169 datasheet chapter 17.8.1 ) { // nothing to do, go to sleep if(timer0_need_clock() || RS_need_clock()) { SMCR = (0<<SM1)|(0<<SM0)|(1<<SE); // Idle mode } else { if (sleep_with_ADC) { SMCR = (0<<SM1)|(1<<SM0)|(1<<SE); // ADC noise reduction mode } else { SMCR = (1<<SM1)|(1<<SM0)|(1<<SE); // Power-save mode } } if (sleep_with_ADC) { sleep_with_ADC=0; // start conversions ADCSRA |= (1<<ADSC); } DEBUG_BEFORE_SLEEP(); asm volatile ("sei"); // sequence from ATMEL datasheet chapter 6.8. asm volatile ("sleep"); asm volatile ("nop"); DEBUG_AFTER_SLEEP(); SMCR = (1<<SM1)|(1<<SM0)|(0<<SE); // Power-save mode } else { asm volatile ("sei"); } // update LCD task if (task & TASK_LCD) { task&=~TASK_LCD; task_lcd_update(); continue; // on most case we have only 1 task, iprove time to sleep } if (task & TASK_ADC) { task&=~TASK_ADC; if (task_ADC()==0) { // ADC is done // TODO } continue; // on most case we have only 1 task, iprove time to sleep } // communication if (task & TASK_COM) { task&=~TASK_COM; COM_commad_parse(); continue; // on most case we have only 1 task, iprove time to sleep } // motor stop if (task & TASK_MOTOR_STOP) { task&=~TASK_MOTOR_STOP; MOTOR_timer_stop(); continue; // on most case we have only 1 task, iprove time to sleep } // update motor possition if (task & TASK_MOTOR_PULSE) { task&=~TASK_MOTOR_PULSE; MOTOR_updateCalibration(mont_contact_pooling()); MOTOR_timer_pulse(); continue; // on most case we have only 1 task, iprove time to sleep } //! check keyboard and set keyboards events if (task & TASK_KB) { task&=~TASK_KB; task_keyboard(); } if (task & TASK_RTC) { task&=~TASK_RTC; { bool minute = RTC_AddOneSecond(); valve_wanted = CTL_update(minute,valve_wanted); if (minute && (RTC_GetDayOfWeek()==6) && (RTC_GetHour()==10) && (RTC_GetMinute()==0)) { // every sunday 10:00AM // TODO: improve this code! // valve protection / CyCL MOTOR_updateCalibration(0); } } MOTOR_updateCalibration(mont_contact_pooling()); MOTOR_Goto(valve_wanted); task_keyboard_long_press_detect(); if ((MOTOR_Dir==stop) || (config.allow_ADC_during_motor)) start_task_ADC(); if (menu_auto_update_timeout>=0) { menu_auto_update_timeout--; } menu_view(false); // TODO: move it, it is wrong place LCD_Update(); // TODO: move it, it is wrong place // do not use continue here (menu_auto_update_timeout==0) } // menu state machine if (kb_events || (menu_auto_update_timeout==0)) { bool update = menu_controller(false); if (update) { menu_controller(true); // menu updated, call it again } menu_view(update); // TODO: move it, it is wrong place LCD_Update(); // TODO: move it, it is wrong place } } //End Main loop
/*! ******************************************************************************* * \brief menu Controller * * \returns true for controler restart ******************************************************************************/ bool menu_controller(bool new_state) { int8_t wheel = wheel_proccess(); //signed number bool ret = false; switch (menu_state) { case menu_startup: if (new_state) { menu_auto_update_timeout=2; } if (menu_auto_update_timeout==0) { menu_state = menu_version; ret=true; } break; case menu_version: if (new_state) { menu_auto_update_timeout=2; } if (menu_auto_update_timeout==0) { #if (DEBUG_SKIP_DATETIME_SETTING_AFTER_RESET) || (REMOTE_SETTING_ONLY) menu_state = menu_home; #else menu_state = menu_set_year; #endif ret=true; } break; #if (! REMOTE_SETTING_ONLY) case menu_set_year: if (wheel != 0) RTC_SetYear(RTC_GetYearYY()+wheel); if ( kb_events & KB_EVENT_PROG) { menu_state = menu_set_month; CTL_update_temp_auto(); ret=true; } break; case menu_set_month: if (wheel != 0) RTC_SetMonth(RTC_GetMonth()+wheel); if ( kb_events & KB_EVENT_PROG ) { menu_state = menu_set_day; CTL_update_temp_auto(); ret=true; } break; case menu_set_day: if (wheel != 0) RTC_SetDay(RTC_GetDay()+wheel); if ( kb_events & KB_EVENT_PROG ) { menu_state = menu_set_hour; CTL_update_temp_auto(); ret=true; } break; case menu_set_hour: if (wheel != 0) RTC_SetHour(RTC_GetHour()+wheel); if ( kb_events & KB_EVENT_PROG ) { menu_state = menu_set_minute; CTL_update_temp_auto(); ret=true; } break; case menu_set_minute: if (wheel != 0) { RTC_SetMinute(RTC_GetMinute()+wheel); RTC_SetSecond(0); } if ( kb_events & KB_EVENT_PROG ) { menu_state = menu_home; CTL_update_temp_auto(); ret=true; } break; #endif case menu_home_no_alter: // same as home screen, but without alternate contend case menu_home: // home screen case menu_home2: // alternate version, real temperature case menu_home3: // alternate version, valve pos case menu_home4: // alternate version, time #if MENU_SHOW_BATTERY case menu_home5: // alternate version, battery #endif if ( kb_events & KB_EVENT_C ) { menu_state++; // go to next alternate home screen #if MENU_SHOW_BATTERY if (menu_state > menu_home5) menu_state=menu_home; #else if (menu_state > menu_home4) menu_state=menu_home; #endif ret=true; } else { if (menu_locked) { if ( kb_events & ( KB_EVENT_WHEEL_PLUS | KB_EVENT_WHEEL_MINUS | KB_EVENT_PROG | KB_EVENT_AUTO | KB_EVENT_PROG_REWOKE | KB_EVENT_C_REWOKE | KB_EVENT_AUTO_REWOKE | KB_EVENT_PROG_LONG | KB_EVENT_C_LONG | KB_EVENT_AUTO_LONG )) { menu_auto_update_timeout=LONG_PRESS_THLD+1; menu_state=menu_lock; ret=true; } } else { // not locked if ((menu_state == menu_home) || (menu_state == menu_home_no_alter)) { if (wheel != 0) { CTL_temp_change_inc(wheel); menu_state = menu_home_no_alter; ret=true; } if ( kb_events & KB_EVENT_AUTO ) { CTL_change_mode(CTL_CHANGE_MODE); // change mode menu_state=menu_home_no_alter; ret=true; } else if ( kb_events & KB_EVENT_AUTO_REWOKE ) { CTL_change_mode(CTL_CHANGE_MODE_REWOKE); // change mode menu_state=menu_home_no_alter; ret=true; } } else { if ( kb_events & ( KB_EVENT_WHEEL_PLUS | KB_EVENT_WHEEL_MINUS | KB_EVENT_PROG | KB_EVENT_AUTO | KB_EVENT_PROG_REWOKE | KB_EVENT_C_REWOKE | KB_EVENT_AUTO_REWOKE | KB_EVENT_PROG_LONG | KB_EVENT_C_LONG | KB_EVENT_AUTO_LONG )) { menu_state = menu_home; ret = true; } } // TODO .... } } break; #if (! REMOTE_SETTING_ONLY) case menu_set_timmer_dow_start: if (new_state) menu_set_dow=((config.timer_mode==1)?RTC_GetDayOfWeek():0); menu_state = menu_set_timmer_dow; // do not use break here case menu_set_timmer_dow: if (wheel != 0) menu_set_dow=(menu_set_dow+wheel+8)%8; if ( kb_events & KB_EVENT_PROG ) { menu_state=menu_set_timmer; menu_set_slot=0; config.timer_mode = (menu_set_dow>0); eeprom_config_save((uint16_t)(&config.timer_mode)-(uint16_t)(&config)); // save value to eeprom // update hourbar menu_update_hourbar((config.timer_mode==1)?RTC_GetDayOfWeek():0); ret=true; } else if ( kb_events & KB_EVENT_AUTO ) { // exit without save menu_state=menu_home; ret=true; } break; case menu_set_timmer: if (new_state) { menu_set_time= RTC_DowTimerGet(menu_set_dow, menu_set_slot, &menu_set_mode); if (menu_set_time>24*60) menu_set_time=24*60; } if (wheel != 0) { menu_set_time=((menu_set_time/10+(24*6+1)+wheel)%(24*6+1))*10; } if ( kb_events & KB_EVENT_C ) { menu_set_mode=(menu_set_mode+5)%4; } else if ( kb_events & KB_EVENT_PROG ) { RTC_DowTimerSet(menu_set_dow, menu_set_slot, menu_set_time, menu_set_mode); if (++menu_set_slot>=RTC_TIMERS_PER_DOW) { if (menu_set_dow!=0) menu_set_dow=menu_set_dow%7+1; menu_state=menu_set_timmer_dow; } CTL_update_temp_auto(); menu_update_hourbar((config.timer_mode==1)?RTC_GetDayOfWeek():0); ret=true; } else if ( kb_events & KB_EVENT_AUTO ) { // exit without save menu_state=menu_home; ret=true; } break; #endif #if (! REMOTE_SETTING_ONLY) case menu_preset_temp0: case menu_preset_temp1: case menu_preset_temp2: case menu_preset_temp3: if (new_state) menu_set_temp=temperature_table[menu_state-menu_preset_temp0]; if (wheel != 0) { menu_set_temp+=wheel; if (menu_set_temp > TEMP_MAX+1) menu_set_temp = TEMP_MAX+1; if (menu_set_temp < TEMP_MIN-1) menu_set_temp = TEMP_MIN-1; } if ( kb_events & KB_EVENT_PROG ) { temperature_table[menu_state-menu_preset_temp0]=menu_set_temp; eeprom_config_save(menu_state+((temperature_table-config_raw)-menu_preset_temp0)); menu_state++; // menu_preset_temp3+1 == menu_home CTL_update_temp_auto(); ret=true; } else if ( kb_events & KB_EVENT_AUTO ) { // exit without save menu_state=menu_home; ret=true; } break; #endif default: case menu_lock: // "bloc" message if (menu_auto_update_timeout==0) { menu_state=menu_home; ret=true; } break; case menu_service1: // service menu case menu_service2: if (kb_events & KB_EVENT_AUTO) { menu_state=menu_home; ret=true; } else if (kb_events & KB_EVENT_C) { menu_state=menu_service_watch; ret=true; } else if (kb_events & KB_EVENT_PROG) { if (menu_state == menu_service2) { eeprom_config_save(service_idx); // save current value menu_state = menu_service1; } else { menu_state = menu_service2; } } else { if (menu_state == menu_service1) { // change index service_idx = (service_idx+wheel+CONFIG_RAW_SIZE)%CONFIG_RAW_SIZE; } else { // change value in RAM, to save press PROG int16_t min = (int16_t)config_min(service_idx); int16_t max_min_1 = (int16_t)(config_max(service_idx))-min+1; config_raw[service_idx] = (uint8_t) ( ((int16_t)(config_raw[service_idx])+(int16_t)wheel-min+max_min_1)%max_min_1+min); if (service_idx==0) LCD_Init(); } } break; case menu_service_watch: if (kb_events & KB_EVENT_AUTO) { menu_state=menu_home; ret=true; } else if (kb_events & KB_EVENT_C) { menu_state=menu_service1; ret=true; } else { service_watch_n=(service_watch_n+wheel+WATCH_N)%WATCH_N; if (wheel != 0) ret=true; } break; } if (events_common()) ret=true; if (ret && (service_idx<CONFIG_RAW_SIZE)) { // back config to default value config_raw[service_idx] = config_value(service_idx); service_idx = CONFIG_RAW_SIZE; } kb_events = 0; // clear unused keys return ret; }