152 lines
4.6 KiB
C
152 lines
4.6 KiB
C
/*
|
|
* MTG RFID Companion - MFRC522 RFID manager (Core 0)
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "esp_log.h"
|
|
#include "esp_event.h"
|
|
#include "rc522.h"
|
|
#include "rc522_picc.h"
|
|
#include "driver/rc522_spi.h"
|
|
#include "hw_pins.h"
|
|
#include "spi_bus_manager.h"
|
|
#include "rfid_manager.h"
|
|
|
|
static const char *TAG = "rfid";
|
|
|
|
#define RC522_TASK_NAME "rc522_polling_task"
|
|
#define RC522_POLL_INTERVAL_MS (100)
|
|
#define RC522_TASK_STACK_SIZE (6 * 1024)
|
|
#define RC522_TASK_PRIORITY (4)
|
|
|
|
/* Conservative clock for MFRC522 clones. If the FIFO self-test still
|
|
* reports a mismatch error, lower further (e.g. 1000000) or check
|
|
* power/wiring. Many clone readers glitch at 4MHz on a shared bus. */
|
|
#define RC522_SPI_CLK_HZ (1000000)
|
|
#define RC522_START_ATTEMPTS (3)
|
|
|
|
static rc522_driver_handle_t s_driver;
|
|
static rc522_handle_t s_scanner;
|
|
|
|
static char s_last_uid[RFID_UID_STR_MAX_LEN] = {0};
|
|
static bool s_pending_card = false;
|
|
|
|
static void uid_to_hex_string(const rc522_picc_uid_t *uid, char *out)
|
|
{
|
|
int i;
|
|
for (i = 0; i < uid->length && i < RC522_PICC_UID_SIZE_MAX; i++) {
|
|
snprintf(out + (i * 2), 3, "%02X", uid->value[i]);
|
|
}
|
|
}
|
|
|
|
static void on_picc_state_changed(void *arg, esp_event_base_t base, int32_t event_id, void *data)
|
|
{
|
|
rc522_picc_state_changed_event_t *event = (rc522_picc_state_changed_event_t *)data;
|
|
rc522_picc_t *picc = event->picc;
|
|
|
|
(void)arg;
|
|
(void)base;
|
|
(void)event_id;
|
|
|
|
if (picc->state == RC522_PICC_STATE_ACTIVE) {
|
|
uid_to_hex_string(&picc->uid, s_last_uid);
|
|
s_pending_card = true;
|
|
ESP_LOGI(TAG, "Card scanned: UID=%s (%d bytes, %s)",
|
|
s_last_uid, picc->uid.length, rc522_picc_type_name(picc->type));
|
|
} else if ((picc->state == RC522_PICC_STATE_IDLE || picc->state == RC522_PICC_STATE_HALT)
|
|
&& event->old_state >= RC522_PICC_STATE_ACTIVE) {
|
|
ESP_LOGI(TAG, "Card removed");
|
|
}
|
|
}
|
|
|
|
esp_err_t rfid_manager_init(void)
|
|
{
|
|
rc522_spi_config_t driver_config = {
|
|
.host_id = HW_SPI_HOST,
|
|
/* Bus already owned by spi_bus_manager: attaching as an extra device. */
|
|
.bus_config = NULL,
|
|
.dev_config = {
|
|
.spics_io_num = HW_RC522_CS_GPIO,
|
|
.clock_speed_hz = RC522_SPI_CLK_HZ,
|
|
},
|
|
.dma_chan = SPI_DMA_CH_AUTO,
|
|
.rst_io_num = HW_RC522_RST_GPIO,
|
|
};
|
|
|
|
esp_err_t ret = rc522_spi_create(&driver_config, &s_driver);
|
|
if (ret != ESP_OK) {
|
|
ESP_LOGE(TAG, "rc522_spi_create failed: %s", esp_err_to_name(ret));
|
|
return ret;
|
|
}
|
|
ESP_ERROR_CHECK(rc522_driver_install(s_driver));
|
|
|
|
rc522_config_t scanner_config = {
|
|
.driver = s_driver,
|
|
.poll_interval_ms = RC522_POLL_INTERVAL_MS,
|
|
.task_stack_size = RC522_TASK_STACK_SIZE,
|
|
.task_priority = RC522_TASK_PRIORITY,
|
|
};
|
|
|
|
ret = rc522_create(&scanner_config, &s_scanner);
|
|
if (ret != ESP_OK) {
|
|
ESP_LOGE(TAG, "rc522_create failed: %s", esp_err_to_name(ret));
|
|
return ret;
|
|
}
|
|
|
|
ESP_ERROR_CHECK(
|
|
rc522_register_events(s_scanner, RC522_EVENT_PICC_STATE_CHANGED, on_picc_state_changed, NULL));
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t rfid_manager_start(void)
|
|
{
|
|
esp_err_t ret = ESP_FAIL;
|
|
for (int attempt = 1; attempt <= RC522_START_ATTEMPTS; attempt++) {
|
|
ret = rc522_start(s_scanner);
|
|
if (ret == ESP_OK) {
|
|
break;
|
|
}
|
|
ESP_LOGW(TAG, "rc522_start attempt %d/%d failed: %s",
|
|
attempt, RC522_START_ATTEMPTS, esp_err_to_name(ret));
|
|
vTaskDelay(pdMS_TO_TICKS(250));
|
|
}
|
|
|
|
if (ret != ESP_OK) {
|
|
ESP_LOGE(TAG, "MFRC522 self-test failed (%s). Check: reader powered "
|
|
"(3.3V), SPI wiring (SCK=18/MOSI=23/MISO=19, CS=5, RST=22), "
|
|
"and if it is a clone try lowering RC522_SPI_CLK_HZ", esp_err_to_name(ret));
|
|
return ret;
|
|
}
|
|
|
|
/* Pin the library's polling task to Core 0 so that RFID I/O never
|
|
* competes with the UI renderer on Core 1. */
|
|
TaskHandle_t task = xTaskGetHandle(RC522_TASK_NAME);
|
|
if (task != NULL) {
|
|
vTaskCoreAffinitySet(task, (UBaseType_t)(1U << 0));
|
|
ESP_LOGI(TAG, "RC522 polling task pinned to Core 0");
|
|
} else {
|
|
ESP_LOGW(TAG, "rc522_polling_task handle not found, affinity not set");
|
|
}
|
|
|
|
ESP_LOGI(TAG, "RFID scanner ready (SPI2_HOST, CS=%d, RST=%d)",
|
|
HW_RC522_CS_GPIO, HW_RC522_RST_GPIO);
|
|
return ESP_OK;
|
|
}
|
|
|
|
const char *rfid_manager_last_uid(void)
|
|
{
|
|
return s_last_uid;
|
|
}
|
|
|
|
bool rfid_manager_has_pending_card(void)
|
|
{
|
|
return s_pending_card;
|
|
}
|
|
|
|
void rfid_manager_consume_card(void)
|
|
{
|
|
s_pending_card = false;
|
|
} |