fix ade7758

This commit is contained in:
2025-06-25 06:34:03 +01:00
parent a0b2e048d4
commit 84f106eee5
53 changed files with 7079 additions and 18456 deletions

View File

@@ -10,7 +10,7 @@ LED_STOP_GPIO=12
#BUZZER
BUZZER=y
BUZZER_GPIO=21
BUZZER_GPIO=27
#Button
BUTTON_WIFI_GPIO=32

View File

@@ -13,16 +13,21 @@
#include "timeout_utils.h"
#include "evse_error.h"
#include "evse_api.h"
#include "evse_limits.h"
#include "evse_state.h"
#include "evse_config.h"
#include "ocpp.h"
#include "board_config.h"
#include "socket_lock.h"
#include "proximity.h"
//#include "modbus.h"
//#include "modbus_tcp.h"
#include "rest.h"
//#include "rest.h"
#include "temp_sensor.h"
// #include "script.h"
#include "date_time.h"
#include "evse_meter.h"
#define RETURN_ON_ERROR(x) \
do \
@@ -335,9 +340,9 @@ cJSON *json_get_state(void)
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "state", evse_state_to_str(evse_get_state()));
cJSON_AddBoolToObject(root, "available", evse_is_available());
cJSON_AddBoolToObject(root, "enabled", evse_is_enabled());
cJSON_AddBoolToObject(root, "pendingAuth", false);
cJSON_AddBoolToObject(root, "available", evse_config_is_available());
cJSON_AddBoolToObject(root, "enabled", evse_config_is_enabled());
cJSON_AddBoolToObject(root, "pendingAuth", evse_is_require_auth());
cJSON_AddBoolToObject(root, "limitReached", evse_is_limit_reached());
uint32_t error = evse_error_get_bits();
@@ -383,17 +388,33 @@ cJSON *json_get_state(void)
cJSON_AddItemToObject(root, "errors", errors);
}
/*
cJSON_AddNumberToObject(root, "sessionTime", energy_meter_get_session_time());
cJSON_AddNumberToObject(root, "chargingTime", energy_meter_get_charging_time());
cJSON_AddNumberToObject(root, "consumption", energy_meter_get_consumption());
cJSON_AddNumberToObject(root, "power", energy_meter_get_power());
float values[3];
energy_meter_get_voltage(values);
cJSON_AddItemToObject(root, "voltage", cJSON_CreateFloatArray(values, 3));
energy_meter_get_current(values);
cJSON_AddItemToObject(root, "current", cJSON_CreateFloatArray(values, 3));
*/
cJSON_AddNumberToObject(root, "sessionTime", evse_get_session_start());
cJSON_AddNumberToObject(root, "chargingTime", 0);
cJSON_AddNumberToObject(root, "consumption", 0);
// 1) Arrays temporários para ler dados do medidor
float voltage_f[EVSE_METER_PHASE_COUNT];
float current_f[EVSE_METER_PHASE_COUNT];
uint32_t power_w[ EVSE_METER_PHASE_COUNT];
// 2) Leitura dos valores via API pública
evse_meter_get_voltage(voltage_f); // já em volts
evse_meter_get_current(current_f); // já em amperes
evse_meter_get_power(power_w); // em watts por fase
// 4) Energia acumulada em kWh
//float consumption_kwh = evse_meter_get_total_energy() / 1000.0f; // Wh → kWh
// 6) Arrays de tensão e corrente
cJSON_AddItemToObject(root, "power",
cJSON_CreateFloatArray(power_w, EVSE_METER_PHASE_COUNT));
cJSON_AddItemToObject(root, "voltage",
cJSON_CreateFloatArray(voltage_f, EVSE_METER_PHASE_COUNT));
cJSON_AddItemToObject(root, "current",
cJSON_CreateFloatArray(current_f, EVSE_METER_PHASE_COUNT));
return root;
}

View File

@@ -5,7 +5,7 @@
#include "timeout_utils.h"
#include "wifi.h"
#include "rest.h"
//#include "rest.h"
static void restart_func(void* arg)
{

View File

@@ -9,6 +9,7 @@ set(srcs
evse_manager.c
evse_hardware.c
evse_pilot.c
evse_meter.c
)
idf_component_register(

View File

@@ -1,4 +1,4 @@
// evse_core.c - Função principal de controle do EVSE
// evse_core.c - Main EVSE control logic
#include "evse_fsm.h"
#include "evse_error.h"
@@ -13,23 +13,30 @@
static const char *TAG = "evse_core";
static SemaphoreHandle_t mutex;
static evse_state_t last_state = EVSE_STATE_A;
static void evse_core_task(void *arg);
// ================================
// Initialization
// ================================
void evse_init(void) {
ESP_LOGI(TAG, "EVSE Init");
mutex = xSemaphoreCreateMutex();
mutex = xSemaphoreCreateMutex(); // Optional: use static version for deterministic memory
evse_check_defaults();
evse_fsm_reset();
pilot_set_level(true); // Estado inicial do piloto
pilot_set_level(true); // Enable pilot output
xTaskCreate(evse_core_task, "evse_core_task", 4096, NULL, 5, NULL);
}
// ================================
// Main Processing Logic
// ================================
void evse_process(void) {
xSemaphoreTake(mutex, portMAX_DELAY);
@@ -39,10 +46,9 @@ void evse_process(void) {
pilot_measure(&pilot_voltage, &is_n12v);
ESP_LOGD(TAG, "Pilot: %d, -12V: %s", pilot_voltage, is_n12v ? "yes" : "no");
if (evse_get_error() == 0 && !evse_is_error_cleared()) {
evse_error_check(pilot_voltage, is_n12v);
// Só chama FSM, que decide tudo
evse_fsm_process(
pilot_voltage,
evse_state_get_authorized(),
@@ -61,20 +67,15 @@ void evse_process(void) {
}
evse_mark_error_cleared();
}
xSemaphoreGive(mutex);
}
// ================================
// Interface pública
// Public Configuration Interface
// ================================
bool evse_is_enabled(void) {
return evse_config_is_enabled();
}
void evse_set_enabled(bool value) {
ESP_LOGI(TAG, "Set enabled %d", value);
evse_config_set_enabled(value);
@@ -90,21 +91,12 @@ void evse_set_available(bool value) {
}
// ================================
// Tarefa principal
// Background Task
// ================================
static void evse_core_task(void *arg) {
while (true) {
evse_process();
vTaskDelay(pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(100)); // 10 Hz cycle
}
}
uint32_t evse_get_total_energy(void) {
return 0; // Stub de 1 kWh
}
uint32_t evse_get_instant_power(void) {
return 0; // Stub de 2 kW
}

View File

@@ -1,5 +1,3 @@
// evse_fsm.c - Máquina de Estados EVSE com controle centralizado
#include "evse_fsm.h"
#include "evse_api.h"
#include "evse_pilot.h"
@@ -11,6 +9,7 @@
#include "proximity.h"
#include "rcm.h"
#include "evse_state.h"
#include "evse_error.h"
static const char *TAG = "evse_fsm";
@@ -27,6 +26,8 @@ void evse_fsm_reset(void) {
c1_d1_relay_to = 0;
}
// ... includes e defines como já estão
static void update_outputs(evse_state_t state) {
const uint16_t current = evse_get_runtime_charging_current();
uint8_t cable_max_current = evse_get_max_charging_current();
@@ -36,6 +37,21 @@ static void update_outputs(evse_state_t state) {
cable_max_current = proximity_get_max_current();
}
// Segurança: relé sempre off e outputs seguros em caso de erro
if (evse_get_error() != 0) {
if (ac_relay_get_state()) {
ac_relay_set_state(false);
ESP_LOGW(TAG, "ERRO ativo: relé estava ligado, agora desligado por segurança!");
}
ac_relay_set_state(false); // redundância tolerável
pilot_set_level(true); // sinal pilot sempre 12V (A)
if (board_config.socket_lock && socket_outlet) {
socket_lock_set_locked(false);
}
return;
}
// Fluxo normal
switch (state) {
case EVSE_STATE_A:
case EVSE_STATE_E:
@@ -53,7 +69,6 @@ static void update_outputs(evse_state_t state) {
if (board_config.socket_lock && socket_outlet) {
socket_lock_set_locked(true);
}
if (rcm_test()) {
ESP_LOGI(TAG, "RCM self test passed");
} else {
@@ -76,12 +91,28 @@ static void update_outputs(evse_state_t state) {
case EVSE_STATE_C2:
case EVSE_STATE_D2:
pilot_set_amps(MIN(current * 10, cable_max_current * 10));
ac_relay_set_state(true);
ac_relay_set_state(true); // Só chega aqui se não há erro!
break;
}
}
void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool available, bool enabled) {
// FSM principal - centraliza a lógica de erro e de todos os estados
void evse_fsm_process(
pilot_voltage_t pilot_voltage,
bool authorized,
bool available,
bool enabled
) {
// Proteção total: erro força F sempre!
if (evse_get_error() != 0) {
if (evse_get_state() != EVSE_STATE_F) {
ESP_LOGW(TAG, "Erro ativo detectado: forçando estado FAULT (F)");
evse_set_state(EVSE_STATE_F);
}
update_outputs(EVSE_STATE_F);
return;
}
TickType_t now = xTaskGetTickCount();
evse_state_t prev = evse_get_state();
evse_state_t curr = prev;
@@ -101,7 +132,6 @@ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool avail
evse_set_state(EVSE_STATE_F);
break;
}
switch (pilot_voltage) {
case PILOT_VOLTAGE_12:
evse_set_state(EVSE_STATE_A);
@@ -127,15 +157,15 @@ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool avail
break;
}
}
__attribute__((fallthrough)); // Evita warning de fallthrough implícito
__attribute__((fallthrough));
case EVSE_STATE_C2:
case EVSE_STATE_D2:
if (!enabled || !available) {
evse_set_state((curr == EVSE_STATE_D2 || curr == EVSE_STATE_D1) ? EVSE_STATE_D1 : EVSE_STATE_C1);
evse_set_state((curr == EVSE_STATE_D2 || curr == EVSE_STATE_D1)
? EVSE_STATE_D1 : EVSE_STATE_C1);
break;
}
switch (pilot_voltage) {
case PILOT_VOLTAGE_6:
evse_set_state((authorized && enabled) ? EVSE_STATE_C2 : EVSE_STATE_C1);
@@ -155,18 +185,23 @@ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool avail
break;
case EVSE_STATE_E:
break; // Sem transições a partir de E
// Estado elétrico grave: só reset manual
break;
case EVSE_STATE_F:
if (available) {
// Fault: só sai se disponível e sem erro
if (available && evse_get_error() == 0) {
evse_set_state(EVSE_STATE_A);
}
break;
}
evse_state_t next = evse_get_state();
if (next != prev) {
ESP_LOGI(TAG, "State changed: %s -> %s", evse_state_to_str(prev), evse_state_to_str(next));
update_outputs(next);
if (next != prev) {
ESP_LOGI(TAG, "State changed: %s -> %s",
evse_state_to_str(prev),
evse_state_to_str(next));
}
}

View File

@@ -1,6 +1,7 @@
#include "evse_state.h"
#include "evse_api.h"
#include "evse_limits.h"
#include "evse_meter.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -146,8 +147,8 @@ void evse_limits_check(void) {
bool reached = false;
uint32_t energy = evse_get_total_energy();
uint32_t power = evse_get_instant_power();
uint32_t energy = evse_meter_get_total_energy();
uint32_t power = evse_meter_get_instant_power();
TickType_t now = xTaskGetTickCount();
TickType_t start = evse_get_session_start();

View File

@@ -4,6 +4,7 @@
#include "evse_hardware.h"
#include "evse_config.h"
#include "evse_api.h"
#include "evse_meter.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -87,6 +88,7 @@ void evse_manager_init(void) {
evse_error_init();
evse_hardware_init();
evse_state_init();
evse_meter_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));
@@ -120,29 +122,3 @@ void evse_manager_tick(void) {
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();
}

View File

@@ -0,0 +1,105 @@
#include "evse_meter.h"
#include "meter_events.h"
#include "esp_event.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include <string.h>
#include <inttypes.h>
static const char *TAG = "evse_meter";
static SemaphoreHandle_t meter_mutex;
typedef struct {
uint32_t power_watts[EVSE_METER_PHASE_COUNT];
float voltage[EVSE_METER_PHASE_COUNT];
float current[EVSE_METER_PHASE_COUNT];
uint32_t energy_wh;
} evse_meter_data_t;
static evse_meter_data_t meter_data;
static void on_meter_event_dispatcher(void* arg, esp_event_base_t base, int32_t id, void* data) {
if (base == METER_EVENT && id == METER_EVENT_DATA_READY && data) {
const meter_event_data_t *evt = (const meter_event_data_t *)data;
if (strcmp(evt->source, "EVSE") == 0) {
evse_meter_on_meter_event(arg, data);
}
}
}
void evse_meter_on_meter_event(void* arg, void* event_data) {
const meter_event_data_t *evt = (const meter_event_data_t *)event_data;
if (!evt) return;
xSemaphoreTake(meter_mutex, portMAX_DELAY);
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
meter_data.power_watts[i] = evt->watt[i];
meter_data.voltage[i] = evt->vrms[i];
meter_data.current[i] = evt->irms[i];
}
meter_data.energy_wh = (uint32_t)(evt->total_energy * 1000.0f);
xSemaphoreGive(meter_mutex);
ESP_LOGD(TAG,
"Meter updated: power[W]={%" PRIu32 ",%" PRIu32 ",%" PRIu32 "}, "
"voltage[V]={%.2f,%.2f,%.2f}, "
"current[A]={%.2f,%.2f,%.2f}, "
"total_energy=%" PRIu32 "Wh",
meter_data.power_watts[0], meter_data.power_watts[1], meter_data.power_watts[2],
meter_data.voltage[0], meter_data.voltage[1], meter_data.voltage[2],
meter_data.current[0], meter_data.current[1], meter_data.current[2],
meter_data.energy_wh
);
}
void evse_meter_init(void) {
meter_mutex = xSemaphoreCreateMutex();
ESP_ERROR_CHECK(meter_mutex ? ESP_OK : ESP_FAIL);
ESP_ERROR_CHECK(esp_event_handler_register(
METER_EVENT, METER_EVENT_DATA_READY,
on_meter_event_dispatcher, NULL));
memset(&meter_data, 0, sizeof(meter_data));
ESP_LOGI(TAG, "EVSE Meter listener registered.");
}
uint32_t evse_meter_get_instant_power(void) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
uint32_t sum = 0;
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
sum += meter_data.power_watts[i];
}
xSemaphoreGive(meter_mutex);
return sum;
}
uint32_t evse_meter_get_total_energy(void) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
uint32_t val = meter_data.energy_wh;
xSemaphoreGive(meter_mutex);
return val;
}
void evse_meter_get_power(uint32_t power[EVSE_METER_PHASE_COUNT]) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
power[i] = meter_data.power_watts[i];
}
xSemaphoreGive(meter_mutex);
}
void evse_meter_get_voltage(float voltage[EVSE_METER_PHASE_COUNT]) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
voltage[i] = meter_data.voltage[i];
}
xSemaphoreGive(meter_mutex);
}
void evse_meter_get_current(float current[EVSE_METER_PHASE_COUNT]) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
current[i] = meter_data.current[i];
}
xSemaphoreGive(meter_mutex);
}

View File

@@ -10,7 +10,7 @@
#include "esp_rom_sys.h"
#include "evse_pilot.h"
#include "adc.h"
#include "adc121s021_dma.h"
#include "board_config.h"
#define PILOT_PWM_TIMER LEDC_TIMER_0
@@ -23,10 +23,24 @@
#define MAX_SAMPLE_ATTEMPTS 1000
#define PILOT_EXTREME_PERCENT 10 // 10% superior e inferior
// ADC121S021 setup
#define ADC121_VREF_MV 3300 // AJUSTE conforme Vref do seu hardware!
#define ADC121_MAX 4095 // 12 bits
static const char *TAG = "evse_pilot";
// Memoização de estado para evitar comandos/logs desnecessários
static int last_pilot_level = -1;
static uint32_t last_pwm_duty = 0;
// Função para converter leitura bruta do ADC para mV
static int adc_raw_to_mv(uint16_t raw) {
return (raw * ADC121_VREF_MV) / ADC121_MAX;
}
void pilot_init(void)
{
// PWM (LEDC) configuração
ledc_timer_config_t ledc_timer = {
.speed_mode = PILOT_PWM_SPEED_MODE,
.timer_num = PILOT_PWM_TIMER,
@@ -47,27 +61,24 @@ void pilot_init(void)
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
ESP_ERROR_CHECK(ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, 0));
ESP_ERROR_CHECK(ledc_fade_func_install(0));
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.pilot_adc_channel, &config));
// Inicializa ADC121S021 externo
adc121s021_dma_init();
}
void pilot_set_level(bool level)
{
if (last_pilot_level == level) return; // só muda se necessário
last_pilot_level = level;
ESP_LOGI(TAG, "Set level %d", level);
ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, level ? 1 : 0);
last_pwm_duty = 0; // PWM parado
}
void pilot_set_amps(uint16_t amps)
{
ESP_LOGI(TAG, "Set amps %d", amps);
if (amps < 60 || amps > 800) {
ESP_LOGE(TAG, "Invalid ampere value: %d A*10", amps);
return;
@@ -79,14 +90,17 @@ void pilot_set_amps(uint16_t amps)
} else {
duty = ((PILOT_PWM_MAX_DUTY * amps) / 2500) + (64 * (PILOT_PWM_MAX_DUTY / 100));
}
if (duty > PILOT_PWM_MAX_DUTY) duty = PILOT_PWM_MAX_DUTY;
if (duty > PILOT_PWM_MAX_DUTY)
duty = PILOT_PWM_MAX_DUTY;
if (last_pilot_level == 0 && last_pwm_duty == duty) return;
last_pilot_level = 0;
last_pwm_duty = duty;
ESP_LOGI(TAG, "Set amp %dA*10 -> duty %lu/%d", amps, duty, PILOT_PWM_MAX_DUTY);
ledc_set_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, duty);
ledc_update_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL);
}
static int compare_int(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
@@ -94,10 +108,8 @@ static int compare_int(const void *a, const void *b) {
static int select_low_median_qsort(int *src, int n, int percent) {
int k = (n * percent) / 100;
if (k == 0) k = 1;
int *copy = alloca(n * sizeof(int));
memcpy(copy, src, n * sizeof(int));
qsort(copy, n, sizeof(int), compare_int);
return copy[k / 2];
}
@@ -105,10 +117,8 @@ static int select_low_median_qsort(int *src, int n, int percent) {
static int select_high_median_qsort(int *src, int n, int percent) {
int k = (n * percent) / 100;
if (k == 0) k = 1;
int *copy = alloca(n * sizeof(int));
memcpy(copy, src, n * sizeof(int));
qsort(copy, n, sizeof(int), compare_int);
return copy[n - k + (k / 2)];
}
@@ -119,11 +129,13 @@ void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12)
int samples[NUM_PILOT_SAMPLES];
int collected = 0, attempts = 0;
int sample;
uint16_t adc_sample = 0;
// Lê samples usando ADC121S021 externo
while (collected < NUM_PILOT_SAMPLES && attempts < MAX_SAMPLE_ATTEMPTS) {
if (adc_oneshot_read(adc_handle, board_config.pilot_adc_channel, &sample) == ESP_OK) {
samples[collected++] = sample;
adc_sample = 0;
if (adc121s021_dma_get_sample(&adc_sample)) {
samples[collected++] = adc_sample;
esp_rom_delay_us(10);
} else {
esp_rom_delay_us(100);
@@ -141,20 +153,10 @@ void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12)
int high_raw = select_high_median_qsort(samples, collected, PILOT_EXTREME_PERCENT);
int low_raw = select_low_median_qsort(samples, collected, PILOT_EXTREME_PERCENT);
int high_mv = adc_raw_to_mv(high_raw);
int low_mv = adc_raw_to_mv(low_raw);
ESP_LOGD(TAG, "Final: high_raw=%d, low_raw=%d", high_raw, low_raw);
int high_mv = 0;
int low_mv = 0;
if (adc_cali_raw_to_voltage(adc_cali_handle, high_raw, &high_mv) != ESP_OK ||
adc_cali_raw_to_voltage(adc_cali_handle, low_raw, &low_mv) != ESP_OK) {
ESP_LOGW(TAG, "ADC calibration failed");
*up_voltage = PILOT_VOLTAGE_1;
*down_voltage_n12 = false;
return;
}
// Aplica thresholds definidos em board_config (em mV)
if (high_mv >= board_config.pilot_down_threshold_12)
*up_voltage = PILOT_VOLTAGE_12;
else if (high_mv >= board_config.pilot_down_threshold_9)

View File

@@ -46,9 +46,14 @@ void evse_set_state(evse_state_t state) {
current_state = state;
changed = true;
// When entering a charging state, record the start tick
if (evse_state_is_charging(state) && !evse_state_is_charging(previous_state)) {
session_start_tick = xTaskGetTickCount();
}
// When exiting a charging state, reset the start tick
else if (!evse_state_is_charging(state) && evse_state_is_charging(previous_state)) {
session_start_tick = 0;
}
}
portEXIT_CRITICAL(&state_mux);
@@ -60,7 +65,11 @@ void evse_set_state(evse_state_t state) {
evse_state_event_data_t evt = {
.state = map_state_to_event(state)
};
esp_event_post(EVSE_EVENTS, EVSE_EVENT_STATE_CHANGED, &evt, sizeof(evt), portMAX_DELAY);
esp_event_post(EVSE_EVENTS,
EVSE_EVENT_STATE_CHANGED,
&evt,
sizeof(evt),
portMAX_DELAY);
}
}

View File

@@ -3,73 +3,77 @@
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "evse_state.h" // Define evse_state_t
#include "evse_state.h" // Tipos e estados
#include "freertos/FreeRTOS.h"
// Inicialização
void evse_init(void);
void evse_process(void);
#ifdef __cplusplus
extern "C" {
#endif
// Estado
// ===============================
// Core EVSE State
// ===============================
/**
* @brief Get current EVSE state (e.g., A, B1, C2).
*/
evse_state_t evse_get_state(void);
const char* evse_state_to_str(evse_state_t state);
bool evse_is_connector_plugged(evse_state_t state);
/**
* @brief Set the EVSE state (e.g., called by FSM or hardware layer).
*/
void evse_set_state(evse_state_t state);
/**
* @brief Get timestamp when the current session started (for timing limits).
*/
TickType_t evse_get_session_start(void);
// ===============================
// Charging Session Info
// ===============================
/**
* @brief Returns true if the EV is charging (C1 or C2).
*/
bool evse_state_is_charging(evse_state_t state);
/**
* @brief Returns true if the EV is connected (plugged).
*/
bool evse_state_is_plugged(evse_state_t state);
/**
* @brief Returns true if a charging session is active (B2, C1, C2).
*/
bool evse_state_is_session(evse_state_t state);
// ===============================
// Authorization
// ===============================
/**
* @brief Set whether the vehicle is authorized to charge.
*/
void evse_state_set_authorized(bool authorized);
/**
* @brief Get current authorization status.
*/
bool evse_state_get_authorized(void);
// ===============================
// Limit Status
// ===============================
/**
* @brief Returns true if any runtime charging limit has been reached.
*/
bool evse_is_limit_reached(void);
// Autorização e disponibilidade
bool evse_is_enabled(void);
void evse_set_enabled(bool value);
bool evse_is_available(void);
void evse_set_available(bool value);
bool evse_is_require_auth(void);
void evse_set_require_auth(bool value);
// Corrente
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);
uint8_t evse_get_max_charging_current(void);
esp_err_t evse_set_max_charging_current(uint8_t value);
// Temperatura
uint8_t evse_get_temp_threshold(void);
esp_err_t evse_set_temp_threshold(uint8_t value);
// RCM / Socket
bool evse_get_socket_outlet(void);
esp_err_t evse_set_socket_outlet(bool value);
bool evse_is_rcm(void);
esp_err_t evse_set_rcm(bool value);
// Limites
uint32_t evse_get_consumption_limit(void);
void evse_set_consumption_limit(uint32_t value);
uint32_t evse_get_charging_time_limit(void);
void evse_set_charging_time_limit(uint32_t value);
uint16_t evse_get_under_power_limit(void);
void evse_set_under_power_limit(uint16_t value);
void evse_set_limit_reached(bool value);
// Energia total acumulada da sessão (em Wh)
uint32_t evse_get_total_energy(void);
// Potência instantânea medida (em W)
uint32_t evse_get_instant_power(void);
// Limites default
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);
uint32_t evse_get_total_energy(void);
uint32_t evse_get_instant_power(void);
#ifdef __cplusplus
}
#endif
#endif // EVSE_API_H

View File

@@ -0,0 +1,17 @@
#ifndef EVSE_CORE_H
#define EVSE_CORE_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initializes the EVSE system and starts core task loop.
*/
void evse_init(void);
#ifdef __cplusplus
}
#endif
#endif // EVSE_CORE_H

