diff -r 000000000000 -r 88d965579617 main/co2meter.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/co2meter.c Tue Oct 08 12:00:31 2019 +0200 @@ -0,0 +1,421 @@ +/* + * co2meter project. + */ + +#include "config.h" + +static const char *TAG = "co2meter"; + +#define PIN_SDA (CONFIG_I2C_MASTER_SDA) +#define PIN_SCL (CONFIG_I2C_MASTER_SCL) +#define ROT_ENC_A_GPIO (CONFIG_ROT_ENC_A_GPIO) +#define ROT_ENC_B_GPIO (CONFIG_ROT_ENC_B_GPIO) +#define ROT_ENC_SW_GPIO (CONFIG_ROT_ENC_SW_GPIO) + + +#define ENABLE_HALF_STEPS false ///< Set to true to enable tracking of rotary encoder at half step resolution +#define RESET_AT 0 ///< Set to a positive non-zero number to reset the position if this value is exceeded +#define FLIP_DIRECTION false ///< Set to true to reverse the clockwise/counterclockwise sense + + +int Main_Loop1 = MAIN_LOOP1_INIT; ///< Loop 1 init +int Main_Loop2 = -1; ///< Loop 2 invalid +bool System_TimeOk = false; ///< System time status +time_t now; ///< Current time +struct tm timeinfo; ///< Current time structure +char strftime_buf[64]; ///< Time buffer +static RTC_DATA_ATTR struct timeval sleep_enter_time; +static TaskHandle_t xTaskDS18B20 = NULL; +static TaskHandle_t xTaskADC = NULL; +static TaskHandle_t xTaskWifi = NULL; +static TaskHandle_t xTaskMQTT = NULL; +const esp_app_desc_t *app_desc = NULL; +unit_t units[3]; ///< Pressure test units + + +extern DS18B20_State *ds18b20_state; ///< DS18B20 state +extern SemaphoreHandle_t xSemaphoreDS18B20; ///< DS18B20 lock semaphore +extern ADC_State *adc_state; ///< ADC state +extern SemaphoreHandle_t xSemaphoreADC; ///< ADC lock semaphore + + +void app_main() +{ + struct timeval now; + gettimeofday(&now, NULL); + int sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000; + int New_Loop2 = MAIN_LOOP2_INIT; + esp_err_t ret; + + Main_Loop1 = MAIN_LOOP1_INIT; + Main_Loop2 = -1; + + switch (esp_sleep_get_wakeup_cause()) { + case ESP_SLEEP_WAKEUP_EXT1: { + uint64_t wakeup_pin_mask = esp_sleep_get_ext1_wakeup_status(); + if (wakeup_pin_mask != 0) { + int pin = __builtin_ffsll(wakeup_pin_mask) - 1; + printf("Wake up from GPIO %d\n", pin); + } else { + printf("Wake up from GPIO\n"); + } + break; + } + case ESP_SLEEP_WAKEUP_TIMER: { + ESP_LOGI(TAG, "Starting from deep sleep, timer wakeup after %dms", sleep_time_ms); + break; + } + case ESP_SLEEP_WAKEUP_UNDEFINED: + default: + ESP_LOGI(TAG, "Starting from hard reset"); + } + + const int wakeup_time_sec = 20; + ESP_LOGI(TAG, "Enabling timer wakeup, %ds", wakeup_time_sec); + esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000); + +// const int ext_wakeup_pin_1 = ROT_ENC_SW_GPIO; // 25 in example, redefine to rotary name. +// const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1; + +// printf("Enabling EXT1 wakeup on pins GPIO%d\n", ext_wakeup_pin_1); +// esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask, ESP_EXT1_WAKEUP_ANY_HIGH); // TODO: what is the logic of the rotary button. + + // Isolate GPIO12 pin from external circuits. This is needed for modules + // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER) + // to minimize current consumption. +// rtc_gpio_isolate(GPIO_NUM_12); + + app_desc = esp_ota_get_app_description(); + + /* + * Initialize NVS + */ + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + 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_t u8g2; // a structure which will contain all the data for one display +//// u8g2_Setup_ssd1306_i2c_128x32_univision_f( +// u8g2_Setup_sh1106_i2c_128x64_noname_f( +// &u8g2, +// U8G2_R0, +// //u8x8_byte_sw_i2c, +// u8g2_esp32_i2c_byte_cb, +// u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure +// u8x8_SetI2CAddress(&u8g2.u8x8,0x78); + +// ESP_LOGI(TAG, "u8g2_InitDisplay"); +// u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this, + +// ESP_LOGI(TAG, "u8g2_SetPowerSave"); +// u8g2_SetPowerSave(&u8g2, 0); // wake up display +// ESP_LOGI(TAG, "u8g2_ClearBuffer"); +// u8g2_ClearBuffer(&u8g2); +// ESP_LOGI(TAG, "u8g2_DrawBox"); +// u8g2_DrawBox(&u8g2, 0, 26, 80,6); +// u8g2_DrawFrame(&u8g2, 0,26,100,6); + +// ESP_LOGI(TAG, "u8g2_SetFont"); +// u8g2_SetFont(&u8g2, u8g2_font_ncenB14_tr); +// ESP_LOGI(TAG, "u8g2_DrawStr"); +// u8g2_DrawStr(&u8g2, 2,17,"Hi nkolban!"); +// ESP_LOGI(TAG, "u8g2_SendBuffer"); +// u8g2_SendBuffer(&u8g2); + + + ESP_LOGI(TAG, "Initializing SPIFFS"); + + esp_vfs_spiffs_conf_t conf = { + .base_path = "/spiffs", + .partition_label = NULL, + .max_files = 5, + .format_if_mount_failed = true + }; + + // Use settings defined above to initialize and mount SPIFFS filesystem. + // Note: esp_vfs_spiffs_register is an all-in-one convenience function. + ret = esp_vfs_spiffs_register(&conf); + + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { + ESP_LOGE(TAG, "Failed to mount or format filesystem"); + } else if (ret == ESP_ERR_NOT_FOUND) { + ESP_LOGE(TAG, "Failed to find SPIFFS partition"); + } else { + ESP_LOGE(TAG, "Failed to initialize SPIFFS (%d)", ret); + } +// _fg = TFT_RED; +// TFT_print((char *)"error\r\n", LASTX, LASTY); + return; // Stop application. + } + + size_t total = 0, used = 0; + ret = esp_spiffs_info(NULL, &total, &used); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to get SPIFFS partition information"); +// _fg = TFT_RED; +// TFT_print((char *)"error\r\n", LASTX, LASTY); + return; // Stop application. + } else { + ESP_LOGI(TAG, "Partition size: %d, used: %d - %d%%", total, used, (used * 100) / total); + } + + // Just to debug, list the /spiffs filesystem. +#if 1 + DIR *dir = opendir("/spiffs"); + struct dirent* de = readdir(dir); + while (de) { + if (de->d_type == DT_REG) { + printf("F "); + } + if (de->d_type == DT_DIR) { + printf("D "); + } + printf("%s\n", de->d_name); + de = readdir(dir); + } + closedir(dir); +#endif + + /* + * Read or create configuration + */ +// TFT_print((char *)"Ophalen configuratie ", LASTX, LASTY); + read_config(); + read_units(); + +//add_station((uint8_t *)"MBSE_WLR", (uint8_t *)"abcjkltuv"); +//remove_station((uint8_t *)"MBSE_WLP"); +//sprintf(config.lastSSID, "%s", "BREWER"); +//write_config(); + + xSemaphoreDS18B20 = xSemaphoreCreateMutex(); + xSemaphoreADC = xSemaphoreCreateMutex(); + + xTaskCreate(&task_ds18b20, "task_ds18b20", 2560, NULL, 8, &xTaskDS18B20); + xTaskCreate(&task_adc, "task_adc", 2560, NULL, 8, &xTaskADC); + esp_log_level_set("wifi", ESP_LOG_ERROR); + xTaskCreate(&task_wifi, "task_wifi", 4096, NULL, 3, &xTaskWifi); + vTaskDelay( (TickType_t)10); + xTaskCreate(&task_mqtt, "task_mqtt", 4096, NULL, 5, &xTaskMQTT); + + // esp32-rotary-encoder requires that the GPIO ISR service is installed before calling rotary_encoder_register() +// ESP_ERROR_CHECK(gpio_install_isr_service(0)); + + // Initialise the rotary encoder device with the GPIOs for A and B signals +// rotary_encoder_info_t info = { 0 }; +// ESP_ERROR_CHECK(rotary_encoder_init(&info, ROT_ENC_A_GPIO, ROT_ENC_B_GPIO)); +// ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(&info, ENABLE_HALF_STEPS)); +#ifdef FLIP_DIRECTION +// ESP_ERROR_CHECK(rotary_encoder_flip_direction(&info)); +#endif + + // Create a queue for events from the rotary encoder driver. + // Tasks can read from this queue to receive up to date position information. +// QueueHandle_t event_queue = rotary_encoder_create_queue(); +// ESP_ERROR_CHECK(rotary_encoder_set_queue(&info, event_queue)); + + + /* Print chip information */ +// esp_chip_info_t chip_info; +// esp_chip_info(&chip_info); +// printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ", +// chip_info.cores, +// (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "", +// (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); + +// printf("silicon revision %d, ", chip_info.revision); + +// printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024), +// (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); + +// esp_err_t status = adc2_vref_to_gpio(GPIO_NUM_26); +// if (status == ESP_OK) { +// printf("v_ref routed to GPIO\n"); +// } else { +// printf("failed to route v_ref\n"); +// } +// vTaskDelay(1000 * wakeup_time_sec / portTICK_PERIOD_MS); + + /* + * Main application loop. + */ + while (1) { + + ESP_LOGI(TAG, "Entered app loop"); + + /* Measure process or user input via rotary switch */ + while (1) { + switch (Main_Loop1) { + case MAIN_LOOP1_INIT: + ESP_LOGI(TAG, "Loop timer: Init"); + // If configured do MAIN_LOOP1_CONNECT + Main_Loop1 = MAIN_LOOP1_CONNECT; + requestWiFi_system(true); + request_ds18b20(); + request_adc(); + break; + + case MAIN_LOOP1_CONNECT: + if (ready_WiFi()) + Main_Loop1 = MAIN_LOOP1_MQTT_CONNECT; + break; + + case MAIN_LOOP1_MQTT_CONNECT: + if (ready_ds18b20() && ready_adc()) { + connect_mqtt(true); + Main_Loop1 = MAIN_LOOP1_WAITCON; + ESP_LOGI(TAG, "Loop timer: Wait MQTT"); + + /* Get global temperature, use for all units. */ + uint32_t temp = 0; + int state = 0; + if (xSemaphoreTake(xSemaphoreDS18B20, 10) == pdTRUE) { + temp = (ds18b20_state->bottle_temperature * 1000); + state = (ds18b20_state->bottle_error == 0) ? 0:1; + xSemaphoreGive(xSemaphoreDS18B20); + } + + /* Copy measured data and calculate results */ + for (int i = 0; i < 3; i++) { + units[i].temperature = temp; + units[i].temperature_state = state; + if (xSemaphoreTake(xSemaphoreADC, 10) == pdTRUE) { + 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; + 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, + units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero, P); +// Moet die echt op 5 volt? +// Verbruik 10 mA +// Setup tijd max 2 mS + xSemaphoreGive(xSemaphoreADC); + } + } + write_units(); + } + break; + + // calculate stap en data copy + + case MAIN_LOOP1_WAITCON: + if (ready_mqtt()) + Main_Loop1 = MAIN_LOOP1_SEND; + break; + + case MAIN_LOOP1_SEND: + ESP_LOGI(TAG, "Loop timer: Send MQTT"); + publishNode(); + publishUnits(); + +Main_Loop1 = MAIN_LOOP1_MQTT_DISCONNECT; + break; + + case MAIN_LOOP1_WAITACK: + break; + + case MAIN_LOOP1_MQTT_DISCONNECT: + ESP_LOGI(TAG, "Loop timer: Disconnect MQTT"); + connect_mqtt(false); + Main_Loop1 = MAIN_LOOP1_DISCONNECT; + break; + + case MAIN_LOOP1_DISCONNECT: + if (! ready_mqtt()) { + ESP_LOGI(TAG, "Loop timer: WiFi off"); + requestWiFi_system(false); + Main_Loop1 = MAIN_LOOP1_WIFI_OFF; + } + break; + + case MAIN_LOOP1_WIFI_OFF: + if (! ready_WiFi()) { + ESP_LOGI(TAG, "Loop timer: Done"); + Main_Loop1 = MAIN_LOOP1_DONE; + } + break; + + case MAIN_LOOP1_DONE: + break; + } + + /* + * One time actions + */ + if (New_Loop2 != Main_Loop2) { + + Main_Loop2 = New_Loop2; + + switch (Main_Loop2) { + case MAIN_LOOP2_INIT: + ESP_LOGI(TAG, "Loop user: Init"); +// u8g2_SetPowerSave(&u8g2, 0); // wake up display +// u8g2_ClearBuffer(&u8g2); +// New_Loop2 = MAIN_LOOP2_INACTIVE; + New_Loop2 = MAIN_LOOP2_DONE; + break; + + case MAIN_LOOP2_INACTIVE: +// u8g2_SetPowerSave(&u8g2, 1); // powersave display + New_Loop2 = MAIN_LOOP2_DONE; + break; + + default: + break; + } + } + + /* + * Action process. + */ + switch (Main_Loop2) { + // If wakeup from GPIO -- state machine 2 + // Init OLED + // If not configured, start configure + // If configured select first unit + // New rotate position, set screen, reset waittimer + // Handle screen (first is show measured values) + // Count inactivity + // flag if inactive and OLED lowpower. + + // Break if all done and inactive. + default: + break; + } + + if (Main_Loop1 == MAIN_LOOP1_DONE && Main_Loop2 == MAIN_LOOP2_DONE) + break; + + vTaskDelay(10 / portTICK_PERIOD_MS); + } + +// printf("Simulate deep sleep\n"); +// vTaskDelay(1000 * wakeup_time_sec / portTICK_PERIOD_MS); + + printf("Entering deep sleep\n"); + gettimeofday(&sleep_enter_time, NULL); + esp_deep_sleep_start(); + + Main_Loop1 = MAIN_LOOP1_INIT; + New_Loop2 = MAIN_LOOP2_INIT; + } + +} +