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

Frame codec for the magicRF M100 family (JRD-4035 / JRD-100 / R200) More...

#include <cstddef>
#include <cstdint>
#include <vector>
#include "uhf/uhf.hpp"

Go to the source code of this file.

Classes

struct  m5::unit::m100::Frame
 Parsed frame. More...
 
struct  m5::unit::m100::TagOperationResult
 What a tag answered to Read, Write, Lock or Kill. More...
 
struct  m5::unit::m100::DemodulatorParameters
 Receiver settings that decide how weak a reply the reader can still make sense of. More...
 

Namespaces

namespace  m5
 Top level namespace of M5Stack.
 
namespace  m100
 magicRF M100 chip specific definitions
 
namespace  jrd
 Framing the JRD-4035 and JRD-100 modules use.
 

Enumerations

enum class  m5::unit::m100::FrameExtract : uint8_t { Ok , NeedMore }
 What came of trying to take a frame out of the bytes received so far. More...
 
enum class  m5::unit::m100::MixerGain : uint8_t {
  dB0 , dB3 , dB6 , dB9 ,
  dB12 , dB15 , dB16
}
 Gain of the receiver's mixer. More...
 
enum class  m5::unit::m100::IFGain : uint8_t {
  dB12 , dB18 , dB21 , dB24 ,
  dB27 , dB30 , dB36 , dB40
}
 Gain of the receiver's intermediate frequency amplifier. More...
 
enum class  m5::unit::m100::Error : uint8_t {
  WatchDogReset = 0x05 , ReadFail = 0x09 , InvalidParameter = 0x0E , WriteFail = 0x10 ,
  KillFail = 0x12 , LockFail = 0x13 , BlockPermalockFail = 0x14 , InventoryFail = 0x15 ,
  AccessFail = 0x16 , CommandError = 0x17 , ChangeConfigFail = 0x1A , ChangeEASFail = 0x1B ,
  EASAlarmFail = 0x1D , FHSSFail = 0x20 , ReadProtectFail = 0x2A , ResetReadProtectFail = 0x2B ,
  QTFail = 0x2E
}
 Error codes carried by a failure notification. More...
 
enum class  m5::unit::m100::FrameRoute : uint8_t { TagNotification , Response , Drop , Unexpected }
 What is to be done with a frame that has just been read. More...
 

Functions

uint8_t m5::unit::m100::checksum (const uint8_t *body, const size_t len)
 Calculate the frame checksum.
 
bool m5::unit::m100::build_frame (std::vector< uint8_t > &out, const uint8_t type, const uint8_t command, const uint8_t *param, const uint16_t param_len, const uint8_t header=jrd::FRAME_HEADER, const uint8_t end=jrd::FRAME_END)
 Build a command frame.
 
bool m5::unit::m100::parse_frame (Frame &out, const uint8_t *raw, const size_t len, const uint8_t header=jrd::FRAME_HEADER, const uint8_t end=jrd::FRAME_END)
 Parse a frame.
 
FrameExtract m5::unit::m100::extract_frame (Frame &out, std::vector< uint8_t > &buffer, size_t &discarded, const uint8_t header, const uint8_t end)
 Take the first whole frame out of received bytes.
 
bool m5::unit::m100::parse_tag_notification (m5::uhf::Tag &out, const uint8_t *param, const size_t len)
 Parse the parameter of a tag notification.
 
uint8_t m5::unit::m100::select_parameter_byte (const uint8_t target, const uint8_t action, const uint8_t membank)
 Build the SelParam byte of Set Select Parameter.
 
bool m5::unit::m100::build_select_parameter (std::vector< uint8_t > &out, const uint8_t sel_param, const uint32_t pointer_bits, const uint8_t mask_length_bits, const uint8_t truncate, const uint8_t *mask, const size_t mask_len)
 Build the parameter of Set Select Parameter (0x0C)
 
bool m5::unit::m100::parse_select_parameter (m5::uhf::SelectParameter &out, const uint8_t *param, const size_t len)
 Parse the answer to Get Select Parameter (0x0B)
 
bool m5::unit::m100::build_read_tag_memory (std::vector< uint8_t > &out, const uint32_t access_password, const uint8_t membank, const uint16_t word_address, const uint16_t word_count)
 Build the parameter of Read Tag Memory Area (0x39)
 