View File

@@ -9,47 +9,58 @@
extern "C" {
#endif
// ========================
// Limit state control
// ========================
// ============================
// Limit Status & Evaluation
// ============================
/**
* @brief Sets the 'limit reached' flag. Used internally when a session exceeds defined thresholds.
* @brief Sets the internal 'limit reached' flag.
* Called internally when a limit condition is triggered.
*/
void evse_set_limit_reached(bool value);
/**
* @brief Returns whether any session limit has been reached (energy, time or power).
* @brief Returns true if any runtime charging limit has been reached.
*/
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.
* @brief Checks if any session limit has been exceeded (energy, time or power).
* Should be called periodically during charging.
*/
void evse_limits_check(void);
// ========================
// Runtime limit configuration
// ========================
// ============================
// Runtime Limit Configuration
// ============================
/**
* @brief Get/set energy consumption limit (in Wh).
*/
uint32_t evse_get_consumption_limit(void);
void evse_set_consumption_limit(uint32_t value); // in Wh
void evse_set_consumption_limit(uint32_t value);
/**
* @brief Get/set maximum charging time (in seconds).
*/
uint32_t evse_get_charging_time_limit(void);
void evse_set_charging_time_limit(uint32_t value); // in seconds
void evse_set_charging_time_limit(uint32_t value);
/**
* @brief Get/set minimum acceptable power level (in Watts).
* If the power remains below this for a long time, the session may be interrupted.
*/
uint16_t evse_get_under_power_limit(void);
void evse_set_under_power_limit(uint16_t value); // in Watts
void evse_set_under_power_limit(uint16_t value);
// ========================
// Default (persistent) limits
// ========================
// ============================
// Default (Persistent) Limits
// ============================
/**
* @brief Default values used after system boot or reset.
* These can be restored from NVS or fallback values.
*/
uint32_t evse_get_default_consumption_limit(void);
void evse_set_default_consumption_limit(uint32_t value);

View File

@@ -26,38 +26,6 @@ void evse_manager_init(void);
*/
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

View File

@@ -0,0 +1,37 @@
#ifndef EVSE_METER_H
#define EVSE_METER_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define EVSE_METER_PHASE_COUNT 3
/// Inicializa o módulo EVSE Meter e registra os tratadores de eventos
void evse_meter_init(void);
/// Retorna a potência instantânea (soma das 3 fases, em watts)
uint32_t evse_meter_get_instant_power(void);
/// Retorna a energia total acumulada (em Wh)
uint32_t evse_meter_get_total_energy(void);
/// Retorna as potências instantâneas nas fases L1, L2 e L3 (em watts)
void evse_meter_get_power(uint32_t power[EVSE_METER_PHASE_COUNT]);
/// Retorna as tensões medidas nas fases L1, L2 e L3 (em volts)
void evse_meter_get_voltage(float voltage[EVSE_METER_PHASE_COUNT]);
/// Retorna as correntes medidas nas fases L1, L2 e L3 (em amperes)
void evse_meter_get_current(float current[EVSE_METER_PHASE_COUNT]);
/// Handler interno para eventos do medidor (não chamar externamente)
void evse_meter_on_meter_event(void* arg, void* event_data);
#ifdef __cplusplus
}
#endif
#endif // EVSE_METER_H

View File

@@ -5,6 +5,10 @@
#include "freertos/FreeRTOS.h"
#include "evse_events.h"
#ifdef __cplusplus
extern "C" {
#endif
// ============================
// EVSE Pilot Signal States
// ============================
@@ -22,21 +26,21 @@ typedef enum {
} evse_state_t;
// ============================
// Initialization & Core Control
// Initialization
// ============================
/**
* @brief Initializes the EVSE state machine.
* @brief Initializes the EVSE state machine and default state.
*/
void evse_state_init(void);
/**
* @brief Periodic tick function for the state machine.
* @brief Periodic tick for state handling (optional hook).
*/
void evse_state_tick(void);
// ============================
// State Access
// State Access & Control
// ============================
/**
@@ -45,51 +49,55 @@ void evse_state_tick(void);
evse_state_t evse_get_state(void);
/**
* @brief Updates the current EVSE state and triggers events.
* @brief Sets the current EVSE state and emits a change event if needed.
*/
void evse_set_state(evse_state_t state);
/**
* @brief Returns the tick count when charging session started.
* @brief Returns the tick count when the current charging session began.
*/
TickType_t evse_get_session_start(void);
/**
* @brief Converts the state enum to a human-readable string.
* @brief Converts the state enum into a human-readable string.
*/
const char* evse_state_to_str(evse_state_t state);
// ============================
// State Evaluators
// State Evaluation Helpers
// ============================
/**
* @brief Returns true if the state represents an active session (B2, C1, C2).
* @brief True if EV is in 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).
* @brief True if EV is actively charging (C1, C2).
*/
bool evse_state_is_charging(evse_state_t state);
/**
* @brief Returns true if the vehicle is plugged in.
* @brief True if EV is physically plugged in (B1 and beyond).
*/
bool evse_state_is_plugged(evse_state_t state);
// ============================
// Authorization
// Authorization Control
// ============================
/**
* @brief Sets the vehicle authorization state.
* @brief Sets whether the EV is authorized to charge.
*/
void evse_state_set_authorized(bool authorized);
/**
* @brief Returns the current vehicle authorization state.
* @brief Gets whether the EV is currently authorized.
*/
bool evse_state_get_authorized(void);
#ifdef __cplusplus
}
#endif
#endif // EVSE_STATE_H

View File

@@ -22,4 +22,4 @@ set(includes
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${includes}"
PRIV_REQUIRES nvs_flash
REQUIRES esp_event esp-modbus)
REQUIRES esp_event esp-modbus spi_bus_manager)

View File

