M5Unit-RFID 0.2.0 git rev:79c1939
Loading...
Searching...
No Matches
uhf.hpp File Reference

Common vocabulary for UHF-RFID (EPCglobal UHF Class 1 Gen 2 / ISO 18000-6C) More...

#include <array>
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
#include <m5_utility/crc.hpp>

Go to the source code of this file.

Classes

struct  m5::uhf::Epc
 EPC of a tag. More...
 
struct  m5::uhf::Tid
 TID of a tag. More...
 
struct  m5::uhf::detail::VendorEntry
 A named mask designer paired with the name the registry spells it out as. More...
 
struct  m5::uhf::Tag
 A tag, as the EPC Gen2 standard calls it. More...
 
struct  m5::uhf::TidReadPlan
 What to read next of a tag's TID, given what has been read of it so far. More...
 
struct  m5::uhf::LockSetting
 One entry of a lock operation. Targets left out keep their current lock state. More...
 
struct  m5::uhf::QueryParameters
 EPC Gen2 query parameters. More...
 
struct  m5::uhf::NxpConfigWord
 Config-Word of an NXP UCODE G2iM or G2iM+, spelled out. More...
 
struct  m5::uhf::QTParameters
 QT control word of an Impinj Monza 4QT. More...
 
struct  m5::uhf::SelectParameter
 The mask the reader holds, and how it is matched. More...
 
struct  m5::uhf::ModuleInformation
 Reader module information. More...
 
struct  m5::uhf::ChannelLevels
 Signal level measured on each channel of the operating region. More...
 

Namespaces

namespace  m5
 Top level namespace of M5Stack.
 
namespace  uhf
 UHF-RFID (EPC Gen2) related namespace.
 

Enumerations

enum class  m5::uhf::Bank : uint8_t { Reserved , Epc , Tid , User }
 EPC Gen2 memory bank. More...
 
enum class  m5::uhf::Region : uint8_t {
  Unspecified = 0x00 , China900MHz = 0x01 , America = 0x02 , Europe = 0x03 ,
  China800MHz = 0x04 , SouthKorea = 0x06
}
 Operating region. More...
 
enum class  m5::uhf::Session : uint8_t { S0 , S1 , S2 , S3 }
 EPC Gen2 session.
 
enum class  m5::uhf::Target : uint8_t { A , B }
 EPC Gen2 inventoried flag target.
 
enum class  m5::uhf::SelectFilter : uint8_t { All , AllAlias , NotSelected , Selected }
 Which tags an inventory round invites, in terms of the SL flag. More...
 
enum class  m5::uhf::Reason : uint8_t {
  NoSelection , BadArgument , Busy , Unsupported ,
  Locked , InsufficientPower , MemoryOverrun , Refused ,
  NoAnswer , AccessFailed , ReaderFault , Malformed
}
 Why an operation meant to change a tag did not change it. More...
 
enum class  m5::uhf::Vendor : uint16_t {
  Unknown = 0x000 , Impinj = 0x001 , TexasInstruments = 0x002 , Alien = 0x003 ,
  Atmel = 0x005 , NXP = 0x006 , STMicroelectronics = 0x007 , EPMicroelectronics = 0x008 ,
  EMMicroelectronic = 0x00B , Quanray = 0x00F , Fujitsu = 0x010 , Nationz = 0x01B ,
  Invengo = 0x01C , RFMicron = 0x024 , FudanMicroelectronics = 0x027 , AMS = 0x02F ,
  HuadaSemiconductor = 0x032 , Mikron = 0x034
}
 Mask designers this library knows by name. More...
 
enum class  m5::uhf::Chip : uint8_t {
  Unknown , AlienHiggs3 , AlienHiggs4 , AlienHiggs9 ,
  Em4423SmallEpc , Em4423LargeEpc , ImpinjMonza4D , ImpinjMonza4E ,
  ImpinjMonza4i , ImpinjMonza4QT , ImpinjM730 , ImpinjM750 ,
  ImpinjM770 , ImpinjM780 , ImpinjM781 , NxpUcodeG2iM ,
  NxpUcodeG2iMPlus , NxpUcode7 , NxpUcode7xm1k , NxpUcode7xm2k ,
  NxpUcode7xmPlus , NxpUcode8 , NxpUcode8m , NxpUcode9 ,
  NxpUcode9xe
}
 Chip a tag is built around, resolved from the mask-designer identifier and model number.
 
enum class  m5::uhf::Support : uint8_t { Unknown , No , Yes }
 What can be said about a chip having a command. More...
 