bool m5::unit::m100::build_write_tag_memory (std::vector< uint8_t > &out, const uint32_t access_password, const uint8_t membank, const uint16_t word_address, const uint8_t *data, const size_t len)
 Build the parameter of Write Tag Memory Area (0x49)
 
bool m5::unit::m100::build_lock_tag (std::vector< uint8_t > &out, const uint32_t access_password, const uint32_t payload)
 Build the parameter of Lock (0x82)
 
bool m5::unit::m100::build_kill_tag (std::vector< uint8_t > &out, const uint32_t kill_password)
 Build the parameter of Kill (0x65)
 
bool m5::unit::m100::parse_tag_operation (TagOperationResult &out, const uint8_t *param, const size_t len)
 Parse the answer to a tag operation.
 
void m5::unit::m100::build_nxp_change_config (std::vector< uint8_t > &out, const uint32_t access_password, const uint16_t toggle)
 Build the parameter of NXP ChangeConfig (0xE0)
 
void m5::unit::m100::build_nxp_password_and_flag (std::vector< uint8_t > &out, const uint32_t access_password, const uint8_t flag)
 Build the parameter of NXP Change EAS (0xE3) or ReadProtect (0xE1)
 
bool m5::unit::m100::parse_nxp_change_config (uint16_t &config, const uint8_t *param, const size_t len)
 Parse the answer to NXP ChangeConfig (0xE0)
 
bool m5::unit::m100::parse_nxp_eas_alarm (std::vector< uint8_t > &alarm, const uint8_t *param, const size_t len)
 Parse the answer to NXP EAS_Alarm (0xE4)
 
bool m5::unit::m100::parse_block_permalock_lock (const uint8_t *param, const size_t len)
 Parse the answer to a BlockPermalock that locked.
 
bool m5::unit::m100::parse_block_permalock_read (std::vector< uint8_t > &mask, const uint8_t *param, const size_t len)
 Parse the answer to a BlockPermalock that read.
 
void m5::unit::m100::parse_query_parameters (m5::uhf::QueryParameters &qp, const uint16_t raw)
 Split a Query parameter word into its fields.
 
uint16_t m5::unit::m100::build_query_parameters (const m5::uhf::QueryParameters &qp, const uint16_t current)
 Place the fields we expose into a Query parameter word.
 
uint8_t m5::unit::m100::mixerGainDb (const MixerGain gain)
 Mixer gain in dB.
 
uint8_t m5::unit::m100::ifGainDb (const IFGain gain)
 Intermediate frequency amplifier gain in dB.
 
bool m5::unit::m100::parse_demodulator_parameters (DemodulatorParameters &dp, const uint8_t *param, const size_t len)
 Split a demodulator parameter payload into its fields.
 
bool m5::unit::m100::build_demodulator_parameters (std::vector< uint8_t > &out, const DemodulatorParameters &dp)
 Build the parameter of Set Demodulator Parameter (0xF0)
 
bool m5::unit::m100::is_error_frame (const uint8_t command)
 Is the command code of a failure notification?
 
bool m5::unit::m100::is_no_tag (const uint8_t error_code)
 Does the error code only mean "no tag was found this round"?
 
bool m5::unit::m100::is_tag_error (const uint8_t error_code)
 Did the tag itself report this error, rather than the module?
 
const char * m5::unit::m100::error_description (const uint8_t error_code)
 Describe an error code in one word.
 
bool m5::unit::m100::error_answers_command (const uint8_t error_code, const uint8_t command)
 Could this error code be the answer to this command?
 
FrameRoute m5::unit::m100::route_for (const Frame &f, const bool response_pending, const uint8_t awaiting_command)
 Decide what a received frame answers.
 
bool m5::unit::m100::is_worth_retrying (const uint8_t error_code)
 Is this failure worth sending the same command again for?
 

Variables

constexpr uint8_t m5::unit::m100::jrd::FRAME_HEADER {0xBB}
 Frame header.
 
constexpr uint8_t m5::unit::m100::jrd::FRAME_END {0x7E}
 Frame end.
 
constexpr uint16_t m5::unit::m100::MAX_PARAMETER_LENGTH {512}
 Maximum parameter length accepted for a frame.
 