@@ -1,186 +1,184 @@
#include <stdio.h>
#include <stdlib.h>
#include "driver/spi_master.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "ade7758.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_rom_sys.h"
spi_bus_config_t _spi_bus_cfg;
// spi_device_interface_config_t _spi_interface_cfg;
spi_device_handle_t _handle;
spi_host_device_t _spi_peripheral;
spi_transaction_t _spi_transaction;
esp_err_t transferByte(const uint8_t reg_addr, const uint8_t data, const uint8_t command)
{
_spi_transaction.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
_spi_transaction.length = 8;
//_spi_transaction.rxlength = 8;
_spi_transaction.cmd = command;
_spi_transaction.addr = reg_addr;
_spi_transaction.tx_data[0] = data;
#define PIN_ADUM_EN 4 // ou o pino real conectado ao VE1 do ADUM1401
return spi_device_transmit(_handle, &_spi_transaction);
static const char *TAG = "ade7758";
// --- SPI internals ---
static spi_device_handle_t ade7758_spi_handle = NULL;
static spi_host_device_t spi_host = SPI2_HOST; // default
static spi_transaction_t spi_transaction;
// --- Configuração SPI do dispositivo ---
static const uint8_t MODE = 2;
static const uint8_t ADDR_BITS = 7;
static const uint8_t CMD_BITS = 1;
static const uint8_t SPI_WRITE = 1;
static const uint8_t SPI_READ = 0;
static const int BUS_SPEED_HZ = 1000000;
static void adum1401_select(void) {
gpio_set_level(PIN_ADUM_EN, 1);
esp_rom_delay_us(2); // curto delay para estabilização
}
esp_err_t transferMultiplesBytes(const uint8_t reg_addr, uint8_t *tx_buf, uint8_t *rx_buf, size_t data_length, const uint8_t command)
{
spi_transaction_t spi_transaction_multibyte; // spi_transaction_t to use the tx and rx buffers
if (data_length < 1)
{
data_length = 1;
}
spi_transaction_multibyte.flags = 0; // SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
spi_transaction_multibyte.length = (8 * data_length);
spi_transaction_multibyte.rxlength = 0;
spi_transaction_multibyte.cmd = command;
spi_transaction_multibyte.addr = reg_addr;
spi_transaction_multibyte.tx_buffer = tx_buf;
spi_transaction_multibyte.rx_buffer = rx_buf;
return spi_device_transmit(_handle, &spi_transaction_multibyte);
static void adum1401_deselect(void) {
esp_rom_delay_us(2); // opcional: aguarde para evitar glitch
gpio_set_level(PIN_ADUM_EN, 0);
}
esp_err_t Init(const spi_host_device_t spi_peripheral, const int pin_miso, const int pin_mosi, const int pin_sclk)
{
esp_err_t status = ESP_OK;
// === Transações básicas ===
_spi_peripheral = spi_peripheral;
static esp_err_t transfer_byte(uint8_t reg_addr, uint8_t data, uint8_t command) {
adum1401_select();
_spi_transaction.tx_buffer = NULL;
_spi_transaction.rx_buffer = NULL;
spi_transaction.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
spi_transaction.length = 8;
spi_transaction.cmd = command;
spi_transaction.addr = reg_addr;
spi_transaction.tx_data[0] = data;
_spi_bus_cfg.mosi_io_num = pin_mosi;
_spi_bus_cfg.miso_io_num = pin_miso;
_spi_bus_cfg.sclk_io_num = pin_sclk;
_spi_bus_cfg.quadwp_io_num = -1;
_spi_bus_cfg.quadhd_io_num = -1;
esp_err_t err = spi_device_transmit(ade7758_spi_handle, &spi_transaction);
status |= spi_bus_initialize(spi_peripheral, &_spi_bus_cfg, SPI_DMA_CH_AUTO);
return status;
adum1401_deselect();
return err;
}
esp_err_t RegisterDevice(const uint8_t mode, const int ss, const int addr_length, const int command_length, const int bus_speed)
{
esp_err_t status = ESP_OK;
spi_device_interface_config_t _spi_interface_cfg = {
.command_bits = command_length,
.address_bits = addr_length,
.mode = mode,
.clock_speed_hz = bus_speed,
.spics_io_num = ss,
static esp_err_t transfer_bytes(uint8_t reg_addr, uint8_t *tx_buf, uint8_t *rx_buf, size_t len, uint8_t command) {
if (len < 1) len = 1;
spi_transaction_t t = {
.flags = 0,
.length = 8 * len,
.cmd = command,
.addr = reg_addr,
.tx_buffer = tx_buf,
.rx_buffer = rx_buf
};
adum1401_select();
esp_err_t err = spi_device_transmit(ade7758_spi_handle, &t);
adum1401_deselect();
return err;
}
// === Interface pública ===
esp_err_t Init(spi_host_device_t host, int pin_miso, int pin_mosi, int pin_sclk) {
// Essa função não inicializa o barramento SPI
// Apenas armazena os parâmetros
spi_host = host;
return ESP_OK;
}
esp_err_t InitSpi(int cs_gpio) {
spi_device_interface_config_t devcfg = {
.command_bits = CMD_BITS,
.address_bits = ADDR_BITS,
.mode = MODE,
.clock_speed_hz = BUS_SPEED_HZ,
.spics_io_num = cs_gpio,
.queue_size = 5,
};
status |= spi_bus_add_device(_spi_peripheral, &_spi_interface_cfg, &_handle);
gpio_config_t io_conf = {
.pin_bit_mask = BIT64(PIN_ADUM_EN),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&io_conf);
gpio_set_level(PIN_ADUM_EN, 0); // inicialmente desativado
return status;
return spi_bus_add_device(spi_host, &devcfg, &ade7758_spi_handle);
}
uint8_t ReadRegister(const uint8_t reg_addr, const uint8_t command)
{
transferByte(reg_addr, 0, command);
return _spi_transaction.rx_data[0];
spi_device_handle_t GetHandle(void) {
return ade7758_spi_handle;
}
esp_err_t WriteRegister(const uint8_t reg_addr, const uint8_t reg_data, const uint8_t command)
{
esp_err_t status = ESP_OK;
// === Registro de acesso ===
status |= transferByte(reg_addr, reg_data, command);
return status;
uint8_t ReadRegister(uint8_t reg_addr, uint8_t command) {
transfer_byte(reg_addr, 0, command);
return spi_transaction.rx_data[0];
}
esp_err_t WriteRegisterMultipleBytes(const uint8_t reg_addr, uint8_t *reg_data_buffer, const uint8_t byte_count, const uint8_t command)
{
return transferMultiplesBytes(reg_addr, reg_data_buffer, NULL, byte_count, command);
esp_err_t WriteRegister(uint8_t reg_addr, uint8_t data, uint8_t command) {
return transfer_byte(reg_addr, data, command);
}
esp_err_t ReadRegisterMultipleBytes(const uint8_t reg_addr, uint8_t *reg_data_buffer, const uint8_t byte_count, const uint8_t command)
{
return transferMultiplesBytes(reg_addr, NULL, reg_data_buffer, byte_count, command);
esp_err_t WriteRegisterMultipleBytes(uint8_t reg, uint8_t *data, uint8_t count, uint8_t command) {
return transfer_bytes(reg, data, NULL, count, command);
}
spi_device_handle_t GetHandle(void)
{
return _handle;
esp_err_t ReadRegisterMultipleBytes(uint8_t reg, uint8_t *buf, uint8_t count, uint8_t command) {
return transfer_bytes(reg, NULL, buf, count, command);
}
static uint8_t MODE = 2;
static uint8_t ADDR_BITS = 7;
static uint8_t CMD_BITS = 1;
// === Leitura e escrita de tamanho fixo ===
static uint8_t SPI_WRITE = 1;
static uint8_t SPI_READ = 0;
static int BUSSPEED = 1000000;
// static const char TAG[] = "ade7758";
esp_err_t write8(uint8_t reg, uint8_t value)
{
esp_err_t write8(uint8_t reg, uint8_t value) {
return WriteRegister(reg, value, SPI_WRITE);
}
esp_err_t write16(uint8_t reg, uint32_t value)
{
uint8_t buff[2];
buff[0] = (value >> 8) & 0xFF;
buff[1] = (value >> 0) & 0xFF;
return WriteRegisterMultipleBytes(reg, buff, 3, SPI_WRITE);
esp_err_t write16(uint8_t reg, uint32_t value) {
uint8_t buf[2] = {
(value >> 8) & 0xFF,
(value >> 0) & 0xFF
};
return WriteRegisterMultipleBytes(reg, buf, 2, SPI_WRITE);
}
esp_err_t write24(uint8_t reg, uint32_t value)
{
uint8_t buff[2];
buff[0] = (value >> 16) & 0xFF;
buff[1] = (value >> 8) & 0xFF;
buff[2] = (value >> 0) & 0xFF;
return WriteRegisterMultipleBytes(reg, buff, 4, SPI_WRITE);
esp_err_t write24(uint8_t reg, uint32_t value) {
uint8_t buf[3] = {
(value >> 16) & 0xFF,
(value >> 8) & 0xFF,
(value >> 0) & 0xFF
};
return WriteRegisterMultipleBytes(reg, buf, 3, SPI_WRITE);
}
uint8_t read8(const uint8_t reg)
{
uint8_t buff[1];
ReadRegisterMultipleBytes(reg, buff, 2, SPI_READ);
return buff[0];
uint8_t read8(uint8_t reg) {
uint8_t buf[1];
ReadRegisterMultipleBytes(reg, buf, 1, SPI_READ);
return buf[0];
}
uint32_t read16(const uint8_t reg)
{
uint8_t buff[2];
ReadRegisterMultipleBytes(reg, buff, 3, SPI_READ);
return buff[0] << 8 | buff[1];
uint32_t read16(uint8_t reg) {
uint8_t buf[2];
ReadRegisterMultipleBytes(reg, buf, 2, SPI_READ);
return (buf[0] << 8) | buf[1];
}
uint32_t read24(const uint8_t reg)
{
uint8_t buff[3];
ReadRegisterMultipleBytes(reg, buff, 4, SPI_READ);
return buff[0] << 16 | buff[1] << 8 | buff[2];
uint32_t read24(uint8_t reg) {
uint8_t buf[3];
ReadRegisterMultipleBytes(reg, buf, 3, SPI_READ);
return (buf[0] << 16) | (buf[1] << 8) | buf[2];
}
esp_err_t readBlockData(const uint8_t reg, uint8_t *buf, const int length)
{
return ReadRegisterMultipleBytes(reg, buf, length, SPI_READ);
esp_err_t readBlockData(uint8_t reg, uint8_t *buf, int len) {
return ReadRegisterMultipleBytes(reg, buf, len, SPI_READ);
}
esp_err_t InitSpi(const int ss)
{
return RegisterDevice(MODE, ss, ADDR_BITS, CMD_BITS, BUSSPEED);
}
/*****************************
*

View File

@@ -1,4 +1,5 @@
#include "meter_ade7758.h"
#include "spi_bus_manager.h"
#include "ade7758.h"
#include "meter_events.h"
@@ -11,16 +12,13 @@
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#define TAG "meter_ade7758"
// === Configurações de hardware ===
#define PIN_NUM_CLK 15
#define PIN_NUM_MOSI 2
#define PIN_NUM_MISO 4
#define PIN_NUM_CS 23
#define EEPROM_HOST HSPI_HOST
// === Pinos ===
#define PIN_NUM_CS 15
#define PIN_ADUM_EN 4
// === Constantes de calibração ===
#define VRMS_CAL 4732.78f
@@ -28,13 +26,13 @@
#define METER_READ_INTERVAL_MS 5000
// === Dados internos ===
// === Estrutura interna ===
typedef struct {
float vrms[3];
float irms[3];
int watt[3];
int var[3]; // reservados
int va[3]; // reservados
int var[3]; // reservado
int va[3]; // reservado
} meter_ade7758_internal_data_t;
static meter_ade7758_internal_data_t meter_data;
@@ -42,7 +40,8 @@ static TaskHandle_t meter_task = NULL;
static SemaphoreHandle_t meter_mutex = NULL;
static uint32_t meter_watchdog_counter = 0;
// === Utilitários internos ===
// === Post de evento ===
static void meter_ade7758_post_event(const meter_ade7758_internal_data_t *data) {
meter_event_data_t evt = {
.frequency = 0,
@@ -54,22 +53,23 @@ static void meter_ade7758_post_event(const meter_ade7758_internal_data_t *data)
memcpy(evt.irms, data->irms, sizeof(evt.irms));
memcpy(evt.watt, data->watt, sizeof(evt.watt));
esp_err_t err = esp_event_post(METER_EVENT, METER_EVENT_DATA_READY,
&evt, sizeof(evt), pdMS_TO_TICKS(10));
esp_err_t err = esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, &evt, sizeof(evt), pdMS_TO_TICKS(10));
if (err != ESP_OK) {
ESP_LOGW(TAG, "Falha ao emitir evento: %s", esp_err_to_name(err));
}
}
// === Task de leitura ===
static void meter_ade7758_task_func(void *param) {
ESP_LOGI(TAG, "Meter task started");
ESP_LOGI(TAG, "Tarefa de medição ADE7758 iniciada");
meter_ade7758_internal_data_t previous = {0};
while (true) {
meter_ade7758_internal_data_t meterData = {0};
//ESP_LOGI(TAG, "Tarefa de medição ADE7758 iniciada %d",getVersion());
meterData.vrms[0] = avrms() / VRMS_CAL;
meterData.vrms[1] = bvrms() / VRMS_CAL;
meterData.vrms[2] = cvrms() / VRMS_CAL;
@@ -97,10 +97,9 @@ static void meter_ade7758_task_func(void *param) {
}
}
// === Interface pública: controle ===
// === Inicialização ===
esp_err_t meter_ade7758_init(void) {
ESP_LOGI(TAG, "Inicializando medidor ADE7758...");
ESP_LOGI(TAG, "Inicializando ADE7758...");
if (!meter_mutex) {
meter_mutex = xSemaphoreCreateMutex();
@@ -110,21 +109,38 @@ esp_err_t meter_ade7758_init(void) {
}
}
esp_err_t err = Init(EEPROM_HOST, PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CLK);
if (!spi_bus_manager_is_initialized()) {
esp_err_t err = spi_bus_manager_init(); // usa pinos padrão
if (err != ESP_OK) {
ESP_LOGE(TAG, "Erro ao inicializar SPI (%d)", err);
ESP_LOGE(TAG, "Erro ao inicializar SPI: %s", esp_err_to_name(err));
return err;
}
}
vTaskDelay(pdMS_TO_TICKS(10)); // Delay de estabilização
esp_err_t err = Init(spi_bus_manager_get_host(), -1, -1, -1);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Erro Init SPI ADE7758: %s", esp_err_to_name(err));
return err;
}
err = InitSpi(PIN_NUM_CS);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Erro ao registrar dispositivo SPI: %s", esp_err_to_name(err));
return err;
}
InitSpi(PIN_NUM_CS);
gainSetup(INTEGRATOR_OFF, FULLSCALESELECT_0_5V, GAIN_1, GAIN_1);
setupDivs(1, 1, 1);
setLcycMode(0x00);
resetStatus();
ESP_LOGI(TAG, "ADE7758 inicializado com sucesso.");
return ESP_OK;
}
// === Execução ===
esp_err_t meter_ade7758_start(void) {
if (meter_task) return ESP_ERR_INVALID_STATE;

View File

@@ -165,7 +165,7 @@ void wifi_ini(void)
char chargeid[6];
uint8_t mac[6];
esp_wifi_get_mac(ESP_IF_WIFI_AP, mac);
sprintf((char *)chargeid, MDNS_SSID, mac[5]);
sprintf((char *)chargeid, MDNS_SSID, 0);
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set(chargeid));
@@ -188,7 +188,9 @@ esp_netif_t *wifi_get_ap_netif(void)
esp_err_t wifi_set_config(bool enabled, const char *ssid, const char *password)
{
ESP_LOGI(TAG, "Wifi set config");
ESP_LOGI(TAG, "wifi_set_config(enabled=%d, ssid=\"%s\")", enabled, ssid?:"<nil>");
if (enabled)
{

View File

@@ -1,143 +0,0 @@
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_mac.h"
#include "nvs.h"
#include "mdns.h"
#include "wifi.h"
#include "nvs_flash.h"
#include <string.h>
#define WIFI_STORAGE_NAMESPACE "wifi_config"
#define TAG "wifi"
#define AP_SSID "plx-%02x%02x%02x"
#define MDNS_HOSTNAME "plx%02x"
#define NVS_NAMESPACE "wifi"
static nvs_handle_t nvs;
static esp_netif_t *ap_netif;
EventGroupHandle_t wifi_event_group;
//
// Event handler para modo AP
//
static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
if (event_base == WIFI_EVENT) {
switch (event_id) {
case WIFI_EVENT_AP_STACONNECTED: {
wifi_event_ap_staconnected_t *event = event_data;
ESP_LOGI(TAG, "STA " MACSTR " conectou, AID=%d", MAC2STR(event->mac), event->aid);
xEventGroupSetBits(wifi_event_group, WIFI_AP_CONNECTED_BIT);
break;
}
case WIFI_EVENT_AP_STADISCONNECTED: {
wifi_event_ap_stadisconnected_t *event = event_data;
ESP_LOGI(TAG, "STA " MACSTR " desconectou, AID=%d", MAC2STR(event->mac), event->aid);
xEventGroupClearBits(wifi_event_group, WIFI_AP_CONNECTED_BIT);
break;
}
}
}
}
//
// Iniciar o AP com SSID baseado no MAC
//
void wifi_ap_start(void)
{
ESP_LOGI(TAG, "Iniciando AP");
ESP_ERROR_CHECK(esp_wifi_stop());
wifi_config_t ap_config = {
.ap = {
.ssid = "",
.ssid_len = 0,
.channel = 1,
.password = "",
.max_connection = 4,
.authmode = WIFI_AUTH_OPEN
}
};
uint8_t mac[6];
ESP_ERROR_CHECK(esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP));
snprintf((char *)ap_config.ap.ssid, sizeof(ap_config.ap.ssid), AP_SSID, mac[3], mac[4], mac[5]);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config));
ESP_ERROR_CHECK(esp_wifi_start());
xEventGroupSetBits(wifi_event_group, WIFI_AP_MODE_BIT);
}
//
// Inicializar Wi-Fi em modo AP
//
void wifi_ini(void)
{
ESP_LOGI(TAG, "Inicializando Wi-Fi (modo AP)");
ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs));
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
/*
if (!esp_event_loop_is_running()) {
ESP_ERROR_CHECK(esp_event_loop_create_default());
}*/
ap_netif = esp_netif_create_default_wifi_ap();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
uint8_t mac[6];
ESP_ERROR_CHECK(esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP));
char hostname[16];
snprintf(hostname, sizeof(hostname), MDNS_HOSTNAME, mac[5]);
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set(hostname));
ESP_ERROR_CHECK(mdns_instance_name_set("EVSE Controller"));
wifi_ap_start();
}
esp_netif_t *wifi_get_ap_netif(void)
{
return ap_netif;
}
esp_err_t wifi_set_config(bool enabled, const char *ssid, const char *password) {
return ESP_OK;
}
void wifi_get_ssid(char *value) {
// Your implementation here
}
void wifi_get_password(char *value) {
// Your implementation here
}
bool wifi_get_enabled(void)
{
return true;
}

View File

@@ -4,6 +4,7 @@
#include "evse_api.h"
#include "evse_error.h"
#include "evse_state.h"
#include "evse_config.h"
#include "esp_wifi.h"
#include "nvs.h"
@@ -48,10 +49,10 @@ static void ocpp_task_func(void *param)
mg_mgr_poll(&mgr, 10);
ocpp_loop();
if (evse_is_enabled() != ocpp_isOperative())
if (evse_config_is_enabled() != ocpp_isOperative())
{
printf("ocpp_isOperative()");
evse_set_enabled(ocpp_isOperative());
evse_config_set_enabled(ocpp_isOperative());
}
}
vTaskDelay(pdMS_TO_TICKS(500));
@@ -129,7 +130,7 @@ void ocpp_set_rfid(char *value)
bool setConnectorPluggedInput()
{
// ESP_LOGI(TAG, "setConnectorPluggedInput");
return evse_is_connector_plugged(evse_get_state());
return evse_state_is_plugged(evse_get_state());
// return true;
}
@@ -143,8 +144,8 @@ bool setEvReadyInput()
bool setEvseReadyInput()
{
// ESP_LOGI(TAG, "EvseReadyInput");
return evse_is_enabled();
// return false;
return evse_config_is_enabled();
//return false;
}
float setPowerMeterInput()

View File

@@ -18,4 +18,4 @@ set(srcs
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
PRIV_REQUIRES nvs_flash driver esp_adc esp_timer
REQUIRES config evse api ntc_driver)
REQUIRES config evse api ntc_driver spi_bus_manager)

View File

@@ -6,6 +6,9 @@
static const char* TAG = "ac_relay";
// Memoization do estado atual do relé (salvo em RAM)
static int last_state = -1;
/**
* @brief Initialize the AC relay GPIO.
*
@@ -16,7 +19,7 @@ void ac_relay_init(void)
gpio_config_t conf = {
.pin_bit_mask = BIT64(board_config.ac_relay_gpio),
.mode = GPIO_MODE_OUTPUT,
.pull_down_en = GPIO_PULLDOWN_DISABLE, ///< Disabled unless required
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
@@ -27,7 +30,8 @@ void ac_relay_init(void)
return;
}
gpio_set_level(board_config.ac_relay_gpio, false); ///< Ensure relay starts OFF
gpio_set_level(board_config.ac_relay_gpio, 0); ///< Ensure relay starts OFF
last_state = 0;
ESP_LOGI(TAG, "AC relay initialized. Pin: %d", board_config.ac_relay_gpio);
}
@@ -38,9 +42,15 @@ void ac_relay_init(void)
*/
void ac_relay_set_state(bool state)
{
if (state == last_state) {
// Estado não mudou; evita log e escrita desnecessária.
return;
}
last_state = state;
ESP_LOGI(TAG, "Setting AC relay state: Pin: %d, State: %d", board_config.ac_relay_gpio, state);
esp_err_t ret = gpio_set_level(board_config.ac_relay_gpio, state);
esp_err_t ret = gpio_set_level(board_config.ac_relay_gpio, state ? 1 : 0);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set GPIO level (error: %s)", esp_err_to_name(ret));
}
@@ -55,5 +65,5 @@ bool ac_relay_get_state(void)
{
int level = gpio_get_level(board_config.ac_relay_gpio);
ESP_LOGD(TAG, "Current AC relay state: Pin: %d, State: %d", board_config.ac_relay_gpio, level);
return level;
return (level != 0);
}

View File

@@ -1,53 +1,64 @@
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "adc121s021_dma.h"
#include "spi_bus_manager.h"
#define TAG "adc_dma"
#define PIN_NUM_MOSI 23
#define PIN_NUM_MISO 19
#define PIN_NUM_CLK 18
#define PIN_NUM_CS 5
#define SPI_HOST_USED SPI2_HOST
#define SAMPLE_SIZE_BYTES 2
#define ADC_BITS 12
#define SPI_CLOCK_HZ (6 * 1000 * 1000) // 6 MHz
static spi_device_handle_t adc_spi;
static spi_device_handle_t adc_spi = NULL;
void adc121s021_dma_init(void)
{
spi_bus_config_t buscfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = SAMPLE_SIZE_BYTES,
};
if (adc_spi) {
ESP_LOGW(TAG, "ADC121S021 já foi inicializado.");
return;
}
if (!spi_bus_manager_is_initialized()) {
ESP_LOGI(TAG, "SPI bus não inicializado. Inicializando...");
esp_err_t err = spi_bus_manager_init(); // 🔧 CORRIGIDO: sem argumentos
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha ao inicializar o SPI bus: %s", esp_err_to_name(err));
return;
}
}
spi_device_interface_config_t devcfg = {
.clock_speed_hz = 6000000, // 6 MHz
.clock_speed_hz = SPI_CLOCK_HZ,
.mode = 0,
.spics_io_num = PIN_NUM_CS,
.queue_size = 2,
.flags = SPI_DEVICE_NO_DUMMY,
.pre_cb = NULL,
.post_cb = NULL,
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI_HOST_USED, &buscfg, SPI_DMA_CH_AUTO));
ESP_ERROR_CHECK(spi_bus_add_device(SPI_HOST_USED, &devcfg, &adc_spi));
esp_err_t err = spi_bus_add_device(spi_bus_manager_get_host(), &devcfg, &adc_spi);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha ao registrar ADC121S021 no SPI: %s", esp_err_to_name(err));
return;
}
ESP_LOGI(TAG, "ADC121S021 registrado no SPI com sucesso.");
}
bool adc121s021_dma_get_sample(uint16_t *sample)
{
uint8_t tx_buffer[2] = {0x00, 0x00}; // Dummy TX
if (!adc_spi) {
ESP_LOGE(TAG, "ADC SPI não inicializado!");
return false;
}
uint8_t tx_buffer[2] = {0x00, 0x00}; // Dummy
uint8_t rx_buffer[2] = {0};
spi_transaction_t t = {
.length = 16, // 16 bits
.length = 16,
.tx_buffer = tx_buffer,
.rx_buffer = rx_buffer,
.flags = 0
@@ -55,12 +66,10 @@ bool adc121s021_dma_get_sample(uint16_t *sample)
esp_err_t err = spi_device_transmit(adc_spi, &t);
if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI transmit error: %s", esp_err_to_name(err));
ESP_LOGE(TAG, "Erro na transmissão SPI: %s", esp_err_to_name(err));
return false;
}
// Extrai os 12 bits significativos da resposta do ADC121S021
*sample = ((rx_buffer[0] << 8) | rx_buffer[1]) & 0x0FFF;
return true;
}

View File

@@ -91,7 +91,7 @@ static void buzzer_worker_task(void *arg) {
while (true) {
if (xQueueReceive(buzzer_queue, &pattern_id, portMAX_DELAY)) {
//buzzer_execute_pattern(pattern_id);
buzzer_execute_pattern(pattern_id);
}
}
}

View File

@@ -1,6 +1,5 @@
set(srcs
"src/protocols.c"
"src/rest.c"
"src/mqtt.c"
"src/date_time.c"
)

View File

@@ -1,14 +0,0 @@
#ifndef REST_H_
#define REST_H_
#include "esp_err.h"
/**
* @brief Initialize REST server
*
* @param base_path Path on the SPIFFS filesystem where static files reside
* @return ESP_OK on success, ESP_FAIL otherwise
*/
esp_err_t rest_init(const char *base_path);
#endif /* REST_H_ */

View File

@@ -31,31 +31,31 @@ static esp_err_t open_mqtt_nvs(nvs_handle_t *handle) {
static void subcribe_topics(void)
{
ESP_LOGI(TAG, "subcribe_topics");
ESP_LOGI(TAG, "[MQTT] Subscribing to topics");
char base[32];
mqtt_get_base_topic(base);
char topic[64];
mqtt_get_base_topic(topic);
strcat(topic, "/request/#");
snprintf(topic, sizeof(topic), "%s/request/#", base);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, "subscribed: %s", topic);
ESP_LOGI(TAG, " subscribed: %s", topic);
mqtt_get_base_topic(topic);
strcat(topic, "/set/config/#");
snprintf(topic, sizeof(topic), "%s/set/config/#", base);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, "subscribed: %s", topic);
ESP_LOGI(TAG, " subscribed: %s", topic);
mqtt_get_base_topic(topic);
strcat(topic, "/enable");
snprintf(topic, sizeof(topic), "%s/enable", base);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, "subscribed: %s", topic);
ESP_LOGI(TAG, " subscribed: %s", topic);
}
static void publish_message(const char* topic, cJSON* root)
{
char target_topic[64];
mqtt_get_base_topic(target_topic);
strcat(target_topic, topic);
strncat(target_topic, topic, sizeof(target_topic) - strlen(target_topic) - 1);
const char* json = cJSON_PrintUnformatted(root);
esp_mqtt_client_publish(client, target_topic, json, 0, 1, 0);
@@ -67,34 +67,51 @@ static void handle_message(const char* topic, const char* data)
char base_topic[32];
mqtt_get_base_topic(base_topic);
ESP_LOGI(TAG, "[MQTT] Message received");
ESP_LOGI(TAG, " > Topic: %s", topic);
ESP_LOGI(TAG, " > Payload: %s", data);
if (strncmp(topic, base_topic, strlen(base_topic)) == 0) {
const char* sub_topic = &topic[strlen(base_topic)];
ESP_LOGI(TAG, " > Subtopic detected: %s", sub_topic);
if (strcmp(sub_topic, "/request/config/evse") == 0) {
ESP_LOGI(TAG, " → Responding with EVSE configuration");
cJSON* root = json_get_evse_config();
publish_message("/response/config/evse", root);
cJSON_Delete(root);
} else {
ESP_LOGW(TAG, " ! Unknown command: %s", sub_topic);
}
// [Outros comandos omitidos para brevidade...]
} else {
ESP_LOGW(TAG, " ! Topic does not match base: %s", topic);
}
}
static void event_handler(void* handler_args, esp_event_base_t base, int32_t event_id, void* event_data)
{
esp_mqtt_event_handle_t event = event_data;
char topic[48], data[256];
switch (event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT conectado");
ESP_LOGI(TAG, "[MQTT] Connected to broker");
if (client_task) vTaskResume(client_task);
subcribe_topics();
break;
case MQTT_EVENT_DATA:
strncpy(topic, event->topic, MIN(event->topic_len, sizeof(topic)-1));
strncpy(data, event->data, MIN(event->data_len, sizeof(data)-1));
case MQTT_EVENT_DATA: {
char topic[64] = {0};
char data[256] = {0};
int tlen = MIN(event->topic_len, sizeof(topic) - 1);
int dlen = MIN(event->data_len, sizeof(data) - 1);
memcpy(topic, event->topic, tlen);
memcpy(data, event->data, dlen);
handle_message(topic, data);
break;
}
default:
break;
}

View File

@@ -1,907 +0,0 @@
/* HTTP Restful API Server
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <fcntl.h>
#include "esp_http_server.h"
#include "esp_chip_info.h"
#include "esp_random.h"
#include "esp_log.h"
#include "esp_vfs.h"
#include "cJSON.h"
#include "rest.h"
#include "evse_api.h"
#include "cJSON.h"
#include "esp_log.h"
#include "esp_http_server.h"
#include "auth.h"
static const char *REST_TAG = "esp-rest";
#define REST_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(REST_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
#define SCRATCH_BUFSIZE (10240)
typedef struct rest_server_context {
char base_path[ESP_VFS_PATH_MAX + 1];
char scratch[SCRATCH_BUFSIZE];
} rest_server_context_t;
#define CHECK_FILE_EXTENSION(filename, ext) (strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0)
// Estruturas para armazenar as configurações
static struct {
bool enabled;
char ssid[128];
char password[128];
} wifi_config = {false, "", ""};
static struct {
bool enabled;
char host[256];
int port;
char username[128];
char password[128];
char topic[128];
} mqtt_config = {false, "", 1883, "", "", ""};
// Estrutura para armazenar as configurações OCPP em memória
static struct {
char url[256];
char chargeBoxId[128];
char certificate[256];
char privateKey[256];
} ocpp_config = {"", "", "", ""};
// Estrutura para armazenar as configurações de energia
static struct {
int currentLimit;
int powerLimit;
int energyLimit;
int chargingTimeLimit;
int temperatureLimit;
} settings_config = {0, 0, 0, 0, 0};
static struct {
char username[128];
} users[10] = {{"admin"}, {"user1"}};
static int num_users = 2; // Contador de usuários cadastrados
// Set HTTP response content type according to file extension
static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath)
{
const char *type = "text/plain";
if (CHECK_FILE_EXTENSION(filepath, ".html")) {
type = "text/html";
} else if (CHECK_FILE_EXTENSION(filepath, ".js")) {
type = "application/javascript";
} else if (CHECK_FILE_EXTENSION(filepath, ".css")) {
type = "text/css";
} else if (CHECK_FILE_EXTENSION(filepath, ".png")) {
type = "image/png";
} else if (CHECK_FILE_EXTENSION(filepath, ".ico")) {
type = "image/x-icon";
} else if (CHECK_FILE_EXTENSION(filepath, ".svg")) {
type = "text/xml";
}
return httpd_resp_set_type(req, type);
}
/* Send HTTP response with the contents of the requested file */
static esp_err_t rest_common_get_handler(httpd_req_t *req)
{
char filepath[FILE_PATH_MAX];
rest_server_context_t *rest_context = (rest_server_context_t *)req->user_ctx;
strlcpy(filepath, rest_context->base_path, sizeof(filepath));
if (req->uri[strlen(req->uri) - 1] == '/') {
strlcat(filepath, "/index.html", sizeof(filepath));
} else {
strlcat(filepath, req->uri, sizeof(filepath));
}
int fd = open(filepath, O_RDONLY, 0);
if (fd == -1) {
ESP_LOGW(REST_TAG, "Failed to open file : %s, redirecting to index", filepath);
/* Try to serve index.html for SPA routing */
strlcpy(filepath, rest_context->base_path, sizeof(filepath));
strlcat(filepath, "/index.html", sizeof(filepath));
fd = open(filepath, O_RDONLY, 0);
if (fd == -1) {
ESP_LOGE(REST_TAG, "Failed to open index file : %s", filepath);
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File not found");
return ESP_FAIL;
}
}
set_content_type_from_file(req, filepath);
char *chunk = rest_context->scratch;
ssize_t read_bytes;
do {
/* Read file in chunks into the scratch buffer */
read_bytes = read(fd, chunk, SCRATCH_BUFSIZE);
if (read_bytes == -1) {
ESP_LOGE(REST_TAG, "Failed to read file : %s", filepath);
} else if (read_bytes > 0) {
/* Send the buffer contents as HTTP response chunk */
if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) {
close(fd);
ESP_LOGE(REST_TAG, "File sending failed!");
/* Abort sending file */
httpd_resp_sendstr_chunk(req, NULL);
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file");
return ESP_FAIL;
}
}
} while (read_bytes > 0);
/* Close file after sending complete */
close(fd);
ESP_LOGI(REST_TAG, "File sending complete");
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/config/electrical
static esp_err_t electrical_config_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com as configurações de rede elétrica
cJSON *config = cJSON_CreateObject();
cJSON *monitor = cJSON_CreateObject();
cJSON_AddStringToObject(monitor, "voltage", "230");
cJSON_AddStringToObject(monitor, "current", "10");
cJSON_AddStringToObject(monitor, "quality", "1");
cJSON_AddItemToObject(config, "monitor", monitor);
cJSON_AddBoolToObject(config, "alerts", true);
// Adicionar mais configurações (security, loadBalancing, solar) no objeto config
// ...
// Enviar a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberar memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint POST /api/v1/config/electrical
static esp_err_t electrical_config_post_handler(httpd_req_t *req)
{
char buf[512];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Request body is empty");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Processar os dados recebidos e atualizar as configurações (monitor, alerts, etc.)
// Exemplo de configuração:
cJSON *monitor = cJSON_GetObjectItem(json, "monitor");
if (monitor) {
// Atualizar configurações do monitor
// ...
}
// Atualizar outras configurações...
// Responder com sucesso
httpd_resp_sendstr(req, "Configuração gravada com sucesso!");
cJSON_Delete(json);
return ESP_OK;
}
// Manipulador para o endpoint /api/v1/config/load-balancing
static esp_err_t config_load_balancing_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON de configuração
cJSON *config = cJSON_CreateObject();
// Configuração de load balancing
cJSON_AddBoolToObject(config, "enabled", true); // Exemplo: load balancing ativado
cJSON_AddNumberToObject(config, "maxChargingCurrent", 32); // Exemplo: corrente máxima de 32A
// Lista de dispositivos disponíveis
cJSON *devices = cJSON_CreateArray();
cJSON_AddItemToArray(devices, cJSON_CreateString("Device 1")); // Exemplo de dispositivo
cJSON_AddItemToArray(devices, cJSON_CreateString("Device 2")); // Outro exemplo de dispositivo
cJSON_AddItemToObject(config, "devices", devices);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/ocpp (Status do OCPP)
static esp_err_t ocpp_status_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON de status
cJSON *status = cJSON_CreateObject();
cJSON_AddStringToObject(status, "status", "connected"); // Status de exemplo, você pode adaptar conforme sua lógica
// Convertendo para string e enviando a resposta
const char *status_str = cJSON_Print(status);
httpd_resp_sendstr(req, status_str);
// Liberando a memória
free((void *)status_str);
cJSON_Delete(status);
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/config/ocpp (Configuração OCPP)
static esp_err_t config_ocpp_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com as configurações do OCPP
cJSON *config = cJSON_CreateObject();
cJSON_AddStringToObject(config, "url", ocpp_config.url);
cJSON_AddStringToObject(config, "chargeBoxId", ocpp_config.chargeBoxId);
cJSON_AddStringToObject(config, "certificate", ocpp_config.certificate);
cJSON_AddStringToObject(config, "privateKey", ocpp_config.privateKey);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint POST /api/v1/config/ocpp (Salvar configuração OCPP)
static esp_err_t config_ocpp_post_handler(httpd_req_t *req)
{
char buf[512]; // Buffer para armazenar a requisição
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Atualizando as configurações OCPP
cJSON *url = cJSON_GetObjectItem(json, "url");
if (url) strlcpy(ocpp_config.url, url->valuestring, sizeof(ocpp_config.url));
cJSON *chargeBoxId = cJSON_GetObjectItem(json, "chargeBoxId");
if (chargeBoxId) strlcpy(ocpp_config.chargeBoxId, chargeBoxId->valuestring, sizeof(ocpp_config.chargeBoxId));
cJSON *certificate = cJSON_GetObjectItem(json, "certificate");
if (certificate) strlcpy(ocpp_config.certificate, certificate->valuestring, sizeof(ocpp_config.certificate));
cJSON *privateKey = cJSON_GetObjectItem(json, "privateKey");
if (privateKey) strlcpy(ocpp_config.privateKey, privateKey->valuestring, sizeof(ocpp_config.privateKey));
cJSON_Delete(json);
// Responder com uma mensagem de sucesso
httpd_resp_sendstr(req, "Configuração OCPP atualizada com sucesso");
return ESP_OK;
}
// Manipulador para o endpoint POST /api/v1/config/settings
static esp_err_t config_settings_post_handler(httpd_req_t *req)
{
char buf[512]; // Buffer para armazenar a requisição
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Atualizando as configurações
cJSON *currentLimit = cJSON_GetObjectItem(json, "currentLimit");
if (currentLimit)
evse_set_max_charging_current(currentLimit->valueint);
//settings_config.currentLimit = currentLimit->valueint;
cJSON *powerLimit = cJSON_GetObjectItem(json, "powerLimit");
if (powerLimit) settings_config.powerLimit = powerLimit->valueint;
cJSON *energyLimit = cJSON_GetObjectItem(json, "energyLimit");
if (energyLimit) settings_config.energyLimit = energyLimit->valueint;
cJSON *chargingTimeLimit = cJSON_GetObjectItem(json, "chargingTimeLimit");
if (chargingTimeLimit) settings_config.chargingTimeLimit = chargingTimeLimit->valueint;
cJSON *temperatureLimit = cJSON_GetObjectItem(json, "temperatureLimit");
if (temperatureLimit)
evse_set_temp_threshold(temperatureLimit->valueint);
//settings_config.temperatureLimit = temperatureLimit->valueint;
cJSON_Delete(json);
// Responder com uma mensagem de sucesso
httpd_resp_sendstr(req, "Configurações de energia atualizadas com sucesso");
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/config/settings
static esp_err_t config_settings_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON para enviar as configurações atuais
cJSON *config = cJSON_CreateObject();
//cJSON_AddNumberToObject(config, "maxCurrentLimit", evse_get_max_charging_current());
cJSON_AddNumberToObject(config, "currentLimit", evse_get_max_charging_current());
cJSON_AddNumberToObject(config, "powerLimit", settings_config.powerLimit);
cJSON_AddNumberToObject(config, "energyLimit", settings_config.energyLimit);
cJSON_AddNumberToObject(config, "chargingTimeLimit", settings_config.chargingTimeLimit);
cJSON_AddNumberToObject(config, "temperatureLimit", evse_get_temp_threshold());
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/dashboard
static esp_err_t dashboard_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com os dados do Dashboard
cJSON *dashboard = cJSON_CreateObject();
// Status do sistema
cJSON_AddStringToObject(dashboard, "status", "Ativo");
// Carregadores (exemplo)
cJSON *chargers = cJSON_CreateArray();
cJSON *charger1 = cJSON_CreateObject();
cJSON_AddNumberToObject(charger1, "id", 1);
cJSON_AddStringToObject(charger1, "status", "Ativo");
cJSON_AddNumberToObject(charger1, "current", 12);
cJSON_AddNumberToObject(charger1, "power", 2200);
cJSON_AddItemToArray(chargers, charger1);
cJSON_AddItemToObject(dashboard, "chargers", chargers);
// Consumo de energia
cJSON_AddNumberToObject(dashboard, "energyConsumed", 50.3);
// Tempo de carregamento
cJSON_AddNumberToObject(dashboard, "chargingTime", 120);
// Alertas
cJSON *alerts = cJSON_CreateArray();
cJSON_AddItemToArray(alerts, cJSON_CreateString("Aviso: Carregador 1 está com erro."));
cJSON_AddItemToObject(dashboard, "alerts", alerts);
// Convertendo para string e enviando a resposta
const char *dashboard_str = cJSON_Print(dashboard);
httpd_resp_sendstr(req, dashboard_str);
// Liberando a memória
free((void *)dashboard_str);
cJSON_Delete(dashboard);
return ESP_OK;
}
static esp_err_t config_wifi_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com as configurações de Wi-Fi
cJSON *config = cJSON_CreateObject();
cJSON_AddBoolToObject(config, "enabled", wifi_config.enabled);
cJSON_AddStringToObject(config, "ssid", wifi_config.ssid);
cJSON_AddStringToObject(config, "password", wifi_config.password);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
/* Manipulador para o endpoint POST /api/v1/config/wifi */
static esp_err_t config_wifi_post_handler(httpd_req_t *req)
{
char buf[512]; // Buffer para armazenar a requisição
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Atualizando as configurações Wi-Fi
cJSON *enabled = cJSON_GetObjectItem(json, "enabled");
if (enabled) wifi_config.enabled = enabled->valueint;
cJSON *ssid = cJSON_GetObjectItem(json, "ssid");
if (ssid) strlcpy(wifi_config.ssid, ssid->valuestring, sizeof(wifi_config.ssid));
cJSON *password = cJSON_GetObjectItem(json, "password");
if (password) strlcpy(wifi_config.password, password->valuestring, sizeof(wifi_config.password));
cJSON_Delete(json);
// Responder com uma mensagem de sucesso
httpd_resp_sendstr(req, "Configuração Wi-Fi atualizada com sucesso");
return ESP_OK;
}
/* Manipulador para o endpoint GET /api/v1/config/mqtt */
static esp_err_t config_mqtt_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com as configurações de MQTT
cJSON *config = cJSON_CreateObject();
cJSON_AddBoolToObject(config, "enabled", mqtt_config.enabled);
cJSON_AddStringToObject(config, "host", mqtt_config.host);
cJSON_AddNumberToObject(config, "port", mqtt_config.port);
cJSON_AddStringToObject(config, "username", mqtt_config.username);
cJSON_AddStringToObject(config, "password", mqtt_config.password);
cJSON_AddStringToObject(config, "topic", mqtt_config.topic);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
/* Manipulador para o endpoint POST /api/v1/config/mqtt */
static esp_err_t config_mqtt_post_handler(httpd_req_t *req)
{
char buf[512]; // Buffer para armazenar a requisição
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Atualizando as configurações MQTT
cJSON *enabled = cJSON_GetObjectItem(json, "enabled");
if (enabled) mqtt_config.enabled = enabled->valueint;
cJSON *host = cJSON_GetObjectItem(json, "host");
if (host) strlcpy(mqtt_config.host, host->valuestring, sizeof(mqtt_config.host));
cJSON *port = cJSON_GetObjectItem(json, "port");
if (port) mqtt_config.port = port->valueint;
cJSON *username = cJSON_GetObjectItem(json, "username");
if (username) strlcpy(mqtt_config.username, username->valuestring, sizeof(mqtt_config.username));
cJSON *password = cJSON_GetObjectItem(json, "password");
if (password) strlcpy(mqtt_config.password, password->valuestring, sizeof(mqtt_config.password));
cJSON *topic = cJSON_GetObjectItem(json, "topic");
if (topic) strlcpy(mqtt_config.topic, topic->valuestring, sizeof(mqtt_config.topic));
cJSON_Delete(json);
// Responder com uma mensagem de sucesso
httpd_resp_sendstr(req, "Configuração MQTT atualizada com sucesso");
return ESP_OK;
}
// GET /api/v1/config/auth-methods
static esp_err_t config_auth_methods_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
cJSON *config = cJSON_CreateObject();
cJSON_AddBoolToObject(config, "RFID", auth_is_enabled());
cJSON_AddBoolToObject(config, "App", false);
cJSON_AddBoolToObject(config, "Password", false);
char *config_str = cJSON_PrintUnformatted(config);
httpd_resp_sendstr(req, config_str);
free(config_str);
cJSON_Delete(config);
return ESP_OK;
}
// POST /api/v1/config/auth-methods
static esp_err_t config_auth_methods_post_handler(httpd_req_t *req)
{
char buf[512];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0';
cJSON *json = cJSON_Parse(buf);
if (!json) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
cJSON *RFID = cJSON_GetObjectItem(json, "RFID");
if (cJSON_IsBool(RFID)) {
auth_set_enabled(cJSON_IsTrue(RFID));
}
/*
cJSON *App = cJSON_GetObjectItem(json, "App");
if (cJSON_IsBool(App)) {
auth_methods.App = cJSON_IsTrue(App);
}
cJSON *Password = cJSON_GetObjectItem(json, "Password");
if (cJSON_IsBool(Password)) {
auth_methods.Password = cJSON_IsTrue(Password);
}*/
cJSON_Delete(json);
httpd_resp_sendstr(req, "Configurações de autenticação atualizadas com sucesso");
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/config/users
static esp_err_t config_users_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com a lista de usuários
cJSON *config = cJSON_CreateObject();
cJSON *users_list = cJSON_CreateArray();
for (int i = 0; i < num_users; i++) {
cJSON *user = cJSON_CreateObject();
cJSON_AddStringToObject(user, "username", users[i].username);
cJSON_AddItemToArray(users_list, user);
}
cJSON_AddItemToObject(config, "users", users_list);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint POST /api/v1/config/users
static esp_err_t config_users_post_handler(httpd_req_t *req)
{
char buf[128]; // Buffer para armazenar o nome do novo usuário
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Adicionar o novo usuário
if (num_users < 10) {
strlcpy(users[num_users].username, buf, sizeof(users[num_users].username));
num_users++;
httpd_resp_sendstr(req, "Usuário adicionado com sucesso");
} else {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Máximo de usuários atingido");
}
return ESP_OK;
}
// Manipulador para o endpoint DELETE /api/v1/config/users/{username}
static esp_err_t config_users_delete_handler(httpd_req_t *req)
{
char username[128]; // Nome do usuário a ser removido
if (httpd_req_get_url_query_str(req, username, sizeof(username)) == ESP_OK) {
// Verificar e remover o usuário
for (int i = 0; i < num_users; i++) {
if (strcmp(users[i].username, username) == 0) {
// Remover o usuário
for (int j = i; j < num_users - 1; j++) {
users[j] = users[j + 1];
}
num_users--;
httpd_resp_sendstr(req, "Usuário removido com sucesso");
return ESP_OK;
}
}
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Usuário não encontrado");
}
return ESP_FAIL;
}
esp_err_t rest_init(const char *base_path)
{
/*
REST_CHECK(base_path, "wrong base path", err);
rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t));
REST_CHECK(rest_context, "No memory for rest context", err_start);
strlcpy(rest_context->base_path, base_path, sizeof(rest_context->base_path));
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_uri_handlers = 30; // Ajuste conforme necessário
config.uri_match_fn = httpd_uri_match_wildcard;
ESP_LOGI(REST_TAG, "Starting HTTP Server");
REST_CHECK(httpd_start(&server, &config) == ESP_OK, "Start server failed", err_start);
// Registrar manipuladores de URI para as configurações
httpd_uri_t config_load_balancing_get_uri = {
.uri = "/api/v1/config/load-balancing",
.method = HTTP_GET,
.handler = config_load_balancing_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_load_balancing_get_uri);
// URI handler for fetching OCPP status
httpd_uri_t ocpp_status_get_uri = {
.uri = "/api/v1/ocpp",
.method = HTTP_GET,
.handler = ocpp_status_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &ocpp_status_get_uri);
// URI handler for fetching OCPP config
httpd_uri_t config_ocpp_get_uri = {
.uri = "/api/v1/config/ocpp",
.method = HTTP_GET,
.handler = config_ocpp_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_ocpp_get_uri);
// URI handler for posting OCPP config
httpd_uri_t config_ocpp_post_uri = {
.uri = "/api/v1/config/ocpp",
.method = HTTP_POST,
.handler = config_ocpp_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_ocpp_post_uri);
// Manipulador para o endpoint POST /api/v1/config/settings
httpd_uri_t config_settings_post_uri = {
.uri = "/api/v1/config/settings",
.method = HTTP_POST,
.handler = config_settings_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_settings_post_uri);
// Manipulador para o endpoint GET /api/v1/config/settings
httpd_uri_t config_settings_get_uri = {
.uri = "/api/v1/config/settings",
.method = HTTP_GET,
.handler = config_settings_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_settings_get_uri);
// Manipulador para o endpoint GET /api/v1/dashboard
httpd_uri_t dashboard_get_uri = {
.uri = "/api/v1/dashboard",
.method = HTTP_GET,
.handler = dashboard_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &dashboard_get_uri);
// Register URI Handlers for electrical configuration
httpd_uri_t electrical_config_get_uri = {
.uri = "/api/v1/config/electrical",
.method = HTTP_GET,
.handler = electrical_config_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &electrical_config_get_uri);
httpd_uri_t electrical_config_post_uri = {
.uri = "/api/v1/config/electrical",
.method = HTTP_POST,
.handler = electrical_config_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &electrical_config_post_uri);
// URI handler for getting Wi-Fi config
httpd_uri_t config_wifi_get_uri = {
.uri = "/api/v1/config/wifi",
.method = HTTP_GET,
.handler = config_wifi_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_wifi_get_uri);
// URI handler for posting Wi-Fi config
httpd_uri_t config_wifi_post_uri = {
.uri = "/api/v1/config/wifi",
.method = HTTP_POST,
.handler = config_wifi_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_wifi_post_uri);
// URI handler for getting MQTT config
httpd_uri_t config_mqtt_get_uri = {
.uri = "/api/v1/config/mqtt",
.method = HTTP_GET,
.handler = config_mqtt_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_mqtt_get_uri);
// URI handler for posting MQTT config
httpd_uri_t config_mqtt_post_uri = {
.uri = "/api/v1/config/mqtt",
.method = HTTP_POST,
.handler = config_mqtt_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_mqtt_post_uri);
// Registrar manipuladores para as configurações de autenticação
httpd_uri_t config_auth_methods_get_uri = {
.uri = "/api/v1/config/auth-methods",
.method = HTTP_GET,
.handler = config_auth_methods_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_auth_methods_get_uri);
httpd_uri_t config_auth_methods_post_uri = {
.uri = "/api/v1/config/auth-methods",
.method = HTTP_POST,
.handler = config_auth_methods_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_auth_methods_post_uri);
// Registrar manipuladores para as configurações de usuários
httpd_uri_t config_users_get_uri = {
.uri = "/api/v1/config/users",
.method = HTTP_GET,
.handler = config_users_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_users_get_uri);
httpd_uri_t config_users_post_uri = {
.uri = "/api/v1/config/users",
.method = HTTP_POST,
.handler = config_users_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_users_post_uri);
httpd_uri_t config_users_delete_uri = {
.uri = "/api/v1/config/users",
.method = HTTP_DELETE,
.handler = config_users_delete_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_users_delete_uri);
// URI handler for getting web server files
httpd_uri_t common_get_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = rest_common_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &common_get_uri);
*/
return ESP_OK;
}

View File

@@ -3,6 +3,9 @@
#include "cJSON.h"
#include "evse_api.h"
#include "evse_error.h"
#include "evse_config.h"
#include "evse_limits.h"
static const char *TAG = "dashboard_api";
@@ -40,10 +43,10 @@ static esp_err_t dashboard_get_handler(httpd_req_t *req) {
if (evse_is_limit_reached()) {
cJSON_AddItemToArray(alerts, cJSON_CreateString("Limite de consumo atingido."));
}
if (!evse_is_available()) {
if (!evse_config_is_available()) {
cJSON_AddItemToArray(alerts, cJSON_CreateString("Estação indisponível."));
}
if (!evse_is_enabled()) {
if (!evse_config_is_enabled()) {
cJSON_AddItemToArray(alerts, cJSON_CreateString("EVSE desativado."));
}
cJSON_AddItemToObject(dashboard, "alerts", alerts);

View File

@@ -3,6 +3,7 @@
// =========================
#include "evse_settings_api.h"
#include "evse_api.h"
#include "evse_config.h"
#include "esp_log.h"
#include "cJSON.h"

View File

@@ -87,7 +87,7 @@ static esp_err_t meters_config_post_handler(httpd_req_t *req) {
// Registrando os manipuladores de URI para os contadores
void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
ESP_LOGI(TAG, "Registering URI handlers for meters settings");
ESP_LOGD(TAG, "Registering URI handlers for meters settings");
// URI para o método GET
httpd_uri_t meters_get_uri = {
@@ -96,7 +96,7 @@ void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
.handler = meters_config_get_handler,
.user_ctx = ctx
};
ESP_LOGI(TAG, "Registering GET handler for /api/v1/config/meters");
ESP_LOGD(TAG, "Registering GET handler for /api/v1/config/meters");
httpd_register_uri_handler(server, &meters_get_uri);
// URI para o método POST
@@ -106,6 +106,6 @@ void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
.handler = meters_config_post_handler,
.user_ctx = ctx
};
ESP_LOGI(TAG, "Registering POST handler for /api/v1/config/meters");
ESP_LOGD(TAG, "Registering POST handler for /api/v1/config/meters");
httpd_register_uri_handler(server, &meters_post_uri);
}

View File

@@ -19,6 +19,9 @@
// #include "inc/version_autogen.h"
#include "sync_master.h"
#include "evse_api.h"
#include "evse_error.h"
#include "evse_state.h"
#include "evse_config.h"
#define VERSION_STRING "2.2"

View File

@@ -20,6 +20,9 @@
#include "sync_slave.h"
#include "loadbalancer.h"
#include "evse_api.h"
#include "evse_error.h"
#include "evse_state.h"
#include "evse_config.h"
#define VERSION_STRING "2.2"

View File

@@ -0,0 +1,10 @@
set(srcs
"src/spi_bus_manager.c"
)
idf_component_register(
SRCS ${srcs}
INCLUDE_DIRS include
PRIV_REQUIRES driver esp_timer
REQUIRES config
)

View File

@@ -0,0 +1,20 @@
#ifndef SPI_BUS_MANAGER_H_
#define SPI_BUS_MANAGER_H_
#include "driver/spi_master.h"
#include "esp_err.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
esp_err_t spi_bus_manager_init(void);
spi_host_device_t spi_bus_manager_get_host(void);
bool spi_bus_manager_is_initialized(void);
#ifdef __cplusplus
}
#endif
#endif // SPI_BUS_MANAGER_H_

View File

@@ -0,0 +1,48 @@
#include "spi_bus_manager.h"
#include "esp_log.h"
#include "esp_err.h"
#define TAG "spi_bus_mgr"
#define SHARED_SPI_HOST SPI2_HOST
// Pinos padrão (podem ser futuramente configuráveis)
#define PIN_NUM_MOSI 23
#define PIN_NUM_MISO 19
#define PIN_NUM_CLK 18
static bool initialized = false;
esp_err_t spi_bus_manager_init(void) {
if (initialized) {
ESP_LOGW(TAG, "SPI bus already initialized on host %d", SHARED_SPI_HOST);
return ESP_OK;
}
spi_bus_config_t buscfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 64, // Ajustável conforme necessidade
};
esp_err_t ret = spi_bus_initialize(SHARED_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));
return ret;
}
initialized = true;
ESP_LOGI(TAG, "SPI bus initialized on host %d", SHARED_SPI_HOST);
return ESP_OK;
}
spi_host_device_t spi_bus_manager_get_host(void) {
return SHARED_SPI_HOST;
}
bool spi_bus_manager_is_initialized(void) {
return initialized;
}

View File

@@ -23,7 +23,7 @@
#include "peripherals.h"
#include "protocols.h"
#include "evse_manager.h"
#include "evse_api.h"
#include "evse_core.h"
#include "auth.h"
#include "loadbalancer.h"
#include "meter_manager.h"
@@ -118,12 +118,13 @@ static void user_input_task_func(void *param) {
if (notification & PRESS_BIT) {
press_tick = xTaskGetTickCount();
pressed = true;
ESP_LOGI(TAG, "Botão pressionado");
ESP_LOGI(TAG, "Pressed Button");
handle_button_press();
}
if (notification & RELEASED_BIT && pressed) {
pressed = false;
ESP_LOGI(TAG, "Botão liberado");
ESP_LOGI(TAG, "Reladead Buttton");
handle_button_press();
}
}
@@ -175,7 +176,8 @@ static void init_modules(void) {
loadbalancer_init();
meter_manager_grid_init();
meter_manager_grid_start();
//meter_manager_evse_init();
meter_manager_evse_init();
meter_manager_evse_start();
// Outros módulos (descomente conforme necessário)
// meter_init();

3707
projeto_parte1.c Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +0,0 @@
// === Início de: components/peripherals/include/temp_sensor.h ===
#ifndef TEMP_SENSOR_H_
#define TEMP_SENSOR_H_
#include <stdint.h>
#include "esp_err.h"
/**
* @brief Initialize DS18S20 temperature sensor bus
*
*/
void temp_sensor_init(void);
/**
* @brief Get found sensor count
*
* @return uint8_t
*/
uint8_t temp_sensor_get_count(void);
/**
* @brief Return lowest temperature after temp_sensor_measure
*
* @return int16_t
*/
int16_t temp_sensor_get_low(void);
/**
* @brief Return highest temperature after temp_sensor_measure
*
* @return int
*/
int temp_sensor_get_high(void);
/**
* @brief Return temperature sensor error
*
* @return bool
*/
bool temp_sensor_is_error(void);
#endif /* TEMP_SENSOR_H_ */
// === Fim de: components/peripherals/include/temp_sensor.h ===

3684
projeto_parte2.c Executable file → Normal file

File diff suppressed because it is too large Load Diff

1768
projeto_parte3.c Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,896 +0,0 @@
// === Início de: components/auth/include/auth.h ===
#ifndef AUTH_H
#define AUTH_H
#include <stdbool.h>
#include <freertos/FreeRTOS.h>
#ifdef __cplusplus
extern "C" {
#endif
/// Tamanho máximo de uma tag RFID (incluindo '\0')
#define AUTH_TAG_MAX_LEN 20
/// Estrutura de evento emitida após leitura de uma tag
typedef struct {
char tag[AUTH_TAG_MAX_LEN]; ///< Tag lida
bool authorized; ///< true se a tag for reconhecida como válida
} auth_event_t;
/**
* @brief Inicializa o sistema de autenticação.
*
* - Carrega a configuração (enabled) da NVS
* - Inicia o leitor Wiegand
* - Emite evento AUTH_EVENT_INIT com estado atual
*/
void auth_init(void);
/**
* @brief Ativa ou desativa o uso de autenticação via RFID.
*
* Esta configuração é persistida em NVS. Se desativado, o sistema
* considerará todas as autorizações como aceitas.
*
* @param value true para ativar, false para desativar
*/
void auth_set_enabled(bool value);
/**
* @brief Verifica se o sistema de autenticação está habilitado.
*/
bool auth_is_enabled(void);
/**
* @brief Adiciona uma nova tag RFID à lista de autorizadas.
*
* @param tag String da tag (máx AUTH_TAG_MAX_LEN-1)
* @return true se a tag foi adicionada, false se já existia ou inválida
*/
bool auth_add_tag(const char *tag);
/**
* @brief Remove uma tag previamente cadastrada.
*
* @param tag String da tag
* @return true se foi removida, false se não encontrada
*/
bool auth_remove_tag(const char *tag);
/**
* @brief Verifica se uma tag já está registrada como válida.
*/
bool auth_tag_exists(const char *tag);
/**
* @brief Lista todas as tags válidas atualmente registradas (via logs).
*/
void auth_list_tags(void);
/**
* @brief Processa uma tag RFID lida (chamada normalmente pelo leitor).
*
* - Verifica validade
* - Emite evento AUTH_EVENT_TAG_PROCESSED
* - Inicia timer de expiração se autorizada
*/
void auth_process_tag(const char *tag);
#ifdef __cplusplus
}
#endif
#endif // AUTH_H
// === Fim de: components/auth/include/auth.h ===
// === Início de: components/auth/include/auth_events.h ===
#pragma once
#include "esp_event.h"
#define AUTH_EVENT_TAG_MAX_LEN 32
ESP_EVENT_DECLARE_BASE(AUTH_EVENTS);
typedef enum {
AUTH_EVENT_TAG_PROCESSED,
AUTH_EVENT_ENABLED_CHANGED,
AUTH_EVENT_INIT,
} auth_event_id_t;
typedef struct {
char tag[AUTH_EVENT_TAG_MAX_LEN];
bool authorized;
} auth_tag_event_data_t;
typedef struct {
bool enabled;
} auth_enabled_event_data_t;
// === Fim de: components/auth/include/auth_events.h ===
// === Início de: components/auth/include/wiegand.h ===
/*
* Copyright (c) 2021 Ruslan V. Uss <unclerus@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of itscontributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file wiegand.h
* @defgroup wiegand wiegand
* @{
*
* ESP-IDF Wiegand protocol receiver
*
* Copyright (c) 2021 Ruslan V. Uss <unclerus@gmail.com>
*
* BSD Licensed as described in the file LICENSE
*/
#ifndef __WIEGAND_H__
#define __WIEGAND_H__
#include <driver/gpio.h>
#include <esp_err.h>
#include <esp_timer.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct wiegand_reader wiegand_reader_t;
typedef void (*wiegand_callback_t)(wiegand_reader_t *reader);
/**
* Bit and byte order of data
*/
typedef enum {
WIEGAND_MSB_FIRST = 0,
WIEGAND_LSB_FIRST
} wiegand_order_t;
/**
* Wiegand reader descriptor
*/
struct wiegand_reader
{
gpio_num_t gpio_d0, gpio_d1;
wiegand_callback_t callback;
wiegand_order_t bit_order;
wiegand_order_t byte_order;
uint8_t *buf;
size_t size;
size_t bits;
esp_timer_handle_t timer;
bool start_parity;
bool enabled;
};
/**
* @brief Create and initialize reader instance.
*
* @param reader Reader descriptor
* @param gpio_d0 GPIO pin for D0
* @param gpio_d1 GPIO pin for D0
* @param internal_pullups Enable internal pull-up resistors for D0 and D1 GPIO
* @param buf_size Reader buffer size in bytes, must be large enough to
* contain entire Wiegand key
* @param callback Callback function for processing received codes
* @param bit_order Bit order of data
* @param byte_order Byte order of data
* @return `ESP_OK` on success
*/
esp_err_t wiegand_reader_init(wiegand_reader_t *reader, gpio_num_t gpio_d0, gpio_num_t gpio_d1,
bool internal_pullups, size_t buf_size, wiegand_callback_t callback, wiegand_order_t bit_order,
wiegand_order_t byte_order);
/**
* @brief Disable reader
*
* While reader is disabled, it will not receive new data
*
* @param reader Reader descriptor
* @return `ESP_OK` on success
*/
esp_err_t wiegand_reader_disable(wiegand_reader_t *reader);
/**
* @brief Enable reader
*
* @param reader Reader descriptor
* @return `ESP_OK` on success
*/
esp_err_t wiegand_reader_enable(wiegand_reader_t *reader);
/**
* @brief Delete reader instance.
*
* @param reader Reader descriptor
* @return `ESP_OK` on success
*/
esp_err_t wiegand_reader_done(wiegand_reader_t *reader);
#ifdef __cplusplus
}
#endif
/**@}*/
#endif /* __WIEGAND_H__ */
// === Fim de: components/auth/include/wiegand.h ===
// === Início de: components/auth/include/wiegand_reader.h ===
#ifndef WIEGAND_READER_H
#define WIEGAND_READER_H
#ifdef __cplusplus
extern "C" {
#endif
void initWiegand(void);
#ifdef __cplusplus
}
#endif
#endif // WIEGAND_READER_H
// === Fim de: components/auth/include/wiegand_reader.h ===
// === Início de: components/rest_api/src/ocpp_api.c ===
// =========================
// ocpp_api.c
// =========================
#include "ocpp_api.h"
#include "esp_log.h"
#include "cJSON.h"
static const char *TAG = "ocpp_api";
static struct {
char url[256];
char chargeBoxId[128];
char certificate[256];
char privateKey[256];
} ocpp_config = {"", "", "", ""};
static esp_err_t ocpp_get_status_handler(httpd_req_t *req) {
httpd_resp_set_type(req, "application/json");
cJSON *status = cJSON_CreateObject();
cJSON_AddStringToObject(status, "status", "connected");
char *str = cJSON_Print(status);
httpd_resp_sendstr(req, str);
free(str);
cJSON_Delete(status);
return ESP_OK;
}
static esp_err_t ocpp_get_config_handler(httpd_req_t *req) {
httpd_resp_set_type(req, "application/json");
cJSON *json = cJSON_CreateObject();
cJSON_AddStringToObject(json, "url", ocpp_config.url);
cJSON_AddStringToObject(json, "chargeBoxId", ocpp_config.chargeBoxId);
cJSON_AddStringToObject(json, "certificate", ocpp_config.certificate);
cJSON_AddStringToObject(json, "privateKey", ocpp_config.privateKey);
char *str = cJSON_Print(json);
httpd_resp_sendstr(req, str);
free(str);
cJSON_Delete(json);
return ESP_OK;
}
static esp_err_t ocpp_post_config_handler(httpd_req_t *req) {
char buf[512];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Empty body");
return ESP_FAIL;
}
buf[len] = '\0';
cJSON *json = cJSON_Parse(buf);
if (!json) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
cJSON *url = cJSON_GetObjectItem(json, "url");
if (url) strlcpy(ocpp_config.url, url->valuestring, sizeof(ocpp_config.url));
cJSON *id = cJSON_GetObjectItem(json, "chargeBoxId");
if (id) strlcpy(ocpp_config.chargeBoxId, id->valuestring, sizeof(ocpp_config.chargeBoxId));
cJSON *cert = cJSON_GetObjectItem(json, "certificate");
if (cert) strlcpy(ocpp_config.certificate, cert->valuestring, sizeof(ocpp_config.certificate));
cJSON *key = cJSON_GetObjectItem(json, "privateKey");
if (key) strlcpy(ocpp_config.privateKey, key->valuestring, sizeof(ocpp_config.privateKey));
cJSON_Delete(json);
httpd_resp_sendstr(req, "OCPP config atualizada com sucesso");
return ESP_OK;
}
void register_ocpp_handlers(httpd_handle_t server, void *ctx) {
httpd_uri_t status_uri = {
.uri = "/api/v1/ocpp",
.method = HTTP_GET,
.handler = ocpp_get_status_handler,
.user_ctx = ctx
};
httpd_register_uri_handler(server, &status_uri);
httpd_uri_t get_uri = {
.uri = "/api/v1/config/ocpp",
.method = HTTP_GET,
.handler = ocpp_get_config_handler,
.user_ctx = ctx
};
httpd_register_uri_handler(server, &get_uri);
httpd_uri_t post_uri = {
.uri = "/api/v1/config/ocpp",
.method = HTTP_POST,
.handler = ocpp_post_config_handler,
.user_ctx = ctx
};
httpd_register_uri_handler(server, &post_uri);
}
// === Fim de: components/rest_api/src/ocpp_api.c ===
// === Início de: components/rest_api/src/static_file_api.c ===
#include "static_file_api.h"
#include "esp_log.h"
#include <fcntl.h>
#include <string.h>
#include "esp_vfs.h"
static const char *TAG = "static_file_api";
#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
#define SCRATCH_BUFSIZE (10240)
typedef struct rest_server_context {
char base_path[ESP_VFS_PATH_MAX + 1];
char scratch[SCRATCH_BUFSIZE];
} rest_server_context_t;
#define CHECK_FILE_EXTENSION(filename, ext) \
(strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0)
static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath) {
const char *type = "text/plain";
if (CHECK_FILE_EXTENSION(filepath, ".html")) type = "text/html";
else if (CHECK_FILE_EXTENSION(filepath, ".js")) type = "application/javascript";
else if (CHECK_FILE_EXTENSION(filepath, ".css")) type = "text/css";
else if (CHECK_FILE_EXTENSION(filepath, ".png")) type = "image/png";
else if (CHECK_FILE_EXTENSION(filepath, ".ico")) type = "image/x-icon";
else if (CHECK_FILE_EXTENSION(filepath, ".svg")) type = "image/svg+xml";
return httpd_resp_set_type(req, type);
}
static esp_err_t static_get_handler(httpd_req_t *req) {
char filepath[FILE_PATH_MAX];
rest_server_context_t *ctx = (rest_server_context_t *) req->user_ctx;
strlcpy(filepath, ctx->base_path, sizeof(filepath));
if (req->uri[strlen(req->uri) - 1] == '/') {
strlcat(filepath, "/index.html", sizeof(filepath));
} else {
strlcat(filepath, req->uri, sizeof(filepath));
}
int fd = open(filepath, O_RDONLY, 0);
if (fd == -1) {
// fallback para /index.html (SPA)
ESP_LOGW(TAG, "Arquivo não encontrado: %s. Tentando index.html", filepath);
strlcpy(filepath, ctx->base_path, sizeof(filepath));
strlcat(filepath, "/index.html", sizeof(filepath));
fd = open(filepath, O_RDONLY, 0);
if (fd == -1) {
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Arquivo não encontrado");
return ESP_FAIL;
}
}
set_content_type_from_file(req, filepath);
char *chunk = ctx->scratch;
ssize_t read_bytes;
do {
read_bytes = read(fd, chunk, SCRATCH_BUFSIZE);
if (read_bytes == -1) {
ESP_LOGE(TAG, "Erro lendo arquivo: %s", filepath);
close(fd);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Erro ao ler arquivo");
return ESP_FAIL;
} else if (read_bytes > 0) {
if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) {
close(fd);
httpd_resp_sendstr_chunk(req, NULL);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Erro ao enviar arquivo");
return ESP_FAIL;
}
}
} while (read_bytes > 0);
close(fd);
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}
void register_static_file_handlers(httpd_handle_t server, void *ctx) {
httpd_uri_t uri = {
.uri = "/*",
.method = HTTP_GET,
.handler = static_get_handler,
.user_ctx = ctx
};
httpd_register_uri_handler(server, &uri);
}
// === Fim de: components/rest_api/src/static_file_api.c ===
// === Início de: components/rest_api/src/meters_settings_api.c ===
#include "meters_settings_api.h"
#include "meter_manager.h" // Atualizado para usar o novo manager
#include "esp_log.h"
#include "cJSON.h"
static const char *TAG = "meters_settings_api";
// Função para recuperar as configurações dos contadores
static esp_err_t meters_config_get_handler(httpd_req_t *req) {
ESP_LOGI(TAG, "Received GET request for /api/v1/config/meters");
httpd_resp_set_type(req, "application/json");
cJSON *config = cJSON_CreateObject();
// Recuperando as configurações dos contadores
meter_type_t gridmeterType = meter_manager_grid_get_model();
meter_type_t evsemeterType = meter_manager_evse_get_model();
ESP_LOGI(TAG, "Grid meter type: %s", meter_type_to_str(gridmeterType));
ESP_LOGI(TAG, "EVSE meter type: %s", meter_type_to_str(evsemeterType));
// Adicionando os tipos de contadores ao objeto JSON
cJSON_AddStringToObject(config, "gridmeter", meter_type_to_str(gridmeterType));
cJSON_AddStringToObject(config, "evsemeter", meter_type_to_str(evsemeterType));
// Convertendo o objeto JSON para uma string
const char *json_str = cJSON_Print(config);
ESP_LOGI(TAG, "Returning meters config: %s", json_str);
httpd_resp_sendstr(req, json_str);
// Liberação da memória
free((void *)json_str);
cJSON_Delete(config);
return ESP_OK;
}
// Função para atualizar as configurações dos contadores
static esp_err_t meters_config_post_handler(httpd_req_t *req) {
ESP_LOGI(TAG, "Received POST request for /api/v1/config/meters");
char buf[512];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
ESP_LOGE(TAG, "Received empty body in POST request");
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Empty body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string está terminada
ESP_LOGI(TAG, "Received POST data: %s", buf);
cJSON *json = cJSON_Parse(buf);
if (!json) {
ESP_LOGE(TAG, "Failed to parse JSON data");
// Resposta detalhada de erro
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON format");
return ESP_FAIL;
}
// Atualizando os contadores
cJSON *gridmeter = cJSON_GetObjectItem(json, "gridmeter");
if (gridmeter) {
meter_type_t gridType = string_to_meter_type(gridmeter->valuestring); // Usando a função string_to_meter_type
ESP_LOGI(TAG, "Updating grid meter type to: %s", gridmeter->valuestring);
meter_manager_grid_set_model(gridType);
}
cJSON *evsemeter = cJSON_GetObjectItem(json, "evsemeter");
if (evsemeter) {
meter_type_t evseType = string_to_meter_type(evsemeter->valuestring); // Usando a função string_to_meter_type
ESP_LOGI(TAG, "Updating EVSE meter type to: %s", evsemeter->valuestring);
meter_manager_evse_set_model(evseType);
}
cJSON_Delete(json);
httpd_resp_sendstr(req, "Meters updated successfully");
ESP_LOGI(TAG, "Meters configuration updated successfully");
return ESP_OK;
}
// Registrando os manipuladores de URI para os contadores
void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
ESP_LOGI(TAG, "Registering URI handlers for meters settings");
// URI para o método GET
httpd_uri_t meters_get_uri = {
.uri = "/api/v1/config/meters",
.method = HTTP_GET,
.handler = meters_config_get_handler,
.user_ctx = ctx
};
ESP_LOGI(TAG, "Registering GET handler for /api/v1/config/meters");
httpd_register_uri_handler(server, &meters_get_uri);
// URI para o método POST
httpd_uri_t meters_post_uri = {
.uri = "/api/v1/config/meters",
.method = HTTP_POST,
.handler = meters_config_post_handler,
.user_ctx = ctx
};
ESP_LOGI(TAG, "Registering POST handler for /api/v1/config/meters");
httpd_register_uri_handler(server, &meters_post_uri);
}
// === Fim de: components/rest_api/src/meters_settings_api.c ===
// === Início de: components/rest_api/src/rest_main.c ===
#include "rest_main.h"
#include "evse_settings_api.h"
#include "meters_settings_api.h"
#include "loadbalancing_settings_api.h"
#include "network_api.h"
#include "ocpp_api.h"
#include "auth_api.h"
#include "dashboard_api.h"
#include "static_file_api.h"
#include "esp_log.h"
static const char *TAG = "rest_main";
esp_err_t rest_server_init(const char *base_path) {
ESP_LOGI(TAG, "Initializing REST API with base path: %s", base_path);
rest_server_context_t *ctx = calloc(1, sizeof(rest_server_context_t));
if (!ctx) {
ESP_LOGE(TAG, "Failed to allocate memory for REST context");
return ESP_ERR_NO_MEM;
}
strlcpy(ctx->base_path, base_path, sizeof(ctx->base_path));
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.uri_match_fn = httpd_uri_match_wildcard;
config.max_uri_handlers = 32;
httpd_handle_t server = NULL;
esp_err_t err = httpd_start(&server, &config);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to start HTTP server: %s", esp_err_to_name(err));
free(ctx);
return err;
}
ESP_LOGI(TAG, "HTTP server started successfully");
// Register endpoint groups
register_evse_settings_handlers(server, ctx); // Apenas chamando a função sem comparação
register_network_handlers(server, ctx); // Apenas chamando a função sem comparação
register_ocpp_handlers(server, ctx); // Apenas chamando a função sem comparação
register_auth_handlers(server, ctx); // Apenas chamando a função sem comparação
register_dashboard_handlers(server, ctx); // Apenas chamando a função sem comparação
register_meters_settings_handlers(server, ctx); // Apenas chamando a função sem comparação
register_loadbalancing_settings_handlers(server, ctx); // Apenas chamando a função sem comparação
register_static_file_handlers(server, ctx); // Apenas chamando a função sem comparação
ESP_LOGI(TAG, "All REST API endpoint groups registered successfully");
return ESP_OK;
}
// === Fim de: components/rest_api/src/rest_main.c ===
// === Início de: components/rest_api/src/network_api.c ===
// =========================
// network_api.c
// =========================
#include "network_api.h"
#include "esp_log.h"
#include "cJSON.h"
#include "wifi.h"
#include "mqtt.h"
static const char *TAG = "network_api";
typedef struct {
bool enabled;
char ssid[33];
char password[65];
} wifi_task_data_t;
static void wifi_apply_config_task(void *param) {
wifi_task_data_t *data = (wifi_task_data_t *)param;
ESP_LOGI("wifi_task", "Applying Wi-Fi config in background task");
wifi_set_config(data->enabled, data->ssid, data->password);
free(data);
vTaskDelete(NULL);
}
static esp_err_t wifi_get_handler(httpd_req_t *req) {
ESP_LOGI(TAG, "Handling GET /api/v1/config/wifi");
httpd_resp_set_type(req, "application/json");
// Obter dados da NVS via wifi.c
bool enabled = wifi_get_enabled();
char ssid[33] = {0};
char password[65] = {0};
wifi_get_ssid(ssid);
wifi_get_password(password);
// Criar JSON
cJSON *json = cJSON_CreateObject();
cJSON_AddBoolToObject(json, "enabled", enabled);
cJSON_AddStringToObject(json, "ssid", ssid);
cJSON_AddStringToObject(json, "password", password);
// Enviar resposta
char *response = cJSON_Print(json);
httpd_resp_sendstr(req, response);
// Limpeza
free(response);
cJSON_Delete(json);
return ESP_OK;
}
static esp_err_t wifi_post_handler(httpd_req_t *req) {
ESP_LOGI(TAG, "Handling POST /api/v1/config/wifi");
char buf[512];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) return ESP_FAIL;
buf[len] = '\0';
cJSON *json = cJSON_Parse(buf);
if (!json) return ESP_FAIL;
// Valores padrão
bool enabled = false;
const char *ssid = NULL;
const char *password = NULL;
cJSON *j_enabled = cJSON_GetObjectItem(json, "enabled");
if (cJSON_IsBool(j_enabled)) enabled = j_enabled->valueint;
cJSON *j_ssid = cJSON_GetObjectItem(json, "ssid");
if (cJSON_IsString(j_ssid)) ssid = j_ssid->valuestring;
cJSON *j_password = cJSON_GetObjectItem(json, "password");
if (cJSON_IsString(j_password)) password = j_password->valuestring;
// Enviar resposta antes de alterar Wi-Fi
httpd_resp_sendstr(req, "Wi-Fi config atualizada com sucesso");
// Alocar struct para passar para a task
wifi_task_data_t *task_data = malloc(sizeof(wifi_task_data_t));
if (!task_data) {
cJSON_Delete(json);
ESP_LOGE(TAG, "Memory allocation failed for Wi-Fi task");
return ESP_ERR_NO_MEM;
}
task_data->enabled = enabled;
strncpy(task_data->ssid, ssid ? ssid : "", sizeof(task_data->ssid));
strncpy(task_data->password, password ? password : "", sizeof(task_data->password));
// Criar task normal com função C
xTaskCreate(
wifi_apply_config_task,
"wifi_config_task",
4096,
task_data,
3,
NULL
);
cJSON_Delete(json);
return ESP_OK;
}
static esp_err_t config_mqtt_get_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "Handling GET /api/v1/config/mqtt");
httpd_resp_set_type(req, "application/json");
bool enabled = mqtt_get_enabled();
char server[64] = {0};
char base_topic[32] = {0};
char username[32] = {0};
char password[64] = {0};
uint16_t periodicity = mqtt_get_periodicity();
mqtt_get_server(server);
mqtt_get_base_topic(base_topic);
mqtt_get_user(username);
mqtt_get_password(password);
ESP_LOGI(TAG, "MQTT Config:");
ESP_LOGI(TAG, " Enabled: %s", enabled ? "true" : "false");
ESP_LOGI(TAG, " Server: %s", server);
ESP_LOGI(TAG, " Topic: %s", base_topic);
ESP_LOGI(TAG, " Username: %s", username);
ESP_LOGI(TAG, " Password: %s", password);
ESP_LOGI(TAG, " Periodicity: %d", periodicity);
cJSON *config = cJSON_CreateObject();
cJSON_AddBoolToObject(config, "enabled", enabled);
cJSON_AddStringToObject(config, "host", server);
cJSON_AddNumberToObject(config, "port", 1883);
cJSON_AddStringToObject(config, "username", username);
cJSON_AddStringToObject(config, "password", password);
cJSON_AddStringToObject(config, "topic", base_topic);
cJSON_AddNumberToObject(config, "periodicity", periodicity);
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
static esp_err_t config_mqtt_post_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "Handling POST /api/v1/config/mqtt");
char buf[512];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
ESP_LOGE(TAG, "Failed to read request body");
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0';
ESP_LOGI(TAG, "Received JSON: %s", buf);
cJSON *json = cJSON_Parse(buf);
if (!json) {
ESP_LOGE(TAG, "Invalid JSON format");
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
bool enabled = false;
const char *host = NULL, *topic = NULL, *username = NULL, *password = NULL;
int periodicity = 30;
if (cJSON_IsBool(cJSON_GetObjectItem(json, "enabled")))
enabled = cJSON_GetObjectItem(json, "enabled")->valueint;
cJSON *j_host = cJSON_GetObjectItem(json, "host");
if (cJSON_IsString(j_host)) host = j_host->valuestring;
cJSON *j_topic = cJSON_GetObjectItem(json, "topic");
if (cJSON_IsString(j_topic)) topic = j_topic->valuestring;
cJSON *j_user = cJSON_GetObjectItem(json, "username");
if (cJSON_IsString(j_user)) username = j_user->valuestring;
cJSON *j_pass = cJSON_GetObjectItem(json, "password");
if (cJSON_IsString(j_pass)) password = j_pass->valuestring;
cJSON *j_periodicity = cJSON_GetObjectItem(json, "periodicity");
if (cJSON_IsNumber(j_periodicity)) periodicity = j_periodicity->valueint;
ESP_LOGI(TAG, "Applying MQTT config:");
ESP_LOGI(TAG, " Enabled: %s", enabled ? "true" : "false");
ESP_LOGI(TAG, " Host: %s", host);
ESP_LOGI(TAG, " Topic: %s", topic);
ESP_LOGI(TAG, " Username: %s", username);
ESP_LOGI(TAG, " Password: %s", password);
ESP_LOGI(TAG, " Periodicity: %d", periodicity);
esp_err_t err = mqtt_set_config(enabled, host, topic, username, password, periodicity);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to apply MQTT config (code %d)", err);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to apply config");
cJSON_Delete(json);
return ESP_FAIL;
}
httpd_resp_sendstr(req, "Configuração MQTT atualizada com sucesso");
cJSON_Delete(json);
return ESP_OK;
}
void register_network_handlers(httpd_handle_t server, void *ctx) {
httpd_uri_t wifi_get = {
.uri = "/api/v1/config/wifi",
.method = HTTP_GET,
.handler = wifi_get_handler,
.user_ctx = ctx
};
httpd_register_uri_handler(server, &wifi_get);
httpd_uri_t wifi_post = {
.uri = "/api/v1/config/wifi",
.method = HTTP_POST,
.handler = wifi_post_handler,
.user_ctx = ctx
};
httpd_register_uri_handler(server, &wifi_post);
// URI handler for getting MQTT config
httpd_uri_t config_mqtt_get_uri = {
.uri = "/api/v1/config/mqtt",
.method = HTTP_GET,
.handler = config_mqtt_get_handler,
.user_ctx = ctx
};
httpd_register_uri_handler(server, &config_mqtt_get_uri);
// URI handler for posting MQTT config
httpd_uri_t config_mqtt_post_uri = {
.uri = "/api/v1/config/mqtt",
.method = HTTP_POST,
.handler = config_mqtt_post_handler,
.user_ctx = ctx
};
httpd_register_uri_handler(server, &config_mqtt_post_uri);
}
// === Fim de: components/rest_api/src/network_api.c ===