enum class  m5::uhf::LockTarget : uint8_t {
  KillPassword , AccessPassword , Epc , Tid ,
  User
}
 What a lock setting applies to, in the order EPC Gen2 lays them out.
 
enum class  m5::uhf::LockAction : uint8_t { Open = 0x00 , PermanentOpen = 0x01 , Lock = 0x02 , PermanentLock = 0x03 }
 What a lock setting does. More...
 

Functions

bool m5::uhf::tagUnchanged (const Reason reason)
 Is the tag known to be as it was before the operation?
 
const char * m5::uhf::reasonAsString (const Reason reason)
 Spell out a Reason.
 
uint16_t m5::uhf::detail::word_at (const uint8_t *data, const size_t word_index)
 Read one big-endian 16-bit word out of a byte buffer.
 
const VendorEntrym5::uhf::detail::vendorEntries (size_t &count)
 The mask designers this library names.
 
uint32_t m5::uhf::chipUserMemoryBits (const Chip chip)
 User memory a chip is known to hold, in bits.
 
uint32_t m5::uhf::chipEpcMaxBits (const Chip chip)
 Largest EPC a chip is known to accept, in bits.
 
uint16_t m5::uhf::chipTidWords (const Chip chip)
 Words of TID a chip carries without an XTID header to say so.
 
uint16_t m5::uhf::chipPermalockBlockCount (const Chip chip)
 How many blocks a chip divides its user memory into for BlockPermalock.
 
const char * m5::uhf::supportAsString (const Support support)
 Spell out a Support.
 
Support m5::uhf::chipBlockPermalockSupport (const Chip chip)
 What the chip's datasheet says about it having BlockPermalock.
 
Support m5::uhf::chipQTSupport (const Chip chip)
 What the chip's datasheet says about it having the Impinj QT command.
 
Support m5::uhf::chipNxpCustomCommandSupport (const Chip chip)
 What the chip's datasheet says about it having the commands NXP added of its own.
 
uint32_t m5::uhf::chipPermalockBlockBits (const Chip chip)
 Size of the block BlockPermalock works in, in bits.
 
uint32_t m5::uhf::chipPermalockLastBlockBits (const Chip chip)
 How many bits the last block of a chip actually covers.
 
bool m5::uhf::chipHasNoUserMemory (const Chip chip)
 Is this a chip whose datasheet says it has no User bank at all?
 
uint32_t m5::uhf::chipSharedUserMemoryBits (const Chip chip, const uint16_t pc)
 User memory of a chip that carves it out of one pool with the EPC, in bits.
 
bool m5::uhf::tidHasXtid (const uint8_t *tid, const size_t len)
 Does a TID say it carries an extended TID, and with it a serial number?
 
uint16_t m5::uhf::xtidSerialBits (const uint16_t xtid_header)
 Serial length an XTID header announces.
 
size_t m5::uhf::xtidTotalWords (const uint16_t xtid_header)
 Length of the whole TID an XTID header describes, in 16-bit words.
 
bool m5::uhf::tidTellsTagsApart (const uint8_t *tid, const size_t len)
 Can a mask built from this TID tell one tag of the chip from another?
 
Vendor m5::uhf::resolveVendor (const uint16_t mdid)
 Resolve a named mask designer from its identifier.
 
Chip m5::uhf::resolveChip (const Vendor vendor, const uint16_t model_number)
 Resolve a chip from its mask designer and model number.
 
void m5::uhf::fillSizesFromChip (Tag &tag)
 Fill in what the tag left unsaid from what its chip is known to hold.
 
Chip m5::uhf::chipFromTid (const uint8_t *tid, const size_t len)
 Name the chip from the two fixed words of a TID.
 
TidReadPlan m5::uhf::tidReadPlan (const uint8_t *tid, const size_t len)
 Say what to read next of a TID.
 
bool m5::uhf::decodeTid (Tag &tag, const uint8_t *tid, const size_t len)
 Decode the fixed part of a TID into a tag.
 
bool m5::uhf::isPermanent (const LockAction action)
 Is this action one of the two that cannot be undone?
 
uint32_t m5::uhf::buildLockPayload (const LockSetting *settings, const size_t count)
 Build the 20-bit payload of the Gen2 Lock command.
 
NxpConfigWord m5::uhf::decodeNxpConfigWord (const uint16_t word)
 Spell out the Config-Word of an NXP UCODE G2iM or G2iM+.
 
std::string m5::uhf::detail::to_hex (const uint8_t *data, const size_t len)
 Render a byte buffer as uppercase hex.
 
