Reading RFID when there is no SDK
What I learned hand-writing a binary protocol for UHF readers over raw TCP: CRC framing, EPC parsing, and why the vendor DLL was a dead end.
Every RFID project I ship eventually hits the same wall: the reader does something the
vendor's SDK doesn't expose, or the SDK only exists for Windows, or it's a closed .dll
with a startup integrity check. At some point I stopped waiting for the SDK and learned
to talk to the hardware directly.
This is the short version of what that took.
The reader speaks in frames, not functions
A UHF reader doesn't give you an API. It gives you a serial or TCP stream of framed binary packets. For the Identium IHZ4 family, a command looks like this:
- a start byte,
- a length,
- a command code (
0x48start inventory,0x49stop,0x91set power), - a payload,
- and a CRC-16 checksum over everything before it.
Get the CRC polynomial wrong and the reader just ignores you. No error, no NAK, nothing on the wire. My first day on the IHZ4 was mostly a hex dump on one monitor and a Wireshark capture of the vendor tool on the other, diffing bytes until my frames matched theirs.
Parsing a tag read is where it gets interesting
When a tag responds, the reader hands back a frame with the EPC in it, but the EPC's length lives inside the PC (Protocol Control) bits rather than in a field of its own. So you read the PC word, mask out the length, and only then do you know how many bytes of EPC to slice. RSSI comes back as a signed byte you have to interpret yourself, not a friendly dBm float.
function parseTagFrame(buf: Buffer) {
const pc = buf.readUInt16BE(offset);
const epcWords = (pc >> 11) & 0x1f; // length is in the top 5 bits
const epc = buf.subarray(offset + 2, offset + 2 + epcWords * 2);
const rssi = buf.readInt8(rssiOffset); // signed, not unsigned
return { epc: epc.toString("hex"), rssi };
}
Why bother, when there's a DLL?
Because the DLL only helps until it doesn't. It's Windows-only, it's closed, and the moment you need to run on macOS or Linux (or read the firmware, or auto-tune the reader) you're stuck. Once I owned the protocol, the reader worked everywhere my code did, which has been worth every hour spent staring at hex.
I'll write up the auto-tuning optimiser I built on top of this in a future post.
WRITTEN BY
Vishwas Jha
Software Engineer · New Delhi, India
Get the next one in your inbox: