/*! ******************************************************************************* * 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 View ******************************************************************************/ void menu_view(bool clear) { switch (menu_state) { case menu_startup: LCD_AllSegments(LCD_MODE_ON); // all segments on break; case menu_version: clr_show1(LCD_SEG_COL1); LCD_PrintHexW(VERSION_N,LCD_MODE_ON); break; #if (! REMOTE_SETTING_ONLY) case menu_set_year: LCD_AllSegments(LCD_MODE_OFF); // all segments off LCD_PrintDecW(RTC_GetYearYYYY(),LCD_MODE_BLINK_1); break; case menu_set_month: case menu_set_day: clr_show1(LCD_SEG_COL1); // decimal point LCD_PrintDec(RTC_GetMonth(), 0, ((menu_state==menu_set_month)?LCD_MODE_BLINK_1:LCD_MODE_ON)); LCD_PrintDec(RTC_GetDay(), 2, ((menu_state==menu_set_day)?LCD_MODE_BLINK_1:LCD_MODE_ON)); break; case menu_set_hour: case menu_set_minute: case menu_home4: // time #if HAVE_NEWLCD if (clear) clr_show1(LCD_SEG_COL2); #else if (clear) clr_show2(LCD_SEG_COL1,LCD_SEG_COL2); #endif LCD_PrintDec(RTC_GetHour(), 2, ((menu_state == menu_set_hour) ? LCD_MODE_BLINK_1 : LCD_MODE_ON)); LCD_PrintDec(RTC_GetMinute(), 0, ((menu_state == menu_set_minute) ? LCD_MODE_BLINK_1 : LCD_MODE_ON)); break; #else case menu_home4: // time #if HAVE_NEWLCD if (clear) clr_show1(LCD_SEG_COL2); #else if (clear) clr_show2(LCD_SEG_COL1,LCD_SEG_COL2); #endif LCD_PrintDec(RTC_GetHour(), 2, LCD_MODE_ON); LCD_PrintDec(RTC_GetMinute(), 0, LCD_MODE_ON); break; #endif #if MENU_SHOW_BATTERY case menu_home5: // battery LCD_AllSegments(LCD_MODE_OFF); LCD_PrintDec(bat_average/100, 2, LCD_MODE_ON); LCD_PrintDec(bat_average%100, 0, LCD_MODE_ON); break; #endif case menu_home: // wanted temp / error code / adaptation status if (MOTOR_calibration_step>0) { clr_show1(LCD_SEG_BAR24); LCD_PrintChar(LCD_CHAR_A,3,LCD_MODE_ON); if (MOTOR_ManuCalibration==-1) LCD_PrintChar(LCD_CHAR_d,2,LCD_MODE_ON); LCD_PrintChar(LCD_CHAR_0 + (MOTOR_calibration_step%10), 0, LCD_MODE_ON); goto MENU_COMMON_STATUS; // optimization } else { if (clear) clr_show1(LCD_SEG_BAR24); if (CTL_error!=0) { #if HAVE_NEWLCD==0 if (CTL_error & CTL_ERR_BATT_LOW) { LCD_PrintStringID(LCD_STRING_BAtt,LCD_MODE_BLINK_1); } else #endif if (CTL_error & CTL_ERR_MONTAGE) { LCD_PrintStringID(LCD_STRING_E2,LCD_MODE_ON); } else if (CTL_error & CTL_ERR_MOTOR) { LCD_PrintStringID(LCD_STRING_E3,LCD_MODE_ON); } else #if HAVE_NEWLCD==0 if (CTL_error & CTL_ERR_BATT_WARNING) { LCD_PrintStringID(LCD_STRING_BAtt,LCD_MODE_ON); } else #endif if (CTL_error & CTL_ERR_RFM_SYNC) { LCD_PrintStringID(LCD_STRING_E4,LCD_MODE_ON); } goto MENU_COMMON_STATUS; // optimization } else { if (mode_window()) { LCD_PrintStringID(LCD_STRING_OPEn,LCD_MODE_ON); goto MENU_COMMON_STATUS; // optimization } } } // do not use break at this position / optimization case menu_home_no_alter: // wanted temp if (clear) clr_show1(LCD_SEG_BAR24); LCD_PrintTemp(CTL_temp_wanted,LCD_MODE_ON); //! \note hourbar status calculation is complex we don't want calculate it every view, use chache MENU_COMMON_STATUS: LCD_SetSeg(LCD_SEG_AUTO, (CTL_test_auto()?LCD_MODE_ON:LCD_MODE_OFF)); LCD_SetSeg(LCD_SEG_MANU, (CTL_mode_auto?LCD_MODE_OFF:LCD_MODE_ON)); #if HAVE_NEWLCD if (CTL_error & (CTL_ERR_BATT_LOW | CTL_ERR_BATT_WARNING)) LCD_SetSeg(LCD_SEG_BAT, (CTL_error & CTL_ERR_BATT_LOW)?LCD_MODE_BLINK_1:LCD_MODE_ON); #endif LCD_HourBarBitmap(hourbar_buff); break; case menu_home2: // real temperature if (clear) LCD_AllSegments(LCD_MODE_OFF); LCD_PrintTempInt(temp_average,LCD_MODE_ON); break; case menu_home3: // valve pos if (clear) LCD_AllSegments(LCD_MODE_OFF); // LCD_PrintDec3(MOTOR_GetPosPercent(), 1 ,LCD_MODE_ON); // LCD_PrintChar(LCD_CHAR_2lines,0,LCD_MODE_ON); { uint8_t prc = MOTOR_GetPosPercent(); if (prc<=100) { LCD_PrintDec3(MOTOR_GetPosPercent(), 0 ,LCD_MODE_ON); } else { LCD_PrintStringID(LCD_STRING_minusCminus,LCD_MODE_ON); } } break; #if (! REMOTE_SETTING_ONLY) case menu_set_timmer_dow: clr_show1(LCD_SEG_PROG); // all segments off LCD_PrintDayOfWeek(menu_set_dow, LCD_MODE_BLINK_1); break; case menu_set_timmer: //! \todo calculate "hourbar" status, actual position in mode LCD_MODE_BLINK_1 // clr_show3(LCD_SEG_COL1,LCD_SEG_COL2,LCD_SEG_PROG); clr_show2(LCD_SEG_COL1,LCD_SEG_COL2); timmers_patch_offset=timers_get_raw_index(menu_set_dow, menu_set_slot); timmers_patch_data = menu_set_time + ((uint16_t)menu_set_mode<<12); LCD_HourBarBitmap(RTC_DowTimerGetHourBar(menu_set_dow)); timmers_patch_offset=0xff; LCD_SetHourBarSeg(menu_set_time/60, LCD_MODE_BLINK_1); if (menu_set_time < 24*60) { LCD_PrintDec(menu_set_time/60, 2, LCD_MODE_BLINK_1); LCD_PrintDec(menu_set_time%60, 0, LCD_MODE_BLINK_1); } else { LCD_PrintStringID(LCD_STRING_4xminus,LCD_MODE_BLINK_1); } show_selected_temperature_type(menu_set_mode,LCD_MODE_BLINK_1); break; #endif case menu_lock: // "bloc" message LCD_AllSegments(LCD_MODE_OFF); // all segments off LCD_PrintStringID(LCD_STRING_bloc,LCD_MODE_ON); break; case menu_service1: case menu_service2: // service menu; left side index, right value LCD_AllSegments(LCD_MODE_ON); LCD_PrintHex(service_idx, 2, ((menu_state == menu_service1) ? LCD_MODE_BLINK_1 : LCD_MODE_ON)); LCD_PrintHex(config_raw[service_idx], 0, ((menu_state == menu_service2) ? LCD_MODE_BLINK_1 : LCD_MODE_ON)); break; case menu_service_watch: LCD_AllSegments(LCD_MODE_ON); LCD_PrintHexW(watch(service_watch_n),LCD_MODE_ON); LCD_SetHourBarSeg(service_watch_n, LCD_MODE_BLINK_1); break; #if (! REMOTE_SETTING_ONLY) case menu_preset_temp0: case menu_preset_temp1: case menu_preset_temp2: case menu_preset_temp3: LCD_AllSegments(LCD_MODE_OFF); LCD_PrintTemp(menu_set_temp,LCD_MODE_BLINK_1); show_selected_temperature_type(menu_state-menu_preset_temp0,LCD_MODE_ON); #endif default: break; } LCD_Update(); }