Support m5::uhf::tagBlockPermalockSupport (const Tag &tag)
 What can be said about this tag having BlockPermalock.
 
Support m5::uhf::tagQTSupport (const Tag &tag)
 What can be said about this tag having the Impinj QT command.
 
Support m5::uhf::tagNxpCustomCommandSupport (const Tag &tag)
 What can be said about this tag having the commands NXP added of its own.
 
uint16_t m5::uhf::gen2_crc16 (const uint8_t *data, const size_t len)
 Calculate the EPC Gen2 CRC-16.
 
bool m5::uhf::verify_tag_crc (const Tag &tag)
 Verify the CRC-16 reported with a detected tag.
 
uint8_t m5::uhf::pcEPCLengthWords (const uint16_t pc)
 EPC length in 16-bit words encoded in the PC.
 
bool m5::uhf::pcUserMemoryIndicator (const uint16_t pc)
 User Memory Indicator of the PC.
 
bool m5::uhf::pcXPCIndicator (const uint16_t pc)
 XPC indicator of the PC.
 
bool m5::uhf::pcToggle (const uint16_t pc)
 Toggle bit of the PC.
 
uint16_t m5::uhf::pcNumberingSystemIdentifier (const uint16_t pc)
 Numbering System Identifier of the PC.
 
bool m5::uhf::append_unique (std::vector< Tag > &dst, const Tag &tag)
 Append a tag unless an identical EPC is already present.
 

Variables

constexpr size_t m5::uhf::EPC_MAX_BYTES {62}
 Longest EPC the standard allows: the PC length field is 5 bits, so 31 words.
 
constexpr size_t m5::uhf::TID_MAX_BYTES {40}
 How much of the TID identify() keeps.
 
constexpr uint8_t m5::uhf::TID_CLASS_EPCGLOBAL {0xE2}
 ISO/IEC 15963 allocation class identifier used by EPCglobal tags.
 
constexpr size_t m5::uhf::TID_FIXED_WORDS {2}
 Words every TID starts with, which say what the chip is and whether an XTID follows.
 
constexpr size_t m5::uhf::XTID_FIXED_WORDS {3}
 Words the two fixed TID words and the XTID header take up.
 
constexpr size_t m5::uhf::TID_CHIP_WORDS {3}
 Words at the front of a TID that name the chip rather than the individual tag.
 
constexpr size_t m5::uhf::SELECT_MASK_MAX_BYTES {32}
 Longest select mask the module accepts, the length field being 8 bits wide.
 
constexpr uint16_t m5::uhf::GEN2_CRC16_INIT {0xFFFF}
 Initial value of the EPC Gen2 CRC-16.
 
constexpr uint16_t m5::uhf::GEN2_CRC16_POLYNOMIAL {0x1021}
 Polynomial of the EPC Gen2 CRC-16 (x^16 + x^12 + x^5 + 1)
 
constexpr uint16_t m5::uhf::GEN2_CRC16_XOROUT {0xFFFF}
 Final xor value of the EPC Gen2 CRC-16.
 
XTID header bits announcing an optional segment (TDS Table 16-3)

The segments follow the serial in the order the bits are listed here, from the most significant down, and a segment that is absent moves the ones below it to lower addresses

constexpr uint16_t m5::uhf::XTID_OPTIONAL_COMMAND_SUPPORT {0x1000}
 bit 12, one word
 
constexpr uint16_t m5::uhf::XTID_BLOCKWRITE_BLOCKERASE {0x0800}
 bit 11, four words
 
constexpr uint16_t m5::uhf::XTID_USER_MEMORY_BLOCKPERMALOCK {0x0400}
 bit 10, two words
 
constexpr uint16_t m5::uhf::XTID_LOCK_BIT {0x0200}
 bit 9, one word
 
constexpr uint16_t m5::uhf::XTID_EXTENDED_HEADER {0x0001}
 bit 0, header continues
 
Bits of the Config-Word of an NXP UCODE G2iM and G2iM+

Named so that a toggle can say what it is inverting. The chip addresses these as bits 200h to 20Fh of the EPC bank, which is the word at address 20h counted from its most significant bit (SL3S1003_1013 Rev3.7 Table 13 and Table 14)