constexpr size_t m5::unit::m100::FRAME_OVERHEAD {7}
 Fixed part of a frame (Header, Type, Command, PL_MSB, PL_LSB, Checksum, End)
 
constexpr size_t m5::unit::m100::FRAME_TYPE_OFFSET {1}
 Offset of the Type byte.
 
constexpr size_t m5::unit::m100::FRAME_PARAMETER_OFFSET {5}
 Offset of the Parameter.
 
constexpr uint8_t m5::unit::m100::TYPE_COMMAND {0x00}
 Frame type: command (host to module)
 
constexpr uint8_t m5::unit::m100::TYPE_RESPONSE {0x01}
 Frame type: response (module to host)
 
constexpr uint8_t m5::unit::m100::TYPE_NOTIFICATION {0x02}
 Frame type: notification (module to host)
 
constexpr uint8_t m5::unit::m100::COMMAND_SINGLE_POLLING {0x22}
 Command code of the single polling notification.
 
constexpr uint8_t m5::unit::m100::COMMAND_MULTIPLE_POLLING {0x27}
 Command code of the multiple polling notification.
 
constexpr size_t m5::unit::m100::TAG_NOTIFICATION_OVERHEAD {5}
 Fixed part of a tag notification (RSSI, PC and CRC)
 
constexpr uint8_t m5::unit::m100::MEMBANK_RESERVED {0x00}
 MemBank values of the Select parameter and of the read/write commands.
 
constexpr uint8_t m5::unit::m100::MEMBANK_EPC {0x01}
 
constexpr uint8_t m5::unit::m100::MEMBANK_TID {0x02}
 
constexpr uint8_t m5::unit::m100::MEMBANK_USER {0x03}
 
constexpr uint8_t m5::unit::m100::SELECT_TRUNCATE_OFF {0x00}
 Truncate field of the Select parameter.
 
constexpr uint8_t m5::unit::m100::SELECT_TRUNCATE_ON {0x80}
 
constexpr uint8_t m5::unit::m100::SELECT_MODE_ALWAYS {0x00}
 Select modes of Set Select Mode (0x12)
 
constexpr uint8_t m5::unit::m100::SELECT_MODE_NEVER {0x01}
 Never send Select.
 
constexpr uint8_t m5::unit::m100::SELECT_MODE_NON_INVENTORY {0x02}
 Select before everything except inventory.
 
constexpr size_t m5::unit::m100::WRITE_MAX_WORDS {32}
 Longest write the module accepts, in 16-bit words.
 
constexpr size_t m5::unit::m100::SELECT_MASK_MAX_BITS {255}
 Longest mask the Select parameter accepts, in bits.
 
constexpr uint8_t m5::unit::m100::TAG_OPERATION_SUCCESS {0x00}
 Status byte a tag returns after a Write, Lock or Kill it carried out.
 
constexpr uint16_t m5::unit::m100::DEMODULATOR_THRESHOLD_DEFAULT {0x01B0}
 Demodulation threshold the module leaves the factory with.
 
constexpr uint8_t m5::unit::m100::MIXER_GAIN_MAX {0x06}
 Highest mixer gain the module accepts.
 
constexpr uint8_t m5::unit::m100::IF_GAIN_MAX {0x07}
 Highest intermediate frequency gain the module accepts.
 
constexpr size_t m5::unit::m100::DEMODULATOR_PARAMETER_LENGTH {4}
 Length of the demodulator parameter payload.
 
constexpr uint8_t m5::unit::m100::COMMAND_ERROR {0xFF}
 Command code used by every failure notification.
 
Command codes of the operations an error code can name
constexpr uint8_t m5::unit::m100::COMMAND_READ_TAG_MEMORY {0x39}
 Command code a BlockPermalock lock is answered under, unlike the read.
 
constexpr uint8_t m5::unit::m100::COMMAND_WRITE_TAG_MEMORY {0x49}
 Command code a BlockPermalock lock is answered under, unlike the read.
 
constexpr uint8_t m5::unit::m100::COMMAND_KILL_TAG {0x65}
 Command code a BlockPermalock lock is answered under, unlike the read.
 
