Initial commit: project docs and ignore rules
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.DS_Store
|
||||
19
README.md
Normal file
19
README.md
Normal 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
279
src/main.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user