Warning
These are the bits of the UCODE G2iM and G2iM+ alone. Other NXP chips lay the word out differently, and reading one of them through these names would say something untrue
constexpr uint16_t m5::uhf::NXP_CONFIG_TAMPER_ALARM {0x8000}
 Read only. Tag Tamper Alarm.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_EXTERNAL_SUPPLY {0x4000}
 Read only. External supply present.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_INVERT_OUTPUT {0x0800}
 Cleared when the tag loses power.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_TRANSPARENT_MODE {0x0400}
 Cleared when the tag loses power.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_RAW_DATA_MODE {0x0200}
 Cleared when the tag loses power.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_CONDITIONAL_RANGE {0x0100}
 Conditional read range reduction.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_CONDITIONAL_SHORT {0x0080}
 Which way the condition is read.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_MAX_BACKSCATTER {0x0040}
 Set as the chip leaves the factory.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_DIGITAL_OUTPUT {0x0020}
 Drives the chip's output pad.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_RANGE_REDUCTION {0x0010}
 Range reduction, G2iM+ only.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_PROTECT_USER {0x0008}
 User memory reads back as zeroes.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_PROTECT_EPC {0x0004}
 EPC reads back as zeroes.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_PROTECT_TID {0x0002}
 TID reads back as zeroes.
 
constexpr uint16_t m5::uhf::NXP_CONFIG_PSF_ALARM {0x0001}
 Product Status Flag, read by EAS.
 

Detailed Description

Common vocabulary for UHF-RFID (EPCglobal UHF Class 1 Gen 2 / ISO 18000-6C)

Enumeration Type Documentation

◆ Bank

enum class m5::uhf::Bank : uint8_t
strong

EPC Gen2 memory bank.

Enumerator
Reserved 

Kill password and access password.

Epc 

CRC-16, PC and EPC.

Tid 

Tag identification.

User 

User memory.

◆ LockAction

enum class m5::uhf::LockAction : uint8_t
strong

What a lock setting does.

EPC Gen2 does not define these as four values but as two independent bits, a pwd-write bit and a permalock bit (v1.2.0 Table 6.43). These four names are the four combinations of those bits

Enumerator
Open 

Writeable from either the open or the secured state.

PermanentOpen 

Permanently writeable and can never be locked. Cannot be undone.

Lock 

Writeable from the secured state only.

PermanentLock 

Not writeable from any state. Cannot be undone.

◆ Reason

enum class m5::uhf::Reason : uint8_t
strong

Why an operation meant to change a tag did not change it.

The three at the end leave the tag's state unknown; every value before them means the tag is as it was, either because nothing was sent or because the tag answered and declined. A tag that answers has not carried the command out

Note
This matters most where the answer cannot be looked up afterwards. A write can be read back, but EPC Gen2 gives no way to read a tag's lock bits, and a killed tag is silent whether it was killed or never heard the command
Enumerator
NoSelection 

No tag had been selected.

BadArgument 

The request cannot succeed as it was asked.

Busy 

The reader could not make room to send it.

Unsupported 

This chip is said not to have the command at all.

Locked 

The memory is locked against this.

InsufficientPower 

The tag has not the power to carry it out.

MemoryOverrun 

The address or length reaches past what the tag holds.

Refused 

Declined without saying which of these it was.

NoAnswer 

Nobody answered. Whether the tag acted on it cannot be told from here.

AccessFailed 

The reader could not get the tag into the state the command needs.

ReaderFault 

The reader answered, and said it had not done it.

Malformed 

The answer could not be read.

◆ Region

enum class m5::uhf::Region : uint8_t
strong

Operating region.

The regions the module's firmware offers, carrying the values it uses for them

Enumerator
Unspecified 

Keep the module's factory setting.

◆ SelectFilter

enum class m5::uhf::SelectFilter : uint8_t
strong

Which tags an inventory round invites, in terms of the SL flag.

Decides whether a stored select mask narrows the field down at all. A reader left on All ignores the SL flag outright, so a Select that acts on SL stores a mask that changes nothing; one that acts on an inventoried flag still works because the round is qualified by the session instead (EPC Gen2 v2.1 Table 6-32 and 6.3.2.3)

Enumerator
All 

Every tag answers, whatever its SL flag says.

AllAlias 

Same as All; the standard leaves this encoding equivalent.

NotSelected 

Only tags whose SL flag is deasserted.

Selected 

Only tags whose SL flag is asserted.

◆ Support

enum class m5::uhf::Support : uint8_t
strong

What can be said about a chip having a command.

Three answers, not two. A datasheet that lists what a chip implements can say yes or no; one that is not to hand says neither, and that is not the same as no. Keeping the third answer means a chip nothing has been read about is tried rather than turned away

Enumerator
Unknown 

Nothing that has been read says either way.

No 

Said not to have it.

Yes 

Said to have it.

◆ Vendor