constexpr uint8_t m5::unit::m100::COMMAND_LOCK_TAG_MEMORY {0x82}
 Command code a BlockPermalock lock is answered under, unlike the read.
 
constexpr uint8_t m5::unit::m100::COMMAND_BLOCK_PERMALOCK {0xD3}
 Command code a BlockPermalock lock is answered under, unlike the read.
 
constexpr uint8_t m5::unit::m100::COMMAND_BLOCK_PERMALOCK_LOCK_ANSWER {0xD4}
 Command code a BlockPermalock lock is answered under, unlike the read.
 
constexpr uint8_t m5::unit::m100::COMMAND_NXP_CHANGE_CONFIG {0xE0}
 NXP ChangeConfig.
 
constexpr uint8_t m5::unit::m100::COMMAND_NXP_READ_PROTECT {0xE1}
 NXP ReadProtect and Reset ReadProtect, which share one command code.
 
constexpr uint8_t m5::unit::m100::COMMAND_NXP_CHANGE_EAS {0xE3}
 NXP Change EAS.
 
constexpr uint8_t m5::unit::m100::COMMAND_NXP_EAS_ALARM {0xE4}
 NXP EAS_Alarm.
 
constexpr uint8_t m5::unit::m100::COMMAND_MONZA_QT {0xE5}
 Impinj Monza QT.
 
constexpr uint8_t m5::unit::m100::COMMAND_MONZA_QT_WRITE_ANSWER {0xE6}
 Command code a Monza QT write is answered under, which is not the one it was sent as.
 
Bit positions of the Query parameter fields

The fields pack into the 16-bit word from the top down as DR(1) M(2) TRext(1) Sel(2) Session(2) Target(1) Q(4), leaving the bottom three bits unused. The vendor documents the layout by worked example: 0x1020 is spelled out as DR=8, M=1, TRext=use pilot tone, Sel=00, Session=00, Target=A, Q=4, which only holds with the padding at the bottom

constexpr uint8_t m5::unit::m100::QUERY_Q_SHIFT {3}
 
constexpr uint8_t m5::unit::m100::QUERY_TARGET_SHIFT {7}
 
constexpr uint8_t m5::unit::m100::QUERY_SESSION_SHIFT {8}
 
constexpr uint8_t m5::unit::m100::QUERY_SEL_SHIFT {10}
 
Masks the module ORs onto an error the tag itself reported

Only the low four bits of an EPC Gen2 error code carry meaning, so the module fills the high nibble with a marker for the operation that provoked it. The marker therefore says which command failed, and the low nibble says why

constexpr uint8_t m5::unit::m100::TAG_ERROR_READ {0xA0}
 
constexpr uint8_t m5::unit::m100::TAG_ERROR_WRITE {0xB0}
 
constexpr uint8_t m5::unit::m100::TAG_ERROR_LOCK {0xC0}
 
constexpr uint8_t m5::unit::m100::TAG_ERROR_KILL {0xD0}
 
constexpr uint8_t m5::unit::m100::TAG_ERROR_BLOCK_PERMALOCK {0xE0}
 

Detailed Description

Frame codec for the magicRF M100 family (JRD-4035 / JRD-100 / R200)

Note
Intentionally free of M5UnitComponent so that it can be built and tested without the ESP32 toolchain

Enumeration Type Documentation

◆ Error

enum class m5::unit::m100::Error : uint8_t
strong

Error codes carried by a failure notification.

Enumerator
WatchDogReset 

The module's watchdog timed out and reset it.

ReadFail 

Failed to read the tag's data memory area.

InvalidParameter 

A parameter in the command frame is wrong.

WriteFail 

Failed to write the tag's data memory area.

KillFail 

Failed to kill the tag.

LockFail 

Failed to lock the tag's data memory area.

BlockPermalockFail 

BlockPermalock execution failed.

InventoryFail 

No tag responded or a data CRC check error occurred.

AccessFail 

Failed to access the tag.

CommandError 

Command error in the command frame.

ChangeConfigFail 

NXP ChangeConfig failed.

ChangeEASFail 

NXP Change EAS failed.

EASAlarmFail 

NXP EAS_Alarm found no tag answering with an alarm code.

FHSSFail 

Frequency hopping channel search timed out.

ReadProtectFail 

NXP ReadProtect failed.

