From 5e55404ca753e6968bd7d0f6266e3e06172ada58 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 17:40:12 +0000 Subject: [PATCH] cyberpunkunicorn-os 0.1.5: read every PN532 answer before the next command Daniel's 0.1.4 log: the PN532 answered GetFirmwareVersion, then every card search ended 'no ack'. startReader() used Adafruit's setPassiveActivationRetries(), which never reads the chip's answer, and SAMConfig(), which reads it without waiting. The answer left in the chip was read in place of the next command's ACK, so every poll looked unanswered. Both setup commands now go through command(), which waits for and checks the answer, and the setup result is logged. A card search that runs past its wait is cancelled with an ACK frame so its late answer can't do the same. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_015Aw32AU4vVqCSEoNA5aP3U --- cyberpunkunicorn-os/apps/frequency/card.cpp | 36 +++++++++++++++++++-- cyberpunkunicorn-os/build.sh | 2 +- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/cyberpunkunicorn-os/apps/frequency/card.cpp b/cyberpunkunicorn-os/apps/frequency/card.cpp index b483906..dde72b9 100644 --- a/cyberpunkunicorn-os/apps/frequency/card.cpp +++ b/cyberpunkunicorn-os/apps/frequency/card.cpp @@ -132,6 +132,30 @@ String parseNdefUri(const std::vector &mem) { return ""; } +// Send a command and read its whole answer before the next one goes out. +// Adafruit's setPassiveActivationRetries() never reads the answer and its +// SAMConfig() reads without waiting for it. An answer left in the chip is then +// read in place of the next command's ACK, so every later poll counts as +// "no ack" and the reader looks dead (2026-10-21: firmware version answered, +// then every card search failed). +bool command(uint8_t *cmd, uint8_t len) { + auto &nfc = rfid->nfc; + if (!nfc.sendCommandCheckAck(cmd, len)) return false; + if (!nfc.waitready(100)) return false; + uint8_t reply[9]; // 00 00 FF LEN LCS D5 CMD+1 DCS 00 + nfc.readdata(reply, sizeof(reply)); + return reply[5] == 0xD5 && reply[6] == uint8_t(cmd[0] + 1); +} + +// A command the chip has not answered yet (a card search that ran past its +// wait) is cancelled by sending it an ACK frame (PN532 user manual 6.2.1.3), so +// its late answer can't be read as the next command's ACK. +void abortCommand() { + static const uint8_t ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00}; + if (rfid->nfc.i2c_dev) rfid->nfc.i2c_dev->write(ack, sizeof(ack)); + delay(2); +} + // A reliable "is a card in the field" check. Bruce's read() reads the // InListPassiveTarget answer without waiting for the PN532 to be ready, so on // its own it misses cards now and then; waiting for RDY here first fixes that. @@ -146,6 +170,7 @@ bool selectCard(uint16_t waitMs) { } if (!rfid->nfc.waitready(waitMs)) { stats.noAnswer++; + abortCommand(); return false; } if (!rfid->nfc.readDetectedPassiveTargetID()) { @@ -210,10 +235,15 @@ bool startReader() { // The PN532 is rated to 400 kHz but clock-stretches; 100 kHz is what Bruce's own NFC tools use. acquireI2CBus()->setClock(100000); if (!commandsAnswered()) continue; - rfid->nfc.SAMConfig(); + // Normal mode, 1 s timeout, IRQ pin (as Adafruit's SAMConfig()). + uint8_t sam[] = {PN532_COMMAND_SAMCONFIGURATION, 0x01, 0x14, 0x01}; // Answer "no tag" after a few tries instead of waiting forever, so a poll - // never leaves a command pending in the chip. - rfid->nfc.setPassiveActivationRetries(0x05); + // never leaves a command pending in the chip (RFConfiguration item 5). + uint8_t retries[] = {PN532_COMMAND_RFCONFIGURATION, 0x05, 0xFF, 0x01, 0x05}; + bool samOk = command(sam, sizeof(sam)); + bool retriesOk = command(retries, sizeof(retries)); + Serial.printf("[freq] PN532 setup: SAM %s, retries %s\n", samOk ? "ok" : "failed", retriesOk ? "ok" : "failed"); + if (!samOk || !retriesOk) continue; return true; } return false; diff --git a/cyberpunkunicorn-os/build.sh b/cyberpunkunicorn-os/build.sh index 328b8cb..c3fbf61 100755 --- a/cyberpunkunicorn-os/build.sh +++ b/cyberpunkunicorn-os/build.sh @@ -9,7 +9,7 @@ PIO_ENV=CYD-2432S028 PLATFORMIO_VERSION=6.2.0 ESPTOOL_VERSION=5.4.0 OS_NAME="CyberUnicorn 5000" -OS_VERSION=0.1.4 +OS_VERSION=0.1.5 source ./boot.conf for var in BOOT_TITLE BOOT_TAGLINE; do