File diff suppressed because it is too large Load Diff

View File

@@ -1,735 +0,0 @@
// === Início de: components/network/include/wifi.h ===
#ifndef WIFI_H_
#define WIFI_H_
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_err.h"
#include "esp_netif.h"
#define WIFI_SCAN_SCAN_LIST_SIZE 10
#define WIFI_AP_CONNECTED_BIT BIT0
#define WIFI_AP_DISCONNECTED_BIT BIT1
#define WIFI_STA_CONNECTED_BIT BIT2
#define WIFI_STA_DISCONNECTED_BIT BIT3
#define WIFI_AP_MODE_BIT BIT4
#define WIFI_STA_MODE_BIT BIT5
typedef struct
{
char ssid[32];
int rssi;
bool auth;
} wifi_scan_ap_t;
/**
* @brief WiFi event group WIFI_AP_CONNECTED_BIT | WIFI_AP_DISCONNECTED_BIT | WIFI_STA_CONNECTED_BIT | WIFI_STA_DISCONNECTED_BIT | WIFI_AP_MODE_BIT | WIFI_STA_MODE_BIT
*
*/
extern EventGroupHandle_t wifi_event_group;
/**
* @brief Initialize WiFi
*
*/
void wifi_ini(void);
/**
* @brief Return WiFi STA network interface
*
* @return esp_netif_t*
*/
esp_netif_t* wifi_get_sta_netif(void);
/**
* @brief Return WiFi AP network interface
*
* @return esp_netif_t*
*/
esp_netif_t* wifi_get_ap_netif(void);
/**
* @brief Set WiFi config
*
* @param enabled
* @param ssid NULL value will be skiped
* @param password NULL value will be skiped
* @return esp_err_t
*/
esp_err_t wifi_set_config(bool enabled, const char* ssid, const char* password);
/**
* @brief Get WiFi STA enabled, stored in NVS
*
* @return true
* @return false
*/
bool wifi_get_enabled(void);
/**
* @brief Scan for AP
*
* @param scan_aps array with length WIFI_SCAN_SCAN_LIST_SIZE
* @return uint16_t number of available AP
*/
uint16_t wifi_scan(wifi_scan_ap_t *scan_aps);
/**
* @brief Get WiFi STA ssid, string length 32, stored in NVS
*
* @param value
*/
void wifi_get_ssid(char* value);
/**
* @brief Get WiFi STA password, string length 32, stored in NVS
*
* @param value
*/
void wifi_get_password(char* value);
/**
* @brief Start WiFi AP mode
*
*/
void wifi_ap_start(void);
/**
* @brief Stop WiFi AP mode
*
*/
void wifi_ap_stop(void);
#endif /* WIFI_H_ */
// === Fim de: components/network/include/wifi.h ===
// === Início de: components/peripherals/src/ac_relay.c ===
#include "esp_log.h"
#include "driver/gpio.h"
#include "ac_relay.h"
#include "board_config.h"
static const char* TAG = "ac_relay";
/**
* @brief Initialize the AC relay GPIO.
*
* Configures the specified GPIO pin as an output and sets its initial state to OFF (low).
*/
void ac_relay_init(void)
{
gpio_config_t conf = {
.pin_bit_mask = BIT64(board_config.ac_relay_gpio),
.mode = GPIO_MODE_OUTPUT,
.pull_down_en = GPIO_PULLDOWN_DISABLE, ///< Disabled unless required
.pull_up_en = GPIO_PULLUP_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
esp_err_t ret = gpio_config(&conf);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to configure GPIO (error: %s)", esp_err_to_name(ret));
return;
}
gpio_set_level(board_config.ac_relay_gpio, false); ///< Ensure relay starts OFF
ESP_LOGI(TAG, "AC relay initialized. Pin: %d", board_config.ac_relay_gpio);
}
/**
* @brief Set the state of the AC relay.
*
* @param state True to turn the relay ON, False to turn it OFF.
*/
void ac_relay_set_state(bool state)
{
ESP_LOGI(TAG, "Setting AC relay state: Pin: %d, State: %d", board_config.ac_relay_gpio, state);
esp_err_t ret = gpio_set_level(board_config.ac_relay_gpio, state);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set GPIO level (error: %s)", esp_err_to_name(ret));
}
}
/**
* @brief Get the current state of the AC relay.
*
* @return true if the relay is ON, false if OFF.
*/
bool ac_relay_get_state(void)
{
int level = gpio_get_level(board_config.ac_relay_gpio);
ESP_LOGD(TAG, "Current AC relay state: Pin: %d, State: %d", board_config.ac_relay_gpio, level);
return level;
}
// === Fim de: components/peripherals/src/ac_relay.c ===
// === Início de: components/peripherals/src/ntc_sensor.c ===
#include <sys/param.h>
#include <freertos/FreeRTOS.h>
#include "freertos/task.h"
#include "esp_log.h"
#include "ntc_sensor.h"
#include "ntc_driver.h"
#include "adc.h"
static const char *TAG = "temp_sensor";
#define MEASURE_PERIOD 15000 // 10s
static float temp = 0.0;
static ntc_device_handle_t ntc = NULL;
static portMUX_TYPE temp_mux = portMUX_INITIALIZER_UNLOCKED;
static void ntc_sensor_task_func(void *param) {
float t;
while (true) {
if (ntc_dev_get_temperature(ntc, &t) == ESP_OK) {
portENTER_CRITICAL(&temp_mux);
temp = t;
portEXIT_CRITICAL(&temp_mux);
}
vTaskDelay(pdMS_TO_TICKS(MEASURE_PERIOD));
}
}
float ntc_temp_sensor(void) {
float t;
portENTER_CRITICAL(&temp_mux);
t = temp;
portEXIT_CRITICAL(&temp_mux);
return t;
}
void ntc_sensor_init(void)
{
ESP_LOGI(TAG, "ntc_sensor_init");
// Select the NTC sensor and initialize the hardware parameters
ntc_config_t ntc_config = {
.b_value = 3950,
.r25_ohm = 10000,
.fixed_ohm = 4700,
.vdd_mv = 3300,
.circuit_mode = CIRCUIT_MODE_NTC_GND,
.atten = ADC_ATTEN_DB_12,
.channel = ADC_CHANNEL_0,
.unit = ADC_UNIT_1};
// Create the NTC Driver and Init ADC
// ntc_device_handle_t ntc = NULL;
// adc_oneshot_unit_handle_t adc_handle = NULL;
ESP_ERROR_CHECK(ntc_dev_create(&ntc_config, &ntc, &adc_handle));
ESP_ERROR_CHECK(ntc_dev_get_adc_handle(ntc, &adc_handle));
xTaskCreate(ntc_sensor_task_func, "ntc_sensor_task", 5 * 1024, NULL, 3, NULL);
}
// === Fim de: components/peripherals/src/ntc_sensor.c ===
// === Início de: components/peripherals/src/proximity.c ===
#include "esp_log.h"
#include "proximity.h"
#include "board_config.h"
#include "adc.h"
static const char *TAG = "proximity";
void proximity_init(void)
{
if (board_config.proximity)
{
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.proximity_adc_channel, &config));
}
}
uint8_t proximity_get_max_current(void)
{
int voltage;
adc_oneshot_read(adc_handle, board_config.proximity_adc_channel, &voltage);
adc_cali_raw_to_voltage(adc_cali_handle, voltage, &voltage);
ESP_LOGI(TAG, "Measured: %dmV", voltage);
uint8_t current;
if (voltage >= board_config.proximity_down_threshold_8)
{
current = 8;
}
else if (voltage >= board_config.proximity_down_threshold_10)
{
current = 10;
}
else if (voltage >= board_config.proximity_down_threshold_13)
{
current = 13;
}
else if (voltage >= board_config.proximity_down_threshold_20)
{
current = 20;
}
else if (voltage >= board_config.proximity_down_threshold_25)
{
current = 25;
}
else if (voltage >= board_config.proximity_down_threshold_32)
{
current = 32;
}
else
{
current = 32;
}
ESP_LOGI(TAG, "Max current: %dA", current);
return current;
}
// === Fim de: components/peripherals/src/proximity.c ===
// === Início de: components/peripherals/src/buzzer.c ===
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "board_config.h"
#include "buzzer.h"
#include "evse_api.h"
static gpio_num_t buzzer_gpio = GPIO_NUM_NC;
static evse_state_t last_buzzer_state = -1;
static QueueHandle_t buzzer_queue = NULL;
void buzzer_on(void) {
if (buzzer_gpio != GPIO_NUM_NC)
gpio_set_level(buzzer_gpio, 1);
}
void buzzer_off(void) {
if (buzzer_gpio != GPIO_NUM_NC)
gpio_set_level(buzzer_gpio, 0);
}
// ----------------------
// Padrões de Buzzer
// ----------------------
typedef struct {
uint16_t on_ms;
uint16_t off_ms;
} buzzer_pattern_step_t;
typedef enum {
BUZZER_PATTERN_NONE = 0,
BUZZER_PATTERN_PLUGGED,
BUZZER_PATTERN_UNPLUGGED,
BUZZER_PATTERN_CHARGING,
} buzzer_pattern_id_t;
static const buzzer_pattern_step_t pattern_plugged[] = {
{100, 100}, {200, 0}
};
static const buzzer_pattern_step_t pattern_unplugged[] = {
{150, 150}, {150, 150}, {150, 0}
};
static const buzzer_pattern_step_t pattern_charging[] = {
{80, 150}, {100, 120}, {120, 100}, {140, 0}
};
// ----------------------
// Executor de padrões
// ----------------------
static void buzzer_execute_pattern(buzzer_pattern_id_t pattern_id) {
const buzzer_pattern_step_t *pattern = NULL;
size_t length = 0;
switch (pattern_id) {
case BUZZER_PATTERN_PLUGGED:
pattern = pattern_plugged;
length = sizeof(pattern_plugged) / sizeof(pattern_plugged[0]);
break;
case BUZZER_PATTERN_UNPLUGGED:
pattern = pattern_unplugged;
length = sizeof(pattern_unplugged) / sizeof(pattern_unplugged[0]);
break;
case BUZZER_PATTERN_CHARGING:
pattern = pattern_charging;
length = sizeof(pattern_charging) / sizeof(pattern_charging[0]);
break;
default:
return;
}
for (size_t i = 0; i < length; i++) {
buzzer_on();
vTaskDelay(pdMS_TO_TICKS(pattern[i].on_ms));
buzzer_off();
if (pattern[i].off_ms > 0)
vTaskDelay(pdMS_TO_TICKS(pattern[i].off_ms));
}
}
// ----------------------
// Task que toca o buzzer
// ----------------------
static void buzzer_worker_task(void *arg) {
buzzer_pattern_id_t pattern_id;
while (true) {
if (xQueueReceive(buzzer_queue, &pattern_id, portMAX_DELAY)) {
//buzzer_execute_pattern(pattern_id);
}
}
}
// ----------------------
// Task de monitoramento
// ----------------------
static void buzzer_monitor_task(void *arg) {
while (true) {
evse_state_t current = evse_get_state();
if (current != last_buzzer_state) {
buzzer_pattern_id_t pattern_id = BUZZER_PATTERN_NONE;
switch (current) {
case EVSE_STATE_A:
if (last_buzzer_state != EVSE_STATE_A)
pattern_id = BUZZER_PATTERN_UNPLUGGED;
break;
case EVSE_STATE_B1:
case EVSE_STATE_B2:
if (last_buzzer_state != EVSE_STATE_B1 && last_buzzer_state != EVSE_STATE_B2)
pattern_id = BUZZER_PATTERN_PLUGGED;
break;
case EVSE_STATE_C2:
case EVSE_STATE_D2:
if (last_buzzer_state != EVSE_STATE_C2 && last_buzzer_state != EVSE_STATE_D2)
pattern_id = BUZZER_PATTERN_CHARGING;
break;
default:
break;
}
if (pattern_id != BUZZER_PATTERN_NONE) {
xQueueSend(buzzer_queue, &pattern_id, 0); // Não bloqueia
}
last_buzzer_state = current;
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
// ----------------------
// Inicialização
// ----------------------
void buzzer_init(void) {
if (board_config.buzzer) {
buzzer_gpio = board_config.buzzer_gpio;
gpio_config_t io_conf = {
.pin_bit_mask = BIT64(buzzer_gpio),
.mode = GPIO_MODE_OUTPUT,
.pull_down_en = GPIO_PULLDOWN_ENABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&io_conf);
gpio_set_level(buzzer_gpio, 0);
}
buzzer_queue = xQueueCreate(4, sizeof(buzzer_pattern_id_t));
xTaskCreate(buzzer_monitor_task, "buzzer_monitor", 2048, NULL, 3, NULL);
xTaskCreate(buzzer_worker_task, "buzzer_worker", 2048, NULL, 3, NULL);
}
// === Fim de: components/peripherals/src/buzzer.c ===
// === Início de: components/peripherals/src/ds18x20.h ===
/*
* Copyright (c) 2016 Grzegorz Hetman <ghetman@gmail.com>
* Copyright (c) 2016 Alex Stewart <foogod@gmail.com>
* Copyright (c) 2018 Ruslan V. Uss <unclerus@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of itscontributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DS18X20_H
#define _DS18X20_H
#include <esp_err.h>
#include "onewire.h"
typedef onewire_addr_t ds18x20_addr_t;
/** An address value which can be used to indicate "any device on the bus" */
#define DS18X20_ANY ONEWIRE_NONE
/** Family ID (lower address byte) of DS18B20 sensors */
#define DS18B20_FAMILY_ID 0x28
/** Family ID (lower address byte) of DS18S20 sensors */
#define DS18S20_FAMILY_ID 0x10
/**
* @brief Find the addresses of all ds18x20 devices on the bus.
*
* Scans the bus for all devices and places their addresses in the supplied
* array. If there are more than `addr_count` devices on the bus, only the
* first `addr_count` are recorded.
*
* @param pin The GPIO pin connected to the ds18x20 bus
* @param addr_list A pointer to an array of ::ds18x20_addr_t values.
* This will be populated with the addresses of the found
* devices.
* @param addr_count Number of slots in the `addr_list` array. At most this
* many addresses will be returned.
* @param found The number of devices found. Note that this may be less
* than, equal to, or more than `addr_count`, depending on
* how many ds18x20 devices are attached to the bus.
*
* @returns `ESP_OK` if the command was successfully issued
*/
esp_err_t ds18x20_scan_devices(gpio_num_t pin, ds18x20_addr_t *addr_list, size_t addr_count, size_t *found);
/**
* @brief Tell one or more sensors to perform a temperature measurement and
* conversion (CONVERT_T) operation.
*
* This operation can take up to 750ms to complete.
*
* If `wait=true`, this routine will automatically drive the pin high for the
* necessary 750ms after issuing the command to ensure parasitically-powered
* devices have enough power to perform the conversion operation (for
* non-parasitically-powered devices, this is not necessary but does not
* hurt). If `wait=false`, this routine will drive the pin high, but will
* then return immediately. It is up to the caller to wait the requisite time
* and then depower the bus using onewire_depower() or by issuing another
* command once conversion is done.
*
* @param pin The GPIO pin connected to the ds18x20 device
* @param addr The 64-bit address of the device on the bus. This can be set
* to ::DS18X20_ANY to send the command to all devices on the bus
* at the same time.
* @param wait Whether to wait for the necessary 750ms for the ds18x20 to
* finish performing the conversion before returning to the
* caller (You will normally want to do this).
*
* @returns `ESP_OK` if the command was successfully issued
*/
esp_err_t ds18x20_measure(gpio_num_t pin, ds18x20_addr_t addr, bool wait);
/**
* @brief Read the value from the last CONVERT_T operation.
*
* This should be called after ds18x20_measure() to fetch the result of the
* temperature measurement.
*
* @param pin The GPIO pin connected to the ds18x20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18X20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
* @param temperature The temperature in degrees Celsius
*
* @returns `ESP_OK` if the command was successfully issued
*/
esp_err_t ds18x20_read_temperature(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
/**
* @brief Read the value from the last CONVERT_T operation (ds18b20 version).
*
* This should be called after ds18x20_measure() to fetch the result of the
* temperature measurement.
*
* @param pin The GPIO pin connected to the ds18x20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18X20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
* @param temperature The temperature in degrees Celsius
*
* @returns `ESP_OK` if the command was successfully issued
*/
esp_err_t ds18b20_read_temperature(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
/**
* @brief Read the value from the last CONVERT_T operation (ds18s20 version).
*
* This should be called after ds18x20_measure() to fetch the result of the
* temperature measurement.
*
* @param pin The GPIO pin connected to the ds18x20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18X20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
* @param temperature The temperature in degrees Celsius
*
* @returns `ESP_OK` if the command was successfully issued
*/
esp_err_t ds18s20_read_temperature(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
/**
* @brief Read the value from the last CONVERT_T operation for multiple devices.
*
* This should be called after ds18x20_measure() to fetch the result of the
* temperature measurement.
*
* @param pin The GPIO pin connected to the ds18x20 bus
* @param addr_list A list of addresses for devices to read.
* @param addr_count The number of entries in `addr_list`.
* @param result_list An array of int16_ts to hold the returned temperature
* values. It should have at least `addr_count` entries.
*
* @returns `ESP_OK` if all temperatures were fetched successfully
*/
esp_err_t ds18x20_read_temp_multi(gpio_num_t pin, ds18x20_addr_t *addr_list, size_t addr_count, int16_t *result_list);
/** Perform a ds18x20_measure() followed by ds18s20_read_temperature()
*
* @param pin The GPIO pin connected to the ds18s20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18X20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
* @param temperature The temperature in degrees Celsius
*/
esp_err_t ds18s20_measure_and_read(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
/** Perform a ds18x20_measure() followed by ds18b20_read_temperature()
*
* @param pin The GPIO pin connected to the ds18x20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18X20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
* @param temperature The temperature in degrees Celsius
*/
esp_err_t ds18b20_measure_and_read(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
/** Perform a ds18x20_measure() followed by ds18x20_read_temperature()
*
* @param pin The GPIO pin connected to the ds18x20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18X20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
* @param temperature The temperature in degrees Celsius
*/
esp_err_t ds18x20_measure_and_read(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
/**
* @brief Perform a ds18x20_measure() followed by ds18x20_read_temp_multi()
*
* @param pin The GPIO pin connected to the ds18x20 bus
* @param addr_list A list of addresses for devices to read.
* @param addr_count The number of entries in `addr_list`.
* @param result_list An array of int16_ts to hold the returned temperature
* values. It should have at least `addr_count` entries.
*
* @returns `ESP_OK` if all temperatures were fetched successfully
*/
esp_err_t ds18x20_measure_and_read_multi(gpio_num_t pin, ds18x20_addr_t *addr_list, size_t addr_count, int16_t *result_list);
/**
* @brief Read the scratchpad data for a particular ds18x20 device.
*
* This is not generally necessary to do directly. It is done automatically
* as part of ds18x20_read_temperature().
*
* @param pin The GPIO pin connected to the ds18x20 device
* @param addr The 64-bit address of the device to read. This can be set
* to ::DS18X20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
* @param buffer An 8-byte buffer to hold the read data.
*
* @returns `ESP_OK` if the command was successfully issued
*/
esp_err_t ds18x20_read_scratchpad(gpio_num_t pin, ds18x20_addr_t addr, uint8_t *buffer);
/**
* @brief Write the scratchpad data for a particular ds18x20 device.
*
* @param pin The GPIO pin connected to the ds18x20 device
* @param addr The 64-bit address of the device to write. This can be set
* to ::DS18X20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
* @param buffer An 3-byte buffer to hold the data to write
*
* @returns `ESP_OK` if the command was successfully issued
*/
esp_err_t ds18x20_write_scratchpad(gpio_num_t pin, ds18x20_addr_t addr, uint8_t *buffer);
/**
* @brief Issue the copy scratchpad command, copying current scratchpad to
* EEPROM.
*
* @param pin The GPIO pin connected to the ds18x20 device
* @param addr The 64-bit address of the device to command. This can be set
* to ::DS18X20_ANY to read any device on the bus (but note
* that this will only work if there is exactly one device
* connected, or they will corrupt each others' transmissions)
*
* @returns `ESP_OK` if the command was successfully issued
*/
esp_err_t ds18x20_copy_scratchpad(gpio_num_t pin, ds18x20_addr_t addr);
#endif /* _DS18X20_H */
// === Fim de: components/peripherals/src/ds18x20.h ===

View File

@@ -1,793 +0,0 @@
// === Início de: components/peripherals/src/socket_lock.c ===
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "nvs.h"
#include "socket_lock.h"
#include "board_config.h"
#define NVS_NAMESPACE "socket_lock"
#define NVS_OPERATING_TIME "op_time"
#define NVS_BREAK_TIME "break_time"
#define NVS_RETRY_COUNT "retry_count"
#define NVS_DETECTION_HIGH "detect_hi"
#define OPERATING_TIME_MIN 100
#define OPERATING_TIME_MAX 1000
#define LOCK_DELAY 500
#define LOCK_BIT BIT0
#define UNLOCK_BIT BIT1
#define REPEAT_LOCK_BIT BIT2
#define REPEAT_UNLOCK_BIT BIT3
static const char* TAG = "socket_lock";
static nvs_handle_t nvs;
static uint16_t operating_time = 300;
static uint16_t break_time = 1000;
static bool detection_high;
static uint8_t retry_count = 5;
static socket_lock_status_t status;
static TaskHandle_t socket_lock_task;
static bool is_locked(void)
{
gpio_set_level(board_config.socket_lock_a_gpio, 1);
gpio_set_level(board_config.socket_lock_b_gpio, 1);
vTaskDelay(pdMS_TO_TICKS(board_config.socket_lock_detection_delay));
return gpio_get_level(board_config.socket_lock_detection_gpio) == detection_high;
}
bool socket_lock_is_locked_state(void)
{
return is_locked();
}
static void socket_lock_task_func(void* param)
{
uint32_t notification;
TickType_t previous_tick = 0;
uint8_t attempt = 0;
while (true) {
if (xTaskNotifyWait(0x00, 0xff, &notification, portMAX_DELAY)) {
if (notification & (LOCK_BIT | UNLOCK_BIT)) {
attempt = retry_count;
}
if (notification & (UNLOCK_BIT | REPEAT_UNLOCK_BIT)) {
gpio_set_level(board_config.socket_lock_a_gpio, 0);
gpio_set_level(board_config.socket_lock_b_gpio, 1);
vTaskDelay(pdMS_TO_TICKS(operating_time));
if (!is_locked()) {
ESP_LOGI(TAG, "Unlock OK");
status = SOCKED_LOCK_STATUS_IDLE;
} else {
if (attempt > 1) {
ESP_LOGW(TAG, "Not unlocked yet, repeating...");
attempt--;
xTaskNotify(socket_lock_task, REPEAT_UNLOCK_BIT, eSetBits);
} else {
ESP_LOGE(TAG, "Not unlocked");
status = SOCKED_LOCK_STATUS_UNLOCKING_FAIL;
}
}
gpio_set_level(board_config.socket_lock_a_gpio, 0);
gpio_set_level(board_config.socket_lock_b_gpio, 0);
} else if (notification & (LOCK_BIT | REPEAT_LOCK_BIT)) {
if (notification & LOCK_BIT) {
vTaskDelay(pdMS_TO_TICKS(LOCK_DELAY)); //delay before first lock attempt
}
gpio_set_level(board_config.socket_lock_a_gpio, 1);
gpio_set_level(board_config.socket_lock_b_gpio, 0);
vTaskDelay(pdMS_TO_TICKS(operating_time));
if (is_locked()) {
ESP_LOGI(TAG, "Lock OK");
status = SOCKED_LOCK_STATUS_IDLE;
} else {
if (attempt > 1) {
ESP_LOGW(TAG, "Not locked yet, repeating...");
attempt--;
xTaskNotify(socket_lock_task, REPEAT_LOCK_BIT, eSetBits);
} else {
ESP_LOGE(TAG, "Not locked");
status = SOCKED_LOCK_STATUS_LOCKING_FAIL;
}
}
gpio_set_level(board_config.socket_lock_a_gpio, 0);
gpio_set_level(board_config.socket_lock_b_gpio, 0);
}
TickType_t delay_tick = xTaskGetTickCount() - previous_tick;
if (delay_tick < pdMS_TO_TICKS(break_time)) {
vTaskDelay(pdMS_TO_TICKS(break_time) - delay_tick);
}
previous_tick = xTaskGetTickCount();
}
}
}
void socket_lock_init(void)
{
if (board_config.socket_lock) {
ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs));
nvs_get_u16(nvs, NVS_OPERATING_TIME, &operating_time);
nvs_get_u16(nvs, NVS_BREAK_TIME, &break_time);
nvs_get_u8(nvs, NVS_RETRY_COUNT, &retry_count);
uint8_t u8;
if (nvs_get_u8(nvs, NVS_DETECTION_HIGH, &u8) == ESP_OK) {
detection_high = u8;
}
gpio_config_t io_conf = {};
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = BIT64(board_config.socket_lock_a_gpio) | BIT64(board_config.socket_lock_b_gpio);
ESP_ERROR_CHECK(gpio_config(&io_conf));
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = BIT64(board_config.socket_lock_detection_gpio);
ESP_ERROR_CHECK(gpio_config(&io_conf));
xTaskCreate(socket_lock_task_func, "socket_lock_task", 2 * 1024, NULL, 10, &socket_lock_task);
}
}
bool socket_lock_is_detection_high(void)
{
return detection_high;
}
void socket_lock_set_detection_high(bool _detection_high)
{
detection_high = _detection_high;
nvs_set_u8(nvs, NVS_DETECTION_HIGH, detection_high);
nvs_commit(nvs);
}
uint16_t socket_lock_get_operating_time(void)
{
return operating_time;
}
esp_err_t socket_lock_set_operating_time(uint16_t _operating_time)
{
if (_operating_time < OPERATING_TIME_MIN || _operating_time > OPERATING_TIME_MAX) {
ESP_LOGE(TAG, "Operating time out of range");
return ESP_ERR_INVALID_ARG;
}
operating_time = _operating_time;
nvs_set_u16(nvs, NVS_OPERATING_TIME, operating_time);
nvs_commit(nvs);
return ESP_OK;
}
uint8_t socket_lock_get_retry_count(void)
{
return retry_count;
}
void socket_lock_set_retry_count(uint8_t _retry_count)
{
retry_count = _retry_count;
nvs_set_u8(nvs, NVS_RETRY_COUNT, retry_count);
nvs_commit(nvs);
}
uint16_t socket_lock_get_break_time(void)
{
return break_time;
}
esp_err_t socket_lock_set_break_time(uint16_t _break_time)
{
if (_break_time < board_config.socket_lock_min_break_time) {
ESP_LOGE(TAG, "Operating time out of range");
return ESP_ERR_INVALID_ARG;
}
break_time = _break_time;
nvs_set_u16(nvs, NVS_BREAK_TIME, break_time);
nvs_commit(nvs);
return ESP_OK;
}
void socket_lock_set_locked(bool locked)
{
ESP_LOGI(TAG, "Set locked %d", locked);
xTaskNotify(socket_lock_task, locked ? LOCK_BIT : UNLOCK_BIT, eSetBits);
status = SOCKED_LOCK_STATUS_OPERATING;
}
socket_lock_status_t socket_lock_get_status(void)
{
return status;
}
// === Fim de: components/peripherals/src/socket_lock.c ===
// === Início de: components/peripherals/src/temp_sensor.c ===
#include <sys/param.h>
#include <freertos/FreeRTOS.h>
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "temp_sensor.h"
#include "lm75a.h"
#define MAX_SENSORS 5
#define MEASURE_PERIOD 10000 // 10s
#define MEASURE_ERR_THRESHOLD 3
static const char *TAG = "temp_sensor";
static uint8_t sensor_count = 0;
static int16_t low_temp = 0;
static int high_temp = 0;
static uint8_t measure_err_count = 0;
static void temp_sensor_task_func(void *param)
{
while (true)
{
high_temp = lm75a_read_temperature(0);
vTaskDelay(pdMS_TO_TICKS(MEASURE_PERIOD));
}
}
void temp_sensor_init(void)
{
ESP_LOGW(TAG, "temp_sensor_init");
lm75a_init();
xTaskCreate(temp_sensor_task_func, "temp_sensor_task", 5 * 1024, NULL, 5, NULL);
}
uint8_t temp_sensor_get_count(void)
{
return sensor_count;
}
int16_t temp_sensor_get_low(void)
{
return low_temp;
}
int temp_sensor_get_high(void)
{
return high_temp;
}
bool temp_sensor_is_error(void)
{
return sensor_count == 0 || measure_err_count > MEASURE_ERR_THRESHOLD;
}
// === Fim de: components/peripherals/src/temp_sensor.c ===
// === Início de: components/peripherals/src/aux_io.c ===
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "nvs.h"
#include "aux_io.h"
#include "board_config.h"
#include "adc.h"
#define MAX_AUX_IN 4
#define MAX_AUX_OUT 4
#define MAX_AUX_AIN 4
//static const char* TAG = "aux";
static int aux_in_count = 0;
static int aux_out_count = 0;
static int aux_ain_count = 0;
static struct aux_gpio_s
{
gpio_num_t gpio;
const char* name;
} aux_in[MAX_AUX_IN], aux_out[MAX_AUX_OUT];
static struct aux_adc_s
{
adc_channel_t adc;
const char* name;
} aux_ain[MAX_AUX_AIN];
void aux_init(void)
{
// IN
gpio_config_t io_conf = {
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLDOWN_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
.pin_bit_mask = 0
};
if (board_config.aux_in_1) {
aux_in[aux_in_count].gpio = board_config.aux_in_1_gpio;
aux_in[aux_in_count].name = board_config.aux_in_1_name;
io_conf.pin_bit_mask |= BIT64(board_config.aux_in_1_gpio);
aux_in_count++;
}
if (board_config.aux_in_2) {
aux_in[aux_in_count].gpio = board_config.aux_in_2_gpio;
aux_in[aux_in_count].name = board_config.aux_in_2_name;
io_conf.pin_bit_mask |= BIT64(board_config.aux_in_2_gpio);
aux_in_count++;
}
if (board_config.aux_in_3) {
aux_in[aux_in_count].gpio = board_config.aux_in_3_gpio;
aux_in[aux_in_count].name = board_config.aux_in_3_name;
io_conf.pin_bit_mask |= BIT64(board_config.aux_in_3_gpio);
aux_in_count++;
}
if (board_config.aux_in_4) {
aux_in[aux_in_count].gpio = board_config.aux_in_4_gpio;
aux_in[aux_in_count].name = board_config.aux_in_4_name;
io_conf.pin_bit_mask |= BIT64(board_config.aux_in_4_gpio);
aux_in_count++;
}
if (io_conf.pin_bit_mask > 0) {
ESP_ERROR_CHECK(gpio_config(&io_conf));
}
// OUT
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 0;
if (board_config.aux_out_1) {
aux_out[aux_out_count].gpio = board_config.aux_out_1_gpio;
aux_out[aux_out_count].name = board_config.aux_out_1_name;
io_conf.pin_bit_mask |= BIT64(board_config.aux_out_1_gpio);
aux_out_count++;
}
if (board_config.aux_out_2) {
aux_out[aux_out_count].gpio = board_config.aux_out_2_gpio;
aux_out[aux_out_count].name = board_config.aux_out_2_name;
io_conf.pin_bit_mask |= BIT64(board_config.aux_out_2_gpio);
aux_out_count++;
}
if (board_config.aux_out_3) {
aux_out[aux_out_count].gpio = board_config.aux_out_3_gpio;
aux_out[aux_out_count].name = board_config.aux_out_3_name;
io_conf.pin_bit_mask |= BIT64(board_config.aux_out_3_gpio);
aux_out_count++;
}
if (board_config.aux_out_4) {
aux_out[aux_out_count].gpio = board_config.aux_out_4_gpio;
aux_out[aux_out_count].name = board_config.aux_out_4_name;
io_conf.pin_bit_mask |= BIT64(board_config.aux_out_4_gpio);
aux_out_count++;
}
if (io_conf.pin_bit_mask > 0) {
ESP_ERROR_CHECK(gpio_config(&io_conf));
}
// AIN
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12
};
if (board_config.aux_ain_1) {
aux_ain[aux_ain_count].adc = board_config.aux_ain_1_adc_channel;
aux_ain[aux_ain_count].name = board_config.aux_out_1_name;
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.aux_ain_1_adc_channel, &config));
aux_ain_count++;
}
if (board_config.aux_ain_2) {
aux_ain[aux_ain_count].adc = board_config.aux_ain_2_adc_channel;
aux_ain[aux_ain_count].name = board_config.aux_out_2_name;
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.aux_ain_2_adc_channel, &config));
aux_ain_count++;
}
}
esp_err_t aux_read(const char* name, bool* value)
{
for (int i = 0; i < aux_in_count; i++) {
if (strcmp(aux_in[i].name, name) == 0) {
*value = gpio_get_level(aux_in[i].gpio) == 1;
return ESP_OK;
}
}
return ESP_ERR_NOT_FOUND;
}
esp_err_t aux_write(const char* name, bool value)
{
for (int i = 0; i < aux_out_count; i++) {
if (strcmp(aux_out[i].name, name) == 0) {
return gpio_set_level(aux_out[i].gpio, value);
}
}
return ESP_ERR_NOT_FOUND;
}
esp_err_t aux_analog_read(const char* name, int* value)
{
for (int i = 0; i < aux_ain_count; i++) {
if (strcmp(aux_ain[i].name, name) == 0) {
int raw = 0;
esp_err_t ret = adc_oneshot_read(adc_handle, aux_ain[i].adc, &raw);
if (ret == ESP_OK) {
return adc_cali_raw_to_voltage(adc_cali_handle, raw, value);
} else {
return ret;
}
}
}
return ESP_ERR_NOT_FOUND;
}
// === Fim de: components/peripherals/src/aux_io.c ===
// === Início de: components/peripherals/src/lm75a.c ===
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "driver/i2c_master.h"
#define I2C_MASTER_NUM I2C_NUM_1
#define I2C_MASTER_SCL_IO GPIO_NUM_22 // CONFIG_EXAMPLE_I2C_SCL /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO GPIO_NUM_21 // CONFIG_EXAMPLE_I2C_SDA /*!< gpio number for I2C master data */
#define I2C_MASTER_FREQ_HZ 100000 // CONFIG_I2C_TRANS_SPEED /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define LM75A_SLAVE_ADDR 0x48 // CONFIG_LM75A_SLAVE_ADDR /*!< LM75A slave address, you can set any 7bit value */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
/*
#define GPIO_INPUT_IO_0 CONFIG_LM75A_OS_PIN
#define GPIO_OUTPUT_IO_0 CONFIG_LM75A_VCC_PIN
#define GPIO_OUTPUT_PIN_SEL (1ULL << GPIO_OUTPUT_IO_0)
#define GPIO_INPUT_PIN_SEL (1ULL << GPIO_INPUT_IO_0)
#define ESP_INTR_FLAG_DEFAULT 0
*/
// static xQueueHandle gpio_evt_queue = NULL;
// static int gpio_int_task_enable = 0;
// static TaskHandle_t gpio_int_task_handle = NULL;
/**
* @brief test code to read esp-i2c-slave
* We need to fill the buffer of esp slave device, then master can read them out.
*
* _______________________________________________________________________________________
* | start | slave_addr + rd_bit +ack | read n-1 bytes + ack | read 1 byte + nack | stop |
* --------|--------------------------|----------------------|--------------------|------|
*
*/
static esp_err_t i2c_master_read_slave(i2c_port_t i2c_num, uint8_t *data_rd, size_t size)
{
if (size == 0)
{
return ESP_OK;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (LM75A_SLAVE_ADDR << 1) | READ_BIT, ACK_CHECK_EN);
if (size > 1)
{
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
}
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
/**
* @brief Test code to write esp-i2c-slave
* Master device write data to slave(both esp32),
* the data will be stored in slave buffer.
* We can read them out from slave buffer.
*
* ___________________________________________________________________
* | start | slave_addr + wr_bit + ack | write n bytes + ack | stop |
* --------|---------------------------|----------------------|------|
*
*/
static esp_err_t i2c_master_write_slave(i2c_port_t i2c_num, uint8_t *data_wr, size_t size)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (LM75A_SLAVE_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
/**
* @brief i2c master initialization
*/
static void i2c_master_init()
{
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = I2C_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
conf.scl_io_num = I2C_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
conf.clk_flags = 0;
i2c_param_config(i2c_master_port, &conf);
i2c_driver_install(i2c_master_port, conf.mode,
I2C_MASTER_RX_BUF_DISABLE,
I2C_MASTER_TX_BUF_DISABLE, 0);
}
int lm75a_read_temperature(int show)
{
uint8_t buf[2];
float tmp;
buf[0] = 0;
i2c_master_write_slave(I2C_MASTER_NUM, buf, 1);
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2);
tmp = buf[0];
if (buf[1] & 128)
tmp += 0.5;
if (show)
printf("lm75a_read_temperature=%.1f\n", tmp);
return tmp;
}
/*
static void IRAM_ATTR gpio_isr_handler(void *arg)
{
uint32_t gpio_num = (uint32_t)arg;
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
static void gpio_int_task(void *arg)
{
uint32_t io_num;
gpio_int_task_enable = 1;
while (gpio_int_task_enable)
{
if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY))
{
// read temperature to clean int;
if (io_num == GPIO_INPUT_IO_0)
{
printf("GPIO[%d] intr, val: %d\n\n", io_num, gpio_get_level(io_num));
lm75a_read_temperature(0); // read to clean interrupt.
}
}
}
printf("quit gpio_int_task\n");
if (gpio_evt_queue)
{
vQueueDelete(gpio_evt_queue);
gpio_evt_queue = NULL;
}
gpio_int_task_handle = NULL;
vTaskDelete(NULL);
}
void init_os_gpio()
{
printf("init_os_gpio!\n");
if (gpio_evt_queue == NULL)
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
if (gpio_int_task_handle == NULL)
{
xTaskCreate(gpio_int_task, "gpio_int_task", 2048, NULL, 10, &gpio_int_task_handle);
// install gpio isr service
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
// hook isr handler for specific gpio pin again
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void *)GPIO_INPUT_IO_0);
}
}
static void deinit_os_gpio()
{
printf("deinit_os_gpio!\n");
if (gpio_int_task_handle)
{
gpio_isr_handler_remove(GPIO_INPUT_IO_0);
gpio_uninstall_isr_service();
gpio_int_task_enable = 0;
int io = 0;
xQueueSend(gpio_evt_queue, &io, 0); // send a fake signal to quit task.
}
}
static void lm75a_vcc_enable()
{
gpio_config_t io_conf;
// enable output for vcc
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
// enable input for interrupt
io_conf.intr_type = GPIO_PIN_INTR_NEGEDGE; // GPIO_PIN_INTR_ANYEDGE;
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = 1;
gpio_set_pull_mode(GPIO_INPUT_IO_0, GPIO_FLOATING);
gpio_config(&io_conf);
gpio_set_level(GPIO_OUTPUT_IO_0, 1);
}
static void lm75a_vcc_disable()
{
gpio_set_level(GPIO_OUTPUT_IO_0, 0);
}
*/
void lm75a_init()
{
// lm75a_vcc_enable();
i2c_master_init();
}
void lm75a_deinit()
{
// deinit_os_gpio();
i2c_driver_delete(I2C_MASTER_NUM);
// lm75a_vcc_disable();
}
void lm75a_set_tos(int tos)
{
uint8_t buf[4];
printf("lm75a_set_tos: %d\n", tos);
// set Tos:
buf[0] = 0x3;
buf[1] = (tos & 0xff);
buf[2] = 0;
i2c_master_write_slave(I2C_MASTER_NUM, buf, 3);
}
void lm75a_set_thys(int thys)
{
uint8_t buf[4];
printf("lm75a_set_thys: %d\n", thys);
// set Thyst:
buf[0] = 0x2;
buf[1] = (thys & 0xff);
buf[2] = 0;
i2c_master_write_slave(I2C_MASTER_NUM, buf, 3);
}
void lm75a_get_tos()
{
uint8_t buf[4];
float tmp;
buf[0] = 0x3;
i2c_master_write_slave(I2C_MASTER_NUM, buf, 1);
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2);
tmp = buf[0];
if (buf[1] & 128)
tmp += 0.5;
printf("lm75a_get_tos: %.1f\n", tmp);
}
void lm75a_get_thys()
{
uint8_t buf[4];
float tmp;
buf[0] = 0x2;
i2c_master_write_slave(I2C_MASTER_NUM, buf, 1);
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2);
tmp = buf[0];
if (buf[1] & 128)
tmp += 0.5;
printf("lm75a_get_thys: %.1f\n", tmp);
}
void lm75a_set_int(int en)
{
uint8_t buf[2];
en = !!en;
if (en)
{
printf("lm75a_set_int: %d\n", en);
buf[0] = 0x1;
buf[1] = (1 << 1); // D1 set to 1;
i2c_master_write_slave(I2C_MASTER_NUM, buf, 2);
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2); // do one time read to clean interrupt before enter interrupt mode.
// gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_NEGEDGE);
// init_os_gpio();
}
else
{
printf("lm75a_set_int: %d\n", en);
// deinit_os_gpio();
buf[0] = 0x1;
buf[1] = 0;
i2c_master_write_slave(I2C_MASTER_NUM, buf, 2);
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2); // do one time read to clean interrupt before enter interrupt mode.
}
}
void lm75a_get_osio()
{
// printf("os_io: %d\n", gpio_get_level(GPIO_INPUT_IO_0));
}
// === Fim de: components/peripherals/src/lm75a.c ===

