new upgrade
This commit is contained in:
@@ -5,150 +5,203 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_event.h"
|
||||
|
||||
// =========================
|
||||
// Internal State Variables
|
||||
// =========================
|
||||
#define EVSE_EVENT_POST_TIMEOUT_MS 50
|
||||
|
||||
static evse_state_t current_state = EVSE_STATE_A;
|
||||
static bool is_authorized = false;
|
||||
|
||||
static portMUX_TYPE state_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static const char *TAG = "evse_state";
|
||||
|
||||
// =========================
|
||||
// Internal Mapping
|
||||
// =========================
|
||||
static evse_state_event_t map_state_to_event(evse_state_t s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case EVSE_STATE_A:
|
||||
return EVSE_STATE_EVENT_IDLE;
|
||||
|
||||
static evse_state_event_t map_state_to_event(evse_state_t s) {
|
||||
switch (s) {
|
||||
case EVSE_STATE_A: return EVSE_STATE_EVENT_IDLE;
|
||||
case EVSE_STATE_B1:
|
||||
case EVSE_STATE_B2: return EVSE_STATE_EVENT_WAITING;
|
||||
case EVSE_STATE_C1:
|
||||
case EVSE_STATE_C2: return EVSE_STATE_EVENT_CHARGING;
|
||||
case EVSE_STATE_E:
|
||||
case EVSE_STATE_F: return EVSE_STATE_EVENT_FAULT;
|
||||
default: return EVSE_STATE_EVENT_IDLE;
|
||||
case EVSE_STATE_B1:
|
||||
case EVSE_STATE_B2:
|
||||
return EVSE_STATE_EVENT_WAITING;
|
||||
|
||||
case EVSE_STATE_C1:
|
||||
case EVSE_STATE_C2:
|
||||
case EVSE_STATE_D1:
|
||||
case EVSE_STATE_D2:
|
||||
return EVSE_STATE_EVENT_CHARGING;
|
||||
|
||||
case EVSE_STATE_E:
|
||||
case EVSE_STATE_F:
|
||||
return EVSE_STATE_EVENT_FAULT;
|
||||
|
||||
default:
|
||||
return EVSE_STATE_EVENT_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
// =========================
|
||||
// Public API
|
||||
// =========================
|
||||
static void post_evse_event(evse_event_id_t id, const void *data, size_t len)
|
||||
{
|
||||
esp_err_t err = esp_event_post(
|
||||
EVSE_EVENTS,
|
||||
id,
|
||||
data,
|
||||
len,
|
||||
portMAX_DELAY);
|
||||
|
||||
void evse_set_state(evse_state_t new_state) {
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "esp_event_post(id=%d) failed: %s", (int)id, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
bool evse_state_is_charging(evse_state_t state)
|
||||
{
|
||||
// “charging” == energia efetiva (relé ON)
|
||||
return (state == EVSE_STATE_C2 || state == EVSE_STATE_D2);
|
||||
}
|
||||
|
||||
bool evse_state_is_power_flowing(evse_state_t state)
|
||||
{
|
||||
return evse_state_is_charging(state);
|
||||
}
|
||||
|
||||
bool evse_state_is_requesting(evse_state_t state)
|
||||
{
|
||||
// EV pediu carga mas o relé ainda está OFF
|
||||
return (state == EVSE_STATE_C1 || state == EVSE_STATE_D1);
|
||||
}
|
||||
|
||||
bool evse_state_is_plugged(evse_state_t state)
|
||||
{
|
||||
return state == EVSE_STATE_B1 || state == EVSE_STATE_B2 ||
|
||||
state == EVSE_STATE_C1 || state == EVSE_STATE_C2 ||
|
||||
state == EVSE_STATE_D1 || state == EVSE_STATE_D2;
|
||||
}
|
||||
|
||||
bool evse_state_is_session(evse_state_t state)
|
||||
{
|
||||
// Sessão lógica: “autorizado/pronto” ou “a pedir/a fornecer energia”
|
||||
return (state == EVSE_STATE_B2 ||
|
||||
state == EVSE_STATE_C1 || state == EVSE_STATE_C2 ||
|
||||
state == EVSE_STATE_D1 || state == EVSE_STATE_D2);
|
||||
}
|
||||
|
||||
void evse_set_state(evse_state_t new_state)
|
||||
{
|
||||
bool changed = false;
|
||||
evse_state_t prev_state;
|
||||
bool start_session = false;
|
||||
bool end_session = false;
|
||||
bool end_session = false;
|
||||
|
||||
// 1) Detecta transição de estado dentro da região crítica
|
||||
portENTER_CRITICAL(&state_mux);
|
||||
prev_state = current_state;
|
||||
if (new_state != current_state) {
|
||||
// se entrou em charging pela primeira vez
|
||||
if (evse_state_is_charging(new_state) && !evse_state_is_charging(prev_state)) {
|
||||
start_session = true;
|
||||
}
|
||||
// se saiu de charging para qualquer outro
|
||||
else if (!evse_state_is_charging(new_state) && evse_state_is_charging(prev_state)) {
|
||||
end_session = true;
|
||||
}
|
||||
current_state = new_state;
|
||||
changed = true;
|
||||
}
|
||||
prev_state = current_state;
|
||||
|
||||
if (new_state != current_state)
|
||||
{
|
||||
|
||||
// Sessão começa quando entra em energia (relé ON)
|
||||
if (evse_state_is_power_flowing(new_state) && !evse_state_is_power_flowing(prev_state))
|
||||
{
|
||||
start_session = true;
|
||||
}
|
||||
// Sessão termina quando sai de energia
|
||||
else if (!evse_state_is_power_flowing(new_state) && evse_state_is_power_flowing(prev_state))
|
||||
{
|
||||
end_session = true;
|
||||
}
|
||||
|
||||
current_state = new_state;
|
||||
changed = true;
|
||||
}
|
||||
portEXIT_CRITICAL(&state_mux);
|
||||
|
||||
// 2) Executa start/end de sessão FORA da região crítica, evitando logs/alloc dentro dela
|
||||
if (start_session) {
|
||||
// Fora da região crítica
|
||||
if (start_session)
|
||||
{
|
||||
evse_session_start();
|
||||
}
|
||||
if (end_session) {
|
||||
if (end_session)
|
||||
{
|
||||
evse_session_end();
|
||||
}
|
||||
|
||||
// 3) Se mudou o estado, faz log e dispara evento
|
||||
if (changed) {
|
||||
const char *prev_str = evse_state_to_str(prev_state);
|
||||
const char *curr_str = evse_state_to_str(new_state);
|
||||
ESP_LOGI(TAG, "State changed: %s → %s", prev_str, curr_str);
|
||||
if (changed)
|
||||
{
|
||||
ESP_LOGI(TAG, "State changed: %s → %s",
|
||||
evse_state_to_str(prev_state),
|
||||
evse_state_to_str(new_state));
|
||||
|
||||
evse_state_event_data_t evt = {
|
||||
.state = map_state_to_event(new_state)
|
||||
};
|
||||
esp_event_post(EVSE_EVENTS,
|
||||
EVSE_EVENT_STATE_CHANGED,
|
||||
&evt,
|
||||
sizeof(evt),
|
||||
portMAX_DELAY);
|
||||
.state = map_state_to_event(new_state)};
|
||||
post_evse_event(EVSE_EVENT_STATE_CHANGED, &evt, sizeof(evt));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
evse_state_t evse_get_state(void) {
|
||||
evse_state_t evse_get_state(void)
|
||||
{
|
||||
portENTER_CRITICAL(&state_mux);
|
||||
evse_state_t s = current_state;
|
||||
portEXIT_CRITICAL(&state_mux);
|
||||
return s;
|
||||
}
|
||||
|
||||
const char* evse_state_to_str(evse_state_t state) {
|
||||
switch (state) {
|
||||
case EVSE_STATE_A: return "A - EV Not Connected (12V)";
|
||||
case EVSE_STATE_B1: return "B1 - EV Connected (9V, Not Authorized)";
|
||||
case EVSE_STATE_B2: return "B2 - EV Connected (9V, Authorized and Ready)";
|
||||
case EVSE_STATE_C1: return "C1 - Charging Requested (6V, Relay Off)";
|
||||
case EVSE_STATE_C2: return "C2 - Charging Active (6V, Relay On)";
|
||||
case EVSE_STATE_D1: return "D1 - Ventilation Required (3V, Relay Off)";
|
||||
case EVSE_STATE_D2: return "D2 - Ventilation Active (3V, Relay On)";
|
||||
case EVSE_STATE_E: return "E - Error: Control Pilot Shorted to Ground (0V)";
|
||||
case EVSE_STATE_F: return "F - Fault: EVSE Unavailable or No Pilot Signal";
|
||||
default: return "Unknown State";
|
||||
const char *evse_state_to_str(evse_state_t state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case EVSE_STATE_A:
|
||||
return "A - EV Not Connected (12V)";
|
||||
case EVSE_STATE_B1:
|
||||
return "B1 - EV Connected (9V, Not Authorized)";
|
||||
case EVSE_STATE_B2:
|
||||
return "B2 - EV Connected (9V, Authorized and Ready)";
|
||||
case EVSE_STATE_C1:
|
||||
return "C1 - Charging Requested (6V, Relay Off)";
|
||||
case EVSE_STATE_C2:
|
||||
return "C2 - Charging Active (6V, Relay On)";
|
||||
case EVSE_STATE_D1:
|
||||
return "D1 - Ventilation Required (3V, Relay Off)";
|
||||
case EVSE_STATE_D2:
|
||||
return "D2 - Ventilation Active (3V, Relay On)";
|
||||
case EVSE_STATE_E:
|
||||
return "E - Error: Control Pilot Shorted to Ground (0V)";
|
||||
case EVSE_STATE_F:
|
||||
return "F - Fault: EVSE Unavailable or No Pilot Signal";
|
||||
default:
|
||||
return "Unknown State";
|
||||
}
|
||||
}
|
||||
|
||||
void evse_state_init(void) {
|
||||
void evse_state_init(void)
|
||||
{
|
||||
portENTER_CRITICAL(&state_mux);
|
||||
current_state = EVSE_STATE_A;
|
||||
is_authorized = true;
|
||||
is_authorized = false;
|
||||
portEXIT_CRITICAL(&state_mux);
|
||||
|
||||
ESP_LOGI("EVSE_STATE", "Initialized in state: %s", evse_state_to_str(current_state));
|
||||
ESP_LOGI(TAG, "Initialized in state: %s", evse_state_to_str(current_state));
|
||||
|
||||
evse_state_event_data_t evt = {
|
||||
.state = map_state_to_event(current_state)
|
||||
};
|
||||
esp_event_post(EVSE_EVENTS, EVSE_EVENT_INIT, &evt, sizeof(evt), portMAX_DELAY);
|
||||
.state = map_state_to_event(current_state)};
|
||||
post_evse_event(EVSE_EVENT_INIT, &evt, sizeof(evt));
|
||||
}
|
||||
|
||||
void evse_state_tick(void) {
|
||||
// Placeholder for future state logic
|
||||
void evse_state_tick(void)
|
||||
{
|
||||
// placeholder
|
||||
}
|
||||
|
||||
bool evse_state_is_charging(evse_state_t state) {
|
||||
return state == EVSE_STATE_C1 || state == EVSE_STATE_C2;
|
||||
}
|
||||
|
||||
bool evse_state_is_plugged(evse_state_t state) {
|
||||
return state == EVSE_STATE_B1 || state == EVSE_STATE_B2 ||
|
||||
state == EVSE_STATE_C1 || state == EVSE_STATE_C2 ||
|
||||
state == EVSE_STATE_D1 || state == EVSE_STATE_D2;
|
||||
}
|
||||
|
||||
bool evse_state_is_session(evse_state_t state) {
|
||||
return state == EVSE_STATE_B2 || state == EVSE_STATE_C1 || state == EVSE_STATE_C2;
|
||||
}
|
||||
|
||||
void evse_state_set_authorized(bool authorized) {
|
||||
void evse_state_set_authorized(bool authorized)
|
||||
{
|
||||
portENTER_CRITICAL(&state_mux);
|
||||
is_authorized = authorized;
|
||||
portEXIT_CRITICAL(&state_mux);
|
||||
}
|
||||
|
||||
bool evse_state_get_authorized(void) {
|
||||
bool evse_state_get_authorized(void)
|
||||
{
|
||||
portENTER_CRITICAL(&state_mux);
|
||||
bool result = is_authorized;
|
||||
portEXIT_CRITICAL(&state_mux);
|
||||
|
||||
Reference in New Issue
Block a user