# HG changeset patch # User Michiel Broek # Date 1572610394 -3600 # Node ID d969e0fe05dc812b744b5c3e300ccaba4822006b # Parent f9eca4a55911708e1d2c70317496df0102f830b1 Added splash screen and unit zero set menu. diff -r f9eca4a55911 -r d969e0fe05dc main/co2meter.c --- a/main/co2meter.c Thu Oct 31 22:22:22 2019 +0100 +++ b/main/co2meter.c Fri Nov 01 13:13:14 2019 +0100 @@ -93,6 +93,20 @@ +void screen_splash() +{ + screen_top("CO2 meter %s", app_desc->version); + + u8g2_SetFont(&u8g2, u8g2_font_t0_22b_tf); + u8g2_uint_t w = u8g2_GetUTF8Width(&u8g2, "START"); + u8g2_DrawUTF8(&u8g2, (128 - w) / 2,50, "START"); + + u8g2_SendBuffer(&u8g2); + u8g2_SetPowerSave(&u8g2, 0); // wake up display +} + + + void screen_main() { char buf[65]; @@ -146,6 +160,19 @@ +void screen_unit_zero(int no, int sub) +{ + screen_top("Unit %d zero mV", no + 1); + menu_line( 0, 2, 25, "Current %d", units[no].pressure_zero); + menu_line(sub == 0, 2, 37, "New value %d", units[no].pressure_voltage / (adc_state->Batt_voltage / 1000)); + menu_line(sub == 1, 2, 49, "Return"); + + u8g2_SendBuffer(&u8g2); + u8g2_SetPowerSave(&u8g2, 0); +} + + + void screen_unit_setup(int no, int sub) { screen_top("Unit %d setup", no + 1); @@ -225,6 +252,27 @@ +int rotate_to_sub(rotary_encoder_position_t pos, int min, int max, int cursub) +{ + int sub = cursub; + + if (pos > 0) { + if (sub < max) + sub++; + else + sub = min; + ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); + } else if (pos < 0) { + if (sub > min) + sub--; + else + sub = max; + ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); + } + return sub; +} + + void app_main() { struct timeval now; @@ -235,10 +283,26 @@ Main_Loop1 = ML1_INIT; Main_Loop2 = -1; + /* + * Setup the OLED display. + * See: https://github.com/nkolban/esp32-snippets/blob/master/hardware/displays/U8G2/ + */ + u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT; + u8g2_esp32_hal.sda = PIN_SDA; + u8g2_esp32_hal.scl = PIN_SCL; + u8g2_esp32_hal_init(u8g2_esp32_hal); + + u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure + u8x8_SetI2CAddress(&u8g2.u8x8, 0x78); + u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this, + + app_desc = esp_ota_get_app_description(); + switch (esp_sleep_get_wakeup_cause()) { case ESP_SLEEP_WAKEUP_EXT1: { ESP_LOGI(TAG, "Starting from deep sleep, Rotary switch pressed"); New_Loop2 = ML2_INIT; + screen_splash(); break; } case ESP_SLEEP_WAKEUP_TIMER: { @@ -248,6 +312,7 @@ case ESP_SLEEP_WAKEUP_UNDEFINED: default: ESP_LOGI(TAG, "Starting from hard reset"); + screen_splash(); } const int wakeup_time_sec = 55; @@ -263,8 +328,6 @@ // to minimize current consumption. // rtc_gpio_isolate(GPIO_NUM_12); - app_desc = esp_ota_get_app_description(); - /* * Initialize NVS */ @@ -276,19 +339,6 @@ ESP_ERROR_CHECK(ret); /* - * Setup the OLED display. - * See: https://github.com/nkolban/esp32-snippets/blob/master/hardware/displays/U8G2/ - */ - u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT; - u8g2_esp32_hal.sda = PIN_SDA; - u8g2_esp32_hal.scl = PIN_SCL; - u8g2_esp32_hal_init(u8g2_esp32_hal); - - u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure - u8x8_SetI2CAddress(&u8g2.u8x8, 0x78); - u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this, - - /* * Setup SPIFFS filesystem */ ESP_LOGI(TAG, "Initializing SPIFFS"); @@ -401,6 +451,7 @@ ESP_LOGI(TAG, "Entered app loop"); rotary_encoder_event_t event = { 0 }; int sub = 0; + u8g2_SetPowerSave(&u8g2, 1); /* Measure process or user input via rotary switch */ while (1) { @@ -450,14 +501,13 @@ units[i].pressure_state = adc_state->Pressure[i].error; units[i].pressure_channel = adc_state->Pressure[i].channel; units[i].pressure_voltage = adc_state->Pressure[i].voltage; - units[i].pressure_zero = 110; if (units[i].pressure_state || units[i].pressure_voltage < 80) units[i].alarm |= ALARM_UNIT_PRESSURE; int P = (units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero) * 14; // in bar if (P < 0) P = 0; units[i].pressure = P; -printf("%d volt: %d batt: %d scale: %d bar: %d\n", i, units[i].pressure_voltage, adc_state->Batt_voltage, +printf("%d volt: %d batt: %d scale: %d mbar: %d\n", i, units[i].pressure_voltage, adc_state->Batt_voltage, units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero, P); // Moet die echt op 5 volt? // Verbruik 10 mA @@ -570,6 +620,14 @@ screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); break; + case ML2_ZERO_UNIT1: + case ML2_ZERO_UNIT2: + case ML2_ZERO_UNIT3: + ESP_LOGI(TAG, "Loop user: Zero Unit %d", Main_Loop2 - ML2_ZERO_UNIT1); + sub = 0; + screen_unit_zero(Main_Loop2 - ML2_ZERO_UNIT1, sub); + break; + case ML2_INACTIVE: ESP_LOGI(TAG, "Loop user: Inactive"); u8g2_SetPowerSave(&u8g2, 1); // powersave display @@ -614,23 +672,13 @@ case ML2_UPDATE: rotate_to_menu(event.state.position, ML2_UPDATE, ML2_SET_MQTT); break; case ML2_SETUP_UNIT1: case ML2_SETUP_UNIT2: - case ML2_SETUP_UNIT3: if (event.state.position > 0) { - if (sub < 3) { - sub++; - } else { - sub = 0; - } - screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); - ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); - } else if (event.state.position < 0) { - if (sub > 0) { - sub--; - } else { - sub = 3; - } - screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); - ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo)); - } + case ML2_SETUP_UNIT3: sub = rotate_to_sub(event.state.position, 0, 3, sub); + screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); + break; + case ML2_ZERO_UNIT1: + case ML2_ZERO_UNIT2: + case ML2_ZERO_UNIT3: sub = rotate_to_sub(event.state.position, 0, 1, sub); + screen_unit_zero(Main_Loop2 - ML2_ZERO_UNIT1, sub); break; default: ESP_LOGI(TAG, "Event: position %d, direction %s", event.state.position, @@ -655,43 +703,71 @@ } } - switch (Main_Loop2) { - // Break if all done and inactive. - case ML2_UNIT1: - case ML2_UNIT2: - case ML2_UNIT3: - if (PushDuration) { - New_Loop2 = ML2_SETUP_UNIT1 + (Main_Loop2 - ML2_UNIT1); - PushDuration = 0; - } + /* + * Handle pressed rotary button. + */ + if (PushDuration) { + int idx = 0; + switch (Main_Loop2) { + case ML2_UNIT1: + case ML2_UNIT2: + case ML2_UNIT3: + New_Loop2 = ML2_SETUP_UNIT1 + (Main_Loop2 - ML2_UNIT1); break; - case ML2_SETUP_UNIT1: - case ML2_SETUP_UNIT2: - case ML2_SETUP_UNIT3: - if (PushDuration) { - if (sub == 0) { - if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) { - if (units[Main_Loop2 - ML2_SETUP_UNIT1].mode) - units[Main_Loop2 - ML2_SETUP_UNIT1].mode = 0; - else - units[Main_Loop2 - ML2_SETUP_UNIT1].mode = 1; - write_units(); - xSemaphoreGive(xSemaphoreUnits); - } - screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub); - if (Main_Loop1 == ML1_DONE) - Main_Loop1 = ML1_INIT; + case ML2_SETUP_UNIT1: + case ML2_SETUP_UNIT2: + case ML2_SETUP_UNIT3: + idx = Main_Loop2 - ML2_SETUP_UNIT1; + if (sub == 0) { + if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) { + if (units[idx].mode) + units[idx].mode = 0; + else + units[idx].mode = 1; + write_units(); + xSemaphoreGive(xSemaphoreUnits); } - if (sub == 3) - New_Loop2 = ML2_UNIT1 + (Main_Loop2 - ML2_SETUP_UNIT1); - printf("sub %d new %d\n", sub, New_Loop2); - PushDuration = 0; + screen_unit_setup(idx, sub); + if (Main_Loop1 == ML1_DONE) + Main_Loop1 = ML1_INIT; } + if (sub == 1) + New_Loop2 = ML2_ZERO_UNIT1 + idx; + if (sub == 3) + New_Loop2 = ML2_UNIT1 + idx; + printf("unit setup sub %d new %d idx %d\n", sub, New_Loop2, idx); break; - default: + case ML2_ZERO_UNIT1: + case ML2_ZERO_UNIT2: + case ML2_ZERO_UNIT3: + idx = Main_Loop2 - ML2_ZERO_UNIT1; + if (sub == 0) { + if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE && + xSemaphoreTake(xSemaphoreADC, 10) == pdTRUE && + adc_state->Pressure[idx].voltage > 165 && + adc_state->Pressure[idx].voltage < 660) { + units[idx].pressure_zero = adc_state->Pressure[idx].voltage / (adc_state->Batt_voltage / 1000); + write_units(); + xSemaphoreGive(xSemaphoreADC); + xSemaphoreGive(xSemaphoreUnits); + screen_unit_zero(idx, sub); + if (Main_Loop1 == ML1_DONE) + Main_Loop1 = ML1_INIT; + } + } + if (sub == 1) { + New_Loop2 = ML2_SETUP_UNIT1 + idx; + sub = 1; + } + printf("unit zero sub %d new %d idx %d\n", sub, New_Loop2, idx); break; + + default: + break; + } + PushDuration = 0; } if (Main_Loop1 == ML1_DONE && Main_Loop2 == ML2_DONE) diff -r f9eca4a55911 -r d969e0fe05dc main/config.h --- a/main/config.h Thu Oct 31 22:22:22 2019 +0100 +++ b/main/config.h Fri Nov 01 13:13:14 2019 +0100 @@ -97,6 +97,9 @@ ML2_SETUP_UNIT1, ///< Unit 1 setup ML2_SETUP_UNIT2, ///< Unit 2 setup ML2_SETUP_UNIT3, ///< Unit 3 setup + ML2_ZERO_UNIT1, ///< Unit 1 set zero + ML2_ZERO_UNIT2, ///< Unit 2 set zero + ML2_ZERO_UNIT3, ///< Unit 3 set zero ML2_INACTIVE, ///< Inactive reached, cleanup ML2_DONE ///< All done } ML2; diff -r f9eca4a55911 -r d969e0fe05dc main/xutil.h --- a/main/xutil.h Thu Oct 31 22:22:22 2019 +0100 +++ b/main/xutil.h Fri Nov 01 13:13:14 2019 +0100 @@ -1,8 +1,32 @@ +/** + * @file xutil.h + * @brief In memory string manipulation. + */ + + #ifndef XUTIL_H #define XUTIL_H -char *xmalloc(size_t); -char *xstrcpy(char *); -char *xstrcat(char *, char *); +/** + * @brief Safe memory allocation. Abort if not enough. + * @param size The amount of memory to allocate. + * @return A pointer to the allocated memory. + */ +char *xmalloc(size_t size); + +/** + * @brief Copy string in memory. + * @param src The source string to copy. + * @return A pointer to the string with the copied string. + */ +char *xstrcpy(char *src); + +/** + * @brief Add data to a string in memory. + * @param src The original string. + * @param add The string to append to src. + * @return A pointer to the combined string. + */ +char *xstrcat(char *src, char *add); #endif