// === Início de: components/evse/evse_limits.c === #include "evse_state.h" #include "evse_api.h" #include "evse_limits.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" // ======================== // External state references // ======================== //extern evse_state_t current_state; // Current EVSE FSM state //extern TickType_t session_start_tick; // Timestamp of charging session start // ======================== // Concurrency protection // ======================== static portMUX_TYPE evse_mux = portMUX_INITIALIZER_UNLOCKED; // ======================== // Runtime state (volatile) // ======================== static bool limit_reached = false; static uint32_t consumption_limit = 0; // Energy limit in Wh static uint32_t charging_time_limit = 0; // Time limit in seconds static uint16_t under_power_limit = 0; // Minimum acceptable power in W // ======================== // Default (persistent) limits // ======================== static uint32_t default_consumption_limit = 0; static uint32_t default_charging_time_limit = 0; static uint16_t default_under_power_limit = 0; // ======================== // Limit status flag // ======================== bool evse_get_limit_reached(void) { bool val; portENTER_CRITICAL(&evse_mux); val = limit_reached; portEXIT_CRITICAL(&evse_mux); return val; } void evse_set_limit_reached(bool v) { portENTER_CRITICAL(&evse_mux); limit_reached = v; portEXIT_CRITICAL(&evse_mux); } // ======================== // Runtime limit accessors // ======================== uint32_t evse_get_consumption_limit(void) { uint32_t val; portENTER_CRITICAL(&evse_mux); val = consumption_limit; portEXIT_CRITICAL(&evse_mux); return val; } void evse_set_consumption_limit(uint32_t value) { portENTER_CRITICAL(&evse_mux); consumption_limit = value; portEXIT_CRITICAL(&evse_mux); } uint32_t evse_get_charging_time_limit(void) { uint32_t val; portENTER_CRITICAL(&evse_mux); val = charging_time_limit; portEXIT_CRITICAL(&evse_mux); return val; } void evse_set_charging_time_limit(uint32_t value) { portENTER_CRITICAL(&evse_mux); charging_time_limit = value; portEXIT_CRITICAL(&evse_mux); } uint16_t evse_get_under_power_limit(void) { uint16_t val; portENTER_CRITICAL(&evse_mux); val = under_power_limit; portEXIT_CRITICAL(&evse_mux); return val; } void evse_set_under_power_limit(uint16_t value) { portENTER_CRITICAL(&evse_mux); under_power_limit = value; portEXIT_CRITICAL(&evse_mux); } // ======================== // Default (persistent) limit accessors // These values can be stored/restored via NVS // ======================== uint32_t evse_get_default_consumption_limit(void) { return default_consumption_limit; } void evse_set_default_consumption_limit(uint32_t value) { default_consumption_limit = value; } uint32_t evse_get_default_charging_time_limit(void) { return default_charging_time_limit; } void evse_set_default_charging_time_limit(uint32_t value) { default_charging_time_limit = value; } uint16_t evse_get_default_under_power_limit(void) { return default_under_power_limit; } void evse_set_default_under_power_limit(uint16_t value) { default_under_power_limit = value; } bool evse_is_limit_reached(void) { return evse_get_limit_reached(); } // ======================== // Limit checking logic // This function must be called periodically while charging. // It will flag the session as "limit reached" when thresholds are violated. // ======================== void evse_limits_check(void) { evse_state_t state = evse_get_state(); if (!evse_state_is_charging(state)) return; bool reached = false; uint32_t energy = evse_get_total_energy(); uint32_t power = evse_get_instant_power(); TickType_t now = xTaskGetTickCount(); TickType_t start = evse_get_session_start(); if (consumption_limit > 0 && energy >= consumption_limit) { ESP_LOGW("EVSE", "Energy limit reached"); reached = true; } if (charging_time_limit > 0 && (now - start) >= pdMS_TO_TICKS(charging_time_limit * 1000)) { ESP_LOGW("EVSE", "Charging time limit reached"); reached = true; } if (under_power_limit > 0 && power < under_power_limit) { ESP_LOGW("EVSE", "Under power limit reached"); reached = true; } if (reached) { evse_set_limit_reached(true); } } // === Fim de: components/evse/evse_limits.c === // === Início de: components/evse/evse_config.c === #include // For PRI macros #include "evse_config.h" #include "board_config.h" #include "evse_limits.h" #include "esp_log.h" #include "nvs.h" static const char *TAG = "evse_config"; static nvs_handle_t nvs; // ======================== // Configurable parameters // ======================== static uint8_t max_charging_current = MAX_CHARGING_CURRENT_LIMIT; static uint16_t charging_current; // Persisted (NVS) static uint16_t charging_current_runtime = 0; // Runtime only static bool socket_outlet; static bool rcm; static uint8_t temp_threshold = 60; static bool require_auth; // ======================== // Initialization // ======================== esp_err_t evse_config_init(void) { ESP_LOGD(TAG, "Initializing NVS configuration..."); return nvs_open("evse", NVS_READWRITE, &nvs); } void evse_check_defaults(void) { esp_err_t err; uint8_t u8; uint16_t u16; uint32_t u32; bool needs_commit = false; ESP_LOGD(TAG, "Checking default parameters..."); // Max charging current err = nvs_get_u8(nvs, "max_chrg_curr", &u8); if (err != ESP_OK || u8 < MIN_CHARGING_CURRENT_LIMIT || u8 > MAX_CHARGING_CURRENT_LIMIT) { max_charging_current = MAX_CHARGING_CURRENT_LIMIT; nvs_set_u8(nvs, "max_chrg_curr", max_charging_current); needs_commit = true; ESP_LOGW(TAG, "Invalid or missing max_chrg_curr, resetting to %d", max_charging_current); } else { max_charging_current = u8; } // Charging current (default, persisted) err = nvs_get_u16(nvs, "def_chrg_curr", &u16); if (err != ESP_OK || u16 < (MIN_CHARGING_CURRENT_LIMIT * 10) || u16 > (max_charging_current * 10)) { charging_current = max_charging_current * 10; nvs_set_u16(nvs, "def_chrg_curr", charging_current); needs_commit = true; ESP_LOGW(TAG, "Invalid or missing def_chrg_curr, resetting to %d", charging_current); } else { charging_current = u16; } // Runtime charging current initialized from persisted default charging_current_runtime = charging_current; ESP_LOGD(TAG, "Runtime charging current initialized to: %d", charging_current_runtime); // Auth required err = nvs_get_u8(nvs, "require_auth", &u8); require_auth = (err == ESP_OK && u8 <= 1) ? u8 : false; if (err != ESP_OK) { nvs_set_u8(nvs, "require_auth", require_auth); needs_commit = true; } // Socket outlet err = nvs_get_u8(nvs, "socket_outlet", &u8); socket_outlet = (err == ESP_OK && u8) && board_config.proximity; if (err != ESP_OK) { nvs_set_u8(nvs, "socket_outlet", socket_outlet); needs_commit = true; } // RCM err = nvs_get_u8(nvs, "rcm", &u8); rcm = (err == ESP_OK && u8) && board_config.rcm; if (err != ESP_OK) { nvs_set_u8(nvs, "rcm", rcm); needs_commit = true; } // Temp threshold err = nvs_get_u8(nvs, "temp_threshold", &u8); temp_threshold = (err == ESP_OK && u8 >= 40 && u8 <= 80) ? u8 : 60; if (err != ESP_OK) { nvs_set_u8(nvs, "temp_threshold", temp_threshold); needs_commit = true; } // Optional limits if (nvs_get_u32(nvs, "def_cons_lim", &u32) == ESP_OK) evse_set_consumption_limit(u32); if (nvs_get_u32(nvs, "def_ch_time_lim", &u32) == ESP_OK) evse_set_charging_time_limit(u32); if (nvs_get_u16(nvs, "def_un_pwr_lim", &u16) == ESP_OK) evse_set_under_power_limit(u16); // Save to NVS if needed if (needs_commit) { err = nvs_commit(nvs); if (err == ESP_OK) { ESP_LOGD(TAG, "Configuration committed to NVS."); } else { ESP_LOGE(TAG, "Failed to commit configuration to NVS: %s", esp_err_to_name(err)); } } } // ======================== // Charging current getters/setters // ======================== uint8_t evse_get_max_charging_current(void) { return max_charging_current; } esp_err_t evse_set_max_charging_current(uint8_t value) { if (value < MIN_CHARGING_CURRENT_LIMIT || value > MAX_CHARGING_CURRENT_LIMIT) return ESP_ERR_INVALID_ARG; max_charging_current = value; nvs_set_u8(nvs, "max_chrg_curr", value); return nvs_commit(nvs); } uint16_t evse_get_charging_current(void) { return charging_current; } esp_err_t evse_set_charging_current(uint16_t value) { if (value < (MIN_CHARGING_CURRENT_LIMIT * 10) || value > (max_charging_current * 10)) return ESP_ERR_INVALID_ARG; charging_current = value; nvs_set_u16(nvs, "def_chrg_curr", value); return nvs_commit(nvs); } uint16_t evse_get_default_charging_current(void) { uint16_t value; if (nvs_get_u16(nvs, "def_chrg_curr", &value) == ESP_OK) return value; return charging_current; } esp_err_t evse_set_default_charging_current(uint16_t value) { if (value < (MIN_CHARGING_CURRENT_LIMIT * 10) || value > (max_charging_current * 10)) return ESP_ERR_INVALID_ARG; nvs_set_u16(nvs, "def_chrg_curr", value); return nvs_commit(nvs); } // ======================== // Runtime current (not saved) // ======================== void evse_set_runtime_charging_current(uint16_t value) { if (value < (MIN_CHARGING_CURRENT_LIMIT) || value > (max_charging_current)) { ESP_LOGW(TAG, "Rejected runtime charging current (out of bounds): %d", value); return; } charging_current_runtime = value; ESP_LOGD(TAG, "Runtime charging current updated: %d", charging_current_runtime); } uint16_t evse_get_runtime_charging_current(void) { return charging_current_runtime; } // ======================== // Socket outlet // ======================== bool evse_get_socket_outlet(void) { return socket_outlet; } esp_err_t evse_set_socket_outlet(bool value) { if (value && !board_config.proximity) return ESP_ERR_INVALID_ARG; socket_outlet = value; nvs_set_u8(nvs, "socket_outlet", value); return nvs_commit(nvs); } // ======================== // RCM // ======================== bool evse_is_rcm(void) { return rcm; } esp_err_t evse_set_rcm(bool value) { if (value && !board_config.rcm) return ESP_ERR_INVALID_ARG; rcm = value; nvs_set_u8(nvs, "rcm", value); return nvs_commit(nvs); } // ======================== // Temperature // ======================== uint8_t evse_get_temp_threshold(void) { return temp_threshold; } esp_err_t evse_set_temp_threshold(uint8_t value) { if (value < 40 || value > 80) return ESP_ERR_INVALID_ARG; temp_threshold = value; nvs_set_u8(nvs, "temp_threshold", value); return nvs_commit(nvs); } // ======================== // Authentication // ======================== bool evse_is_require_auth(void) { return require_auth; } void evse_set_require_auth(bool value) { require_auth = value; nvs_set_u8(nvs, "require_auth", value); nvs_commit(nvs); } // ======================== // Availability // ======================== static bool is_available = true; bool evse_config_is_available(void) { return is_available; } void evse_config_set_available(bool available) { is_available = available; } // ======================== // Enable/Disable // ======================== static bool is_enabled = true; bool evse_config_is_enabled(void) { return is_enabled; } void evse_config_set_enabled(bool enabled) { is_enabled = enabled; } // === Fim de: components/evse/evse_config.c === // === Início de: components/evse/evse_manager.c === #include "evse_manager.h" #include "evse_state.h" #include "evse_error.h" #include "evse_hardware.h" #include "evse_config.h" #include "evse_api.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/queue.h" #include "esp_log.h" #include #include "auth_events.h" #include "loadbalancer_events.h" #include "esp_event.h" static const char *TAG = "EVSE_Manager"; static SemaphoreHandle_t evse_mutex; static bool auth_enabled = false; #define EVSE_MANAGER_TICK_PERIOD_MS 1000 // 1 segundo // ===== Task de ciclo principal ===== static void evse_manager_task(void *arg) { while (true) { evse_manager_tick(); vTaskDelay(pdMS_TO_TICKS(EVSE_MANAGER_TICK_PERIOD_MS)); } } // ===== Tratador de eventos de autenticação ===== static void on_auth_event(void* arg, esp_event_base_t base, int32_t id, void* data) { if (base != AUTH_EVENTS || data == NULL) return; switch (id) { case AUTH_EVENT_TAG_PROCESSED: { auth_tag_event_data_t *evt = (auth_tag_event_data_t*)data; ESP_LOGI("EVSE", "Tag: %s | Autorizada: %s", evt->tag, evt->authorized ? "SIM" : "NÃO"); evse_state_set_authorized(evt->authorized); break; } case AUTH_EVENT_ENABLED_CHANGED: case AUTH_EVENT_INIT: { auth_enabled_event_data_t *evt = (auth_enabled_event_data_t*)data; auth_enabled = evt->enabled; ESP_LOGI("EVSE", "Auth %s (%s)", id == AUTH_EVENT_ENABLED_CHANGED ? "ficou" : "init", evt->enabled ? "ATIVO" : "INATIVO"); if (!auth_enabled) { evse_state_set_authorized(true); ESP_LOGI("EVSE", "Autenticação desativada → autorização forçada."); } else { evse_state_set_authorized(false); ESP_LOGI("EVSE", "Autenticação ativada → aguardando autorização por tag."); } break; } } } // ===== Tratador de eventos de loadbalancer ===== static void on_loadbalancer_event(void* handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_id == LOADBALANCER_EVENT_INIT || event_id == LOADBALANCER_EVENT_STATE_CHANGED) { const loadbalancer_state_event_t* evt = (const loadbalancer_state_event_t*) event_data; ESP_LOGI(TAG, "Loadbalancer %s (ts: %lld)", evt->enabled ? "ENABLED" : "DISABLED", evt->timestamp_us); // Ações adicionais podem ser adicionadas aqui conforme necessário } else if (event_id == LOADBALANCER_EVENT_CHARGING_LIMIT_CHANGED) { const loadbalancer_charging_limit_event_t* evt = (const loadbalancer_charging_limit_event_t*) event_data; ESP_LOGD(TAG, "Novo limite de corrente: %.1f A (ts: %lld)", evt->limit, evt->timestamp_us); evse_set_runtime_charging_current((uint16_t)(evt->limit)); } } // ===== Inicialização ===== void evse_manager_init(void) { evse_mutex = xSemaphoreCreateMutex(); evse_config_init(); evse_error_init(); evse_hardware_init(); evse_state_init(); ESP_ERROR_CHECK(esp_event_handler_register(AUTH_EVENTS, ESP_EVENT_ANY_ID, &on_auth_event, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(LOADBALANCER_EVENTS, ESP_EVENT_ANY_ID, &on_loadbalancer_event, NULL)); ESP_LOGI(TAG, "EVSE Manager inicializado."); xTaskCreate(evse_manager_task, "evse_manager_task", 4096, NULL, 5, NULL); } // ===== Main Tick ===== void evse_manager_tick(void) { xSemaphoreTake(evse_mutex, portMAX_DELAY); evse_hardware_tick(); evse_error_tick(); evse_state_tick(); evse_temperature_check(); if (auth_enabled) { // If the car is disconnected, revoke authorization if (evse_state_get_authorized() && evse_get_state() == EVSE_STATE_A) { ESP_LOGI(TAG, "Vehicle disconnected → revoking authorization."); evse_state_set_authorized(false); } } else { // If authentication is disabled, ensure authorization is always granted if (!evse_state_get_authorized()) { evse_state_set_authorized(true); ESP_LOGI(TAG, "Authentication disabled → forced authorization."); } } xSemaphoreGive(evse_mutex); } // ===== API pública ===== bool evse_manager_is_available(void) { return evse_config_is_available(); } void evse_manager_set_available(bool available) { evse_config_set_available(available); } void evse_manager_set_authorized(bool authorized) { evse_state_set_authorized(authorized); } bool evse_manager_is_charging(void) { return evse_state_is_charging(evse_get_state()); } void evse_manager_set_enabled(bool enabled) { evse_config_set_enabled(enabled); } bool evse_manager_is_enabled(void) { return evse_config_is_enabled(); } // === Fim de: components/evse/evse_manager.c === // === Início de: components/evse/evse_events.c === #include "evse_events.h" ESP_EVENT_DEFINE_BASE(EVSE_EVENTS); // === Fim de: components/evse/evse_events.c === // === Início de: components/evse/include/evse_pilot.h === #ifndef PILOT_H_ #define PILOT_H_ #ifdef __cplusplus extern "C" { #endif #include #include /** * @brief Níveis categóricos de tensão no sinal CP (Control Pilot) */ typedef enum { PILOT_VOLTAGE_12, ///< Estado A: +12V PILOT_VOLTAGE_9, ///< Estado B: +9V PILOT_VOLTAGE_6, ///< Estado C: +6V PILOT_VOLTAGE_3, ///< Estado D: +3V PILOT_VOLTAGE_1 ///< Estado E/F: abaixo de 3V } pilot_voltage_t; /** * @brief Inicializa o driver do sinal Pilot */ void pilot_init(void); /** * @brief Define o nível do Pilot: +12V ou -12V * * @param level true = +12V, false = -12V */ void pilot_set_level(bool level); /** * @brief Ativa o PWM do Pilot com corrente limitada * * @param amps Corrente em décimos de ampère (ex: 160 = 16A) */ void pilot_set_amps(uint16_t amps); /** * @brief Mede o nível de tensão do Pilot e detecta -12V * * @param up_voltage Valor categórico da tensão positiva * @param down_voltage_n12 true se o nível negativo atingir -12V */ void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12); /** * @brief Retorna o estado lógico atual do Pilot (nível alto = +12V) * * @return true se nível atual for +12V, false se for -12V */ bool pilot_get_state(void); /** * @brief Cache interno opcional dos níveis de tensão reais do Pilot */ typedef struct { uint16_t high_mv; ///< Pico positivo medido (mV) uint16_t low_mv; ///< Pico negativo medido (mV) } pilot_voltage_cache_t; #ifdef __cplusplus } #endif #endif /* PILOT_H_ */ // === Fim de: components/evse/include/evse_pilot.h === // === Início de: components/evse/include/evse_manager.h === #ifndef EVSE_MANAGER_H #define EVSE_MANAGER_H #pragma once #ifdef __cplusplus extern "C" { #endif #include #include #include #include /** * @brief Inicializa os módulos internos do EVSE (hardware, estado, erros, etc.) * e inicia a tarefa de supervisão periódica (tick). */ void evse_manager_init(void); /** * @brief Executa uma iteração do ciclo de controle do EVSE. * * Esta função é chamada automaticamente pela task periódica, * mas pode ser chamada manualmente em testes. */ void evse_manager_tick(void); /** * @brief Verifica se o EVSE está disponível para uso. * * Isso considera falhas críticas, disponibilidade configurada, etc. */ bool evse_manager_is_available(void); /** * @brief Define se o EVSE deve estar disponível (ex: via controle remoto). */ void evse_manager_set_available(bool available); /** * @brief Define se o EVSE está autorizado a carregar (ex: após autenticação). */ void evse_manager_set_authorized(bool authorized); /** * @brief Verifica se o EVSE está atualmente carregando. */ bool evse_manager_is_charging(void); /** * @brief Ativa ou desativa logicamente o EVSE (controla habilitação geral). */ void evse_manager_set_enabled(bool enabled); /** * @brief Verifica se o EVSE está ativado logicamente. */ bool evse_manager_is_enabled(void); #ifdef __cplusplus } #endif #endif // EVSE_MANAGER_H // === Fim de: components/evse/include/evse_manager.h === // === Início de: components/evse/include/evse_fsm.h === #ifndef EVSE_FSM_H #define EVSE_FSM_H #include #include #include "evse_api.h" #include "evse_pilot.h" #include "freertos/FreeRTOS.h" #ifdef __cplusplus extern "C" { #endif /** * @brief Reinicia a máquina de estados do EVSE para o estado inicial (A). */ void evse_fsm_reset(void); /** * @brief Processa uma leitura do sinal de piloto e atualiza a máquina de estados do EVSE. * * Esta função deve ser chamada periodicamente pelo núcleo de controle para * avaliar mudanças no estado do conector, disponibilidade do carregador e * autorização do usuário. * * @param pilot_voltage Leitura atual da tensão do sinal piloto. * @param authorized Indica se o carregamento foi autorizado. * @param available Indica se o carregador está disponível (ex: sem falhas). * @param enabled Indica se o carregador está habilitado via software. */ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool available, bool enabled); #ifdef __cplusplus } #endif #endif // EVSE_FSM_H // === Fim de: components/evse/include/evse_fsm.h === // === Início de: components/evse/include/evse_hardware.h === #ifndef EVSE_HARDWARE_H #define EVSE_HARDWARE_H #ifdef __cplusplus extern "C" { #endif #include #include /** * @brief Inicializa todos os periféricos de hardware do EVSE (pilot, relé, trava, etc.) */ void evse_hardware_init(void); /** * @brief Executa atualizações periódicas no hardware (tick) */ void evse_hardware_tick(void); /** * @brief Verifica se o sinal piloto está em nível alto (12V) */ bool evse_hardware_is_pilot_high(void); /** * @brief Verifica se o veículo está fisicamente conectado via Proximity */ bool evse_hardware_is_vehicle_connected(void); /** * @brief Verifica se há consumo de energia (corrente detectada) */ bool evse_hardware_is_energy_detected(void); /** * @brief Liga o relé de fornecimento de energia */ void evse_hardware_relay_on(void); /** * @brief Desliga o relé de fornecimento de energia */ void evse_hardware_relay_off(void); /** * @brief Consulta o estado atual do relé * @return true se ligado, false se desligado */ bool evse_hardware_relay_status(void); /** * @brief Aciona a trava física do conector */ void evse_hardware_lock(void); /** * @brief Libera a trava física do conector */ void evse_hardware_unlock(void); /** * @brief Verifica se o conector está travado */ bool evse_hardware_is_locked(void); #ifdef __cplusplus } #endif #endif // EVSE_HARDWARE_H // === Fim de: components/evse/include/evse_hardware.h === // === Início de: components/evse/include/evse_config.h === #ifndef EVSE_CONFIG_H #define EVSE_CONFIG_H #include #include #include "esp_err.h" #ifdef __cplusplus extern "C" { #endif // ======================== // Limites Globais (Defines) // ======================== // Corrente máxima de carregamento (configurável pelo usuário) #define MIN_CHARGING_CURRENT_LIMIT 6 // A #define MAX_CHARGING_CURRENT_LIMIT 32 // A // Corrente via cabo (proximity) — se configurável #define MIN_CABLE_CURRENT_LIMIT 6 // A #define MAX_CABLE_CURRENT_LIMIT 63 // A // ======================== // Funções de Configuração // ======================== // Inicialização esp_err_t evse_config_init(void); void evse_check_defaults(void); // Corrente de carregamento uint8_t evse_get_max_charging_current(void); esp_err_t evse_set_max_charging_current(uint8_t value); uint16_t evse_get_charging_current(void); esp_err_t evse_set_charging_current(uint16_t value); uint16_t evse_get_default_charging_current(void); esp_err_t evse_set_default_charging_current(uint16_t value); // Configuração de socket outlet bool evse_get_socket_outlet(void); esp_err_t evse_set_socket_outlet(bool socket_outlet); void evse_set_runtime_charging_current(uint16_t value); uint16_t evse_get_runtime_charging_current(void); // RCM bool evse_is_rcm(void); esp_err_t evse_set_rcm(bool rcm); // Temperatura uint8_t evse_get_temp_threshold(void); esp_err_t evse_set_temp_threshold(uint8_t threshold); // Autenticação bool evse_is_require_auth(void); void evse_set_require_auth(bool require); // Disponibilidade bool evse_config_is_available(void); void evse_config_set_available(bool available); // Ativação/desativação do EVSE bool evse_config_is_enabled(void); void evse_config_set_enabled(bool enabled); #ifdef __cplusplus } #endif #endif // EVSE_CONFIG_H // === Fim de: components/evse/include/evse_config.h === // === Início de: components/evse/include/evse_state.h === #ifndef EVSE_STATE_H #define EVSE_STATE_H #include #include "freertos/FreeRTOS.h" #include "evse_events.h" // ============================ // EVSE Pilot Signal States // ============================ typedef enum { EVSE_STATE_A, // EV Not Connected (12V) EVSE_STATE_B1, // EV Connected (9V, Not Authorized) EVSE_STATE_B2, // EV Connected (9V, Authorized and Ready) EVSE_STATE_C1, // Charging Requested (6V, Relay Off) EVSE_STATE_C2, // Charging Active (6V, Relay On) EVSE_STATE_D1, // Ventilation Required (3V, Relay Off) EVSE_STATE_D2, // Ventilation Active (3V, Relay On) EVSE_STATE_E, // Error: Pilot Short to Ground (0V) EVSE_STATE_F // Fault: No Pilot or EVSE Unavailable } evse_state_t; // ============================ // Initialization & Core Control // ============================ /** * @brief Initializes the EVSE state machine. */ void evse_state_init(void); /** * @brief Periodic tick function for the state machine. */ void evse_state_tick(void); // ============================ // State Access // ============================ /** * @brief Returns the current EVSE state. */ evse_state_t evse_get_state(void); /** * @brief Updates the current EVSE state and triggers events. */ void evse_set_state(evse_state_t state); /** * @brief Returns the tick count when charging session started. */ TickType_t evse_get_session_start(void); /** * @brief Converts the state enum to a human-readable string. */ const char* evse_state_to_str(evse_state_t state); // ============================ // State Evaluators // ============================ /** * @brief Returns true if the state represents an active session (B2, C1, C2). */ bool evse_state_is_session(evse_state_t state); /** * @brief Returns true if the state represents active charging (C1, C2). */ bool evse_state_is_charging(evse_state_t state); /** * @brief Returns true if the vehicle is plugged in. */ bool evse_state_is_plugged(evse_state_t state); // ============================ // Authorization // ============================ /** * @brief Sets the vehicle authorization state. */ void evse_state_set_authorized(bool authorized); /** * @brief Returns the current vehicle authorization state. */ bool evse_state_get_authorized(void); #endif // EVSE_STATE_H // === Fim de: components/evse/include/evse_state.h === // === Início de: components/evse/include/evse_error.h === #ifndef EVSE_ERROR_H #define EVSE_ERROR_H #include #include #include "evse_pilot.h" #define EVSE_ERR_AUTO_CLEAR_BITS ( \ EVSE_ERR_DIODE_SHORT_BIT | \ EVSE_ERR_TEMPERATURE_HIGH_BIT | \ EVSE_ERR_RCM_TRIGGERED_BIT ) // Error bits #define EVSE_ERR_DIODE_SHORT_BIT (1 << 0) #define EVSE_ERR_LOCK_FAULT_BIT (1 << 1) #define EVSE_ERR_UNLOCK_FAULT_BIT (1 << 2) #define EVSE_ERR_RCM_SELFTEST_FAULT_BIT (1 << 3) #define EVSE_ERR_RCM_TRIGGERED_BIT (1 << 4) #define EVSE_ERR_TEMPERATURE_HIGH_BIT (1 << 5) #define EVSE_ERR_PILOT_FAULT_BIT (1 << 6) #define EVSE_ERR_TEMPERATURE_FAULT_BIT (1 << 7) // Inicialização do módulo de erros void evse_error_init(void); // Verificações e monitoramento void evse_error_check(pilot_voltage_t pilot_voltage, bool is_n12v); void evse_temperature_check(void); void evse_error_tick(void); // Leitura e controle de erros uint32_t evse_get_error(void); bool evse_is_error_cleared(void); void evse_mark_error_cleared(void); void evse_error_set(uint32_t bitmask); void evse_error_clear(uint32_t bitmask); bool evse_error_is_active(void); uint32_t evse_error_get_bits(void); void evse_error_reset_flag(void); bool evse_error_cleared_flag(void); #endif // EVSE_ERROR_H // === Fim de: components/evse/include/evse_error.h === // === Início de: components/evse/include/evse_limits.h === #ifndef EVSE_LIMITS_H #define EVSE_LIMITS_H #include #include #include "evse_state.h" #ifdef __cplusplus extern "C" { #endif // ======================== // Limit state control // ======================== /** * @brief Sets the 'limit reached' flag. Used internally when a session exceeds defined thresholds. */ void evse_set_limit_reached(bool value); /** * @brief Returns whether any session limit has been reached (energy, time or power). */ bool evse_get_limit_reached(void); // ======================== // Limit checking // ======================== /** * @brief Evaluates if the session has exceeded any configured limits. * Should be called periodically while in charging state. */ void evse_limits_check(void); // ======================== // Runtime limit configuration // ======================== uint32_t evse_get_consumption_limit(void); void evse_set_consumption_limit(uint32_t value); // in Wh uint32_t evse_get_charging_time_limit(void); void evse_set_charging_time_limit(uint32_t value); // in seconds uint16_t evse_get_under_power_limit(void); void evse_set_under_power_limit(uint16_t value); // in Watts // ======================== // Default (persistent) limits // ======================== uint32_t evse_get_default_consumption_limit(void); void evse_set_default_consumption_limit(uint32_t value); uint32_t evse_get_default_charging_time_limit(void); void evse_set_default_charging_time_limit(uint32_t value); uint16_t evse_get_default_under_power_limit(void); void evse_set_default_under_power_limit(uint16_t value); #ifdef __cplusplus } #endif #endif // EVSE_LIMITS_H // === Fim de: components/evse/include/evse_limits.h ===