Sat, 06 Jun 2020 13:28:46 +0200
Changed the recipe database so that it is expandable, version 2. More mash fields and allow 16 steps. Allow 20 Additions. Removed separate mash steps from the state machine, the steps are moved to the runtime data. There is no fixed step number for mashout anymore. There is no fixed step for mash-in anymore, just use the first step and heat to the infusion temperature. After malt add, switch to the normal step temperature. Implemented decoction steps.
/** * @file task_tft.c * @brief BrewBoard TFT and Touch screen driver for a 320x240 ILI9341 based display. * But because the application is controlled using the touch screen, all the * processing of menus is also found here. * It's the first started task, but it does nothing until the Main_Screen * variable is set. */ #include "config.h" spi_lobo_device_handle_t spi; ///< TFT screen SPI handler spi_lobo_device_handle_t tsspi = NULL; ///< Touchscreen SPI handler extern sButton Buttons[MAXBUTTONS]; ///< 40 buttons on a screen. time_t now; ///< Current time time_t last = 0; ///< Last time struct tm timeinfo; ///< Current time structure char s_timer[16]; ///< Timer string buffer char s_top_msg[64]; ///< Top message string buffer extern float stageTemp; extern uint16_t stageTime; extern uint16_t TimeWhirlPool; extern uint32_t TimeLeft; extern uint32_t TimeSpent; extern uint32_t SecsCount; extern uint32_t pumpTime; extern uint32_t TimeBrewing; extern uint16_t Steady; esp_timer_handle_t timerHandle; ///< Timer handler extern bool _NewMinute; extern bool _UseHLT; extern bool System_TimeOk; extern const esp_app_desc_t *app_desc; static const char *TAG = "task_tft"; #define SPI_BUS TFT_HSPI_HOST ///< SPI bus for the TFT, TFT_VSPI_HOST or TFT_HSPI_HOST extern int Main_Screen; extern int Sub_Screen; extern int Old_Screen; extern int MLT_pin; extern int HLT_pin; extern int Pump_pin; extern DS18B20_State *ds18b20_state; extern DRIVER_State *driver_state; extern JSON_log *json_log; extern SemaphoreHandle_t xSemaphoreDS18B20; extern SemaphoreHandle_t xSemaphoreDriver; extern SemaphoreHandle_t xSemaphoreWiFi; extern WIFI_State *wifi_state; extern double Output; extern sButton Buttons[MAXBUTTONS]; extern int BoilPower, LastMashStep; extern char temp_buf[], logline[], strftime_buf[64]; extern bool loop, CoolBeep, Resume, pumpRest, updateRuntime; extern bool NewMinute, TempReached; extern uint8_t MashState; extern float temp_MLT, MinMash, MaxMash; extern uint32_t power_MLT, power_HLT, counts; #ifdef CONFIG_TEMP_SENSORS_SIMULATOR extern float Fake_MLT; extern float Fake_HLT; #endif /** * @brief Seconds timer callback. */ void TimerCallback(void *arg); /***************************************************************************/ int init_tft_display(void) { esp_err_t ret; esp_timer_create_args_t timerSecond = { .callback = &TimerCallback, .name = "SecondsTimer" }; ESP_LOGI(TAG, "Initialize TFT"); max_rdclock = 8000000; TFT_PinsInit(); spi_lobo_bus_config_t buscfg = { .miso_io_num=PIN_NUM_MISO, // set SPI MISO pin .mosi_io_num=PIN_NUM_MOSI, // set SPI MOSI pin .sclk_io_num=PIN_NUM_CLK, // set SPI CLK pin .quadwp_io_num=-1, .quadhd_io_num=-1, .max_transfer_sz = 6*1024, }; spi_lobo_device_interface_config_t devcfg={ .clock_speed_hz=8000000, // Initial clock out at 8 MHz .mode=0, // SPI mode 0 .spics_io_num=-1, // we will use external CS pin .spics_ext_io_num=PIN_NUM_CS, // external CS pin .flags=LB_SPI_DEVICE_HALFDUPLEX, // ALWAYS SET to HALF DUPLEX MODE!! for display spi }; spi_lobo_device_interface_config_t tsdevcfg={ .clock_speed_hz=2500000, //Clock out at 2.5 MHz .mode=0, //SPI mode 0 .spics_io_num=PIN_NUM_TCS, //Touch CS pin .spics_ext_io_num=-1, //Not using the external CS }; ESP_LOGI(TAG, "TFT pins: miso=%d, mosi=%d, sck=%d, cs=%d", PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CLK, PIN_NUM_CS); ret = spi_lobo_bus_add_device(SPI_BUS, &buscfg, &devcfg, &spi); assert(ret == ESP_OK); disp_spi = spi; // ==== Test select/deselect ==== ret = spi_lobo_device_select(spi, 1); assert(ret == ESP_OK); ret = spi_lobo_device_deselect(spi); assert(ret == ESP_OK); ESP_LOGI(TAG, "SPI: attached display, spi bus: %d, speed: %u, bus uses native pins: %s", SPI_BUS, spi_lobo_get_speed(spi), spi_lobo_uses_native_pins(spi) ? "true" : "false"); ESP_LOGI(TAG, "TS pins : miso=%d, mosi=%d, sck=%d, cs=%d", PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CLK, PIN_NUM_TCS); ret=spi_lobo_bus_add_device(SPI_BUS, &buscfg, &tsdevcfg, &tsspi); assert(ret == ESP_OK); ts_spi = tsspi; // ==== Test select/deselect ==== ret = spi_lobo_device_select(tsspi, 1); assert(ret == ESP_OK); ret = spi_lobo_device_deselect(tsspi); assert(ret == ESP_OK); ESP_LOGI(TAG, "SPI: attached TS device, spi bus: %d, speed: %u", SPI_BUS, spi_lobo_get_speed(tsspi)); // ==== Initialize the Display ==== TFT_display_init(); // ---- Detect maximum read speed ---- max_rdclock = find_rd_speed(); // ==== Set SPI clock used for display operations ==== spi_lobo_set_speed(spi, DEFAULT_SPI_CLOCK); ESP_LOGI(TAG, "SPI: Max rd speed: %u, changed speed to %u", max_rdclock, spi_lobo_get_speed(spi)); font_rotate = 0; text_wrap = 0; font_transparent = 0; font_forceFixed = 0; gray_scale = 0; TFT_setGammaCurve(DEFAULT_GAMMA_CURVE); TFT_setRotation(LANDSCAPE); TFT_setFont(DEFAULT_FONT, NULL); TFT_resetclipwin(); /* * Create a one second periodic timer. */ ret = esp_timer_create(&timerSecond, &timerHandle); assert(ret == ESP_OK); ret = esp_timer_start_periodic(timerHandle, 1000000); assert(ret == ESP_OK); return ret; } void TimerCallback(void *arg) { TimeSpent++; SecsCount++; Steady++; TimeBrewing++; runtime.TimeBrewing++; if ((SecsCount % 60) == 0) _NewMinute = true; if (TimeLeft) { TimeLeft--; if (TimeLeft == 5) { SoundPlay(SOUND_TimeOut); } if ((TimeLeft % 60) == 0) { pumpTime++; } } } void TimerSet(uint32_t seconds) { Steady = TimeSpent = SecsCount = 0; TimeLeft = seconds; } void TimerShow(uint32_t Time, int X, int Y) { uint8_t Hours = (uint8_t)(Time / 3600); uint8_t Minutes = (uint8_t)((Time % 3600) / 60); uint8_t Seconds = (uint8_t)(Time % 60); char msg[32]; static uint32_t _oldTime = 0; if (Time != _oldTime) { _fg = TFT_GREEN; TFT_setFont(FONT_7SEG, NULL); set_7seg_font_atrib(12, 2, 1, TFT_DARKGREY); snprintf(s_timer, 15, "%02d:%02d:%02d", Hours, Minutes, Seconds); TFT_print(s_timer, X, Y); _oldTime = Time; snprintf(msg, 31, "{\"timer\":\"%s\"}", s_timer); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } } void TopMessage(char *text) { char msg[96]; snprintf(s_top_msg, 63, "%s", text); _fg = TFT_YELLOW; font_transparent = 1; TFT_setFont(DEJAVU24_FONT, NULL); TFT_fillRect(0, 0, 319, 25, TFT_NAVY); TFT_print(s_top_msg, CENTER, 2); font_transparent = 0; snprintf(msg, 95, "{\"top_msg\":\"%s\"}", s_top_msg); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } void MLT_info(int x, int y, bool update) { char ctemp[16], csp[16], cpower[16], msg[96]; static char ltemp[16], lsp[16], lpower[16]; bool con, cpwr, cpump = false; static bool lon, lpwr, lpump; _bg = (color_t){ 48, 48, 48 }; _fg = TFT_WHITE; color_t _led = { 31,255, 31}; color_t _pump = {127,175,255}; color_t _pwr = {255, 47, 47}; if (! update) { TFT_fillRect(x, y, 178, 90, _bg); TFT_drawRect(x, y, 178, 90, _fg); TFT_drawFastHLine(x, y + 21, 178, _fg); TFT_setFont(DEJAVU18_FONT, NULL); TFT_print((char *)"MLT", x + 67, y + 3); } if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) { sprintf(ctemp, "%7.3f", driver_state->mlt_pv); if (driver_state->mlt_mode) { sprintf(csp, "%6.2f sp", driver_state->mlt_sp); } else { csp[0] = '\0'; } if ((driver_state->mlt_mode == MLT_MODE_BANG) || (driver_state->mlt_mode == MLT_MODE_PID) || (driver_state->mlt_mode == MLT_MODE_EXT)) { sprintf(cpower, "%3d%%", driver_state->mlt_power); } else { cpower[0] = '\0'; } xSemaphoreGive(xSemaphoreDriver); } con = (MLT_pin) ? true : false; if ((con != lon) || (! update)) { if (con) { TFT_fillCircle(x + 166, y + 11, 8, _led); } else { TFT_fillCircle(x + 166, y + 11, 8, _bg); } lon = con; snprintf(msg, 95, "{\"mlt_led\":\"%s\"}", con ? "1":"0"); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } cpump = (Pump_pin) ? true : false; if ((cpump != lpump) || (! update)) { if (cpump) { TFT_fillCircle(x + 11, y + 11, 8, _pump); } else { TFT_fillCircle(x + 11, y + 11, 8, _bg); } lpump = cpump; snprintf(msg, 95, "{\"pump_led\":\"%s\"}", cpump ? "1":"0"); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } if (equipment.SSR2 == SSR2_ON_IDLE) { cpwr = (HLT_pin) ? true : false; if ((cpwr != lpwr) || (! update)) { if (cpwr) { TFT_fillCircle(x + 126, y + 11, 8, _pwr); } else { TFT_fillCircle(x + 126, y + 11, 8, _bg); } lpwr = cpwr; snprintf(msg, 95, "{\"hlt_led\":\"%s\"}", cpwr ? "1":"0"); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } } if (strcmp(ctemp, ltemp) || (! update)) { TFT_setFont(USER_FONT, "/spiffs/fonts/Grotesk24x48.fon"); TFT_print(ctemp, x + 5, y + 23); strncpy(ltemp, ctemp, 16); snprintf(msg, 95, "{\"mlt_pv\":\"%s\"}", ctemp); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } TFT_setFont(DEJAVU18_FONT, NULL); if (strcmp(csp, lsp) || (! update)) { TFT_clearStringRect(x + 5, y + 70, (char *)"123.45 sp"); TFT_print(csp, x + 5, y + 70); strncpy(lsp, csp, 16); snprintf(msg, 95, "{\"mlt_sp\":\"%s\"}", csp); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } if (strcmp(cpower, lpower) || (! update)) { TFT_clearStringRect(x + 120, y + 70, (char *)"100%"); TFT_print(cpower, x + 120, y + 70); strncpy(lpower, cpower, 16); snprintf(msg, 95, "{\"mlt_power\":\"%s\"}", cpower); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } } void HLT_info(int x, int y, bool update, bool small) { char ctemp[16], csp[16], cpower[16], msg[96]; static char ltemp[16], lsp[16], lpower[16]; bool con = false; static bool lon; uint8_t H; _bg = (color_t){ 63, 63, 64 }; _fg = TFT_YELLOW; color_t _led = {255, 47, 47}; H = (small) ? 70 : 90; if (! update) { TFT_fillRect(x, y, 178, H, _bg); TFT_drawRect(x, y, 178, H, _fg); TFT_drawFastHLine(x, y + 21, 178, _fg); TFT_setFont(DEJAVU18_FONT, NULL); TFT_print((char *)"HLT", x + 67, y + 3); } if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) { sprintf(ctemp, "%7.3f", driver_state->hlt_pv); if (driver_state->hlt_mode == HLT_MODE_BANG) { sprintf(cpower, "%3d%%", driver_state->hlt_power); } else { cpower[0] = '\0'; } if (driver_state->hlt_mode == HLT_MODE_BANG || driver_state->hlt_mode == HLT_MODE_OFF) { sprintf(csp, "%6.2f sp", driver_state->hlt_sp); } else { csp[0] = '\0'; } xSemaphoreGive(xSemaphoreDriver); } con = (HLT_pin) ? true : false; if ((con != lon) || (! update)) { if (con) { TFT_fillCircle(x + 166, y + 11, 8, _led); } else { TFT_fillCircle(x + 166, y + 11, 8, _bg); } lon = con; snprintf(msg, 95, "{\"hlt_led\":\"%s\"}", con ? "1":"0"); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } if (strcmp(ltemp, ctemp) || (! update)) { if (small) { TFT_setFont(USER_FONT, "/spiffs/fonts/DejaVuSans24.fon"); TFT_print(ctemp, x + 40, y + 25); } else { TFT_setFont(USER_FONT, "/spiffs/fonts/Grotesk24x48.fon"); TFT_print(ctemp, x + 5, y + 23); } strncpy(ltemp, ctemp, 16); snprintf(msg, 95, "{\"hlt_pv\":\"%s\"}", ctemp); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } H = (small) ? 50 : 70; TFT_setFont(DEJAVU18_FONT, NULL); if (strcmp(csp, lsp) || (! update)) { TFT_clearStringRect(x + 5, y + H, (char *)"123.45 sp"); TFT_print(csp, x + 5, y + H); strncpy(lsp, csp, 16); snprintf(msg, 95, "{\"hlt_sp\":\"%s\"}", csp); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } if (strcmp(cpower, lpower) || (! update)) { TFT_clearStringRect(x + 120, y + H, (char *)"100%"); TFT_print(cpower, x + 120, y + H); strncpy(lpower, cpower, 16); snprintf(msg, 95, "{\"hlt_power\":\"%s\"}", cpower); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } } void update_json(void) { int Hour = (TimeBrewing / 3600); int Minute = ((TimeBrewing % 3600) / 60); if (counts == 0) counts = 1; // Prevent division by zero. if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) { snprintf(json_log->time, 11, "%02d:%02d", Hour, Minute); json_log->mlt_sp = driver_state->mlt_sp; json_log->mlt_pv = driver_state->mlt_pv; json_log->mlt_power = power_MLT / counts; json_log->mlt_tempreached = TempReached ? 1:0; json_log->pump_run = driver_state->pump_run; json_log->hlt_sp = driver_state->hlt_sp; json_log->hlt_pv = driver_state->hlt_pv; json_log->hlt_power = power_HLT / counts; json_log->event[0] = '\0'; xSemaphoreGive(xSemaphoreDriver); } } void TFTstartWS(int client) { char msg[1024]; char mlt_sp[16], mlt_power[16], hlt_sp[16], hlt_power[16]; if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) { if (driver_state->mlt_sp) { snprintf(mlt_sp, 15, "%6.2f sp", driver_state->mlt_sp); snprintf(mlt_power, 15, "%3d%%", driver_state->mlt_power); } else { mlt_sp[0] = '\0'; mlt_power[0] = '\0'; } if (driver_state->hlt_sp) { snprintf(hlt_sp, 15, "%6.2f sp", driver_state->hlt_sp); snprintf(hlt_power, 15, "%3d%%", driver_state->hlt_power); } else { hlt_sp[0] = '\0'; hlt_power[0] = '\0'; } snprintf(msg, 1023, "{\"main\":\"%d\",\"sub\":\"%d\",\"mlt_led\":\"%d\",\"mlt_pv\":\"%7.3f\",\"mlt_sp\":\"%s\",\"mlt_power\":\"%s\"" \ ",\"pump_led\":\"%d\",\"hlt_led\":\"%d\",\"hlt_pv\":\"%7.3f\",\"hlt_sp\":\"%s\",\"hlt_power\":\"%s\"" \ ",\"timer\":\"%s\",\"top_msg\":\"%s\"}", Main_Screen, Sub_Screen, (MLT_pin) ? 1:0, driver_state->mlt_pv, mlt_sp, mlt_power, (Pump_pin) ? 1:0, (HLT_pin) ? 1:0, driver_state->hlt_pv, hlt_sp, hlt_power, s_timer, s_top_msg); xSemaphoreGive(xSemaphoreDriver); ws_server_send_text_client(client, msg, strlen(msg)); } } void task_tft(void *pvParameter) { char msg[96]; ESP_LOGI(TAG, "Starting TFT/Touch"); /* * Task loop. Read touchscreen events. */ while (1) { /* * Build new screen. */ startover: updateRuntime = false; if (_NewMinute) { _NewMinute = false; NewMinute = true; } /* * Timekeeping. * In the WiFi task sntp is started and sets System_TimeOk if the * clock is synced once. */ time(&now); localtime_r(&now, &timeinfo); if (Old_Screen != Main_Screen) { if ((Main_Screen == MAIN_MODE_FREE) && ((config.ts_xleft == 0) || (config.ts_ybottom == 0))) { Main_Screen = MAIN_MODE_CALIBRATION; } /* * With each screenchange, remove the timer too. */ Sub_Screen = 0; snprintf(msg, 95, "{\"main\":\"%d\",\"sub\":\"%d\",\"timer\":\"\"}", Main_Screen, Sub_Screen); ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); ESP_LOGD(TAG, "Change screen %d to %d", Old_Screen, Main_Screen); _bg = TFT_BLACK; TFT_fillScreen(_bg); TFT_resetclipwin(); Buttons_Clear(); Old_Screen = Main_Screen; switch (Main_Screen) { case MAIN_MODE_FREE: TopMessage((char *)"Hoofdmenu"); MLT_info(71, 26, false); if ((equipment.SSR2 == SSR2_HLT_SHARE) || (equipment.SSR2 == SSR2_HLT_IND)) { HLT_info(71,150, false, false); } Buttons_Add( 5, 26, 60, 40, (char *)"Hand", 0); Buttons_Add(255, 26, 60, 40, (char *)"Auto", 1); Buttons_Add( 5, 200, 60, 40, (char *)"Info", 2); Buttons_Add(255, 200, 60, 40, (char *)"Tools", 3); Buttons_Show(); break; case MAIN_MODE_CALIBRATION: Calibration_Init(); break; case MAIN_INFO: sprintf(temp_buf, "BrewBoard %s", app_desc->version); TopMessage(temp_buf); _fg = TFT_YELLOW; TFT_setFont(UBUNTU16_FONT, NULL); TFT_print((char *)"Written by Michiel Broek (C) 2018-2020\r\n\n", 0, 50); // ------------------------------------- _fg = TFT_ORANGE; TFT_print((char *)"Parts are written by Chris Morgan,\r\n", 0, LASTY); TFT_print((char *)"Brett Beauregard, Blake Felt, LoBo,\r\n", 0, LASTY); TFT_print((char *)"and David Antliff.\r\n", 0, LASTY); ShowInteger(1,140, (char *)"Free memory", (char *)" bytes", esp_get_free_heap_size()); ShowText(1,158, (char *)"IDF version", (char *)esp_get_idf_version()); Buttons_Add(130, 200, 60, 40, (char *)"Ok", 0); Buttons[0].dark = true; Buttons_Show(); break; case MAIN_TOOLS: TopMessage((char *)"Tools menu"); Buttons_Add( 20, 40,120, 40, (char *)"Setup", 0); Buttons_Add( 20,120,120, 40, (char *)"Bestanden", 1); Buttons_Add(180, 40,120, 40, (char *)"Recepten", 2); Buttons_Add(180,120,120, 40, (char *)"Updates", 3); Buttons_Add(130, 200, 60, 40, (char *)"Ok", 4); Buttons[4].dark = true; Buttons_Show(); break; case MAIN_TOOLS_SETUP: case MAIN_TOOLS_SETUP_CONFIG: case MAIN_TOOLS_SETUP_CO_EDIT: case MAIN_TOOLS_SETUP_EQUIPMENT: case MAIN_TOOLS_SETUP_EQ_EDIT: case MAIN_TOOLS_SETUP_CALIBRATION: Setup_Init(); break; case MAIN_TOOLS_SETUP_WIFI: case MAIN_TOOLS_SETUP_WIFI_CUR: case MAIN_TOOLS_SETUP_WIFI_CON: case MAIN_TOOLS_SETUP_WIFI_NEW: if (WiFi_Init()) goto startover; break; case MAIN_TOOLS_RECIPE: case MAIN_TOOLS_RECIPE_EDIT: Recipes_Init(); break; case MAIN_TOOLS_FILES: case MAIN_TOOLS_FILES_DIR: case MAIN_TOOLS_FILES_RESTORE: case MAIN_TOOLS_FILES_BACKUP: Files_Init(); break; case MAIN_TOOLS_UPDATES: Updates_Init(); break; case MAIN_AUTO_INIT1: case MAIN_AUTO_INIT2: case MAIN_AUTO_DELAYSTART: case MAIN_AUTO_HEATUP: case MAIN_AUTO_MASH: case MAIN_AUTO_TOBOIL: case MAIN_AUTO_BOILING: case MAIN_AUTO_COOLING_H: case MAIN_AUTO_COOLING_M: case MAIN_AUTO_COOLING_C: case MAIN_AUTO_WHIRLPOOL9: case MAIN_AUTO_WHIRLPOOL7: case MAIN_AUTO_WHIRLPOOL6: case MAIN_AUTO_WHIRLPOOL2: case MAIN_AUTO_DONE: case MAIN_AUTO_ABORT: if (Automation_Init()) goto startover; break; case MAIN_MANUAL_INIT: case MAIN_MANUAL_MAIN: if (Manual_Init()) goto startover; break; default: break; } } /* * Update screen */ switch (Main_Screen) { case MAIN_MODE_FREE: MLT_info(71, 26, true); if ((equipment.SSR2 == SSR2_HLT_SHARE) || (equipment.SSR2 == SSR2_HLT_IND)) { HLT_info(71, 150, true, false); } switch (Buttons_Scan()) { case 0: Main_Screen = MAIN_MANUAL_INIT; break; case 1: Main_Screen = MAIN_AUTO_INIT1; break; case 2: Main_Screen = MAIN_INFO; break; case 3: Main_Screen = MAIN_TOOLS; break; default: break; } if (System_TimeOk && (now != last)) { last = now; //strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); strftime(strftime_buf, sizeof(strftime_buf), "%a %e %b %Y %T", &timeinfo); _bg = TFT_BLACK; _fg = TFT_ORANGE; TFT_setFont(DEJAVU18_FONT, NULL); snprintf(msg, 95, " %s ", strftime_buf); TFT_print(msg, CENTER, 125); snprintf(msg, 95, "{\"timer\":\"%s\"}", strftime_buf); // Fix string termination and only send once/second. ws_server_send_text_clients((char *)"/ws", msg, strlen(msg)); } break; case MAIN_MODE_CALIBRATION: Calibration_Loop(); Main_Screen = MAIN_MODE_FREE; break; case MAIN_TOOLS: switch (Buttons_Scan()) { case 0: Main_Screen = MAIN_TOOLS_SETUP; break; case 1: Main_Screen = MAIN_TOOLS_FILES; break; case 2: Main_Screen = MAIN_TOOLS_RECIPE; break; case 3: Main_Screen = MAIN_TOOLS_UPDATES; break; case 4: Main_Screen = MAIN_MODE_FREE; break; default: break; } break; case MAIN_TOOLS_SETUP: case MAIN_TOOLS_SETUP_CONFIG: case MAIN_TOOLS_SETUP_CO_EDIT: case MAIN_TOOLS_SETUP_EQUIPMENT: case MAIN_TOOLS_SETUP_EQ_EDIT: case MAIN_TOOLS_SETUP_CALIBRATION: Setup_Loop(); break; case MAIN_TOOLS_SETUP_WIFI: case MAIN_TOOLS_SETUP_WIFI_CUR: case MAIN_TOOLS_SETUP_WIFI_CON: case MAIN_TOOLS_SETUP_WIFI_NEW: if (WiFi_Loop()) goto startover; break; case MAIN_TOOLS_RECIPE: case MAIN_TOOLS_RECIPE_EDIT: Recipes_Loop(); break; case MAIN_TOOLS_FILES: case MAIN_TOOLS_FILES_DIR: case MAIN_TOOLS_FILES_RESTORE: case MAIN_TOOLS_FILES_BACKUP: Files_Loop(); break; case MAIN_TOOLS_UPDATES: Updates_Loop(); break; case MAIN_INFO: if (Buttons_Scan() == 0) { Main_Screen = MAIN_MODE_FREE; } break; case MAIN_AUTO_INIT1: case MAIN_AUTO_INIT2: case MAIN_AUTO_DELAYSTART: case MAIN_AUTO_HEATUP: case MAIN_AUTO_MASH: case MAIN_AUTO_TOBOIL: case MAIN_AUTO_BOILING: case MAIN_AUTO_COOLING_H: case MAIN_AUTO_COOLING_M: case MAIN_AUTO_COOLING_C: case MAIN_AUTO_WHIRLPOOL9: case MAIN_AUTO_WHIRLPOOL7: case MAIN_AUTO_WHIRLPOOL6: case MAIN_AUTO_WHIRLPOOL2: case MAIN_AUTO_DONE: case MAIN_AUTO_ABORT: if (Automation_Loop()) goto startover; break; case MAIN_MANUAL_INIT: case MAIN_MANUAL_MAIN: if (Manual_Loop()) goto startover; break; default: break; } if (updateRuntime) { write_runtime(); } /* * Count power average during brewing. */ if ((Main_Screen >= MAIN_AUTO_MASH) && (Main_Screen < MAIN_AUTO_DONE)) { if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) { power_MLT += driver_state->mlt_power; power_HLT += driver_state->hlt_power; counts++; xSemaphoreGive(xSemaphoreDriver); } } if (NewMinute) { /* * Brew logging. */ if ((Main_Screen >= MAIN_AUTO_MASH) && (Main_Screen < MAIN_AUTO_DONE)) { update_json(); log_json(); power_MLT = power_HLT = counts = 0; } } NewMinute = false; vTaskDelay(50 / portTICK_PERIOD_MS); } }