new module
This commit is contained in:
@@ -4,4 +4,4 @@ idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "src"
|
||||
PRIV_REQUIRES nvs_flash driver esp_timer
|
||||
REQUIRES esp_event esp_idf_lib_helpers evse ocpp)
|
||||
REQUIRES esp_event evse ocpp evse_link)
|
||||
@@ -1,5 +1,3 @@
|
||||
// components/auth/src/auth.c
|
||||
|
||||
#include "auth.h"
|
||||
#include "auth_events.h"
|
||||
#include "esp_event.h"
|
||||
@@ -9,11 +7,13 @@
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <string.h>
|
||||
#include <strings.h> // <-- necessário para strcasecmp
|
||||
#include <strings.h> // strcasecmp
|
||||
#include "wiegand_reader.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
#include "esp_random.h"
|
||||
|
||||
#include "evse_link.h"
|
||||
#include "evse_link_events.h"
|
||||
|
||||
#define MAX_TAGS 50
|
||||
|
||||
@@ -25,63 +25,100 @@ static bool waiting_for_registration = false;
|
||||
static char valid_tags[MAX_TAGS][AUTH_TAG_MAX_LEN];
|
||||
static int tag_count = 0;
|
||||
static uint32_t s_next_req_id = 1;
|
||||
static bool s_wiegand_started = false; // controla se o Wiegand já foi iniciado
|
||||
|
||||
/* ===== NVS keys ===== */
|
||||
#define NVS_NAMESPACE "auth"
|
||||
#define NVS_TAG_PREFIX "tag_"
|
||||
#define NVS_TAG_COUNT_KEY "count"
|
||||
#define NVS_MODE_KEY "mode" // uint8_t
|
||||
#define NVS_NAMESPACE "auth"
|
||||
#define NVS_TAG_PREFIX "tag_"
|
||||
#define NVS_TAG_COUNT_KEY "count"
|
||||
#define NVS_MODE_KEY "mode" // uint8_t
|
||||
|
||||
/* =========================
|
||||
* NVS Persistence (tags)
|
||||
* ========================= */
|
||||
static void load_tags_from_nvs(void) {
|
||||
static void load_tags_from_nvs(void)
|
||||
{
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(NVS_NAMESPACE, NVS_READONLY, &handle) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "No stored tags in NVS");
|
||||
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &handle);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "No stored tags in NVS (nvs_open: %s)", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t count = 0;
|
||||
if (nvs_get_u8(handle, NVS_TAG_COUNT_KEY, &count) != ESP_OK) {
|
||||
err = nvs_get_u8(handle, NVS_TAG_COUNT_KEY, &count);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "No tag count key in NVS (nvs_get_u8: %s)", esp_err_to_name(err));
|
||||
nvs_close(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
tag_count = 0;
|
||||
for (int i = 0; i < count && i < MAX_TAGS; i++) {
|
||||
for (int i = 0; i < count && i < MAX_TAGS; i++)
|
||||
{
|
||||
char key[16];
|
||||
char tag_buf[AUTH_TAG_MAX_LEN];
|
||||
size_t len = sizeof(tag_buf);
|
||||
|
||||
snprintf(key, sizeof(key), "%s%d", NVS_TAG_PREFIX, i);
|
||||
if (nvs_get_str(handle, key, tag_buf, &len) == ESP_OK) {
|
||||
err = nvs_get_str(handle, key, tag_buf, &len);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
strncpy(valid_tags[tag_count], tag_buf, AUTH_TAG_MAX_LEN - 1);
|
||||
valid_tags[tag_count][AUTH_TAG_MAX_LEN - 1] = '\0';
|
||||
tag_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Failed to load tag %d from NVS (%s)", i, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
nvs_close(handle);
|
||||
ESP_LOGI(TAG, "Loaded %d tags from NVS", tag_count);
|
||||
}
|
||||
|
||||
static void save_tags_to_nvs(void) {
|
||||
static void save_tags_to_nvs(void)
|
||||
{
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to open NVS to save tags");
|
||||
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to open NVS to save tags: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
nvs_set_u8(handle, NVS_TAG_COUNT_KEY, tag_count);
|
||||
|
||||
for (int i = 0; i < tag_count; i++) {
|
||||
char key[16];
|
||||
snprintf(key, sizeof(key), "%s%d", NVS_TAG_PREFIX, i);
|
||||
nvs_set_str(handle, key, valid_tags[i]);
|
||||
err = nvs_set_u8(handle, NVS_TAG_COUNT_KEY, tag_count);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_set_u8(count) failed: %s", esp_err_to_name(err));
|
||||
nvs_close(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tag_count; i++)
|
||||
{
|
||||
char key[16];
|
||||
snprintf(key, sizeof(key), "%s%d", NVS_TAG_PREFIX, i);
|
||||
err = nvs_set_str(handle, key, valid_tags[i]);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_set_str(%s) failed: %s", key, esp_err_to_name(err));
|
||||
nvs_close(handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
err = nvs_commit(handle);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_commit failed when saving tags: %s", esp_err_to_name(err));
|
||||
nvs_close(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
nvs_commit(handle);
|
||||
nvs_close(handle);
|
||||
ESP_LOGI(TAG, "Tags saved to NVS (%d tags)", tag_count);
|
||||
}
|
||||
@@ -89,95 +126,220 @@ static void save_tags_to_nvs(void) {
|
||||
/* =========================
|
||||
* NVS Persistence (mode)
|
||||
* ========================= */
|
||||
static void load_mode_from_nvs(void) {
|
||||
static void load_mode_from_nvs(void)
|
||||
{
|
||||
nvs_handle_t h;
|
||||
if (nvs_open(NVS_NAMESPACE, NVS_READONLY, &h) == ESP_OK) {
|
||||
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &h);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
uint8_t u = (uint8_t)AUTH_MODE_OPEN;
|
||||
if (nvs_get_u8(h, NVS_MODE_KEY, &u) == ESP_OK) {
|
||||
if (u <= (uint8_t)AUTH_MODE_OCPP_RFID) s_mode = (auth_mode_t)u;
|
||||
err = nvs_get_u8(h, NVS_MODE_KEY, &u);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
if (u <= (uint8_t)AUTH_MODE_OCPP_RFID)
|
||||
s_mode = (auth_mode_t)u;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "No stored auth mode in NVS (nvs_get_u8: %s). Default OPEN", esp_err_to_name(err));
|
||||
}
|
||||
nvs_close(h);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "No stored auth mode in NVS; default OPEN");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "No stored auth mode in NVS (nvs_open: %s). Default OPEN", esp_err_to_name(err));
|
||||
}
|
||||
ESP_LOGI(TAG, "Loaded mode = %d (%s)", (int)s_mode, auth_mode_to_str(s_mode));
|
||||
}
|
||||
|
||||
static void save_mode_to_nvs(auth_mode_t mode) {
|
||||
static void save_mode_to_nvs(auth_mode_t mode)
|
||||
{
|
||||
nvs_handle_t h;
|
||||
if (nvs_open(NVS_NAMESPACE, NVS_READWRITE, &h) == ESP_OK) {
|
||||
nvs_set_u8(h, NVS_MODE_KEY, (uint8_t)mode);
|
||||
nvs_commit(h);
|
||||
nvs_close(h);
|
||||
ESP_LOGI(TAG, "Saved mode = %d (%s)", (int)mode, auth_mode_to_str(mode));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to save auth mode to NVS");
|
||||
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &h);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to open NVS to save auth mode: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
err = nvs_set_u8(h, NVS_MODE_KEY, (uint8_t)mode);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_set_u8(mode) failed: %s", esp_err_to_name(err));
|
||||
nvs_close(h);
|
||||
return;
|
||||
}
|
||||
|
||||
err = nvs_commit(h);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_commit failed when saving mode: %s", esp_err_to_name(err));
|
||||
nvs_close(h);
|
||||
return;
|
||||
}
|
||||
|
||||
nvs_close(h);
|
||||
ESP_LOGI(TAG, "Saved mode = %d (%s)", (int)mode, auth_mode_to_str(mode));
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Helpers
|
||||
* ========================= */
|
||||
static bool is_tag_valid(const char *tag) {
|
||||
for (int i = 0; i < tag_count; i++) {
|
||||
if (strncmp(valid_tags[i], tag, AUTH_TAG_MAX_LEN) == 0) {
|
||||
static bool is_tag_valid(const char *tag)
|
||||
{
|
||||
for (int i = 0; i < tag_count; i++)
|
||||
{
|
||||
if (strncmp(valid_tags[i], tag, AUTH_TAG_MAX_LEN) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Bridge: EVSE-Link -> AUTH (remote AUTH_GRANTED no slave)
|
||||
* ========================= */
|
||||
static void on_remote_auth_grant(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
if (base != EVSE_LINK_EVENTS || id != LINK_EVENT_REMOTE_AUTH_GRANTED || data == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const evse_link_auth_grant_event_t *src = (const evse_link_auth_grant_event_t *)data;
|
||||
|
||||
// Só faz sentido em SLAVE; em MASTER este evento não deve aparecer
|
||||
if (evse_link_get_mode() != EVSE_LINK_MODE_SLAVE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auth_tag_event_data_t ev = {0};
|
||||
strncpy(ev.tag, src->tag, AUTH_TAG_MAX_LEN - 1);
|
||||
ev.tag[AUTH_TAG_MAX_LEN - 1] = '\0';
|
||||
ev.authorized = true;
|
||||
|
||||
ESP_LOGI(TAG, "Remote auth grant on SLAVE for tag=%s", ev.tag);
|
||||
|
||||
esp_err_t err = esp_event_post(
|
||||
AUTH_EVENTS,
|
||||
AUTH_EVENT_TAG_PROCESSED,
|
||||
&ev,
|
||||
sizeof(ev),
|
||||
portMAX_DELAY);
|
||||
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to post AUTH_EVENT_TAG_PROCESSED (remote grant): %s",
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Public API
|
||||
* ========================= */
|
||||
void auth_init(void) {
|
||||
void auth_init(void)
|
||||
{
|
||||
load_mode_from_nvs();
|
||||
load_tags_from_nvs();
|
||||
|
||||
if (s_mode == AUTH_MODE_LOCAL_RFID || s_mode == AUTH_MODE_OCPP_RFID) {
|
||||
bool need_wiegand = (s_mode == AUTH_MODE_LOCAL_RFID || s_mode == AUTH_MODE_OCPP_RFID);
|
||||
if (need_wiegand)
|
||||
{
|
||||
initWiegand();
|
||||
s_wiegand_started = true;
|
||||
ESP_LOGI(TAG, "Wiegand reader initialized (mode=%s)", auth_mode_to_str(s_mode));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "Mode OPEN: Wiegand not started");
|
||||
}
|
||||
|
||||
auth_mode_event_data_t evt = { .mode = s_mode };
|
||||
// Registar bridge para autorizações remotas vindas do EVSE-Link
|
||||
{
|
||||
esp_err_t err = esp_event_handler_register(
|
||||
EVSE_LINK_EVENTS,
|
||||
LINK_EVENT_REMOTE_AUTH_GRANTED,
|
||||
on_remote_auth_grant,
|
||||
NULL);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to register EVSE-Link auth grant handler: %s",
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
auth_mode_event_data_t evt = {.mode = s_mode};
|
||||
esp_event_post(AUTH_EVENTS, AUTH_EVENT_INIT, &evt, sizeof(evt), portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "AUTH INIT sent (mode=%s)", auth_mode_to_str(s_mode));
|
||||
}
|
||||
|
||||
void auth_set_mode(auth_mode_t mode) {
|
||||
if (mode < AUTH_MODE_OPEN || mode > AUTH_MODE_OCPP_RFID) {
|
||||
void auth_set_mode(auth_mode_t mode)
|
||||
{
|
||||
if (mode < AUTH_MODE_OPEN || mode > AUTH_MODE_OCPP_RFID)
|
||||
{
|
||||
ESP_LOGW(TAG, "Invalid mode: %d", (int)mode);
|
||||
return;
|
||||
}
|
||||
if (mode == s_mode) {
|
||||
|
||||
if (mode == s_mode)
|
||||
{
|
||||
ESP_LOGI(TAG, "Mode unchanged: %s", auth_mode_to_str(mode));
|
||||
return;
|
||||
}
|
||||
|
||||
auth_mode_t old = s_mode;
|
||||
s_mode = mode;
|
||||
save_mode_to_nvs(mode);
|
||||
|
||||
// Nota: se precisares, aqui podes parar/iniciar o Wiegand consoante o modo.
|
||||
if (s_mode == AUTH_MODE_OPEN) {
|
||||
ESP_LOGI(TAG, "Mode set to OPEN");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Mode set to %s; ensure Wiegand reader is running", auth_mode_to_str(s_mode));
|
||||
bool need_wiegand = (s_mode == AUTH_MODE_LOCAL_RFID || s_mode == AUTH_MODE_OCPP_RFID);
|
||||
|
||||
if (need_wiegand && !s_wiegand_started)
|
||||
{
|
||||
ESP_LOGI(TAG, "Mode changed %s -> %s, starting Wiegand",
|
||||
auth_mode_to_str(old), auth_mode_to_str(s_mode));
|
||||
initWiegand();
|
||||
s_wiegand_started = true;
|
||||
}
|
||||
else if (!need_wiegand && s_wiegand_started)
|
||||
{
|
||||
// Aqui poderias implementar um wiegand_deinit() se o driver o expuser.
|
||||
ESP_LOGI(TAG, "Mode changed %s -> %s, Wiegand remains started (no deinit implemented)",
|
||||
auth_mode_to_str(old), auth_mode_to_str(s_mode));
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "Mode changed %s -> %s, no change in Wiegand state",
|
||||
auth_mode_to_str(old), auth_mode_to_str(s_mode));
|
||||
}
|
||||
|
||||
auth_mode_event_data_t evt = { .mode = s_mode };
|
||||
if (s_mode == AUTH_MODE_OPEN)
|
||||
{
|
||||
ESP_LOGI(TAG, "Mode set to OPEN");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "Mode set to %s", auth_mode_to_str(s_mode));
|
||||
}
|
||||
|
||||
auth_mode_event_data_t evt = {.mode = s_mode};
|
||||
esp_event_post(AUTH_EVENTS, AUTH_EVENT_MODE_CHANGED, &evt, sizeof(evt), portMAX_DELAY);
|
||||
}
|
||||
|
||||
auth_mode_t auth_get_mode(void) {
|
||||
auth_mode_t auth_get_mode(void)
|
||||
{
|
||||
return s_mode;
|
||||
}
|
||||
|
||||
bool auth_add_tag(const char *tag) {
|
||||
if (tag_count >= MAX_TAGS) return false;
|
||||
if (!tag || strlen(tag) >= AUTH_TAG_MAX_LEN) return false;
|
||||
if (is_tag_valid(tag)) return true; // já existe
|
||||
bool auth_add_tag(const char *tag)
|
||||
{
|
||||
if (!tag || strlen(tag) >= AUTH_TAG_MAX_LEN)
|
||||
return false;
|
||||
if (tag_count >= MAX_TAGS)
|
||||
return false;
|
||||
if (is_tag_valid(tag))
|
||||
return true; // já existe
|
||||
|
||||
strncpy(valid_tags[tag_count], tag, AUTH_TAG_MAX_LEN - 1);
|
||||
valid_tags[tag_count][AUTH_TAG_MAX_LEN - 1] = '\0';
|
||||
@@ -188,11 +350,19 @@ bool auth_add_tag(const char *tag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool auth_remove_tag(const char *tag) {
|
||||
for (int i = 0; i < tag_count; i++) {
|
||||
if (strncmp(valid_tags[i], tag, AUTH_TAG_MAX_LEN) == 0) {
|
||||
for (int j = i; j < tag_count - 1; j++) {
|
||||
bool auth_remove_tag(const char *tag)
|
||||
{
|
||||
if (!tag)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < tag_count; i++)
|
||||
{
|
||||
if (strncmp(valid_tags[i], tag, AUTH_TAG_MAX_LEN) == 0)
|
||||
{
|
||||
for (int j = i; j < tag_count - 1; j++)
|
||||
{
|
||||
strncpy(valid_tags[j], valid_tags[j + 1], AUTH_TAG_MAX_LEN);
|
||||
valid_tags[j][AUTH_TAG_MAX_LEN - 1] = '\0';
|
||||
}
|
||||
tag_count--;
|
||||
|
||||
@@ -204,19 +374,26 @@ bool auth_remove_tag(const char *tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool auth_tag_exists(const char *tag) {
|
||||
bool auth_tag_exists(const char *tag)
|
||||
{
|
||||
if (!tag)
|
||||
return false;
|
||||
return is_tag_valid(tag);
|
||||
}
|
||||
|
||||
void auth_list_tags(void) {
|
||||
void auth_list_tags(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Registered Tags (%d):", tag_count);
|
||||
for (int i = 0; i < tag_count; i++) {
|
||||
for (int i = 0; i < tag_count; i++)
|
||||
{
|
||||
ESP_LOGI(TAG, "- %s", valid_tags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void auth_wait_for_tag_registration(void) {
|
||||
if (s_mode != AUTH_MODE_LOCAL_RFID) {
|
||||
void auth_wait_for_tag_registration(void)
|
||||
{
|
||||
if (s_mode != AUTH_MODE_LOCAL_RFID)
|
||||
{
|
||||
ESP_LOGW(TAG, "Registration is only available in LOCAL mode");
|
||||
return;
|
||||
}
|
||||
@@ -224,61 +401,82 @@ void auth_wait_for_tag_registration(void) {
|
||||
ESP_LOGI(TAG, "Tag registration mode enabled.");
|
||||
}
|
||||
|
||||
void auth_process_tag(const char *tag) {
|
||||
if (!tag || !*tag) {
|
||||
void auth_process_tag(const char *tag)
|
||||
{
|
||||
if (!tag || !*tag)
|
||||
{
|
||||
ESP_LOGW(TAG, "NULL/empty tag received");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (s_mode) {
|
||||
case AUTH_MODE_OPEN: {
|
||||
// Sem verificação; normalmente nem é necessário evento.
|
||||
ESP_LOGI(TAG, "Mode OPEN: tag=%s (no verification)", tag);
|
||||
break;
|
||||
}
|
||||
switch (s_mode)
|
||||
{
|
||||
case AUTH_MODE_OPEN:
|
||||
{
|
||||
// Sem verificação; normalmente nem é necessário evento.
|
||||
ESP_LOGI(TAG, "Mode OPEN: tag=%s (no verification)", tag);
|
||||
break;
|
||||
}
|
||||
|
||||
case AUTH_MODE_LOCAL_RFID: {
|
||||
if (waiting_for_registration) {
|
||||
waiting_for_registration = false;
|
||||
case AUTH_MODE_LOCAL_RFID:
|
||||
{
|
||||
if (waiting_for_registration)
|
||||
{
|
||||
waiting_for_registration = false;
|
||||
|
||||
if (auth_add_tag(tag)) {
|
||||
auth_tag_event_data_t ev = {0};
|
||||
strncpy(ev.tag, tag, AUTH_TAG_MAX_LEN - 1);
|
||||
ev.authorized = true;
|
||||
esp_event_post(AUTH_EVENTS, AUTH_EVENT_TAG_SAVED, &ev, sizeof(ev), portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "Tag registered: %s", tag);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Failed to register tag: %s", tag);
|
||||
}
|
||||
return;
|
||||
if (auth_add_tag(tag))
|
||||
{
|
||||
auth_tag_event_data_t ev = {0};
|
||||
strncpy(ev.tag, tag, AUTH_TAG_MAX_LEN - 1);
|
||||
ev.tag[AUTH_TAG_MAX_LEN - 1] = '\0';
|
||||
ev.authorized = true;
|
||||
esp_event_post(AUTH_EVENTS, AUTH_EVENT_TAG_SAVED,
|
||||
&ev, sizeof(ev), portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "Tag registered: %s", tag);
|
||||
}
|
||||
|
||||
auth_tag_event_data_t ev = {0};
|
||||
strncpy(ev.tag, tag, AUTH_TAG_MAX_LEN - 1);
|
||||
ev.authorized = is_tag_valid(tag);
|
||||
|
||||
ESP_LOGI(TAG, "LOCAL tag %s: %s", tag, ev.authorized ? "AUTHORIZED" : "DENIED");
|
||||
esp_event_post(AUTH_EVENTS, AUTH_EVENT_TAG_PROCESSED, &ev, sizeof(ev), portMAX_DELAY);
|
||||
break;
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Failed to register tag: %s", tag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case AUTH_MODE_OCPP_RFID: {
|
||||
// Não decide localmente. Pede validação ao OCPP.
|
||||
auth_tag_verify_event_t rq = {0};
|
||||
strncpy(rq.tag, tag, AUTH_TAG_MAX_LEN - 1);
|
||||
rq.req_id = s_next_req_id++;
|
||||
ESP_LOGI(TAG, "OCPP VERIFY requested for tag=%s (req_id=%u)", rq.tag, (unsigned)rq.req_id);
|
||||
esp_event_post(AUTH_EVENTS, AUTH_EVENT_TAG_VERIFY, &rq, sizeof(rq), portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
auth_tag_event_data_t ev = {0};
|
||||
strncpy(ev.tag, tag, AUTH_TAG_MAX_LEN - 1);
|
||||
ev.tag[AUTH_TAG_MAX_LEN - 1] = '\0';
|
||||
ev.authorized = is_tag_valid(tag);
|
||||
|
||||
ESP_LOGI(TAG, "LOCAL tag %s: %s", tag,
|
||||
ev.authorized ? "AUTHORIZED" : "DENIED");
|
||||
esp_event_post(AUTH_EVENTS, AUTH_EVENT_TAG_PROCESSED,
|
||||
&ev, sizeof(ev), portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
|
||||
case AUTH_MODE_OCPP_RFID:
|
||||
{
|
||||
// Não decide localmente. Pede validação ao OCPP.
|
||||
auth_tag_verify_event_t rq = {0};
|
||||
strncpy(rq.tag, tag, AUTH_TAG_MAX_LEN - 1);
|
||||
rq.tag[AUTH_TAG_MAX_LEN - 1] = '\0';
|
||||
rq.req_id = s_next_req_id++;
|
||||
ESP_LOGI(TAG, "OCPP VERIFY requested for tag=%s (req_id=%u)",
|
||||
rq.tag, (unsigned)rq.req_id);
|
||||
esp_event_post(AUTH_EVENTS, AUTH_EVENT_TAG_VERIFY,
|
||||
&rq, sizeof(rq), portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int auth_get_tag_count(void) {
|
||||
int auth_get_tag_count(void)
|
||||
{
|
||||
return tag_count;
|
||||
}
|
||||
|
||||
const char *auth_get_tag_by_index(int index) {
|
||||
if (index < 0 || index >= tag_count) return NULL;
|
||||
const char *auth_get_tag_by_index(int index)
|
||||
{
|
||||
if (index < 0 || index >= tag_count)
|
||||
return NULL;
|
||||
return valid_tags[index];
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// === Início de: components/auth/src/wiegand.c ===
|
||||
/**
|
||||
* @file wiegand.c
|
||||
*
|
||||
@@ -6,9 +7,13 @@
|
||||
#include <esp_log.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <esp_idf_lib_helpers.h>
|
||||
#include <esp_attr.h> // <- para IRAM_ATTR
|
||||
#include "wiegand.h"
|
||||
|
||||
#ifndef IRAM_ATTR
|
||||
#define IRAM_ATTR
|
||||
#endif
|
||||
|
||||
static const char *TAG = "wiegand";
|
||||
|
||||
#define TIMER_INTERVAL_US 50000 // 50ms
|
||||
@@ -39,11 +44,7 @@ static void isr_enable(wiegand_reader_t *reader)
|
||||
gpio_set_intr_type(reader->gpio_d1, GPIO_INTR_NEGEDGE);
|
||||
}
|
||||
|
||||
#if HELPER_TARGET_IS_ESP32
|
||||
static void IRAM_ATTR isr_handler(void *arg)
|
||||
#else
|
||||
static void isr_handler(void *arg)
|
||||
#endif
|
||||
{
|
||||
wiegand_reader_t *reader = (wiegand_reader_t *)arg;
|
||||
if (!reader->enabled)
|
||||
@@ -181,3 +182,5 @@ esp_err_t wiegand_reader_done(wiegand_reader_t *reader)
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// === Fim de: components/auth/src/wiegand.c ===
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <wiegand.h>
|
||||
#include "auth.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define CONFIG_EXAMPLE_BUF_SIZE 50
|
||||
#define IDTAG_MAX_LEN 20
|
||||
|
||||
static const char *TAG = "WiegandReader";
|
||||
|
||||
// ---- Parâmetro global/locale para controlar a convenção de paridade ----
|
||||
// ---- Parâmetro global/local para controlar a convenção de paridade ----
|
||||
static const bool PARITY_INVERTED = false; // mude para true se o seu leitor vier "invertido"
|
||||
|
||||
static wiegand_reader_t reader;
|
||||
@@ -35,7 +35,7 @@ static inline uint8_t get_bit_msb_first(const uint8_t *buf, size_t bit_index)
|
||||
return (buf[bit_index / 8] >> (7 - (bit_index % 8))) & 0x01;
|
||||
}
|
||||
|
||||
// Versão parametrizável
|
||||
// Versão parametrizável de verificação de paridade
|
||||
static bool check_parity_param(const uint8_t *buf, size_t bits, bool invert)
|
||||
{
|
||||
if (bits != 26 && bits != 34)
|
||||
@@ -55,8 +55,8 @@ static bool check_parity_param(const uint8_t *buf, size_t bits, bool invert)
|
||||
if (get_bit_msb_first(buf, i))
|
||||
right++;
|
||||
}
|
||||
else
|
||||
{ // 34
|
||||
else // 34 bits
|
||||
{
|
||||
for (int i = 1; i <= 16; i++)
|
||||
if (get_bit_msb_first(buf, i))
|
||||
left++;
|
||||
@@ -117,24 +117,28 @@ static bool wiegand_extract_fc_cn(const uint8_t *buf, size_t bits, uint32_t *fc,
|
||||
{
|
||||
if (bits != 26 && bits != 34)
|
||||
return false;
|
||||
|
||||
uint32_t payload = 0;
|
||||
size_t payload_bits = bits - 2;
|
||||
|
||||
for (size_t i = 0; i < payload_bits; i++)
|
||||
{
|
||||
size_t bit = 1 + i; // ignora bit de paridade inicial
|
||||
uint8_t bitval = (buf[bit / 8] >> (7 - (bit % 8))) & 0x01;
|
||||
payload = (payload << 1) | bitval;
|
||||
}
|
||||
|
||||
if (bits == 26)
|
||||
{
|
||||
*fc = (payload >> 16) & 0xFF; // 8b
|
||||
*cn = payload & 0xFFFF; // 16b
|
||||
}
|
||||
else
|
||||
else // 34 bits
|
||||
{
|
||||
*fc = (payload >> 16) & 0xFFFF; // 16b
|
||||
*cn = payload & 0xFFFF; // 16b
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -145,10 +149,14 @@ static bool build_idtag_w26_4B(uint32_t fc, uint32_t cn, char *out, size_t outle
|
||||
(uint8_t)((cn >> 8) & 0xFF),
|
||||
(uint8_t)(cn & 0xFF),
|
||||
0};
|
||||
|
||||
raw[3] = crc8_atm(raw, 3);
|
||||
|
||||
if (outlen < 9)
|
||||
return false;
|
||||
int n = snprintf(out, outlen, "%02X%02X%02X%02X", raw[0], raw[1], raw[2], raw[3]);
|
||||
|
||||
int n = snprintf(out, outlen, "%02X%02X%02X%02X",
|
||||
raw[0], raw[1], raw[2], raw[3]);
|
||||
return (n > 0 && (size_t)n < outlen);
|
||||
}
|
||||
|
||||
@@ -160,31 +168,42 @@ static bool build_idtag_w34_7B(uint32_t fc, uint32_t cn, char *out, size_t outle
|
||||
raw[2] = (uint8_t)(fc & 0xFF);
|
||||
raw[3] = (uint8_t)((cn >> 8) & 0xFF);
|
||||
raw[4] = (uint8_t)(cn & 0xFF);
|
||||
|
||||
uint16_t crc = crc16_ibm(raw, 5);
|
||||
raw[5] = (uint8_t)((crc >> 8) & 0xFF);
|
||||
raw[6] = (uint8_t)(crc & 0xFF);
|
||||
|
||||
if (outlen < 15)
|
||||
return false;
|
||||
|
||||
int n = snprintf(out, outlen, "%02X%02X%02X%02X%02X%02X%02X",
|
||||
raw[0], raw[1], raw[2], raw[3], raw[4], raw[5], raw[6]);
|
||||
raw[0], raw[1], raw[2], raw[3],
|
||||
raw[4], raw[5], raw[6]);
|
||||
return (n > 0 && (size_t)n < outlen);
|
||||
}
|
||||
|
||||
// Se o callback for de ISR, troque para xQueueSendToBackFromISR.
|
||||
// Callback chamado pelo esp_timer_task (contexto de task, NÃO ISR)
|
||||
static void reader_callback(wiegand_reader_t *r)
|
||||
{
|
||||
if (!queue)
|
||||
{
|
||||
ESP_LOGW(TAG, "Queue not ready, dropping packet");
|
||||
return;
|
||||
}
|
||||
|
||||
data_packet_t p = {0};
|
||||
p.bits = r->bits;
|
||||
p.bytes = (r->bits + 7) / 8;
|
||||
|
||||
if (p.bytes > sizeof(p.data))
|
||||
p.bytes = sizeof(p.data);
|
||||
|
||||
memcpy(p.data, r->buf, p.bytes);
|
||||
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
// Se NÃO for ISR, use xQueueSendToBack(queue, &p, 0);
|
||||
xQueueSendToBackFromISR(queue, &p, &xHigherPriorityTaskWoken);
|
||||
if (xHigherPriorityTaskWoken)
|
||||
portYIELD_FROM_ISR();
|
||||
if (xQueueSendToBack(queue, &p, 0) != pdPASS)
|
||||
{
|
||||
ESP_LOGW(TAG, "Queue full, dropping Wiegand packet");
|
||||
}
|
||||
}
|
||||
|
||||
static void wiegand_task(void *arg)
|
||||
@@ -197,13 +216,20 @@ static void wiegand_task(void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(wiegand_reader_init(&reader, 21, 22,
|
||||
true, CONFIG_EXAMPLE_BUF_SIZE, reader_callback, WIEGAND_MSB_FIRST, WIEGAND_LSB_FIRST));
|
||||
ESP_ERROR_CHECK(wiegand_reader_init(&reader,
|
||||
21, 22, // GPIO D0, D1
|
||||
true, // internal pullups
|
||||
CONFIG_EXAMPLE_BUF_SIZE,
|
||||
reader_callback,
|
||||
WIEGAND_MSB_FIRST,
|
||||
WIEGAND_LSB_FIRST));
|
||||
|
||||
data_packet_t p;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ESP_LOGI(TAG, "Waiting for Wiegand data...");
|
||||
|
||||
if (xQueueReceive(queue, &p, portMAX_DELAY) != pdPASS)
|
||||
continue;
|
||||
|
||||
@@ -216,7 +242,7 @@ static void wiegand_task(void *arg)
|
||||
continue;
|
||||
}
|
||||
|
||||
char tag[21] = {0}; // OCPP 1.6: máx 20 chars (+NUL)
|
||||
char tag[IDTAG_MAX_LEN + 1] = {0}; // OCPP 1.6: máx 20 chars (+NUL)
|
||||
uint32_t fc = 0, cn = 0;
|
||||
|
||||
if (!wiegand_extract_fc_cn(p.data, p.bits, &fc, &cn))
|
||||
@@ -230,8 +256,8 @@ static void wiegand_task(void *arg)
|
||||
{
|
||||
ok = build_idtag_w26_4B(fc, cn, tag, sizeof(tag)); // 8 hex
|
||||
}
|
||||
else
|
||||
{ // 34
|
||||
else // 34
|
||||
{
|
||||
ok = build_idtag_w34_7B(fc, cn, tag, sizeof(tag)); // 14 hex
|
||||
}
|
||||
|
||||
@@ -250,9 +276,9 @@ static void wiegand_sim_task(void *arg)
|
||||
{
|
||||
// lista fixa de idTags simuladas
|
||||
static const char *idtaglist[] = {
|
||||
"0000004134962107",
|
||||
"00000041349",
|
||||
"W2602312345",
|
||||
"W34ABCDE12345",
|
||||
"W34ABCDE123",
|
||||
};
|
||||
const size_t list_size = sizeof(idtaglist) / sizeof(idtaglist[0]);
|
||||
|
||||
@@ -263,7 +289,7 @@ static void wiegand_sim_task(void *arg)
|
||||
ESP_LOGI(TAG, "Simulação -> idTag: %s", idtaglist[i]);
|
||||
auth_process_tag(idtaglist[i]);
|
||||
|
||||
// espera 20 segundos entre cada tag
|
||||
// espera 30 segundos entre cada tag
|
||||
vTaskDelay(pdMS_TO_TICKS(30000));
|
||||
}
|
||||
}
|
||||
@@ -274,6 +300,8 @@ void initWiegand(void)
|
||||
ESP_LOGI(TAG, "Initializing Wiegand reader");
|
||||
xTaskCreate(wiegand_task, TAG, configMINIMAL_STACK_SIZE * 4, NULL, 4, NULL);
|
||||
|
||||
// ESP_LOGI(TAG, "Inicializando Wiegand simulado");
|
||||
// xTaskCreate(wiegand_sim_task, "WiegandSim", configMINIMAL_STACK_SIZE * 3, NULL, 3, NULL);
|
||||
// Para testes, podes ativar o simulador:
|
||||
//ESP_LOGI(TAG, "Inicializando Wiegand simulado");
|
||||
//xTaskCreate(wiegand_sim_task, "WiegandSim",
|
||||
// configMINIMAL_STACK_SIZE * 3, NULL, 3, NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user