View File

@@ -1,783 +0,0 @@
// === Início de: components/peripherals/src/onewire.c ===
/*
* The MIT License (MIT)
*
* Copyright (c) 2014 zeroday nodemcu.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* -------------------------------------------------------------------------------
* Portions copyright (C) 2000 Dallas Semiconductor Corporation, under the
* following additional terms:
*
* Except as contained in this notice, the name of Dallas Semiconductor
* shall not be used except as stated in the Dallas Semiconductor
* Branding Policy.
*/
#include <string.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "rom/ets_sys.h"
#include "onewire.h"
#define ONEWIRE_SELECT_ROM 0x55
#define ONEWIRE_SKIP_ROM 0xcc
#define ONEWIRE_SEARCH 0xf0
#define ONEWIRE_CRC8_TABLE
static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
// Waits up to `max_wait` microseconds for the specified pin to go high.
// Returns true if successful, false if the bus never comes high (likely
// shorted).
static inline bool _onewire_wait_for_bus(gpio_num_t pin, int max_wait)
{
bool state;
for (int i = 0; i < ((max_wait + 4) / 5); i++) {
if (gpio_get_level(pin))
break;
ets_delay_us(5);
}
state = gpio_get_level(pin);
// Wait an extra 1us to make sure the devices have an adequate recovery
// time before we drive things low again.
ets_delay_us(1);
return state;
}
static void setup_pin(gpio_num_t pin, bool open_drain)
{
gpio_set_direction(pin, open_drain ? GPIO_MODE_INPUT_OUTPUT_OD : GPIO_MODE_OUTPUT);
// gpio_set_pull_mode(pin, GPIO_PULLUP_ONLY);
}
// Perform the onewire reset function. We will wait up to 250uS for
// the bus to come high, if it doesn't then it is broken or shorted
// and we return false;
//
// Returns true if a device asserted a presence pulse, false otherwise.
//
bool onewire_reset(gpio_num_t pin)
{
setup_pin(pin, true);
gpio_set_level(pin, 1);
// wait until the wire is high... just in case
if (!_onewire_wait_for_bus(pin, 250))
return false;
gpio_set_level(pin, 0);
ets_delay_us(480);
portENTER_CRITICAL(&mux);
gpio_set_level(pin, 1); // allow it to float
ets_delay_us(70);
bool r = !gpio_get_level(pin);
portEXIT_CRITICAL(&mux);
// Wait for all devices to finish pulling the bus low before returning
if (!_onewire_wait_for_bus(pin, 410))
return false;
return r;
}
static bool _onewire_write_bit(gpio_num_t pin, bool v)
{
if (!_onewire_wait_for_bus(pin, 10))
return false;
portENTER_CRITICAL(&mux);
if (v) {
gpio_set_level(pin, 0); // drive output low
ets_delay_us(10);
gpio_set_level(pin, 1); // allow output high
ets_delay_us(55);
} else {
gpio_set_level(pin, 0); // drive output low
ets_delay_us(65);
gpio_set_level(pin, 1); // allow output high
}
ets_delay_us(1);
portEXIT_CRITICAL(&mux);
return true;
}
static int _onewire_read_bit(gpio_num_t pin)
{
if (!_onewire_wait_for_bus(pin, 10))
return -1;
portENTER_CRITICAL(&mux);
gpio_set_level(pin, 0);
ets_delay_us(2);
gpio_set_level(pin, 1); // let pin float, pull up will raise
ets_delay_us(11);
int r = gpio_get_level(pin); // Must sample within 15us of start
ets_delay_us(48);
portEXIT_CRITICAL(&mux);
return r;
}
// Write a byte. The writing code uses open-drain mode and expects the pullup
// resistor to pull the line high when not driven low. If you need strong
// power after the write (e.g. DS18B20 in parasite power mode) then call
// onewire_power() after this is complete to actively drive the line high.
//
bool onewire_write(gpio_num_t pin, uint8_t v)
{
for (uint8_t bitMask = 0x01; bitMask; bitMask <<= 1)
if (!_onewire_write_bit(pin, (bitMask & v)))
return false;
return true;
}
bool onewire_write_bytes(gpio_num_t pin, const uint8_t* buf, size_t count)
{
for (size_t i = 0; i < count; i++)
if (!onewire_write(pin, buf[i]))
return false;
return true;
}
// Read a byte
//
int onewire_read(gpio_num_t pin)
{
int r = 0;
for (uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) {
int bit = _onewire_read_bit(pin);
if (bit < 0)
return -1;
else if (bit)
r |= bitMask;
}
return r;
}
bool onewire_read_bytes(gpio_num_t pin, uint8_t* buf, size_t count)
{
size_t i;
int b;
for (i = 0; i < count; i++) {
b = onewire_read(pin);
if (b < 0)
return false;
buf[i] = b;
}
return true;
}
bool onewire_select(gpio_num_t pin, onewire_addr_t addr)
{
uint8_t i;
if (!onewire_write(pin, ONEWIRE_SELECT_ROM))
return false;
for (i = 0; i < 8; i++) {
if (!onewire_write(pin, addr & 0xff))
return false;
addr >>= 8;
}
return true;
}
bool onewire_skip_rom(gpio_num_t pin)
{
return onewire_write(pin, ONEWIRE_SKIP_ROM);
}
bool onewire_power(gpio_num_t pin)
{
// Make sure the bus is not being held low before driving it high, or we
// may end up shorting ourselves out.
if (!_onewire_wait_for_bus(pin, 10))
return false;
setup_pin(pin, false);
gpio_set_level(pin, 1);
return true;
}
void onewire_depower(gpio_num_t pin)
{
setup_pin(pin, true);
}
void onewire_search_start(onewire_search_t* search)
{
// reset the search state
memset(search, 0, sizeof(*search));
}
void onewire_search_prefix(onewire_search_t* search, uint8_t family_code)
{
uint8_t i;
search->rom_no[0] = family_code;
for (i = 1; i < 8; i++) {
search->rom_no[i] = 0;
}
search->last_discrepancy = 64;
search->last_device_found = false;
}
// Perform a search. If the next device has been successfully enumerated, its
// ROM address will be returned. If there are no devices, no further
// devices, or something horrible happens in the middle of the
// enumeration then ONEWIRE_NONE is returned. Use OneWire::reset_search() to
// start over.
//
// --- Replaced by the one from the Dallas Semiconductor web site ---
//--------------------------------------------------------------------------
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
// search state.
// Return 1 : device found, ROM number in ROM_NO buffer
// 0 : device not found, end of search
//
onewire_addr_t onewire_search_next(onewire_search_t* search, gpio_num_t pin)
{
//TODO: add more checking for read/write errors
uint8_t id_bit_number;
uint8_t last_zero, search_result;
int rom_byte_number;
int8_t id_bit, cmp_id_bit;
onewire_addr_t addr;
unsigned char rom_byte_mask;
bool search_direction;
// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
rom_byte_mask = 1;
search_result = 0;
// if the last call was not the last one
if (!search->last_device_found) {
// 1-Wire reset
if (!onewire_reset(pin)) {
// reset the search
search->last_discrepancy = 0;
search->last_device_found = false;
return ONEWIRE_NONE;
}
// issue the search command
onewire_write(pin, ONEWIRE_SEARCH);
// loop to do the search
do {
// read a bit and its complement
id_bit = _onewire_read_bit(pin);
cmp_id_bit = _onewire_read_bit(pin);
if ((id_bit == 1) && (cmp_id_bit == 1))
break;
else {
// all devices coupled have 0 or 1
if (id_bit != cmp_id_bit)
search_direction = id_bit; // bit write value for search
else {
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < search->last_discrepancy)
search_direction = ((search->rom_no[rom_byte_number] & rom_byte_mask) > 0);
else
// if equal to last pick 1, if not then pick 0
search_direction = (id_bit_number == search->last_discrepancy);
// if 0 was picked then record its position in LastZero
if (!search_direction)
last_zero = id_bit_number;
}
// set or clear the bit in the ROM byte rom_byte_number
// with mask rom_byte_mask
if (search_direction)
search->rom_no[rom_byte_number] |= rom_byte_mask;
else
search->rom_no[rom_byte_number] &= ~rom_byte_mask;
// serial number search direction write bit
_onewire_write_bit(pin, search_direction);
// increment the byte counter id_bit_number
// and shift the mask rom_byte_mask
id_bit_number++;
rom_byte_mask <<= 1;
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
if (rom_byte_mask == 0) {
rom_byte_number++;
rom_byte_mask = 1;
}
}
} while (rom_byte_number < 8); // loop until through all ROM bytes 0-7
// if the search was successful then
if (!(id_bit_number < 65)) {
// search successful so set last_discrepancy,last_device_found,search_result
search->last_discrepancy = last_zero;
// check for last device
if (search->last_discrepancy == 0)
search->last_device_found = true;
search_result = 1;
}
}
// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !search->rom_no[0]) {
search->last_discrepancy = 0;
search->last_device_found = false;
return ONEWIRE_NONE;
} else {
addr = 0;
for (rom_byte_number = 7; rom_byte_number >= 0; rom_byte_number--) {
addr = (addr << 8) | search->rom_no[rom_byte_number];
}
//printf("Ok I found something at %08x%08x...\n", (uint32_t)(addr >> 32), (uint32_t)addr);
}
return addr;
}
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
//
#ifdef ONEWIRE_CRC8_TABLE
// This table comes from Dallas sample code where it is freely reusable,
// though Copyright (c) 2000 Dallas Semiconductor Corporation
static const uint8_t dscrc_table[] = {
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
};
//
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
// and the registers. (note: this might better be done without to
// table, it would probably be smaller and certainly fast enough
// compared to all those delayMicrosecond() calls. But I got
// confused, so I use this table from the examples.)
//
uint8_t onewire_crc8(const uint8_t* data, uint8_t len)
{
uint8_t crc = 0;
while (len--)
crc = dscrc_table[crc ^ *data++];
return crc;
}
#else
//
// Compute a Dallas Semiconductor 8 bit CRC directly.
// this is much slower, but much smaller, than the lookup table.
//
uint8_t onewire_crc8(const uint8_t* data, uint8_t len)
{
uint8_t crc = 0;
while (len--)
{
uint8_t inbyte = *data++;
for (int i = 8; i; i--)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix)
crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
#endif /* ONEWIRE_CRC8_TABLE */
// Compute the 1-Wire CRC16 and compare it against the received CRC.
// Example usage (reading a DS2408):
// // Put everything in a buffer so we can compute the CRC easily.
// uint8_t buf[13];
// buf[0] = 0xF0; // Read PIO Registers
// buf[1] = 0x88; // LSB address
// buf[2] = 0x00; // MSB address
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
// if (!CheckCRC16(buf, 11, &buf[11])) {
// // Handle error.
// }
//
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param inverted_crc - The two CRC16 bytes in the received data.
// This should just point into the received data,
// *not* at a 16-bit integer.
// @param crc - The crc starting value (optional)
// @return 1, iff the CRC matches.
bool onewire_check_crc16(const uint8_t* input, size_t len, const uint8_t* inverted_crc, uint16_t crc_iv)
{
uint16_t crc = ~onewire_crc16(input, len, crc_iv);
return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
}
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
// the integrity of data received from many 1-Wire devices. Note that the
// CRC computed here is *not* what you'll get from the 1-Wire network,
// for two reasons:
// 1) The CRC is transmitted bitwise inverted.
// 2) Depending on the endian-ness of your processor, the binary
// representation of the two-byte return value may have a different
// byte order than the two bytes you get from 1-Wire.
// @param input - Array of bytes to checksum.
// @param len - How many bytes to use.
// @param crc - The crc starting value (optional)
// @return The CRC16, as defined by Dallas Semiconductor.
uint16_t onewire_crc16(const uint8_t* input, size_t len, uint16_t crc_iv)
{
uint16_t crc = crc_iv;
static const uint8_t oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
uint16_t i;
for (i = 0; i < len; i++) {
// Even though we're just copying a byte from the input,
// we'll be doing 16-bit computation with it.
uint16_t cdata = input[i];
cdata = (cdata ^ crc) & 0xff;
crc >>= 8;
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])
crc ^= 0xC001;
cdata <<= 6;
crc ^= cdata;
cdata <<= 1;
crc ^= cdata;
}
return crc;
}
// === Fim de: components/peripherals/src/onewire.c ===
// === Início de: components/peripherals/src/onewire.h ===
/*
* The MIT License (MIT)
*
* Copyright (c) 2014 zeroday nodemcu.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* -------------------------------------------------------------------------------
* Portions copyright (C) 2000 Dallas Semiconductor Corporation, under the
* following additional terms:
*
* Except as contained in this notice, the name of Dallas Semiconductor
* shall not be used except as stated in the Dallas Semiconductor
* Branding Policy.
*/
#ifndef ONEWIRE_H_
#define ONEWIRE_H_
#include <stdbool.h>
#include <stdint.h>
#include "driver/gpio.h"
/**
* Type used to hold all 1-Wire device ROM addresses (64-bit)
*/
typedef uint64_t onewire_addr_t;
/**
* Structure to contain the current state for onewire_search_next(), etc
*/
typedef struct
{
uint8_t rom_no[8];
uint8_t last_discrepancy;
bool last_device_found;
} onewire_search_t;
/**
* ::ONEWIRE_NONE is an invalid ROM address that will never occur in a device
* (CRC mismatch), and so can be useful as an indicator for "no-such-device",
* etc.
*/
#define ONEWIRE_NONE ((onewire_addr_t)(0xffffffffffffffffLL))
/**
* @brief Perform a 1-Wire reset cycle.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
*
* @return `true` if at least one device responds with a presence pulse,
* `false` if no devices were detected (or the bus is shorted, etc)
*/
bool onewire_reset(gpio_num_t pin);
/**
* @brief Issue a 1-Wire "ROM select" command to select a particular device.
*
* It is necessary to call ::onewire_reset() before calling this function.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* @param addr The ROM address of the device to select
*
* @return `true` if the "ROM select" command could be successfully issued,
* `false` if there was an error.
*/
bool onewire_select(gpio_num_t pin, const onewire_addr_t addr);
/**
* @brief Issue a 1-Wire "skip ROM" command to select *all* devices on the bus.
*
* It is necessary to call ::onewire_reset() before calling this function.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
*
* @return `true` if the "skip ROM" command could be successfully issued,
* `false` if there was an error.
*/
bool onewire_skip_rom(gpio_num_t pin);
/**
* @brief Write a byte on the onewire bus.
*
* The writing code uses open-drain mode and expects the pullup resistor to
* pull the line high when not driven low. If you need strong power after the
* write (e.g. DS18B20 in parasite power mode) then call ::onewire_power()
* after this is complete to actively drive the line high.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* @param v The byte value to write
*
* @return `true` if successful, `false` on error.
*/
bool onewire_write(gpio_num_t pin, uint8_t v);
/**
* @brief Write multiple bytes on the 1-Wire bus.
*
* See ::onewire_write() for more info.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* @param buf A pointer to the buffer of bytes to be written
* @param count Number of bytes to write
*
* @return `true` if all bytes written successfully, `false` on error.
*/
bool onewire_write_bytes(gpio_num_t pin, const uint8_t *buf, size_t count);
/**
* @brief Read a byte from a 1-Wire device.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
*
* @return the read byte on success, negative value on error.
*/
int onewire_read(gpio_num_t pin);
/**
* @brief Read multiple bytes from a 1-Wire device.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
* @param[out] buf A pointer to the buffer to contain the read bytes
* @param count Number of bytes to read
*
* @return `true` on success, `false` on error.
*/
bool onewire_read_bytes(gpio_num_t pin, uint8_t *buf, size_t count);
/**
* @brief Actively drive the bus high to provide extra power for certain
* operations of parasitically-powered devices.
*
* For parasitically-powered devices which need more power than can be
* provided via the normal pull-up resistor, it may be necessary for some
* operations to drive the bus actively high. This function can be used to
* perform that operation.
*
* The bus can be depowered once it is no longer needed by calling
* ::onewire_depower(), or it will be depowered automatically the next time
* ::onewire_reset() is called to start another command.
*
* @note Make sure the device(s) you are powering will not pull more current
* than the ESP32/ESP8266 is able to supply via its GPIO pins (this is
* especially important when multiple devices are on the same bus and
* they are all performing a power-intensive operation at the same time
* (i.e. multiple DS18B20 sensors, which have all been given a
* "convert T" operation by using ::onewire_skip_rom())).
*
* @note This routine will check to make sure that the bus is already high
* before driving it, to make sure it doesn't attempt to drive it high
* while something else is pulling it low (which could cause a reset or
* damage the ESP32/ESP8266).
*
* @param pin The GPIO pin connected to the 1-Wire bus.
*
* @return `true` on success, `false` on error.
*/
bool onewire_power(gpio_num_t pin);
/**
* @brief Stop forcing power onto the bus.
*
* You only need to do this if you previously called ::onewire_power() to drive
* the bus high and now want to allow it to float instead. Note that
* onewire_reset() will also automatically depower the bus first, so you do
* not need to call this first if you just want to start a new operation.
*
* @param pin The GPIO pin connected to the 1-Wire bus.
*/
void onewire_depower(gpio_num_t pin);
/**
* @brief Clear the search state so that it will start from the beginning on
* the next call to ::onewire_search_next().
*
* @param[out] search The onewire_search_t structure to reset.
*/
void onewire_search_start(onewire_search_t *search);
/**
* @brief Setup the search to search for devices with the specified
* "family code".
*
* @param[out] search The onewire_search_t structure to update.
* @param family_code The "family code" to search for.
*/
void onewire_search_prefix(onewire_search_t *search, uint8_t family_code);
/**
* @brief Search for the next device on the bus.
*
* The order of returned device addresses is deterministic. You will always
* get the same devices in the same order.
*
* @note It might be a good idea to check the CRC to make sure you didn't get
* garbage.
*
* @return the address of the next device on the bus, or ::ONEWIRE_NONE if
* there is no next address. ::ONEWIRE_NONE might also mean that
* the bus is shorted, there are no devices, or you have already
* retrieved all of them.
*/
onewire_addr_t onewire_search_next(onewire_search_t *search, gpio_num_t pin);
/**
* @brief Compute a Dallas Semiconductor 8 bit CRC.
*
* These are used in the ROM address and scratchpad registers to verify the
* transmitted data is correct.
*/
uint8_t onewire_crc8(const uint8_t *data, uint8_t len);
/**
* @brief Compute the 1-Wire CRC16 and compare it against the received CRC.
*
* Example usage (reading a DS2408):
* @code{.c}
* // Put everything in a buffer so we can compute the CRC easily.
* uint8_t buf[13];
* buf[0] = 0xF0; // Read PIO Registers
* buf[1] = 0x88; // LSB address
* buf[2] = 0x00; // MSB address
* onewire_write_bytes(pin, buf, 3); // Write 3 cmd bytes
* onewire_read_bytes(pin, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
* if (!onewire_check_crc16(buf, 11, &buf[11])) {
* // TODO: Handle error.
* }
* @endcode
*
* @param input Array of bytes to checksum.
* @param len Number of bytes in `input`
* @param inverted_crc The two CRC16 bytes in the received data.
* This should just point into the received data,
* *not* at a 16-bit integer.
* @param crc_iv The crc starting value (optional)
*
* @return `true` if the CRC matches, `false` otherwise.
*/
bool onewire_check_crc16(const uint8_t* input, size_t len, const uint8_t* inverted_crc, uint16_t crc_iv);
/**
* @brief Compute a Dallas Semiconductor 16 bit CRC.
*
* This is required to check the integrity of data received from many 1-Wire
* devices. Note that the CRC computed here is *not* what you'll get from the
* 1-Wire network, for two reasons:
*
* 1. The CRC is transmitted bitwise inverted.
* 2. Depending on the endian-ness of your processor, the binary
* representation of the two-byte return value may have a different
* byte order than the two bytes you get from 1-Wire.
*
* @param input Array of bytes to checksum.
* @param len How many bytes are in `input`.
* @param crc_iv The crc starting value (optional)
*
* @return the CRC16, as defined by Dallas Semiconductor.
*/
uint16_t onewire_crc16(const uint8_t* input, size_t len, uint16_t crc_iv);
#endif /* ONEWIRE_H_ */
// === Fim de: components/peripherals/src/onewire.h ===

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -1,6 +1,6 @@
import os
TAMANHO_MAX = 31000 # Limite por arquivo
TAMANHO_MAX = 100000 # Limite por arquivo
def coletar_arquivos(diretorios, extensoes=(".c", ".h")):
arquivos = []
@@ -15,7 +15,7 @@ def coletar_arquivos(diretorios, extensoes=(".c", ".h")):
def unir_em_partes(arquivos, prefixo="projeto_parte", limite=TAMANHO_MAX):
parte = 1
conteudo_atual = ""
conteudo_atual = "."
total_arquivos = 0
for arquivo in arquivos:
@@ -53,8 +53,7 @@ def unir_em_partes(arquivos, prefixo="projeto_parte", limite=TAMANHO_MAX):
def main():
diretorio_main = "main"
componentes_escolhidos = [
"evse", "loadbalancer", "auth", "manager_meter",
"rest_api", "network", "peripherals"
"peripherals" , "meter_manager"
]
diretorios_componentes = [os.path.join("components", nome) for nome in componentes_escolhidos]