new module

This commit is contained in:
2025-12-09 11:48:31 +00:00
parent 4820d9111e
commit e6e2622a95
98 changed files with 5349 additions and 8607 deletions

View File

@@ -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];
}

View File

@@ -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 ===

View File

@@ -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);
}