enum class m5::uhf::Vendor : uint16_t
strong

Mask designers this library knows by name.

The value is the mask-designer identifier the registration authority assigned, as held in TID bits 0Bh to 13h. The list covers the designers whose chips turn up on tags in the field, not the whole registry; a tag from any other reports Vendor::Unknown while Tag::mdid still carries the raw identifier, which can be looked up in the GS1 registry at https://www.gs1.org/docs/epc/mdid_list.json

Note
Being named here says who made the chip, nothing more. Chip resolution is a separate step, and only the designers in resolveChip() have their model numbers listed

Function Documentation

◆ append_unique()

bool m5::uhf::append_unique ( std::vector< Tag > & dst,
const Tag & tag )
inline

Append a tag unless an identical EPC is already present.

Parameters
[in,out]dstDestination
tagTag to append
Returns
True if the tag was appended
Note
A tag whose EPC is empty is never appended

◆ buildLockPayload()

uint32_t m5::uhf::buildLockPayload ( const LockSetting * settings,
const size_t count )
inline

Build the 20-bit payload of the Gen2 Lock command.

Parameters
settingsSettings to apply
countNumber of settings
Returns
20-bit payload, Mask in bits 19-10 and Action in bits 9-0

Each target owns a 2-bit action, a pwd-write bit and a permalock bit, and a 2-bit mask that says which of those two to overwrite. Only the permalock bit is masked in when the action asserts it: a permalock bit can never be cleared once set (v1.2.0 6.3.2.11.3.5), so asking to write a zero there would be asking for an error

◆ chipBlockPermalockSupport()

Support m5::uhf::chipBlockPermalockSupport ( const Chip chip)
inline

What the chip's datasheet says about it having BlockPermalock.

Parameters
chipChip
Returns
Yes, No, or Unknown where nothing to hand says either

Gen2 leaves BlockPermalock optional, and a tag says whether it has it only through an XTID segment that almost no chip carries. Where the datasheet says so, this is where the answer comes from instead

◆ chipEpcMaxBits()

uint32_t m5::uhf::chipEpcMaxBits ( const Chip chip)
inline

Largest EPC a chip is known to accept, in bits.

Parameters
chipChip
Returns
Size in bits, 0 when this library does not know

Sourced the same way as chipUserMemoryBits

◆ chipFromTid()

Chip m5::uhf::chipFromTid ( const uint8_t * tid,
const size_t len )
inline

Name the chip from the two fixed words of a TID.

Parameters
tidTID bytes starting at word 0
lenTheir length in bytes
Returns
Chip, or Chip::Unknown where the bytes do not name one

The mask-designer identifier and the model number sit in the first two words, which is what makes the chip known before the rest of the TID has been read

◆ chipHasNoUserMemory()

bool m5::uhf::chipHasNoUserMemory ( const Chip chip)
inline

Is this a chip whose datasheet says it has no User bank at all?

Parameters
chipChip
Returns
True when the chip is known to have none

Nothing a tag says distinguishes "no User bank" from "a User bank nobody has written to yet", so this is the only thing that can tell a caller the bank is not worth reading

◆ chipNxpCustomCommandSupport()

Support m5::uhf::chipNxpCustomCommandSupport ( const Chip chip)
inline

What the chip's datasheet says about it having the commands NXP added of its own.

Parameters
chipChip
Returns
Yes, No, or Unknown where nothing to hand says either

ChangeConfig, ReadProtect, ChangeEAS and EAS_Alarm belong to the UCODE G2X line and the chips backward compatible with it. NXP's later parts dropped them

◆ chipPermalockBlockBits()

uint32_t m5::uhf::chipPermalockBlockBits ( const Chip chip)
inline

Size of the block BlockPermalock works in, in bits.

Parameters
chipChip
Returns
Block size, or zero where it is not known

The standard leaves this to the chip, and a tag says it only through the XTID segment that most chips do not carry. Where the datasheet gives it, this is where it comes from instead

Note
One size covers every block: Gen2 has a manufacturer "predefine a single fixed, unchangeable block size" (v2.1 6.3.2.11.3). Where the user memory does not divide by it the last block is the one that comes up short, which is what chipPermalockLastBlockBits() says

◆ chipPermalockBlockCount()

uint16_t m5::uhf::chipPermalockBlockCount ( const Chip chip)
inline

How many blocks a chip divides its user memory into for BlockPermalock.

Parameters
chipChip
Returns
Number of blocks, or zero where it is not known

