new release

This commit is contained in:
2025-11-20 07:45:00 +00:00
parent 96b2ab1f57
commit 4820d9111e
106 changed files with 4264 additions and 15581 deletions

View File

@@ -174,23 +174,6 @@ auth_mode_t auth_get_mode(void) {
return s_mode;
}
const char *auth_mode_to_str(auth_mode_t mode) {
switch (mode) {
case AUTH_MODE_OPEN: return "open";
case AUTH_MODE_LOCAL_RFID: return "local";
case AUTH_MODE_OCPP_RFID: return "ocpp";
default: return "open";
}
}
bool auth_mode_from_str(const char *s, auth_mode_t *out) {
if (!s || !out) return false;
if (!strcasecmp(s, "open")) { *out = AUTH_MODE_OPEN; return true; }
if (!strcasecmp(s, "local")) { *out = AUTH_MODE_LOCAL_RFID; return true; }
if (!strcasecmp(s, "ocpp")) { *out = AUTH_MODE_OCPP_RFID; return true; }
return false;
}
bool auth_add_tag(const char *tag) {
if (tag_count >= MAX_TAGS) return false;
if (!tag || strlen(tag) >= AUTH_TAG_MAX_LEN) return false;

View File

@@ -1,5 +1,6 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
@@ -7,61 +8,272 @@
#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 ----
static const bool PARITY_INVERTED = false; // mude para true se o seu leitor vier "invertido"
static wiegand_reader_t reader;
static QueueHandle_t queue = NULL;
typedef struct {
typedef struct
{
uint8_t data[CONFIG_EXAMPLE_BUF_SIZE];
size_t bits;
size_t bytes;
} data_packet_t;
static void reader_callback(wiegand_reader_t *r) {
data_packet_t p;
p.bits = r->bits;
memcpy(p.data, r->buf, CONFIG_EXAMPLE_BUF_SIZE);
xQueueSendToBack(queue, &p, 0);
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;
}
static void wiegand_task(void *arg) {
queue = xQueueCreate(5, sizeof(data_packet_t));
if (!queue) {
// Versão parametrizável
static bool check_parity_param(const uint8_t *buf, size_t bits, bool invert)
{
if (bits != 26 && bits != 34)
return false;
const int first_parity = get_bit_msb_first(buf, 0);
const int last_parity = get_bit_msb_first(buf, bits - 1);
uint32_t left = 0, right = 0;
if (bits == 26)
{
for (int i = 1; i <= 12; i++)
if (get_bit_msb_first(buf, i))
left++;
for (int i = 13; i <= 24; i++)
if (get_bit_msb_first(buf, i))
right++;
}
else
{ // 34
for (int i = 1; i <= 16; i++)
if (get_bit_msb_first(buf, i))
left++;
for (int i = 17; i <= 32; i++)
if (get_bit_msb_first(buf, i))
right++;
}
// Regra padrão (W26/W34 “normais”): primeiro = PAR (left), último = ÍMPAR (right)
bool exp_first = (left % 2 == 0);
bool exp_last = (right % 2 == 1);
// Se invertido, troca as expectativas (par <-> ímpar)
if (invert)
{
exp_first = !exp_first;
exp_last = !exp_last;
}
return (first_parity == exp_first) && (last_parity == exp_last);
}
// CRC-8/ATM (polinómio 0x07, init 0x00, sem ref, xor 0x00)
static uint8_t crc8_atm(const uint8_t *data, size_t len)
{
uint8_t crc = 0x00;
for (size_t i = 0; i < len; i++)
{
crc ^= data[i];
for (int b = 0; b < 8; b++)
{
crc = (crc & 0x80) ? (uint8_t)((crc << 1) ^ 0x07) : (uint8_t)(crc << 1);
}
}
return crc;
}
// CRC-16/IBM (CRC-16-ANSI) poly 0xA001 (refin/refout), init 0xFFFF
static uint16_t crc16_ibm(const uint8_t *data, size_t len)
{
uint16_t crc = 0xFFFF;
for (size_t i = 0; i < len; i++)
{
crc ^= data[i];
for (int b = 0; b < 8; b++)
{
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc >>= 1;
}
}
return crc;
}
// Extrai payload (sem paridades) e devolve FC/CN para W26/34
static bool wiegand_extract_fc_cn(const uint8_t *buf, size_t bits, uint32_t *fc, uint32_t *cn)
{
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
{
*fc = (payload >> 16) & 0xFFFF; // 16b
*cn = payload & 0xFFFF; // 16b
}
return true;
}
static bool build_idtag_w26_4B(uint32_t fc, uint32_t cn, char *out, size_t outlen)
{
uint8_t raw[4] = {
(uint8_t)(fc & 0xFF),
(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]);
return (n > 0 && (size_t)n < outlen);
}
static bool build_idtag_w34_7B(uint32_t fc, uint32_t cn, char *out, size_t outlen)
{
uint8_t raw[7];
raw[0] = 0x34;
raw[1] = (uint8_t)((fc >> 8) & 0xFF);
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]);
return (n > 0 && (size_t)n < outlen);
}
// Se o callback for de ISR, troque para xQueueSendToBackFromISR.
static void reader_callback(wiegand_reader_t *r)
{
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();
}
static void wiegand_task(void *arg)
{
queue = xQueueCreate(8, sizeof(data_packet_t));
if (!queue)
{
ESP_LOGE(TAG, "Failed to create queue");
vTaskDelete(NULL);
return;
}
ESP_ERROR_CHECK(wiegand_reader_init(&reader, 21, 22,
true, CONFIG_EXAMPLE_BUF_SIZE, reader_callback, WIEGAND_MSB_FIRST, WIEGAND_LSB_FIRST));
true, CONFIG_EXAMPLE_BUF_SIZE, reader_callback, WIEGAND_MSB_FIRST, WIEGAND_LSB_FIRST));
data_packet_t p;
while (1) {
for (;;)
{
ESP_LOGI(TAG, "Waiting for Wiegand data...");
if (xQueueReceive(queue, &p, portMAX_DELAY) == pdPASS) {
ESP_LOGI(TAG, "Bits received: %d", p.bits);
if (xQueueReceive(queue, &p, portMAX_DELAY) != pdPASS)
continue;
char tag[20] = {0};
ESP_LOGI(TAG, "Bits received: %d", (int)p.bits);
if (p.bits == 26) {
snprintf(tag, sizeof(tag), "%03d%03d%03d", p.data[0], p.data[1], p.data[2]);
} else if (p.bits == 34) {
snprintf(tag, sizeof(tag), "%03d%03d%03d%03d", p.data[0], p.data[1], p.data[2], p.data[3]);
} else {
ESP_LOGW(TAG, "Unsupported bit length: %d", (int)p.bits);
ESP_LOG_BUFFER_HEX(TAG, p.data, sizeof(p.data)); // loga o buffer bruto
continue;
}
if (!check_parity_param(p.data, p.bits, PARITY_INVERTED))
{
ESP_LOGW(TAG, "Parity check failed (%d bits). Dump:", (int)p.bits);
ESP_LOG_BUFFER_HEX(TAG, p.data, p.bytes);
continue;
}
ESP_LOGI(TAG, "Tag read: %s", tag);
auth_process_tag(tag); // agora delega toda a lógica à auth.c
char tag[21] = {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))
{
ESP_LOGW(TAG, "Unsupported bit length: %d", (int)p.bits);
continue;
}
bool ok = false;
if (p.bits == 26)
{
ok = build_idtag_w26_4B(fc, cn, tag, sizeof(tag)); // 8 hex
}
else
{ // 34
ok = build_idtag_w34_7B(fc, cn, tag, sizeof(tag)); // 14 hex
}
if (!ok)
{
ESP_LOGW(TAG, "Failed to build idTag");
continue;
}
ESP_LOGI(TAG, "idTag: %s", tag); // apenas [0-9A-F], alfanumérico
auth_process_tag(tag);
}
}
static void wiegand_sim_task(void *arg)
{
// lista fixa de idTags simuladas
static const char *idtaglist[] = {
"0000004134962107",
"W2602312345",
"W34ABCDE12345",
};
const size_t list_size = sizeof(idtaglist) / sizeof(idtaglist[0]);
for (;;)
{
for (size_t i = 0; i < list_size; i++)
{
ESP_LOGI(TAG, "Simulação -> idTag: %s", idtaglist[i]);
auth_process_tag(idtaglist[i]);
// espera 20 segundos entre cada tag
vTaskDelay(pdMS_TO_TICKS(30000));
}
}
}
void initWiegand(void) {
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);
}