#include #include #include #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_ota_ops.h" #include "esp_log.h" #include "esp_err.h" #include "nvs_flash.h" #include "esp_event.h" #include "esp_spiffs.h" #include "driver/gpio.h" #include "evse_api.h" #include "peripherals.h" #include "led.h" #include "api.h" #include "protocols.h" #include "serial_mt.h" #include "board_config.h" #include "wifi.h" #include "logger.h" // #include "ocpp.h" // #include "currentshaper.h" // #include "serial_mdb.h" // #include "meter.h" // #include "rc522_2.h" // #include "main_wiegand.h" // #include "app_main.h" // #include "sync_slave.h" // #include "sync_master.h" #define AP_CONNECTION_TIMEOUT 60000 // 60sec #define RESET_HOLD_TIME 10000 // 10sec #define PRESS_BIT BIT0 #define RELEASED_BIT BIT1 static const char *TAG = "app_main"; static TaskHandle_t user_input_task; static evse_state_t led_state = -1; static void reset_and_reboot(void) { ESP_LOGW(TAG, "All settings will be erased..."); ESP_ERROR_CHECK(nvs_flash_erase()); ESP_LOGW(TAG, "Rebooting..."); vTaskDelay(pdMS_TO_TICKS(500)); esp_restart(); } static void wifi_event_task_func(void *param) { EventBits_t mode_bits; while (true) { // led_set_off(LED_ID_WIFI); mode_bits = xEventGroupWaitBits(wifi_event_group, WIFI_AP_MODE_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY); if (mode_bits & WIFI_AP_MODE_BIT) { // led_set_state(LED_ID_WIFI, 100, 900); if (xEventGroupWaitBits(wifi_event_group, WIFI_AP_CONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(AP_CONNECTION_TIMEOUT)) & WIFI_AP_CONNECTED_BIT) { // led_set_state(LED_ID_WIFI, 1900, 100); do { } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_AP_DISCONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_AP_DISCONNECTED_BIT)); } else { if (xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT) { // serial_mdb_set_meter_test(false); wifi_ap_stop(); } } } else if (mode_bits & WIFI_STA_MODE_BIT) { // led_set_state(LED_ID_WIFI, 500, 500); if (xEventGroupWaitBits(wifi_event_group, WIFI_STA_CONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_CONNECTED_BIT) { // led_set_on(LED_ID_WIFI); do { } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_DISCONNECTED_BIT)); } } } } static void user_input_task_func(void *param) { uint32_t notification; bool pressed = false; TickType_t press_tick = 0; while (true) { if (xTaskNotifyWait(0x00, 0xff, ¬ification, portMAX_DELAY)) { if (notification & PRESS_BIT) { press_tick = xTaskGetTickCount(); pressed = true; } if (notification & RELEASED_BIT) { if (pressed) { // sometimes after connect debug UART emit RELEASED_BIT without preceding PRESS_BIT if (xTaskGetTickCount() - press_tick >= pdMS_TO_TICKS(RESET_HOLD_TIME)) { evse_set_available(false); reset_and_reboot(); } else { if (!(xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT)) { led_set_buzzer(); wifi_ap_start(); // serial_mdb_set_meter_test(true); } } } pressed = false; } } } } static void IRAM_ATTR button_isr_handler(void *arg) { BaseType_t higher_task_woken = pdFALSE; if (!gpio_get_level(board_config.button_wifi_gpio)) { xTaskNotifyFromISR(user_input_task, RELEASED_BIT, eSetBits, &higher_task_woken); } else { xTaskNotifyFromISR(user_input_task, PRESS_BIT, eSetBits, &higher_task_woken); } if (higher_task_woken) { portYIELD_FROM_ISR(); } } static void button_init(void) { gpio_config_t conf = { .pin_bit_mask = BIT64(board_config.button_wifi_gpio), .mode = GPIO_MODE_INPUT, .pull_down_en = GPIO_PULLDOWN_DISABLE, .pull_up_en = GPIO_PULLUP_ENABLE, .intr_type = GPIO_INTR_ANYEDGE}; ESP_ERROR_CHECK(gpio_config(&conf)); ESP_ERROR_CHECK(gpio_isr_handler_add(board_config.button_wifi_gpio, button_isr_handler, NULL)); } static void fs_info(esp_vfs_spiffs_conf_t *conf) { size_t total = 0, used = 0; esp_err_t ret = esp_spiffs_info(conf->partition_label, &total, &used); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to get partition %s information %s", conf->partition_label, esp_err_to_name(ret)); } else { ESP_LOGI(TAG, "Partition %s size: total: %d, used: %d", conf->partition_label, total, used); } } static void fs_init(void) { esp_vfs_spiffs_conf_t cfg_conf = { .base_path = "/cfg", .partition_label = "cfg", .max_files = 1, .format_if_mount_failed = false}; ESP_ERROR_CHECK(esp_vfs_spiffs_register(&cfg_conf)); esp_vfs_spiffs_conf_t data_conf = { .base_path = "/data", .partition_label = "data", .max_files = 5, .format_if_mount_failed = true}; ESP_ERROR_CHECK(esp_vfs_spiffs_register(&data_conf)); fs_info(&cfg_conf); fs_info(&data_conf); } static bool ota_diagnostic(void) { // TODO diagnostic after ota return true; } static void update_leds(void) { if (led_state != evse_get_state()) { led_state = evse_get_state(); switch (led_state) { case EVSE_STATE_A: led_set_off(LED_ID_CHARGING); led_set_off(LED_ID_ERROR); led_set_on(LED_ID_WIFI); break; case EVSE_STATE_B1: case EVSE_STATE_B2: led_set_off(LED_ID_ERROR); led_set_off(LED_ID_WIFI); led_set_on(LED_ID_CHARGING); break; case EVSE_STATE_C1: case EVSE_STATE_D1: led_set_off(LED_ID_ERROR); led_set_off(LED_ID_WIFI); led_set_state(LED_ID_CHARGING, 1000, 1000); break; case EVSE_STATE_C2: case EVSE_STATE_D2: led_set_off(LED_ID_ERROR); led_set_off(LED_ID_WIFI); led_set_state(LED_ID_CHARGING, 1000, 500); led_set_buzzer(); break; case EVSE_STATE_E: led_set_off(LED_ID_WIFI); led_set_off(LED_ID_CHARGING); led_set_state(LED_ID_ERROR, 500, 500); break; case EVSE_STATE_F: led_set_off(LED_ID_CHARGING); led_set_off(LED_ID_WIFI); led_set_state(LED_ID_ERROR, 500, 500); break; } } } void app_main(void) { logger_init(); esp_log_set_vprintf(logger_vprintf); const esp_partition_t *running = esp_ota_get_running_partition(); ESP_LOGI(TAG, "Running partition: %s", running->label); esp_ota_img_states_t ota_state; if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) { if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) { ESP_LOGI(TAG, "OTA pending verify"); if (ota_diagnostic()) { ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution ..."); esp_ota_mark_app_valid_cancel_rollback(); } else { ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version ..."); esp_ota_mark_app_invalid_rollback_and_reboot(); } } } esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_LOGW(TAG, "Erasing NVS flash"); ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); fs_init(); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(gpio_install_isr_service(0)); board_config_load(); wifi_ini(); peripherals_init(); api_init(); protocols_init(); evse_init(); button_init(); xTaskCreate(wifi_event_task_func, "wifi_event_task", 4 * 1024, NULL, 5, NULL); xTaskCreate(user_input_task_func, "user_input_task", 4 * 1024, NULL, 5, &user_input_task); // meter_init(); // ocpp_start(); // serial_mdb_start(); // currentshaper_start(); // initRc522(); // initWiegand(); // serial_mt_start(); // master_sync_start(); // slave_sync_start(); while (true) { evse_process(); update_leds(); // ESP_LOGI(TAG, "getPower %d", getDataMeter().wattA); vTaskDelay(pdMS_TO_TICKS(100)); } }