pokusew / nfc-pcsc

Easy reading and writing NFC tags and cards in Node.js
MIT License
535 stars 132 forks source link

Get Serialnumber/UID from reader? #130

Open atterdal opened 2 years ago

atterdal commented 2 years ago

I have four 1252u readers connected and it works great. However I need to know what card is read from what reader even after reboot or some usb-devices are plug out/in and the name is changed depending on the order they are booted.

Is there a way to solve this?

Cheers, Stefan

kur0s4ki commented 2 years ago

Did you solve this ? I have the same issue.

vaaski commented 2 months ago

Might be a little late, but I found a way that seems to be reliable so far. I have two readers plugged into my Raspberry Pi 4.

First I check what the addresses are with lsusb, which looks like this:

lsusb

# Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
# Bus 001 Device 010: ID 072f:2200 Advanced Card Systems, Ltd ACR122U
# Bus 001 Device 011: ID 072f:2200 Advanced Card Systems, Ltd ACR122U
# Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
# Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Then I use udevadm info to get more info about each device, the relevant bits look like this:

udevadm info -a -n /dev/bus/usb/001/010

# [...]
# looking at device '/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.2':
#   KERNEL=="1-1.2"
#   [...]
#   ATTR{power/active_duration}=="798352"
#   [...]

With the info provided by the udevadm info -a -n ${address} command I can check the physical port and the duration they've been connected for. Then I just map those to the names that nfc-pcsc provides, which seem to be in the order they connected, in my case they look like this:

Here's my code to do all that ```ts // usb.ts import { execaCommand } from "execa" const LSUSB_MATCHER = /^Bus (\d+) Device (\d+).+ACR122U/ const KERNEL_MATCHER = /KERNEL=="(.+)"$/m const TIME_MATCHER = /ATTR{power\/active_duration}=="(.+)"$/m const DEVICE_MATCHER = /ACS ACR122U PICC Interface (\d+) 00/m const PORTS = { "1-1.1": "upper", "1-1.2": "lower", } as const type USBDevice = { kernel: string time: string } export const parseUSBData = async () => { const output = await execaCommand("lsusb") const devices: USBDevice[] = [] for (const line of output.stdout.split("\n")) { const match = LSUSB_MATCHER.exec(line) if (!match) continue const [, bus, device] = match const address = `/dev/bus/usb/${bus}/${device}` const info = await execaCommand(`udevadm info -a -n ${address}`) const kernelMatch = KERNEL_MATCHER.exec(info.stdout) if (!kernelMatch) throw new Error("no kernel match") const [, kernel] = kernelMatch const timeMatcher = TIME_MATCHER.exec(info.stdout) if (!timeMatcher) throw new Error("no time match") const [, time] = timeMatcher devices.push({ kernel, time }) } return devices.sort((a, b) => Number.parseInt(b.time) - Number.parseInt(a.time)) } export const getPort = async (deviceName: string) => { const deviceIndexMatch = DEVICE_MATCHER.exec(deviceName) if (!deviceIndexMatch) throw new Error("no device index match") const [, deviceIndex] = deviceIndexMatch const devices = await parseUSBData() const device = devices[Number.parseInt(deviceIndex)] if (!device) throw new Error("no device found") const port = PORTS[device.kernel as keyof typeof PORTS] if (!port) throw new Error("no port found") return port as (typeof PORTS)[keyof typeof PORTS] } ```

With that I just get the port like this:

import { NFC } from "nfc-pcsc"
import { getPort } from "./usb"

const nfc = new NFC()

nfc.on("reader", async reader => {
  const port = await getPort(reader.reader.name)
  console.log("connected reader", port)
})