commit eeee0490c1aec5b16acd7a643c89fabb8b73ed45 Author: Dr Jones Date: Sun May 3 23:20:16 2026 -0700 Initial commit: project docs and ignore rules diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba13302 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.pio +.vscode/.browse.c_cpp.db* +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..d3814e9 --- /dev/null +++ b/README.md @@ -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). diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..0428efc --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,279 @@ +#include +#include +#include +#include +#include +#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); + } +} \ No newline at end of file