iso14443_4a poller logic enhanced

This commit is contained in:
RebornedBrain 2024-09-28 21:48:48 +03:00
parent 8027c300c3
commit 180d1f0471
5 changed files with 185 additions and 8 deletions

View file

@ -2,10 +2,42 @@
#include <furi.h>
#define ISO14443_4_BLOCK_PCB (1U << 1)
#define ISO14443_4_BLOCK_PCB_I (0U)
#define ISO14443_4_BLOCK_PCB_R (5U << 5)
#define ISO14443_4_BLOCK_PCB_S (3U << 6)
#define ISO14443_4_BLOCK_PCB (1U << 1)
#define ISO14443_4_BLOCK_PCB_MASK (0x03)
#define ISO14443_4_BLOCK_PCB_I (0U)
#define ISO14443_4_BLOCK_PCB_I_NAD_OFFSET (2)
#define ISO14443_4_BLOCK_PCB_I_CID_OFFSET (3)
#define ISO14443_4_BLOCK_PCB_I_CHAIN_OFFSET (4)
#define ISO14443_4_BLOCK_PCB_I_NAD_MASK (1U << ISO14443_4_BLOCK_PCB_I_NAD_OFFSET)
#define ISO14443_4_BLOCK_PCB_I_CID_MASK (1U << ISO14443_4_BLOCK_PCB_I_CID_OFFSET)
#define ISO14443_4_BLOCK_PCB_I_CHAIN_MASK (1U << ISO14443_4_BLOCK_PCB_I_CHAIN_OFFSET)
#define ISO14443_4_BLOCK_PCB_R_MASK (5U << 5)
#define ISO14443_4_BLOCK_PCB_R_NACK_OFFSET (4)
#define ISO14443_4_BLOCK_PCB_R_CID_OFFSET (3)
#define ISO14443_4_BLOCK_PCB_R_CID_MASK (1U << ISO14443_4_BLOCK_PCB_R_CID_OFFSET)
#define ISO14443_4_BLOCK_PCB_R_NACK_MASK (1U << ISO14443_4_BLOCK_PCB_R_NACK_OFFSET)
#define ISO14443_4_BLOCK_PCB_S_MASK (3U << 6)
#define ISO14443_4_BLOCK_PCB_S_CID_OFFSET (3)
#define ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_OFFSET (4)
#define ISO14443_4_BLOCK_PCB_S_CID_MASK (1U << ISO14443_4_BLOCK_PCB_R_CID_OFFSET)
#define ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_MASK (3U << ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_OFFSET)
#define ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, mask) (((pcb) & mask) == mask)
#define ISO14443_4_BLOCK_PCB_IS_R_BLOCK(pcb) \
ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, ISO14443_4_BLOCK_PCB_R_MASK)
#define ISO14443_4_BLOCK_PCB_IS_S_BLOCK(pcb) \
ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, ISO14443_4_BLOCK_PCB_S_MASK)
#define ISO14443_4_BLOCK_PCB_IS_CHAIN_ACTIVE(pcb) \
ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, ISO14443_4_BLOCK_PCB_I_CHAIN_MASK)
#define ISO14443_4_BLOCK_PCB_R_NACK_ACTIVE(pcb) \
ISO14443_4_BLOCK_PCB_BITS_ACTIVE(pcb, ISO14443_4_BLOCK_PCB_R_NACK_MASK)
struct Iso14443_4Layer {
uint8_t pcb;
@ -31,9 +63,31 @@ void iso14443_4_layer_free(Iso14443_4Layer* instance) {
void iso14443_4_layer_reset(Iso14443_4Layer* instance) {
furi_assert(instance);
instance->pcb_prev = 0;
instance->pcb = ISO14443_4_BLOCK_PCB_I | ISO14443_4_BLOCK_PCB;
}
void iso14443_4_layer_set_i_block(Iso14443_4Layer* instance, bool chaining, bool CID_present) {
uint8_t block_pcb = instance->pcb & ISO14443_4_BLOCK_PCB_MASK;
instance->pcb = ISO14443_4_BLOCK_PCB_I | (chaining << ISO14443_4_BLOCK_PCB_I_CHAIN_OFFSET) |
(CID_present << ISO14443_4_BLOCK_PCB_I_CID_OFFSET) | block_pcb;
}
void iso14443_4_layer_set_r_block(Iso14443_4Layer* instance, bool acknowledged, bool CID_present) {
furi_assert(instance);
uint8_t block_pcb = instance->pcb & ISO14443_4_BLOCK_PCB_MASK;
instance->pcb = ISO14443_4_BLOCK_PCB_R_MASK |
(!acknowledged << ISO14443_4_BLOCK_PCB_R_NACK_OFFSET) |
(CID_present << ISO14443_4_BLOCK_PCB_R_CID_OFFSET) | block_pcb;
}
void iso14443_4_layer_set_s_block(Iso14443_4Layer* instance, bool deselect, bool CID_present) {
furi_assert(instance);
uint8_t des_wtx = !deselect ? (ISO14443_4_BLOCK_PCB_S_WTX_DESELECT_MASK) : 0;
instance->pcb = ISO14443_4_BLOCK_PCB_S_MASK | des_wtx |
(CID_present << ISO14443_4_BLOCK_PCB_S_CID_OFFSET) | ISO14443_4_BLOCK_PCB;
}
void iso14443_4_layer_encode_block(
Iso14443_4Layer* instance,
const BitBuffer* input_data,
@ -46,6 +100,11 @@ void iso14443_4_layer_encode_block(
iso14443_4_layer_update_pcb(instance);
}
static inline uint8_t iso14443_4_layer_get_response_pcb(const BitBuffer* block_data) {
const uint8_t* data = bit_buffer_get_data(block_data);
return data[0];
}
bool iso14443_4_layer_decode_block(
Iso14443_4Layer* instance,
BitBuffer* output_data,
@ -55,9 +114,26 @@ bool iso14443_4_layer_decode_block(
bool ret = false;
do {
if(!bit_buffer_starts_with_byte(block_data, instance->pcb_prev)) break;
bit_buffer_copy_right(output_data, block_data, 1);
ret = true;
if(ISO14443_4_BLOCK_PCB_IS_R_BLOCK(instance->pcb_prev)) {
const uint8_t response_pcb = iso14443_4_layer_get_response_pcb(block_data);
ret = (ISO14443_4_BLOCK_PCB_IS_R_BLOCK(response_pcb)) &&
(!ISO14443_4_BLOCK_PCB_R_NACK_ACTIVE(response_pcb));
instance->pcb &= ISO14443_4_BLOCK_PCB_MASK;
iso14443_4_layer_update_pcb(instance);
} else if(ISO14443_4_BLOCK_PCB_IS_CHAIN_ACTIVE(instance->pcb_prev)) {
const uint8_t response_pcb = iso14443_4_layer_get_response_pcb(block_data);
ret = (ISO14443_4_BLOCK_PCB_IS_R_BLOCK(response_pcb)) &&
(!ISO14443_4_BLOCK_PCB_R_NACK_ACTIVE(response_pcb));
instance->pcb &= ~(ISO14443_4_BLOCK_PCB_I_CHAIN_MASK);
} else if(ISO14443_4_BLOCK_PCB_IS_S_BLOCK(instance->pcb_prev)) {
ret = bit_buffer_starts_with_byte(block_data, instance->pcb_prev);
if(bit_buffer_get_size_bytes(block_data) > 1)
bit_buffer_copy_right(output_data, block_data, 1);
} else {
if(!bit_buffer_starts_with_byte(block_data, instance->pcb_prev)) break;
bit_buffer_copy_right(output_data, block_data, 1);
ret = true;
}
} while(false);
return ret;

View file

@ -14,6 +14,10 @@ void iso14443_4_layer_free(Iso14443_4Layer* instance);
void iso14443_4_layer_reset(Iso14443_4Layer* instance);
void iso14443_4_layer_set_i_block(Iso14443_4Layer* instance, bool chaining, bool CID_present);
void iso14443_4_layer_set_r_block(Iso14443_4Layer* instance, bool acknowledged, bool CID_present);
void iso14443_4_layer_set_s_block(Iso14443_4Layer* instance, bool deselect, bool CID_present);
void iso14443_4_layer_encode_block(
Iso14443_4Layer* instance,
const BitBuffer* input_data,

View file

@ -56,6 +56,69 @@ Iso14443_4aError iso14443_4a_poller_send_block(
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer);
/**
* @brief Transmit and receive Iso14443_4a chained block in poller mode. Also it
* automatically modifies PCB packet byte with appropriate bits then resets them back
*
* Must ONLY be used inside the callback function.
*
* The rx_buffer will be filled with any data received as a response to data
* sent from tx_buffer. The fwt parameter is calculated during activation procedure.
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
* @return Iso14443_4aErrorNone on success, an error code on failure.
*/
Iso14443_4aError iso14443_4a_poller_send_chain_block(
Iso14443_4aPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer);
/**
* @brief Transmit Iso14443_4a R-block in poller mode. This block never contains
* data, but can contain CID and NAD, therefore in tx_buffer only two bytes can be added.
* The first one will represent CID, the second one will represent NAD.
*
* Must ONLY be used inside the callback function.
*
* The rx_buffer will be filled with R-block repsonse
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] acknowledged Sets appropriate bit in PCB byte. True - ACK, false - NAK
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
* @return Iso14443_4aErrorNone on success, an error code on failure.
*/
Iso14443_4aError iso14443_4a_poller_send_receive_ready_block(
Iso14443_4aPoller* instance,
bool acknowledged,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer);
/**
* @brief Transmit Iso14443_4a S-block in poller mode. S-block used to exchange control
* information between the card and the reader. Two different types of S-blocks
* are defined:
* - Waiting time extension containing a 1 byte long INF field and (deselect = false)
* - DESELECT containing no INF field (deselect = true)
*
* Must ONLY be used inside the callback function.
*
* The rx_buffer will be filled with R-block repsonse
*
* @param[in, out] instance pointer to the instance to be used in the transaction.
* @param[in] deselect Sets appropriate bit in PCB byte.
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
* @return Iso14443_4aErrorNone on success, an error code on failure.
*/
Iso14443_4aError iso14443_4a_poller_send_supervisory_block(
Iso14443_4aPoller* instance,
bool deselect,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer);
/**
* @brief Send HALT command to the card.
*

View file

@ -114,3 +114,34 @@ Iso14443_4aError iso14443_4a_poller_send_block(
return error;
}
Iso14443_4aError iso14443_4a_poller_send_chain_block(
Iso14443_4aPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer) {
iso14443_4_layer_set_i_block(instance->iso14443_4_layer, true, false);
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
return error;
}
Iso14443_4aError iso14443_4a_poller_send_receive_ready_block(
Iso14443_4aPoller* instance,
bool acknowledged,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer) {
bool CID_present = bit_buffer_get_size_bytes(tx_buffer) != 0;
iso14443_4_layer_set_r_block(instance->iso14443_4_layer, acknowledged, CID_present);
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
return error;
}
Iso14443_4aError iso14443_4a_poller_send_supervisory_block(
Iso14443_4aPoller* instance,
bool deselect,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer) {
bool CID_present = bit_buffer_get_size_bytes(tx_buffer) != 0;
iso14443_4_layer_set_s_block(instance->iso14443_4_layer, deselect, CID_present);
Iso14443_4aError error = iso14443_4a_poller_send_block(instance, tx_buffer, rx_buffer);
return error;
}

View file

@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,75.0,,
Version,+,75.3,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
@ -2125,6 +2125,9 @@ Function,+,iso14443_4a_load,_Bool,"Iso14443_4aData*, FlipperFormat*, uint32_t"
Function,+,iso14443_4a_poller_halt,Iso14443_4aError,Iso14443_4aPoller*
Function,+,iso14443_4a_poller_read_ats,Iso14443_4aError,"Iso14443_4aPoller*, Iso14443_4aAtsData*"
Function,+,iso14443_4a_poller_send_block,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*"
Function,+,iso14443_4a_poller_send_chain_block,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*"
Function,+,iso14443_4a_poller_send_receive_ready_block,Iso14443_4aError,"Iso14443_4aPoller*, _Bool, const BitBuffer*, BitBuffer*"
Function,+,iso14443_4a_poller_send_supervisory_block,Iso14443_4aError,"Iso14443_4aPoller*, _Bool, const BitBuffer*, BitBuffer*"
Function,+,iso14443_4a_reset,void,Iso14443_4aData*
Function,+,iso14443_4a_save,_Bool,"const Iso14443_4aData*, FlipperFormat*"
Function,+,iso14443_4a_set_uid,_Bool,"Iso14443_4aData*, const uint8_t*, size_t"

1 entry status name type params
2 Version + 75.0 75.3
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/bt/bt_service/bt_keys_storage.h
2125 Function + iso14443_4a_poller_halt Iso14443_4aError Iso14443_4aPoller*
2126 Function + iso14443_4a_poller_read_ats Iso14443_4aError Iso14443_4aPoller*, Iso14443_4aAtsData*
2127 Function + iso14443_4a_poller_send_block Iso14443_4aError Iso14443_4aPoller*, const BitBuffer*, BitBuffer*
2128 Function + iso14443_4a_poller_send_chain_block Iso14443_4aError Iso14443_4aPoller*, const BitBuffer*, BitBuffer*
2129 Function + iso14443_4a_poller_send_receive_ready_block Iso14443_4aError Iso14443_4aPoller*, _Bool, const BitBuffer*, BitBuffer*
2130 Function + iso14443_4a_poller_send_supervisory_block Iso14443_4aError Iso14443_4aPoller*, _Bool, const BitBuffer*, BitBuffer*
2131 Function + iso14443_4a_reset void Iso14443_4aData*
2132 Function + iso14443_4a_save _Bool const Iso14443_4aData*, FlipperFormat*
2133 Function + iso14443_4a_set_uid _Bool Iso14443_4aData*, const uint8_t*, size_t