Initial commit: project docs and ignore rules

This commit is contained in:
Dr Jones
2026-05-03 23:20:16 -07:00
commit eeee0490c1
3 changed files with 301 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.pio
.vscode/.browse.c_cpp.db*
.DS_Store

19
README.md Normal file
View File

@@ -0,0 +1,19 @@
# listener_firmware
**Listener / scanner module** for the dual-PN532 NFC setup: continuously polls NFC tags and forwards data to the emulator over **ESP-NOW**.
## Build
Use PlatformIO from the **parent directory** (see root `platformio.ini`):
```bash
cd ..
pio run -e listener
pio run -e listener -t upload
```
Includes headers from `../common/`.
## Hardware
Pinout and stack description: [parent README](../README.md).

279
src/main.cpp Normal file
View File

@@ -0,0 +1,279 @@
#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
#include <Wire.h>
#include <Adafruit_PN532.h>
#include "../../common/nfc_protocol.h"
// Pin definitions for ESP32-C3
#define PN532_SDA 8
#define PN532_SCL 9
#define LED_PIN 10
// PN532 instance
Adafruit_PN532 nfc(PN532_SDA, PN532_SCL);
// Communication variables
uint8_t emulator_mac[6] = {0};
bool is_paired = false;
uint8_t message_sequence = 0;
unsigned long last_heartbeat = 0;
unsigned long last_scan = 0;
const unsigned long SCAN_INTERVAL = 100; // Scan every 100ms
// Function prototypes
void initializeNFC();
void initializeESPNow();
void scanForEmulator();
void scanNFCTags();
void sendNFCData(const NFCData& data);
void sendHeartbeat();
void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status);
void onDataReceived(const uint8_t *mac, const uint8_t *incomingData, int len);
void blinkLED(int times, int delay_ms = 200);
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("=== NFC Listener Module Starting ===");
// Initialize LED
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Initialize NFC
initializeNFC();
// Initialize ESP-NOW
initializeESPNow();
// Start scanning for emulator
scanForEmulator();
Serial.println("Listener module ready!");
blinkLED(3, 100);
}
void loop() {
unsigned long current_time = millis();
// Send heartbeat every second if paired
if (is_paired && (current_time - last_heartbeat > HEARTBEAT_INTERVAL_MS)) {
sendHeartbeat();
last_heartbeat = current_time;
}
// Scan for NFC tags
if (current_time - last_scan > SCAN_INTERVAL) {
scanNFCTags();
last_scan = current_time;
}
// If not paired, try to find emulator again
if (!is_paired && (current_time % 5000 == 0)) {
scanForEmulator();
}
delay(10);
}
void initializeNFC() {
Serial.println("Initializing PN532...");
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (!versiondata) {
Serial.println("ERROR: PN532 not found!");
while (1) {
blinkLED(1, 100);
delay(500);
}
}
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
// Configure board to read RFID tags
nfc.SAMConfig();
Serial.println("PN532 initialized successfully!");
}
void initializeESPNow() {
Serial.println("Initializing ESP-NOW...");
WiFi.mode(WIFI_STA);
WiFi.disconnect();
if (esp_now_init() != ESP_OK) {
Serial.println("ERROR: ESP-NOW init failed!");
return;
}
esp_now_register_send_cb(onDataSent);
esp_now_register_recv_cb(onDataReceived);
Serial.println("ESP-NOW initialized successfully!");
}
void scanForEmulator() {
Serial.println("Scanning for emulator module...");
// Broadcast pairing request
CommMessage msg;
msg.type = MSG_PAIRING_REQUEST;
msg.sequence = message_sequence++;
msg.payload_size = 0;
msg.checksum = calculateChecksum((uint8_t*)&msg, sizeof(msg) - sizeof(msg.checksum));
// Broadcast to all devices
uint8_t broadcast_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
esp_now_peer_info_t peer_info = {};
memcpy(peer_info.peer_addr, broadcast_mac, 6);
peer_info.channel = ESPNOW_CHANNEL;
peer_info.encrypt = false;
if (esp_now_add_peer(&peer_info) == ESP_OK || esp_err_t(ESP_ERR_ESPNOW_EXIST)) {
esp_now_send(broadcast_mac, (uint8_t*)&msg, sizeof(msg));
}
}
void scanNFCTags() {
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
uint8_t uidLength;
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 50)) {
// Tag detected!
digitalWrite(LED_PIN, HIGH);
NFCData nfc_data = {};
// Copy UID
nfc_data.uid_length = min(uidLength, (uint8_t)10);
memcpy(nfc_data.uid, uid, nfc_data.uid_length);
// Get additional tag information
uint8_t sak, atqa[2];
if (nfc.getTargetInfo(&sak, atqa)) {
nfc_data.sak = sak;
nfc_data.atqa[0] = atqa[0];
nfc_data.atqa[1] = atqa[1];
}
// Determine tag type
if (uidLength == 4) {
nfc_data.tag_type = 1; // MIFARE Classic 1K
} else if (uidLength == 7) {
nfc_data.tag_type = 2; // MIFARE Ultralight
} else {
nfc_data.tag_type = 0; // Unknown
}
// Try to read some data from the tag
uint8_t data[16];
if (nfc.mifareclassic_ReadDataBlock(1, data)) {
nfc_data.data_length = min(16, MAX_NFC_DATA_SIZE);
memcpy(nfc_data.raw_data, data, nfc_data.data_length);
}
nfc_data.timestamp = millis();
Serial.println("NFC Tag detected!");
printNFCData(&nfc_data);
// Send data to emulator if paired
if (is_paired) {
sendNFCData(nfc_data);
}
digitalWrite(LED_PIN, LOW);
// Wait a bit to avoid multiple reads of the same tag
delay(500);
}
}
void sendNFCData(const NFCData& data) {
if (!is_paired) return;
CommMessage msg;
msg.type = MSG_NFC_DATA;
msg.sequence = message_sequence++;
msg.payload_size = sizeof(NFCData);
msg.nfc_data = data;
msg.checksum = calculateChecksum((uint8_t*)&msg, sizeof(msg) - sizeof(msg.checksum));
esp_now_send(emulator_mac, (uint8_t*)&msg, sizeof(msg));
Serial.println("NFC data sent to emulator");
}
void sendHeartbeat() {
if (!is_paired) return;
CommMessage msg;
msg.type = MSG_HEARTBEAT;
msg.sequence = message_sequence++;
msg.payload_size = 0;
msg.checksum = calculateChecksum((uint8_t*)&msg, sizeof(msg) - sizeof(msg.checksum));
esp_now_send(emulator_mac, (uint8_t*)&msg, sizeof(msg));
}
void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
// Optional: Handle send status
}
void onDataReceived(const uint8_t *mac, const uint8_t *incomingData, int len) {
if (len != sizeof(CommMessage)) return;
CommMessage* msg = (CommMessage*)incomingData;
if (!validateMessage(msg)) {
Serial.println("Invalid message received");
return;
}
switch (msg->type) {
case MSG_PAIRING_RESPONSE:
if (!is_paired) {
memcpy(emulator_mac, mac, 6);
is_paired = true;
// Add emulator as peer
esp_now_peer_info_t peer_info = {};
memcpy(peer_info.peer_addr, emulator_mac, 6);
peer_info.channel = ESPNOW_CHANNEL;
peer_info.encrypt = false;
esp_now_add_peer(&peer_info);
Serial.println("Paired with emulator!");
Serial.print("Emulator MAC: ");
for (int i = 0; i < 6; i++) {
Serial.printf("%02X", emulator_mac[i]);
if (i < 5) Serial.print(":");
}
Serial.println();
blinkLED(5, 100);
}
break;
case MSG_ACK:
// Handle acknowledgment
break;
}
}
void blinkLED(int times, int delay_ms) {
for (int i = 0; i < times; i++) {
digitalWrite(LED_PIN, HIGH);
delay(delay_ms);
digitalWrite(LED_PIN, LOW);
delay(delay_ms);
}
}