Not the user memory divided by the block size: an Alien Higgs-3 has 32-bit blocks and says it has four of them, which covers 128 of its bits and not the whole bank. Only a datasheet can say how many there are

◆ chipPermalockLastBlockBits()

uint32_t m5::uhf::chipPermalockLastBlockBits ( const Chip chip)
inline

How many bits the last block of a chip actually covers.

Parameters
chipChip
Returns
Bits in the last block, or zero where the layout is not known

Every block is the same size, but the user memory does not have to be a multiple of it. Where it is not, the last block is the one that runs out early: an Impinj Monza 4i has 480 bits of user memory in blocks of 128, so its fourth block holds 96 of them. Locking it locks what is there; the bits past the end are not any tag's to lock

◆ chipQTSupport()

Support m5::uhf::chipQTSupport ( const Chip chip)
inline

What the chip's datasheet says about it having the Impinj QT command.

Parameters
chipChip
Returns
Yes, No, or Unknown where nothing to hand says either

◆ chipSharedUserMemoryBits()

uint32_t m5::uhf::chipSharedUserMemoryBits ( const Chip chip,
const uint16_t pc )
inline

User memory of a chip that carves it out of one pool with the EPC, in bits.

Parameters
chipChip
pcProtocol Control of the tag, which is where the length of the EPC is
Returns
Size in bits, 0 when the chip holds the two apart or the PC is not known

A few chips give the EPC and the User bank one pool to share, so neither size can be stated without the other. Measured on a Higgs 9: every word the EPC grows by is a word the User bank loses, and the two always add up to 49. Its datasheet offers 496 bit of EPC and 688 bit of User, which overrun the 1024 bit the same sheet gives the chip; both are true, and neither is true at the same time as the other

◆ chipTidWords()

uint16_t m5::uhf::chipTidWords ( const Chip chip)
inline

Words of TID a chip carries without an XTID header to say so.

Parameters
chipChip
Returns
Total words of TID, or zero where the header is the only thing that says

A chip whose XTID header reads zero still has whatever its datasheet lays out, and some keep a permalocked serial there. Stopping at the two fixed words would leave that behind, and a TID that stops short of the serial is the same on every tag of the model

◆ chipUserMemoryBits()

uint32_t m5::uhf::chipUserMemoryBits ( const Chip chip)
inline

User memory a chip is known to hold, in bits.

Parameters
chipChip
Returns
Size in bits, 0 when this library does not know

Where a tag says nothing about itself this is what is left

Note
Zero means unknown, not empty. chipHasNoUserMemory is what says a chip has none

◆ decodeNxpConfigWord()

NxpConfigWord m5::uhf::decodeNxpConfigWord ( const uint16_t word)
inline

Spell out the Config-Word of an NXP UCODE G2iM or G2iM+.

Parameters
wordWord as the chip reported it
Returns
The bits it holds
Warning
Only the UCODE G2iM and G2iM+ lay the word out this way

◆ decodeTid()

bool m5::uhf::decodeTid ( Tag & tag,
const uint8_t * tid,
const size_t len )
inline

Decode the fixed part of a TID into a tag.

Parameters
[in,out]tagTag to fill
tidTID bytes starting at word 0
lenLength of tid in bytes, at least 4
Returns
True if the TID carries the EPCglobal class identifier

Gen2 v2.1 6.3.2.1.3 fixes the layout of the first 32 bits: an 8-bit class identifier, the XTID, security and file indicators, a 9-bit mask-designer identifier and a 12-bit model number. Bytes 4 and 5, when present and the tag has an XTID, hold the XTID header

◆ fillSizesFromChip()

void m5::uhf::fillSizesFromChip ( Tag & tag)
inline

Fill in what the tag left unsaid from what its chip is known to hold.

Parameters
[in,out]tagTag whose TID has been decoded

The XTID is where a tag states its own memory sizes, and hardly any tag does: in practice an XTID carries a serial number and nothing else. What the chip is known to hold is the only thing left, and the mask designer and model number are what name the chip

◆ gen2_crc16()

uint16_t m5::uhf::gen2_crc16 ( const uint8_t * data,
const size_t len )
inline

Calculate the EPC Gen2 CRC-16.

Parameters
dataData to calculate over
lenLength in bytes
Returns
CRC-16

◆ pcEPCLengthWords()

uint8_t m5::uhf::pcEPCLengthWords ( const uint16_t pc)
inline

EPC length in 16-bit words encoded in the PC.

