#include "evse_error.h" #include "evse_config.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/portmacro.h" #include "esp_log.h" #include "ntc_sensor.h" static const char *TAG = "evse_error"; // Estado global de erros static uint32_t error_bits = 0; static TickType_t auto_clear_timeout = 0; // Sticky flag: "todos erros foram limpos" static bool error_cleared = false; // Proteção contra concorrência static portMUX_TYPE error_mux = portMUX_INITIALIZER_UNLOCKED; void evse_error_init(void) { portENTER_CRITICAL(&error_mux); error_bits = 0; auto_clear_timeout = 0; error_cleared = false; portEXIT_CRITICAL(&error_mux); } void evse_error_check(pilot_voltage_t pilot_voltage, bool is_n12v) { ESP_LOGD(TAG, "Verificando erro: pilot_voltage=%d, is_n12v=%s", pilot_voltage, is_n12v ? "true" : "false"); // 1) Falha elétrica geral no pilot if (pilot_voltage == PILOT_VOLTAGE_1) { bool first_time = false; portENTER_CRITICAL(&error_mux); if (!(error_bits & EVSE_ERR_PILOT_FAULT_BIT)) { error_cleared = false; error_bits |= EVSE_ERR_PILOT_FAULT_BIT; first_time = true; } portEXIT_CRITICAL(&error_mux); if (first_time) { ESP_LOGW(TAG, "Erro: pilot abaixo de 2V (falha)"); } } else { // Pilot voltou a nível válido → limpa erro de pilot fault evse_error_clear(EVSE_ERR_PILOT_FAULT_BIT); } // 2) Falta de -12V durante PWM (C ou D) if ((pilot_voltage == PILOT_VOLTAGE_6 || pilot_voltage == PILOT_VOLTAGE_3) && !is_n12v) { bool first_time = false; portENTER_CRITICAL(&error_mux); if (!(error_bits & EVSE_ERR_DIODE_SHORT_BIT)) { error_cleared = false; error_bits |= EVSE_ERR_DIODE_SHORT_BIT; auto_clear_timeout = xTaskGetTickCount() + pdMS_TO_TICKS(60000); first_time = true; } portEXIT_CRITICAL(&error_mux); if (first_time) { ESP_LOGW(TAG, "Erro: ausência de -12V no PWM (sem diodo)"); } } else { // Se já não estamos em C/D sem -12V, limpa o erro de diodo curto evse_error_clear(EVSE_ERR_DIODE_SHORT_BIT); } } void evse_temperature_check(void) { float temp_c = ntc_temp_sensor(); uint8_t threshold = evse_get_temp_threshold(); ESP_LOGD(TAG, "Verificando temperatura: atual=%.2f °C, limite=%d °C", temp_c, threshold); // Temperatura inválida -> erro de sensor if (temp_c < -40.0f || temp_c > 150.0f) { bool first_time = false; portENTER_CRITICAL(&error_mux); if (!(error_bits & EVSE_ERR_TEMPERATURE_FAULT_BIT)) { error_cleared = false; error_bits |= EVSE_ERR_TEMPERATURE_FAULT_BIT; first_time = true; } portEXIT_CRITICAL(&error_mux); if (first_time) { ESP_LOGW(TAG, "Sensor NTC falhou ou está desconectado"); } return; } // Leitura válida -> limpa erro de sensor evse_error_clear(EVSE_ERR_TEMPERATURE_FAULT_BIT); // Temperatura máxima if (temp_c >= threshold) { bool first_time = false; portENTER_CRITICAL(&error_mux); if (!(error_bits & EVSE_ERR_TEMPERATURE_HIGH_BIT)) { error_cleared = false; error_bits |= EVSE_ERR_TEMPERATURE_HIGH_BIT; auto_clear_timeout = xTaskGetTickCount() + pdMS_TO_TICKS(60000); first_time = true; } portEXIT_CRITICAL(&error_mux); if (first_time) { ESP_LOGW(TAG, "Temperatura acima do limite: %.2f °C ≥ %d °C", temp_c, threshold); } } else { evse_error_clear(EVSE_ERR_TEMPERATURE_HIGH_BIT); } } uint32_t evse_get_error(void) { portENTER_CRITICAL(&error_mux); uint32_t val = error_bits; portEXIT_CRITICAL(&error_mux); return val; } bool evse_error_cleared_flag(void) { portENTER_CRITICAL(&error_mux); bool v = error_cleared; portEXIT_CRITICAL(&error_mux); return v; } void evse_error_reset_flag(void) { portENTER_CRITICAL(&error_mux); error_cleared = false; portEXIT_CRITICAL(&error_mux); } void evse_error_set(uint32_t bitmask) { portENTER_CRITICAL(&error_mux); error_cleared = false; error_bits |= bitmask; if (bitmask & EVSE_ERR_AUTO_CLEAR_BITS) { auto_clear_timeout = xTaskGetTickCount() + pdMS_TO_TICKS(60000); // 60s } portEXIT_CRITICAL(&error_mux); } void evse_error_clear(uint32_t bitmask) { portENTER_CRITICAL(&error_mux); bool had_error = (error_bits != 0); error_bits &= ~bitmask; if (had_error && error_bits == 0) { error_cleared = true; } portEXIT_CRITICAL(&error_mux); } void evse_error_tick(void) { portENTER_CRITICAL(&error_mux); if ((error_bits & EVSE_ERR_AUTO_CLEAR_BITS) && auto_clear_timeout != 0 && xTaskGetTickCount() >= auto_clear_timeout) { error_bits &= ~EVSE_ERR_AUTO_CLEAR_BITS; if (error_bits == 0) { error_cleared = true; } auto_clear_timeout = 0; } portEXIT_CRITICAL(&error_mux); } bool evse_error_is_active(void) { return evse_get_error() != 0; } uint32_t evse_error_get_bits(void) { return evse_get_error(); }