new meter

This commit is contained in:
2025-06-14 11:46:10 +01:00
parent 6f95c7ba59
commit a0b2e048d4
20 changed files with 17741 additions and 74 deletions

View File

@@ -50,7 +50,7 @@ void evse_process(void) {
evse_config_is_enabled() evse_config_is_enabled()
); );
evse_limits_check(evse_get_state()); evse_limits_check();
evse_state_t current = evse_get_state(); evse_state_t current = evse_get_state();
if (current != last_state) { if (current != last_state) {
@@ -99,3 +99,12 @@ static void evse_core_task(void *arg) {
vTaskDelay(pdMS_TO_TICKS(100)); vTaskDelay(pdMS_TO_TICKS(100));
} }
} }
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,62 +1,108 @@
#include "evse_state.h"
#include "evse_api.h"
#include "evse_limits.h" #include "evse_limits.h"
#include <stdint.h> #include "esp_log.h"
#include <stdbool.h> #include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// ======================== // ========================
// Estado interno // External state references
// ========================
//extern evse_state_t current_state; // Current EVSE FSM state
//extern TickType_t session_start_tick; // Timestamp of charging session start
// ========================
// Concurrency protection
// ========================
static portMUX_TYPE evse_mux = portMUX_INITIALIZER_UNLOCKED;
// ========================
// Runtime state (volatile)
// ======================== // ========================
static bool limit_reached = false; static bool limit_reached = false;
static uint32_t consumption_limit = 0; static uint32_t consumption_limit = 0; // Energy limit in Wh
static uint32_t charging_time_limit = 0; static uint32_t charging_time_limit = 0; // Time limit in seconds
static uint16_t under_power_limit = 0; static uint16_t under_power_limit = 0; // Minimum acceptable power in W
// ========================
// Default (persistent) limits
// ========================
static uint32_t default_consumption_limit = 0; static uint32_t default_consumption_limit = 0;
static uint32_t default_charging_time_limit = 0; static uint32_t default_charging_time_limit = 0;
static uint16_t default_under_power_limit = 0; static uint16_t default_under_power_limit = 0;
// ======================== // ========================
// Estado de controle // Limit status flag
// ======================== // ========================
void evse_set_limit_reached(uint8_t value) { bool evse_get_limit_reached(void) {
limit_reached = (value != 0); bool val;
portENTER_CRITICAL(&evse_mux);
val = limit_reached;
portEXIT_CRITICAL(&evse_mux);
return val;
} }
bool evse_is_limit_reached(void) { void evse_set_limit_reached(bool v) {
return limit_reached; portENTER_CRITICAL(&evse_mux);
limit_reached = v;
portEXIT_CRITICAL(&evse_mux);
} }
// ======================== // ========================
// Limites em tempo de execução // Runtime limit accessors
// ======================== // ========================
uint32_t evse_get_consumption_limit(void) { uint32_t evse_get_consumption_limit(void) {
return consumption_limit; uint32_t val;
portENTER_CRITICAL(&evse_mux);
val = consumption_limit;
portEXIT_CRITICAL(&evse_mux);
return val;
} }
void evse_set_consumption_limit(uint32_t value) { void evse_set_consumption_limit(uint32_t value) {
portENTER_CRITICAL(&evse_mux);
consumption_limit = value; consumption_limit = value;
portEXIT_CRITICAL(&evse_mux);
} }
uint32_t evse_get_charging_time_limit(void) { uint32_t evse_get_charging_time_limit(void) {
return charging_time_limit; uint32_t val;
portENTER_CRITICAL(&evse_mux);
val = charging_time_limit;
portEXIT_CRITICAL(&evse_mux);
return val;
} }
void evse_set_charging_time_limit(uint32_t value) { void evse_set_charging_time_limit(uint32_t value) {
portENTER_CRITICAL(&evse_mux);
charging_time_limit = value; charging_time_limit = value;
portEXIT_CRITICAL(&evse_mux);
} }
uint16_t evse_get_under_power_limit(void) { uint16_t evse_get_under_power_limit(void) {
return under_power_limit; uint16_t val;
portENTER_CRITICAL(&evse_mux);
val = under_power_limit;
portEXIT_CRITICAL(&evse_mux);
return val;
} }
void evse_set_under_power_limit(uint16_t value) { void evse_set_under_power_limit(uint16_t value) {
portENTER_CRITICAL(&evse_mux);
under_power_limit = value; under_power_limit = value;
portEXIT_CRITICAL(&evse_mux);
} }
// ======================== // ========================
// Limites padrão (persistentes) // Default (persistent) limit accessors
// These values can be stored/restored via NVS
// ======================== // ========================
uint32_t evse_get_default_consumption_limit(void) { uint32_t evse_get_default_consumption_limit(void) {
@@ -83,15 +129,45 @@ void evse_set_default_under_power_limit(uint16_t value) {
default_under_power_limit = value; default_under_power_limit = value;
} }
bool evse_is_limit_reached(void) {
return evse_get_limit_reached();
}
// ======================== // ========================
// Lógica de verificação de limites // Limit checking logic
// This function must be called periodically while charging.
// It will flag the session as "limit reached" when thresholds are violated.
// ======================== // ========================
void evse_limits_check(evse_state_t state) { void evse_limits_check(void) {
// Se algum limite estiver ativo, verifique o estado evse_state_t state = evse_get_state();
if ((consumption_limit > 0 || charging_time_limit > 0 || under_power_limit > 0) if (!evse_state_is_charging(state)) return;
&& evse_state_is_charging(state)) {
// (Lógica real a ser aplicada aqui, ex: medição de consumo, tempo ou potência) bool reached = false;
evse_set_limit_reached(1);
uint32_t energy = evse_get_total_energy();
uint32_t power = evse_get_instant_power();
TickType_t now = xTaskGetTickCount();
TickType_t start = evse_get_session_start();
if (consumption_limit > 0 && energy >= consumption_limit) {
ESP_LOGW("EVSE", "Energy limit reached");
reached = true;
}
if (charging_time_limit > 0 &&
(now - start) >= pdMS_TO_TICKS(charging_time_limit * 1000)) {
ESP_LOGW("EVSE", "Charging time limit reached");
reached = true;
}
if (under_power_limit > 0 && power < under_power_limit) {
ESP_LOGW("EVSE", "Under power limit reached");
reached = true;
}
if (reached) {
evse_set_limit_reached(true);
} }
} }

View File

@@ -1,32 +1,41 @@
#include "evse_api.h"
#include "evse_state.h" #include "evse_state.h"
#include "evse_events.h" #include "evse_events.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h" #include "freertos/portmacro.h"
#include "esp_log.h" #include "esp_log.h"
// =========================
// Internal State Variables
// =========================
static evse_state_t current_state = EVSE_STATE_A; static evse_state_t current_state = EVSE_STATE_A;
static bool is_authorized = false; static bool is_authorized = false;
static TickType_t session_start_tick = 0;
// Proteção básica para variáveis globais em sistemas concorrentes
static portMUX_TYPE state_mux = portMUX_INITIALIZER_UNLOCKED; static portMUX_TYPE state_mux = portMUX_INITIALIZER_UNLOCKED;
// =========================
// Internal Mapping
// =========================
static evse_state_event_t map_state_to_event(evse_state_t s) { static evse_state_event_t map_state_to_event(evse_state_t s) {
switch (s) { switch (s) {
case EVSE_STATE_A: case EVSE_STATE_A: return EVSE_STATE_EVENT_IDLE;
return EVSE_STATE_EVENT_IDLE; case EVSE_STATE_B1: return EVSE_STATE_EVENT_WAITING;
case EVSE_STATE_B1:
return EVSE_STATE_EVENT_WAITING;
case EVSE_STATE_B2: case EVSE_STATE_B2:
case EVSE_STATE_C1: case EVSE_STATE_C1:
case EVSE_STATE_C2: case EVSE_STATE_C2: return EVSE_STATE_EVENT_CHARGING;
return EVSE_STATE_EVENT_CHARGING;
case EVSE_STATE_E: case EVSE_STATE_E:
case EVSE_STATE_F: case EVSE_STATE_F: return EVSE_STATE_EVENT_FAULT;
return EVSE_STATE_EVENT_FAULT; default: return EVSE_STATE_EVENT_IDLE;
default:
return EVSE_STATE_EVENT_IDLE;
} }
} }
// =========================
// Public API
// =========================
void evse_set_state(evse_state_t state) { void evse_set_state(evse_state_t state) {
bool changed = false; bool changed = false;
evse_state_t previous_state; evse_state_t previous_state;
@@ -36,11 +45,15 @@ void evse_set_state(evse_state_t state) {
if (state != current_state) { if (state != current_state) {
current_state = state; current_state = state;
changed = true; changed = true;
if (evse_state_is_charging(state) && !evse_state_is_charging(previous_state)) {
session_start_tick = xTaskGetTickCount();
}
} }
portEXIT_CRITICAL(&state_mux); portEXIT_CRITICAL(&state_mux);
if (changed) { if (changed) {
ESP_LOGI("EVSE_STATE", "Estado alterado de %s para %s", ESP_LOGI("EVSE_STATE", "State changed from %s to %s",
evse_state_to_str(previous_state), evse_state_to_str(previous_state),
evse_state_to_str(state)); evse_state_to_str(state));
@@ -58,6 +71,13 @@ evse_state_t evse_get_state(void) {
return s; return s;
} }
TickType_t evse_get_session_start(void) {
portENTER_CRITICAL(&state_mux);
TickType_t t = session_start_tick;
portEXIT_CRITICAL(&state_mux);
return t;
}
const char* evse_state_to_str(evse_state_t state) { const char* evse_state_to_str(evse_state_t state) {
switch (state) { switch (state) {
case EVSE_STATE_A: return "A - EV Not Connected (12V)"; case EVSE_STATE_A: return "A - EV Not Connected (12V)";
@@ -76,10 +96,11 @@ const char* evse_state_to_str(evse_state_t state) {
void evse_state_init(void) { void evse_state_init(void) {
portENTER_CRITICAL(&state_mux); portENTER_CRITICAL(&state_mux);
current_state = EVSE_STATE_A; current_state = EVSE_STATE_A;
session_start_tick = xTaskGetTickCount();
is_authorized = true; is_authorized = true;
portEXIT_CRITICAL(&state_mux); portEXIT_CRITICAL(&state_mux);
ESP_LOGI("EVSE_STATE", "Inicializado em estado: %s", evse_state_to_str(current_state)); ESP_LOGI("EVSE_STATE", "Initialized in state: %s", evse_state_to_str(current_state));
evse_state_event_data_t evt = { evse_state_event_data_t evt = {
.state = map_state_to_event(current_state) .state = map_state_to_event(current_state)
@@ -88,7 +109,7 @@ void evse_state_init(void) {
} }
void evse_state_tick(void) { void evse_state_tick(void) {
// Tick do estado (placeholder) // Placeholder for future state logic
} }
bool evse_state_is_charging(evse_state_t state) { bool evse_state_is_charging(evse_state_t state) {

View File

@@ -50,7 +50,13 @@ void evse_set_charging_time_limit(uint32_t value);
uint16_t evse_get_under_power_limit(void); uint16_t evse_get_under_power_limit(void);
void evse_set_under_power_limit(uint16_t value); void evse_set_under_power_limit(uint16_t value);
void evse_set_limit_reached(uint8_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 // Limites default
uint32_t evse_get_default_consumption_limit(void); uint32_t evse_get_default_consumption_limit(void);
@@ -60,4 +66,10 @@ void evse_set_default_charging_time_limit(uint32_t value);
uint16_t evse_get_default_under_power_limit(void); uint16_t evse_get_default_under_power_limit(void);
void evse_set_default_under_power_limit(uint16_t value); void evse_set_default_under_power_limit(uint16_t value);
uint32_t evse_get_total_energy(void);
uint32_t evse_get_instant_power(void);
#endif // EVSE_API_H #endif // EVSE_API_H

View File

@@ -9,24 +9,47 @@
extern "C" { extern "C" {
#endif #endif
/// Estado dos limites // ========================
void evse_set_limit_reached(uint8_t value); // Limit state control
bool evse_is_limit_reached(void); // ========================
/// Verifica e aplica lógica de limites com base no estado atual do EVSE /**
void evse_limits_check(evse_state_t state); * @brief Sets the 'limit reached' flag. Used internally when a session exceeds defined thresholds.
*/
void evse_set_limit_reached(bool value);
/**
* @brief Returns whether any session limit has been reached (energy, time or power).
*/
bool evse_get_limit_reached(void);
// ========================
// Limit checking
// ========================
/**
* @brief Evaluates if the session has exceeded any configured limits.
* Should be called periodically while in charging state.
*/
void evse_limits_check(void);
// ========================
// Runtime limit configuration
// ========================
/// Limites ativos (runtime)
uint32_t evse_get_consumption_limit(void); uint32_t evse_get_consumption_limit(void);
void evse_set_consumption_limit(uint32_t value); void evse_set_consumption_limit(uint32_t value); // in Wh
uint32_t evse_get_charging_time_limit(void); uint32_t evse_get_charging_time_limit(void);
void evse_set_charging_time_limit(uint32_t value); void evse_set_charging_time_limit(uint32_t value); // in seconds
uint16_t evse_get_under_power_limit(void); uint16_t evse_get_under_power_limit(void);
void evse_set_under_power_limit(uint16_t value); void evse_set_under_power_limit(uint16_t value); // in Watts
// ========================
// Default (persistent) limits
// ========================
/// Limites padrão (persistentes)
uint32_t evse_get_default_consumption_limit(void); uint32_t evse_get_default_consumption_limit(void);
void evse_set_default_consumption_limit(uint32_t value); void evse_set_default_consumption_limit(uint32_t value);

View File

@@ -1,49 +1,95 @@
#ifndef EVSE_STATE_H #ifndef EVSE_STATE_H
#define EVSE_STATE_H #define EVSE_STATE_H
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "evse_events.h" #include "evse_events.h"
// ============================
// EVSE Pilot Signal States
// ============================
#include <stdbool.h>
// Estado do EVSE (pilot signal)
typedef enum { typedef enum {
EVSE_STATE_A, EVSE_STATE_A, // EV Not Connected (12V)
EVSE_STATE_B1, EVSE_STATE_B1, // EV Connected (9V, Not Authorized)
EVSE_STATE_B2, EVSE_STATE_B2, // EV Connected (9V, Authorized and Ready)
EVSE_STATE_C1, EVSE_STATE_C1, // Charging Requested (6V, Relay Off)
EVSE_STATE_C2, EVSE_STATE_C2, // Charging Active (6V, Relay On)
EVSE_STATE_D1, EVSE_STATE_D1, // Ventilation Required (3V, Relay Off)
EVSE_STATE_D2, EVSE_STATE_D2, // Ventilation Active (3V, Relay On)
EVSE_STATE_E, EVSE_STATE_E, // Error: Pilot Short to Ground (0V)
EVSE_STATE_F EVSE_STATE_F // Fault: No Pilot or EVSE Unavailable
} evse_state_t; } evse_state_t;
// ============================
// Initialization & Core Control
// ============================
// Funções públicas necessárias /**
* @brief Initializes the EVSE state machine.
*/
void evse_state_init(void); void evse_state_init(void);
/**
* @brief Periodic tick function for the state machine.
*/
void evse_state_tick(void); void evse_state_tick(void);
void evse_state_set_authorized(bool authorized); // ============================
bool evse_state_get_authorized(void); // State Access
// ============================
/**
* @brief Returns the current EVSE state.
*/
evse_state_t evse_get_state(void); evse_state_t evse_get_state(void);
/**
* @brief Updates the current EVSE state and triggers events.
*/
void evse_set_state(evse_state_t state); void evse_set_state(evse_state_t state);
// Converte o estado para string /**
* @brief Returns the tick count when charging session started.
*/
TickType_t evse_get_session_start(void);
/**
* @brief Converts the state enum to a human-readable string.
*/
const char* evse_state_to_str(evse_state_t state); const char* evse_state_to_str(evse_state_t state);
// Retorna true se o estado representa sessão ativa // ============================
// State Evaluators
// ============================
/**
* @brief Returns true if the state represents an active session (B2, C1, C2).
*/
bool evse_state_is_session(evse_state_t state); bool evse_state_is_session(evse_state_t state);
// Retorna true se o estado representa carregamento ativo /**
* @brief Returns true if the state represents active charging (C1, C2).
*/
bool evse_state_is_charging(evse_state_t state); bool evse_state_is_charging(evse_state_t state);
// Retorna true se o estado representa veículo conectado /**
* @brief Returns true if the vehicle is plugged in.
*/
bool evse_state_is_plugged(evse_state_t state); bool evse_state_is_plugged(evse_state_t state);
//evse_state_event_t map_state_to_event(evse_state_t state); // ============================
// Authorization
// ============================
/**
* @brief Sets the vehicle authorization state.
*/
void evse_state_set_authorized(bool authorized);
/**
* @brief Returns the current vehicle authorization state.
*/
bool evse_state_get_authorized(void);
#endif // EVSE_STATE_H #endif // EVSE_STATE_H

View File

@@ -311,7 +311,7 @@ void notificationOutput(OCPP_Transaction *transaction, enum OCPP_TxNotification
case DeAuthorized: case DeAuthorized:
ESP_LOGI(TAG, "DeAuthorized ---->"); ESP_LOGI(TAG, "DeAuthorized ---->");
//evse_set_authorized(false); //evse_set_authorized(false);
evse_set_limit_reached(2); //evse_set_limit_reached(2);
// ocpp_set_charging(false); // ocpp_set_charging(false);
break; // server rejected StartTx break; // server rejected StartTx
case RemoteStart: case RemoteStart:

1025
projeto_parte1.c Executable file

File diff suppressed because it is too large Load Diff

46
projeto_parte10.c Normal file
View File

@@ -0,0 +1,46 @@
// === 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 ===

1166
projeto_parte2.c Executable file

File diff suppressed because it is too large Load Diff

1058
projeto_parte3.c Executable file

File diff suppressed because it is too large Load Diff

896
projeto_parte4.c Executable file
View File

@@ -0,0 +1,896 @@
// === 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 ===

1066
projeto_parte5.c Executable file

File diff suppressed because it is too large Load Diff

735
projeto_parte6.c Executable file
View File

@@ -0,0 +1,735 @@
// === 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 ===

793
projeto_parte7.c Executable file
View File

@@ -0,0 +1,793 @@
// === 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 ===

783
projeto_parte8.c Executable file
View File

@@ -0,0 +1,783 @@
// === 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 ===

1232
projeto_parte9.c Executable file

File diff suppressed because it is too large Load Diff

8613
projeto_unificado.c Executable file

File diff suppressed because it is too large Load Diff

BIN
projeto_unificado.zip Normal file

Binary file not shown.

67
readproject.py Normal file
View File

@@ -0,0 +1,67 @@
import os
TAMANHO_MAX = 31000 # Limite por arquivo
def coletar_arquivos(diretorios, extensoes=(".c", ".h")):
arquivos = []
for diretorio in diretorios:
for raiz, pastas, nomes_arquivos in os.walk(diretorio):
pastas[:] = [p for p in pastas if p != "build"] # Ignorar "build"
for nome in nomes_arquivos:
if nome.endswith(extensoes):
caminho_completo = os.path.join(raiz, nome)
arquivos.append(caminho_completo)
return arquivos
def unir_em_partes(arquivos, prefixo="projeto_parte", limite=TAMANHO_MAX):
parte = 1
conteudo_atual = ""
total_arquivos = 0
for arquivo in arquivos:
try:
with open(arquivo, "r", encoding="utf-8") as f_origem:
conteudo = f_origem.read()
except Exception as e:
print(f"⚠️ Erro ao ler {arquivo}: {e}")
continue
bloco = f"\n\n// === Início de: {arquivo} ===\n{conteudo}\n// === Fim de: {arquivo} ===\n"
# Se ultrapassar o limite, salva em um novo arquivo
if len(conteudo_atual) + len(bloco) > limite:
nome_saida = f"{prefixo}{parte}.c"
with open(nome_saida, "w", encoding="utf-8") as f_saida:
f_saida.write(conteudo_atual)
print(f"✅ Criado: {nome_saida}")
parte += 1
conteudo_atual = "" # reinicia buffer
conteudo_atual += bloco
total_arquivos += 1
# Salvar o que sobrou
if conteudo_atual:
nome_saida = f"{prefixo}{parte}.c"
with open(nome_saida, "w", encoding="utf-8") as f_saida:
f_saida.write(conteudo_atual)
print(f"✅ Criado: {nome_saida}")
print(f"\n🔹 {total_arquivos} arquivos de código processados.")
print(f"🔹 Arquivos gerados: {parte}")
def main():
diretorio_main = "main"
componentes_escolhidos = [
"evse", "loadbalancer", "auth", "manager_meter",
"rest_api", "network", "peripherals"
]
diretorios_componentes = [os.path.join("components", nome) for nome in componentes_escolhidos]
diretorios_para_incluir = [diretorio_main] + diretorios_componentes
arquivos = coletar_arquivos(diretorios_para_incluir)
unir_em_partes(arquivos)
if __name__ == "__main__":
main()