Parameters
pcProtocol Control
Returns
Number of 16-bit words comprising the EPC
Warning
The PC a tag backscatters is not the one in its memory. A tag that sends an XPC ahead of its EPC raises the length here by the word or two that takes, while leaving EPC memory 10h to 14h alone (EPC Gen2 v2.1 6.3.2.1.2.2). Counted from a backscattered PC this is therefore the length of what came over the air, not the length of the EPC

◆ pcNumberingSystemIdentifier()

uint16_t m5::uhf::pcNumberingSystemIdentifier ( const uint16_t pc)
inline

Numbering System Identifier of the PC.

Parameters
pcProtocol Control
Returns
NSI (0x000 for EPCglobal)
Warning
These bits cannot be relied on to be the identifier. What is spoken of as the PC word is the top eight bits of the Protocol Control joined to the bottom eight of the Extended Protocol Control, and a tag substitutes the latter for its own flags whether or not it goes on to send an XPC word (GS1 TDS 2.3 9.4). Only pcToggle() sits outside what is substituted

◆ pcToggle()

bool m5::uhf::pcToggle ( const uint16_t pc)
inline

Toggle bit of the PC.

Parameters
pcProtocol Control
Returns
True when the EPC bank holds an ISO 15961 UII rather than an EPC

Of the bits below the length this is the one that can always be believed: it is never one of the bits a tag substitutes from its XPC (GS1 TDS 2.3 9.4). A tag asserting it is telling the reader that what follows the PC is not an EPC, and nothing here decodes it as one

◆ pcUserMemoryIndicator()

bool m5::uhf::pcUserMemoryIndicator ( const uint16_t pc)
inline

User Memory Indicator of the PC.

Parameters
pcProtocol Control
Returns
True if the bit is asserted
Warning
This does not say whether the tag has a User bank. EPC Gen2 v2.1 6.3.2.1.2.1 lets a chip either fix the bit at what it was built with or compute it, and a chip that computes it ORs together bits 03h to 07h of File_0 and nothing else, so it reports zero for a bank it has but whose first five bits have never been written. A UCODE G2iM was measured reporting zero with 512 usable bits

◆ pcXPCIndicator()

bool m5::uhf::pcXPCIndicator ( const uint16_t pc)
inline

XPC indicator of the PC.

Parameters
pcProtocol Control
Returns
True if an XPC word follows

◆ resolveChip()

Chip m5::uhf::resolveChip ( const Vendor vendor,
const uint16_t model_number )
inline

Resolve a chip from its mask designer and model number.

Parameters
vendorNamed mask designer
model_numberTag model number
Returns
Chip, or Chip::Unknown when the pair is not one we have confirmed
Note
A tag whose chip comes back Unknown still reports its raw mask-designer identifier and model number

◆ resolveVendor()

Vendor m5::uhf::resolveVendor ( const uint16_t mdid)
inline

Resolve a named mask designer from its identifier.

Parameters
mdidMask-designer identifier (9 bits)
Returns
Vendor, or Vendor::Unknown when the identifier is not one we list

◆ tagBlockPermalockSupport()

Support m5::uhf::tagBlockPermalockSupport ( const Tag & tag)
inline

What can be said about this tag having BlockPermalock.

Parameters
tagTag, identified as far as it has been
Returns
Yes, No, or Unknown

The tag itself is asked first. Where its XTID carries the segment that says so, that settles it whatever the chip turns out to be. Otherwise it comes down to what the chip's datasheet says

◆ tagNxpCustomCommandSupport()

Support m5::uhf::tagNxpCustomCommandSupport ( const Tag & tag)
inline

What can be said about this tag having the commands NXP added of its own.

Parameters
tagTag, identified as far as it has been
Returns
Yes, No, or Unknown

Two things can say no. The commands are NXP's own, so a tag whose mask designer is somebody else does not have them whatever the chip is; and NXP's own later parts dropped them, which is what the chip table names. A tag whose TID has not been read says neither

◆ tagQTSupport()

Support m5::uhf::tagQTSupport ( const Tag & tag)
inline

What can be said about this tag having the Impinj QT command.

Parameters
tagTag, identified as far as it has been
Returns
Yes, No, or Unknown

The command is Impinj's own, so a tag whose mask designer is somebody else does not have it whatever the chip is. That answer holds even where the chip could not be named

◆ tagUnchanged()

bool m5::uhf::tagUnchanged ( const Reason reason)
inline

Is the tag known to be as it was before the operation?

Parameters
reasonWhy the operation did not go through
Returns
True when nothing can have changed

False does not mean the tag changed, only that this cannot say. A write that goes unanswered may have erased a word without programming it, and reading it back is the only way to find out

