|
M5Unit-RFID 0.2.0 git rev:79c1939
|
Frame codec for the magicRF M100 family (JRD-4035 / JRD-100 / R200) More...
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} |
Frame codec for the magicRF M100 family (JRD-4035 / JRD-100 / R200)
|
strong |
Error codes carried by a failure notification.
|
strong |
|
strong |
|
strong |
|
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 |
|
inline |
Build the parameter of Set Demodulator Parameter (0xF0)
| [out] | out | Parameter |
| dp | Demodulator parameters |
|
inline |
Build a command frame.
| [out] | out | Built frame |
| type | Frame type (0x00: command) | |
| command | Command code | |
| param | Parameter (nullptr if none) | |
| param_len | Parameter length | |
| header | Frame header (0xBB for JRD-4035, 0xAA for R200) | |
| end | Frame end (0x7E for JRD-4035, 0xDD for R200) |
|
inline |
Build the parameter of Kill (0x65)
| [out] | out | Parameter |
| kill_password | Kill password |
|
inline |
Build the parameter of Lock (0x82)
| [out] | out | Parameter |
| access_password | Access password | |
| payload | 20-bit lock payload, see m5::uhf::buildLockPayload |
|
inline |
Build the parameter of NXP ChangeConfig (0xE0)
| [out] | out | Parameter |
| access_password | Access password of the tag | |
| toggle | Bits 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
|
inline |
Build the parameter of NXP Change EAS (0xE3) or ReadProtect (0xE1)
| [out] | out | Parameter |
| access_password | Access password of the tag | |
| flag | Value 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
|
inline |
Place the fields we expose into a Query parameter word.
| qp | Query parameters |
| current | Word the module currently holds |
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
|
inline |
Build the parameter of Read Tag Memory Area (0x39)
| [out] | out | Parameter |
| access_password | Access password, 0 when the tag has none | |
| membank | Memory bank | |
| word_address | Start address in 16-bit words | |
| word_count | Number of 16-bit words |
|
inline |
Build the parameter of Set Select Parameter (0x0C)
| [out] | out | Parameter |
| sel_param | SelParam byte | |
| pointer_bits | Start of the mask as a bit address inside the bank | |
| mask_length_bits | Mask length in bits | |
| truncate | SELECT_TRUNCATE_OFF or SELECT_TRUNCATE_ON | |
| mask | Mask bytes | |
| mask_len | Length of mask in bytes |
|
inline |
Build the parameter of Write Tag Memory Area (0x49)
| [out] | out | Parameter |
| access_password | Access password, 0 when the tag has none | |
| membank | Memory bank | |
| word_address | Start address in 16-bit words | |
| data | Bytes to write | |
| len | Length of data, which must be even and at most 64 |
|
inline |
Calculate the frame checksum.
| body | Pointer to the Type byte (the checksum covers Type through the last Parameter byte) |
| len | Length in bytes |
|
inline |
Could this error code be the answer to this command?
| error_code | Error code carried by the failure notification |
| command | Command code the module was asked to carry out |
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
|
inline |
Describe an error code in one word.
| error_code | Error code carried by the failure notification |
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
|
inline |
Take the first whole frame out of received bytes.
| [out] | out | Frame, filled in only when Ok is returned |
| [in,out] | buffer | Bytes received so far. What was used, and what was thrown away, is removed; everything else is left for the next call |
| [out] | discarded | Bytes thrown away before a frame could be found |
| header | Frame header byte | |
| end | Frame end byte |
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
|
inline |
Is the command code of a failure notification?
| command | Command code of the received frame |
|
inline |
Does the error code only mean "no tag was found this round"?
| error_code | Error code carried by the failure notification |
|
inline |
Did the tag itself report this error, rather than the module?
| error_code | Error code carried by the failure notification |
|
inline |
Is this failure worth sending the same command again for?
| error_code | Error code carried by the failure notification |
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
|
inline |
Parse the answer to a BlockPermalock that locked.
| param | Parameter of the response frame |
| len | Length of param |
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
|
inline |
Parse the answer to a BlockPermalock that read.
| [out] | mask | Permalock bits, one word for every sixteen blocks, the first block being the most significant bit |
| param | Parameter of the response frame | |
| len | Length of param |
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
|
inline |
Split a demodulator parameter payload into its fields.
| [out] | dp | Demodulator parameters |
| param | Parameter of the response frame | |
| len | Length of param |
|
inline |
Parse a frame.
| [out] | out | Parsed frame |
| raw | Raw bytes (a whole frame including the header and the end) | |
| len | Length of raw | |
| header | Expected frame header | |
| end | Expected frame end |
|
inline |
Parse the answer to NXP ChangeConfig (0xE0)
| [out] | config | Config-Word the tag holds once the command has been carried out |
| param | Parameter of the response frame | |
| len | Length of param |
The tag that replied comes first, and the word it ended up with after it
|
inline |
Parse the answer to NXP EAS_Alarm (0xE4)
| [out] | alarm | Alarm code the tag backscattered |
| param | Parameter of the response frame | |
| len | Length of param |
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
|
inline |
Split a Query parameter word into its fields.
| [out] | qp | Query parameters |
| raw | Query parameter word |
|
inline |
Parse the answer to Get Select Parameter (0x0B)
| [out] | out | Select parameter |
| param | Parameter of the response frame | |
| len | Length of param |
|
inline |
Parse the parameter of a tag notification.
| [out] | out | Parsed tag |
| param | Parameter of the notification frame (RSSI, PC, EPC and CRC) | |
| len | Parameter length |
|
inline |
Parse the answer to a tag operation.
| [out] | out | Parsed result |
| param | Parameter of the response frame | |
| len | Length of param |
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
|
inline |
Decide what a received frame answers.
| f | Frame that has been read |
| response_pending | Is a command waiting for its answer? |
| awaiting_command | Command code being waited on, where there is one |
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
|
inline |
Build the SelParam byte of Set Select Parameter.
| target | Target (3 bits) |
| action | Action (3 bits) |
| membank | Memory bank (2 bits) |
|
constexpr |
Demodulation threshold the module leaves the factory with.
Documented as the lowest value worth using, not as the best one
|
constexpr |
Select modes of Set Select Mode (0x12)
Select before every operation, inventory included