LLRP has a reputation for being difficult, and the reputation is half deserved. The encoding is binary, the message catalogue is long, and the documentation reads like a standards committee wrote it — because it was one. But the subset that a working deployment needs is small, and once that subset is understood, the protocol becomes the least interesting part of the project.
This is a map of that subset: what to configure, in what order, and which fields actually change what the reader does.
What LLRP is and where it sits
LLRP is a host-to-reader protocol, not an application protocol, and keeping that distinction saves a lot of design confusion.
- It is defined by EPCglobal and standardised as LLRP 1.0.1, with 1.1 adding finer control and better extension support.
- It runs over TCP on port 5084 by default and encodes messages as binary type-length-value structures.
- Its job is to configure the radio and deliver tag reports, not to decide what a tag read means.
- Nearly every enterprise fixed reader supports it, which is why LLRP code can be portable across brands.
- Above LLRP you still need your own gateway: deduplication, business mapping and ERP writes are outside the protocol.
The message model: requests, responses and reports
Three message families cover everything, and knowing which is which prevents most confusion.
- Requests carry a message identifier and expect exactly one response with the same identifier.
- Responses carry a status code; a success code with an unexpected payload is more common than an outright failure.
- Reports arrive asynchronously once a ROSpec is running, and they are not responses to anything.
- Reader events and error notifications may also arrive asynchronously, so the client must always be reading.
- A client that only reads after sending a request will eventually fill its socket buffer and stall.
Reader configuration: the five messages you always send
Configuration is a state machine, and the order matters more than the individual fields.
- Read capabilities first; it tells you which options the reader supports and prevents sending unsupported settings.
- Set reader configuration next: keepalive, report buffer, and the default antenna properties.
- Add the ROSpec, enable it, then start it; an enabled but not started ROSpec does nothing and looks like a failure.
- Add the AccessSpec separately, and only when a write or a lock is genuinely needed.
- Delete and re-add a ROSpec rather than editing it in place; in-place edits are where vendor differences appear.
ROSpec: describing an inventory operation
A ROSpec is a container for a report specification and one or more inventory parameter specifications.
- The report specification selects which tag fields come back and how often reports are emitted.
- The inventory parameter specification names the antennas and the air-protocol behaviour in one unit.
- Every executing ROSpec competes for the same radio, so two ROSpecs on one reader usually mean one of them is wrong.
- Tag observation triggers control when a tag is reported: immediately, after N reads, or when it is no longer seen.
- Keep one ROSpec per business behaviour, name it in the description field, and treat that name as part of your configuration contract.
Air-protocol settings: the fields that change behaviour
The C1G2 inventory command is where reader behaviour is really decided.
- Transmit power and the channel or hop table come first; power is regulation-bound, not a tuning knob.
- The receiver sensitivity setting trades a wider listening window against noise, and defaults are rarely optimal for a dense aisle.
- Singulation session choice determines whether tags are re-reported quickly or held quiet; session two suits moving goods.
- Tag population estimate helps the reader choose Q values; a wrong estimate costs time, not correctness.
- Tag filters reduce the population before singulation, and they are the cheapest performance improvement available.
AccessSpec: reading and writing tag memory
Access operations are used sparingly, and each use has a specific failure profile.
- An AccessSpec targets a filter, so it should never run without one unless you intend to write to every tag in range.
- Reading a memory bank is the safe diagnostic; writing EPC or user memory is the operation that damages data.
- Write operations should be verified by a subsequent read, in the same session, not assumed from a success status.
- Access passwords must be handled as secrets; a lock without a recorded password is an irreversible mistake.
- A failed access operation returns a status code, and the code is often more useful than a retry.
Error handling: status codes worth branching on
Most LLRP clients treat every non-success as a generic failure, which makes field diagnosis impossible.
- Distinguish parameter errors from state errors: the first means the message was wrong, the second means the reader was in the wrong state.
- A capability mismatch should be handled by falling back to a supported option, not by aborting the deployment.
- Repeated timeouts usually mean a dropped TCP session rather than a slow reader, so check the socket before retrying.
- Log the message identifier with the status code; without it, a multi-message sequence cannot be debugged.
- Treat an unexpected success as a bug too — a successful response with an empty payload often means the reader ignored the request.
Keeping LLRP code portable across vendors
Portability is a design choice made at the start, and it is expensive to retrofit.
- Use only standard messages and standard parameters wherever the standard covers your need.
- Feature-detect through the capabilities message instead of assuming a vendor supports an option.
- Isolate vendor extensions behind a thin adapter, so the rest of the gateway never imports them.
- Test the same configuration against a second brand before committing to the design; differences surface early and cheaply.
- Version your configuration files, because a working ROSpec is an asset that should survive a reader replacement.






