new release

This commit is contained in:
2026-05-15 12:20:47 +01:00
parent 286028b6a8
commit d0d431daf2
440 changed files with 2776 additions and 2462 deletions

View File

@@ -33,10 +33,41 @@
#include "led.h"
#include "scheduler.h"
#include "storage_service.h"
#include "time_service.h"
#define AP_CONNECTION_TIMEOUT 120000
#define RESET_HOLD_TIME 30000 // ms
#define DEBOUNCE_TIME_MS 50
/*
* Modos de controlo do AP:
*
* APP_AP_CONTROL_BUTTON:
* - Usa botão físico.
* - Pressão curta: inicia AP.
* - Pressão longa: apaga NVS e reinicia.
*
* APP_AP_CONTROL_BOOT_WINDOW:
* - Não usa botão físico.
* - Inicia AP automaticamente no arranque.
* - Mantém AP ativo durante os primeiros 3 minutos.
* - Depois desliga AP e volta ao modo STA.
*/
#define APP_AP_CONTROL_BUTTON 0
#define APP_AP_CONTROL_BOOT_WINDOW 1
/*
* Escolher aqui o modo pretendido:
*
* Para placa COM botão:
* #define APP_AP_CONTROL_MODE APP_AP_CONTROL_BUTTON
*
* Para placa SEM botão:
* #define APP_AP_CONTROL_MODE APP_AP_CONTROL_BOOT_WINDOW
*/
#define APP_AP_CONTROL_MODE APP_AP_CONTROL_BOOT_WINDOW
#define AP_BOOT_WINDOW_MS 180000UL // 3 minutos
#define AP_CONNECTION_TIMEOUT AP_BOOT_WINDOW_MS
#define RESET_HOLD_TIME 30000UL // ms
#define DEBOUNCE_TIME_MS 50UL
#define PRESS_BIT BIT0
#define RELEASED_BIT BIT1
@@ -98,6 +129,7 @@ static void wifi_event_task_func(void *param)
{
(void)param;
EventBits_t mode_bits;
for (;;)
{
mode_bits = xEventGroupWaitBits(
@@ -130,7 +162,8 @@ static void wifi_event_task_func(void *param)
if (xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT)
{
// Timeout sem cliente ligado
// wifi_ap_stop();
// O desligar do AP no modo sem botão é feito pela boot_ap_task_func().
// No modo com botão, mantemos o comportamento antigo.
ESP_LOGW(TAG, "AP timeout sem conexões");
}
}
@@ -165,9 +198,15 @@ static void handle_button_press(void)
ESP_LOGI(TAG, "Starting Wi-Fi AP mode (short press)");
wifi_ap_start();
}
else
{
ESP_LOGI(TAG, "Wi-Fi AP mode já está ativo");
}
}
//
// Task para lidar com notificações de botão (PRESS / RELEASE)
//
static void user_input_task_func(void *param)
{
(void)param;
@@ -186,12 +225,13 @@ static void user_input_task_func(void *param)
press_tick = xTaskGetTickCount();
pressed = true;
ESP_LOGI(TAG, "Button Pressed");
// Decisão (short/long) é feita na soltura
// Decisão short/long é feita na soltura
}
if ((notification & RELEASED_BIT) && pressed)
{
pressed = false;
TickType_t held_ticks = xTaskGetTickCount() - press_tick;
uint32_t held_ms = pdTICKS_TO_MS(held_ticks);
@@ -200,7 +240,13 @@ static void user_input_task_func(void *param)
if (held_ms >= RESET_HOLD_TIME)
{
ESP_LOGW(TAG, "Long press: erasing NVS + reboot");
nvs_flash_erase();
esp_err_t ret = nvs_flash_erase();
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Erro ao apagar NVS: %s", esp_err_to_name(ret));
}
esp_restart();
}
else
@@ -213,7 +259,9 @@ static void user_input_task_func(void *param)
}
}
// ISR para GPIO do botão (ativo em nível baixo)
//
// ISR para GPIO do botão ativo em nível baixo
//
static void IRAM_ATTR button_isr_handler(void *arg)
{
(void)arg;
@@ -221,11 +269,13 @@ static void IRAM_ATTR button_isr_handler(void *arg)
TickType_t now = xTaskGetTickCountFromISR();
portENTER_CRITICAL_ISR(&button_spinlock);
if (now - last_interrupt_tick < pdMS_TO_TICKS(DEBOUNCE_TIME_MS))
{
portEXIT_CRITICAL_ISR(&button_spinlock);
return;
}
last_interrupt_tick = now;
if (user_input_task == NULL)
@@ -265,11 +315,45 @@ static void button_init(void)
}
//
// Inicialização dos módulos do sistema (SEM botão)
// AP automático no arranque para placas sem botão
//
static void boot_ap_task_func(void *param)
{
(void)param;
if (wifi_event_group == NULL)
{
ESP_LOGW(TAG, "Wi-Fi ainda não inicializado, não é possível iniciar AP");
vTaskDelete(NULL);
return;
}
ESP_LOGI(TAG, "Modo sem botão: iniciar AP automaticamente durante 3 minutos");
wifi_ap_start();
vTaskDelay(pdMS_TO_TICKS(AP_BOOT_WINDOW_MS));
EventBits_t bits = xEventGroupGetBits(wifi_event_group);
if (bits & WIFI_AP_MODE_BIT)
{
ESP_LOGI(TAG, "Modo sem botão: janela de AP terminou, a desligar AP");
wifi_ap_stop();
}
else
{
ESP_LOGI(TAG, "Modo sem botão: AP já não estava ativo");
}
vTaskDelete(NULL);
}
//
// Inicialização dos módulos do sistema
//
static void init_modules(void)
{
ESP_ERROR_CHECK(storage_service_init());
peripherals_init();
@@ -284,6 +368,7 @@ static void init_modules(void)
meter_manager_init();
meter_manager_start();
ocpp_start();
time_service_init();
scheduler_init();
protocols_init();
loadbalancer_init();
@@ -295,7 +380,6 @@ static void init_modules(void)
//
void app_main(void)
{
esp_reset_reason_t reason = esp_reset_reason();
ESP_LOGI(TAG, "Reset reason: %d", reason);
@@ -309,25 +393,74 @@ void app_main(void)
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();
// 1) Inicia todos os módulos (inclui Wi-Fi, EVSE, etc.)
/*
* O serviço GPIO ISR tem de estar instalado antes de qualquer módulo
* chamar gpio_isr_handler_add().
*
* O RFID/Wiegand usa interrupções GPIO durante auth_init(),
* que é chamado dentro de init_modules().
*/
esp_err_t gpio_isr_ret = gpio_install_isr_service(0);
if (gpio_isr_ret != ESP_OK && gpio_isr_ret != ESP_ERR_INVALID_STATE)
{
ESP_ERROR_CHECK(gpio_isr_ret);
}
// 1) Inicia todos os módulos, incluindo Wi-Fi, EVSE, etc.
init_modules();
// 2) Cria a task que recebe notificações do botão
BaseType_t rc;
rc = xTaskCreate(user_input_task_func, "user_input_task", 4 * 1024, NULL, 3, &user_input_task);
#if APP_AP_CONTROL_MODE == APP_AP_CONTROL_BUTTON
ESP_LOGI(TAG, "Modo AP por botão ativo");
// 2) Cria a task que recebe notificações do botão
rc = xTaskCreate(
user_input_task_func,
"user_input_task",
4 * 1024,
NULL,
3,
&user_input_task);
configASSERT(rc == pdPASS);
// 3) Agora é seguro registrar ISR do botão
button_init();
#elif APP_AP_CONTROL_MODE == APP_AP_CONTROL_BOOT_WINDOW
ESP_LOGI(TAG, "Modo AP automático no arranque ativo");
// 2) Inicia AP automaticamente durante os primeiros 3 minutos
rc = xTaskCreate(
boot_ap_task_func,
"boot_ap_task",
4 * 1024,
NULL,
3,
NULL);
configASSERT(rc == pdPASS);
#else
#error "APP_AP_CONTROL_MODE inválido"
#endif
// 4) Task auxiliar para eventos Wi-Fi
rc = xTaskCreate(wifi_event_task_func, "wifi_event_task", 8 * 1024, NULL, 3, NULL);
rc = xTaskCreate(
wifi_event_task_func,
"wifi_event_task",
8 * 1024,
NULL,
3,
NULL);
configASSERT(rc == pdPASS);
}