ResetReadProtectFail 

NXP Reset ReadProtect failed.

QTFail 

Impinj Monza QT failed.

◆ FrameExtract

enum class m5::unit::m100::FrameExtract : uint8_t
strong

What came of trying to take a frame out of the bytes received so far.

Enumerator
Ok 

A frame was taken out, and the bytes it was made of are gone from the buffer.

NeedMore 

What is in the buffer could still turn into a frame once more bytes arrive.

◆ FrameRoute

enum class m5::unit::m100::FrameRoute : uint8_t
strong

What is to be done with a frame that has just been read.

Enumerator
TagNotification 

A tag the module found. Parse it and queue it.

Response 

The answer to the command being waited on.

Drop 

Left over from an exchange that has already given up.

Unexpected 

Nobody asked for this one.

◆ IFGain

enum class m5::unit::m100::IFGain : uint8_t
strong

Gain of the receiver's intermediate frequency amplifier.

Lowering it shortens the distance the reader works over, as with MixerGain

Enumerator
dB12 

12dB

dB18 

18dB

dB21 

21dB

dB24 

24dB

dB27 

27dB

dB30 

30dB

dB36 

36dB, the value the module leaves the factory with

dB40 

40dB

◆ MixerGain

enum class m5::unit::m100::MixerGain : uint8_t
strong

Gain of the receiver's mixer.

These are the gain steps the M100 receiver offers, not anything the EPC Gen2 standard defines, so they live with the chip rather than in the portable vocabulary. Lowering the gain shortens the distance the reader works over, which is what makes a tag sitting on the antenna readable

Enumerator
dB0 

0dB

dB3 

3dB

dB6 

6dB

dB9 

9dB, the value the module leaves the factory with

dB12 

12dB

dB15 

15dB

dB16 

16dB

Function Documentation

◆ build_demodulator_parameters()

bool m5::unit::m100::build_demodulator_parameters ( std::vector< uint8_t > & out,
const DemodulatorParameters & dp )
inline

Build the parameter of Set Demodulator Parameter (0xF0)

Parameters
[out]outParameter
dpDemodulator parameters
Returns
True if successful

◆ build_frame()

bool m5::unit::m100::build_frame ( std::vector< uint8_t > & out,
const uint8_t type,
const uint8_t command,
const uint8_t * param,
const uint16_t param_len,
const uint8_t header = jrd::FRAME_HEADER,
const uint8_t end = jrd::FRAME_END )
inline

Build a command frame.

Parameters
[out]outBuilt frame
typeFrame type (0x00: command)
commandCommand code
paramParameter (nullptr if none)
param_lenParameter length
headerFrame header (0xBB for JRD-4035, 0xAA for R200)
endFrame end (0x7E for JRD-4035, 0xDD for R200)
Returns
True if successful

◆ build_kill_tag()

bool m5::unit::m100::build_kill_tag ( std::vector< uint8_t > & out,
const uint32_t kill_password )
inline

Build the parameter of Kill (0x65)

Parameters
[out]outParameter
kill_passwordKill password
Returns
True if successful
Note
A tag whose kill password is zero refuses to be killed, so zero is refused here

◆ build_lock_tag()

bool m5::unit::m100::build_lock_tag ( std::vector< uint8_t > & out,
const uint32_t access_password,
const uint32_t payload )
inline

Build the parameter of Lock (0x82)

Parameters
[out]outParameter
access_passwordAccess password
payload20-bit lock payload, see m5::uhf::buildLockPayload
Returns
True if successful

◆ build_nxp_change_config()

void m5::unit::m100::build_nxp_change_config ( std::vector< uint8_t > & out,
const uint32_t access_password,
const uint16_t toggle )
inline

Build the parameter of NXP ChangeConfig (0xE0)

Parameters
[out]outParameter
access_passwordAccess password of the tag
toggleBits to invert in the Config-Word. Zero reads it without changing anything

The word is not assigned but toggled: a one inverts the bit it stands over and a zero leaves it alone (M100 protocol 2.35), which is why nothing here is called a write

Note
Every argument is a fixed-width integer laid out byte by byte, so there is nothing here that can be out of range and nothing to report

◆ build_nxp_password_and_flag()

void m5::unit::m100::build_nxp_password_and_flag ( std::vector< uint8_t > & out,
const uint32_t access_password,
const uint8_t flag )
inline

Build the parameter of NXP Change EAS (0xE3) or ReadProtect (0xE1)

Parameters
[out]outParameter
access_passwordAccess password of the tag
flagValue of the single byte the command carries

Both commands are an access password and one byte saying which way to go, so they are built the same way and only the command code tells them apart

Note
Every argument is a fixed-width integer laid out byte by byte, so there is nothing here that can be out of range and nothing to report

◆ build_query_parameters()

uint16_t m5::unit::m100::build_query_parameters ( const m5::uhf::QueryParameters & qp,
const uint16_t current )
inline

Place the fields we expose into a Query parameter word.

Parameters
qpQuery parameters
currentWord the module currently holds
Returns
Word to write back

DR, M and TRext are carried over from the current word rather than being rebuilt. The module supports exactly one value of each, so there is nothing to choose and nothing to gain from letting a caller set them wrong

◆ build_read_tag_memory()

bool m5::unit::m100::build_read_tag_memory ( std::vector< uint8_t > & out,
const uint32_t access_password,
const uint8_t membank,
const uint16_t word_address,
const uint16_t word_count )
inline

Build the parameter of Read Tag Memory Area (0x39)

Parameters
[out]outParameter
access_passwordAccess password, 0 when the tag has none
membankMemory bank
word_addressStart address in 16-bit words
word_countNumber of 16-bit words
Returns
True if successful
Note
A word_count of zero would mean "to the end of the bank" in EPC Gen2, but the module does not document that, so it is refused here

◆ build_select_parameter()

bool m5::unit::m100::build_select_parameter ( std::vector< uint8_t > & out,
const uint8_t sel_param,
const uint32_t pointer_bits,
const uint8_t mask_length_bits,
const uint8_t truncate,
const uint8_t * mask,
const size_t mask_len )
inline

Build the parameter of Set Select Parameter (0x0C)

Parameters
[out]outParameter
sel_paramSelParam byte
pointer_bitsStart of the mask as a bit address inside the bank
mask_length_bitsMask length in bits
truncateSELECT_TRUNCATE_OFF or SELECT_TRUNCATE_ON
maskMask bytes
mask_lenLength of mask in bytes
Returns
True if successful
Note
Reserved memory cannot be selected on: a tag ignores a Select that names it

◆ build_write_tag_memory()

bool m5::unit::m100::build_write_tag_memory ( std::vector< uint8_t > & out,
const uint32_t access_password,
const uint8_t membank,
const uint16_t word_address,
const uint8_t * data,
const size_t len )
inline

Build the parameter of Write Tag Memory Area (0x49)

Parameters
[out]outParameter
access_passwordAccess password, 0 when the tag has none
membankMemory bank
word_addressStart address in 16-bit words
dataBytes to write
lenLength of data, which must be even and at most 64
Returns
True if successful

◆ checksum()

uint8_t m5::unit::m100::checksum ( const uint8_t * body,
const size_t len )
inline

Calculate the frame checksum.

Parameters
bodyPointer to the Type byte (the checksum covers Type through the last Parameter byte)
lenLength in bytes
Returns
Least significant byte of the sum

◆ error_answers_command()

bool m5::unit::m100::error_answers_command ( const uint8_t error_code,
const uint8_t command )
inline

Could this error code be the answer to this command?

Parameters
error_codeError code carried by the failure notification
commandCommand code the module was asked to carry out
Returns
True when the code can have come from that command

An error the tag reported carries the operation in its high nibble, and the module's own failures are named after the command they belong to, so most codes say what they answer. A code that any command can provoke, and any code not listed here, is accepted for all of them: turning away an error that did belong to the command would leave the caller waiting out its timeout for a reply that has already arrived

◆ error_description()

const char * m5::unit::m100::error_description ( const uint8_t error_code)
inline

Describe an error code in one word.

Parameters
error_codeError code carried by the failure notification
Returns
Description, never null

A tag error is named by its Gen2 meaning (v1.2.0 Annex I), everything else by what the module's own documentation says the code stands for. Read, Write, Kill, Lock, BlockPermalock and Inventory all share one wording there, and it names two causes: the tag said nothing, or what it said did not pass the CRC check. Which of the two it was is not reported, so neither is claimed here

◆ extract_frame()

FrameExtract m5::unit::m100::extract_frame ( Frame & out,
std::vector< uint8_t > & buffer,
size_t & discarded,
const uint8_t header,
const uint8_t end )
inline

Take the first whole frame out of received bytes.

Parameters
[out]outFrame, filled in only when Ok is returned
[in,out]bufferBytes received so far. What was used, and what was thrown away, is removed; everything else is left for the next call
[out]discardedBytes thrown away before a frame could be found
headerFrame header byte
endFrame end byte
Returns
Ok when a frame came out, NeedMore when the buffer has to grow first

The header byte also occurs inside the data a tag notification carries, so a byte that looks like the start of a frame may be the middle of one. Rather than trusting it, the length, the checksum and the end byte are all made to agree; when they do not, one byte is thrown away and the search goes on from the next. Bytes are never read again to do this, so a frame that arrived in pieces costs nothing to wait for

◆ is_error_frame()

bool m5::unit::m100::is_error_frame ( const uint8_t command)
inline

Is the command code of a failure notification?

Parameters
commandCommand code of the received frame
Returns
True if the frame reports a failure

◆ is_no_tag()

bool m5::unit::m100::is_no_tag ( const uint8_t error_code)
inline

Does the error code only mean "no tag was found this round"?

Parameters
error_codeError code carried by the failure notification
Returns
True if no tag responded
Note
This answers a polling command and nothing else. Read, Write, Lock and Kill each report their own failure, so anywhere but in front of a polling command this is a notification left over from polling that has not finished draining

◆ is_tag_error()

bool m5::unit::m100::is_tag_error ( const uint8_t error_code)
inline

Did the tag itself report this error, rather than the module?

Parameters
error_codeError code carried by the failure notification
Returns
True when the code is a Gen2 error the tag returned

◆ is_worth_retrying()

bool m5::unit::m100::is_worth_retrying ( const uint8_t error_code)
inline

Is this failure worth sending the same command again for?

Parameters
error_codeError code carried by the failure notification
Returns
True when a repeat has a chance of succeeding

A failure that means the tag said nothing, or said something that did not survive the air, says nothing about the tag being unwilling: this one exchange did not complete and the next one may. A tag that answered with a reason of its own will answer the same way however often it is asked, so those are excluded. A failed access is excluded for a different reason. Repeating one straight away is what starts a security timeout on the tag (EPC Gen2 v2.1 6.3.2.5), and the timeout outlasts the gap between two attempts here, so a repeat would be worth less than the harm it does

◆ parse_block_permalock_lock()

bool m5::unit::m100::parse_block_permalock_lock ( const uint8_t * param,
const size_t len )
inline

Parse the answer to a BlockPermalock that locked.

Parameters
paramParameter of the response frame
lenLength of param
Returns
True when the module says it carried the lock out

The tag that replied comes first, and a single byte after it says how it went. A frame that reached this far still has to be read: the module answers a lock under a command code of its own whether or not the tag did anything

◆ parse_block_permalock_read()

bool m5::unit::m100::parse_block_permalock_read ( std::vector< uint8_t > & mask,
const uint8_t * param,
const size_t len )
inline

Parse the answer to a BlockPermalock that read.

Parameters
[out]maskPermalock bits, one word for every sixteen blocks, the first block being the most significant bit
paramParameter of the response frame
lenLength of param
Returns
True if successful

The tag that replied comes first, then the range the answer covers and that many words of mask. The range is counted in sixteens, which is what one word of mask holds

◆ parse_demodulator_parameters()

bool m5::unit::m100::parse_demodulator_parameters ( DemodulatorParameters & dp,
const uint8_t * param,
const size_t len )
inline

Split a demodulator parameter payload into its fields.

Parameters
[out]dpDemodulator parameters
paramParameter of the response frame
lenLength of param
Returns
True if successful

◆ parse_frame()

bool m5::unit::m100::parse_frame ( Frame & out,
const uint8_t * raw,
const size_t len,
const uint8_t header = jrd::FRAME_HEADER,
const uint8_t end = jrd::FRAME_END )
inline

Parse a frame.

Parameters
[out]outParsed frame
rawRaw bytes (a whole frame including the header and the end)
lenLength of raw
headerExpected frame header
endExpected frame end
Returns
True if the frame is well-formed and the checksum matches

◆ parse_nxp_change_config()

bool m5::unit::m100::parse_nxp_change_config ( uint16_t & config,
const uint8_t * param,
const size_t len )
inline

Parse the answer to NXP ChangeConfig (0xE0)

Parameters
[out]configConfig-Word the tag holds once the command has been carried out
paramParameter of the response frame
lenLength of param
Returns
True if successful

The tag that replied comes first, and the word it ended up with after it

◆ parse_nxp_eas_alarm()

bool m5::unit::m100::parse_nxp_eas_alarm ( std::vector< uint8_t > & alarm,
const uint8_t * param,
const size_t len )
inline

Parse the answer to NXP EAS_Alarm (0xE4)

Parameters
[out]alarmAlarm code the tag backscattered
paramParameter of the response frame
lenLength of param
Returns
True when something answered

Alone among these, this answer carries no tag at all: the alarm asks the field rather than one tag, and what comes back is the code itself. An NXP UCODE G2iM answers with a fixed 64-bit one (SL3S1003_1013 Rev3.7 10.7.8), so eight bytes is what to expect, but the length is left to the tag rather than insisted on here

◆ parse_query_parameters()

void m5::unit::m100::parse_query_parameters ( m5::uhf::QueryParameters & qp,
const uint16_t raw )
inline

Split a Query parameter word into its fields.

Parameters
[out]qpQuery parameters
rawQuery parameter word

◆ parse_select_parameter()

bool m5::unit::m100::parse_select_parameter ( m5::uhf::SelectParameter & out,
const uint8_t * param,
const size_t len )
inline

Parse the answer to Get Select Parameter (0x0B)

Parameters
[out]outSelect parameter
paramParameter of the response frame
lenLength of param
Returns
True if successful

◆ parse_tag_notification()

bool m5::unit::m100::parse_tag_notification ( m5::uhf::Tag & out,
const uint8_t * param,
const size_t len )
inline

Parse the parameter of a tag notification.

Parameters
[out]outParsed tag
paramParameter of the notification frame (RSSI, PC, EPC and CRC)
lenParameter length
Returns
True if successful
Note
The EPC length is derived from len, so a variable length EPC is supported

◆ parse_tag_operation()

bool m5::unit::m100::parse_tag_operation ( TagOperationResult & out,
const uint8_t * param,
const size_t len )
inline

Parse the answer to a tag operation.

Parameters
[out]outParsed result
paramParameter of the response frame
lenLength of param
Returns
True if successful

The leading byte counts the PC and EPC that follow it, so what comes after them is the payload however long the EPC happened to be

◆ route_for()

FrameRoute m5::unit::m100::route_for ( const Frame & f,
const bool response_pending,
const uint8_t awaiting_command )
inline

Decide what a received frame answers.

Parameters
fFrame that has been read
response_pendingIs a command waiting for its answer?
awaiting_commandCommand code being waited on, where there is one
Returns
What is to be done with the frame

A frame carries nothing to say which exchange it belongs to, so the command code and the error code are all there is to go on. One that cannot have come from the command being waited on is left over from an exchange that already gave up, and answering with it would shift every later exchange by one

◆ select_parameter_byte()

uint8_t m5::unit::m100::select_parameter_byte ( const uint8_t target,
const uint8_t action,
const uint8_t membank )
inline

Build the SelParam byte of Set Select Parameter.

Parameters
targetTarget (3 bits)
actionAction (3 bits)
membankMemory bank (2 bits)
Returns
SelParam

Variable Documentation

◆ DEMODULATOR_THRESHOLD_DEFAULT

uint16_t m5::unit::m100::DEMODULATOR_THRESHOLD_DEFAULT {0x01B0}
constexpr

Demodulation threshold the module leaves the factory with.

Documented as the lowest value worth using, not as the best one

◆ SELECT_MODE_ALWAYS

uint8_t m5::unit::m100::SELECT_MODE_ALWAYS {0x00}
constexpr

Select modes of Set Select Mode (0x12)

Select before every operation, inventory included