Note
This reads the order Reason is written in: NoAnswer is where the values that leave the tag's state unknown begin. A value added before it is one this says nothing changed for, so where a new one belongs is which side of NoAnswer it goes

◆ tidHasXtid()

bool m5::uhf::tidHasXtid ( const uint8_t * tid,
const size_t len )
inline

Does a TID say it carries an extended TID, and with it a serial number?

Parameters
tidTID bytes starting at word 0
lenLength of tid in bytes, at least 2
Returns
True when the XTID indicator is set

Bit 08h of the TID. What lies past word 1 is only defined when this is set: the Tag Data Standard calls a TID without it a short TID, "in which the values beyond address 1Fh are not defined" (TDS 1.5 16.1), and EPC Gen2 v3 asks for a serial number only of tags that set it

◆ tidReadPlan()

TidReadPlan m5::uhf::tidReadPlan ( const uint8_t * tid,
const size_t len )
inline

Say what to read next of a TID.

Parameters
tidBytes read so far, starting at TID word 0
lenTheir length in bytes
Returns
The next read, asking for no words once the TID is complete

A TID cannot be read in one go because each part says how much more there is: the two fixed words say whether an XTID follows, and the XTID header says how long the rest is (TDS 16.1 and 16.2). Calling this after every read walks the whole TID in

Note
A header describing more than TID_MAX_BYTES gives fits == false. Nothing is read for it, since what came back could not be kept

◆ tidTellsTagsApart()

bool m5::uhf::tidTellsTagsApart ( const uint8_t * tid,
const size_t len )
inline

Can a mask built from this TID tell one tag of the chip from another?

Parameters
tidTID bytes, starting at word 0
lenTheir length in bytes
Returns
True when the TID reaches past what names the chip and carries something there

What makes a TID unique is the serial, and the serial begins at word 3 in both of the layouts in use: after the XTID header when a tag has one (TDS 16.2), and at TID 30h on chips that keep a serial without advertising it in the header. Asking what the mask can actually tell apart therefore answers for both, where the XTID indicator answers only for the first

Note
A chip with no serial there is not addressed by such a mask at all, so getting this wrong ends in a tag that does not answer rather than in the wrong tag being addressed
The rule this replaced came from the XTID indicator, on the strength of TDS 1.5 16 calling everything past address 1Fh undefined without one. That sentence is not in TDS 1.13 or anything after it, and chips carry a serial there regardless

◆ vendorEntries()

const VendorEntry * m5::uhf::detail::vendorEntries ( size_t & count)
inline

The mask designers this library names.

Parameters
[out]countNumber of entries
Returns
Pointer to the first entry

resolveVendor and Tag::vendorAsString both read this table, so a designer added here becomes both recognised and printable in a single edit

◆ verify_tag_crc()

bool m5::uhf::verify_tag_crc ( const Tag & tag)
inline

Verify the CRC-16 reported with a detected tag.

Parameters
tagTag to verify
Returns
True if the CRC-16 recalculated from PC and EPC matches the reported one
Note
The Gen2 CRC-16 covers the PC followed by the EPC

◆ xtidSerialBits()

uint16_t m5::uhf::xtidSerialBits ( const uint16_t xtid_header)
inline

Serial length an XTID header announces.

Parameters
xtid_headerXTID header word, TID bits 20h to 2Fh
Returns
Length of the serial in bits, 0 when the tag carries none

TDS 16.2.2 puts the serialisation bits in 15 to 13: zero means no serial, and any other value means 48 + (value - 1) * 16 bits, so up to 144

◆ xtidTotalWords()

size_t m5::uhf::xtidTotalWords ( const uint16_t xtid_header)
inline

Length of the whole TID an XTID header describes, in 16-bit words.

Parameters
xtid_headerXTID header word
Returns
Words from TID word 0 through the end of the last segment the header announces

Reading the TID takes two passes because of this: the header has to be in hand before the length of what follows it is known (TDS 16.2)

Variable Documentation

◆ TID_CHIP_WORDS

size_t m5::uhf::TID_CHIP_WORDS {3}
constexpr

Words at the front of a TID that name the chip rather than the individual tag.

The allocation class identifier, the mask designer and the model number, then the XTID header. Every tag of one model carries the same bytes there

◆ TID_MAX_BYTES

size_t m5::uhf::TID_MAX_BYTES {40}
constexpr

How much of the TID identify() keeps.

The longest XTID the standard can describe: the two fixed words, the header, a 144-bit serial and all four optional segments (TDS Table 16-2). Twenty words in all, so a fully populated XTID always fits