Skip to content

feat: add pn532killer support - #2

Open
treyturner wants to merge 1 commit into
spiercey:mainfrom
treyturner:feat/support_pn532killer
Open

feat: add pn532killer support#2
treyturner wants to merge 1 commit into
spiercey:mainfrom
treyturner:feat/support_pn532killer

Conversation

@treyturner

@treyturner treyturner commented Jul 17, 2026

Copy link
Copy Markdown

Hey @spiercey! I started using this script before I recognized you from plexamp-tui, cheers for another great idea.

I picked up a PN532Killer to play with, but it wasn't immediately recognized by this script. They enumerate as CDC serial devices and require different DTR/RTS states than a typical PN532 USB-UART adapter. Applying them conditionally can add PN532Killer support without changing existing behavior.

Note that I only have a wired PN532Killer and not the BLE version, so I stopped short of updating the README with explicit support.

Summary

Adds (wired) PN532Killer support while preserving compatibility with standard PN532 USB-UART readers.

  • Replace glob-based discovery with serial.tools.list_ports
  • Detect PN532Killer devices using USB product metadata or VID/PID 1a86:55d3
  • Support readers exposed as either /dev/ttyUSB* or /dev/ttyACM*
  • Configure DTR and RTS specifically for PN532Killer devices
  • Handle zero-target responses as normal no-card polls
  • Add a PN532Killer-specific NTAG read implementation using InCommunicateThru and CRC-A
  • Update README device paths and troubleshooting instructions

Motivation

The PN532Killer presents several compatibility differences from a standard PN532 UART reader:

  1. It appears as a CDC ACM device such as /dev/ttyACM0, rather than /dev/ttyUSB0.
  2. pySerial asserts DTR and RTS by default, but the PN532Killer requires both lines to be deasserted. References:
    1. https://pn532killer.com/tutorial/how-to-fix-device-unauthorized
    2. https://github.com/whywilson/pn532-python/blob/main/script/pn532_communication.py#L61-L66
  3. The Adafruit driver incorrectly reports a zero-target response as "More than one card detected."
  4. The Killer acknowledges InDataExchange NTAG reads, but doesn't return the requested data. Its supported raw-card path uses InCommunicateThru with an appended ISO14443A CRC.

These issues prevented the reader from reading Plexamp tags.

Implementation

Reader discovery

Serial ports are enumerated using serial.tools.list_ports, allowing access to USB metadata such as product name, description, VID, and PID.

A positively identified PN532Killer is preferred. Generic /dev/ttyUSB* devices remain the fallback for standard PN532 USB-UART adapters, followed by generic /dev/ttyACM* devices.

Serial configuration

PN532Killer ports are opened with:

ser.dtr = False
ser.rts = False

These states are configured before opening the port. Standard PN532 readers retain pySerial’s existing defaults.

No-card polling

The custom reader class treats a valid InListPassiveTarget response containing zero targets as a normal no-card result:

D5 4B 00

This prevents unnecessary reader reconnections and preserves errors for genuinely unexpected target counts.

PN532Killer NTAG reads

Standard Adafruit NTAG reads use InDataExchange, but the PN532Killer only acknowledges those commands without returning data.

For PN532Killer devices, NTAG reads now:

  • Build a MIFARE READ command for the requested page.
  • Calculate and append the ISO14443A CRC-A.
  • Send the command through InCommunicateThru.
  • Extract the requested four-byte page from the returned 16-byte block.

Standard PN532 readers continue using Adafruit’s existing InDataExchange implementation.

Testing

Validated with both a standard PN532 USB-UART adapter and a PN532Killer.

  • Confirmed standard reader discovery at /dev/ttyUSB0
  • Confirmed PN532Killer discovery at /dev/ttyACM0
  • Verified metadata-based selection when both reader types are present
  • Verified DTR/RTS are disabled only for PN532Killer
  • Verified zero-target polling returns None without reconnecting
  • Verified InCommunicateThru successfully reads NTAG pages
  • Validated CRC-A output against known command frames
  • Read UID 04e3c36cce2a81 from physical hardware
  • Read 184 bytes across pages 4-49 without errors
  • Successfully parsed many complete Plexamp NDEF URIs from both devices

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant