mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-25 01:38:11 -07:00
nfc: add ISO15693-3 and SLIX write-back support
Add Write Single Block poller functions for ISO 15693-3 and SLIX/SLIX2, enable the Write scene for both protocols, and skip blocks that already contain the correct data to minimise RF session time and avoid timeouts on large tags (e.g. 80-block ICODE SLIX2). Tested on NXP ICODE SLIX2 (UID E0 04 01 09 05 05 09 37, 80 x 4 byte blocks).
This commit is contained in:
@@ -15,6 +15,11 @@ extern "C" {
|
||||
#define ISO15693_3_FDT_LISTEN_FC (4320U)
|
||||
#define ISO15693_3_POLL_POLL_MIN_US (1500U)
|
||||
|
||||
/* NVM write time varies by tag type (ICODE SLIX: 9.6ms, generic: up to 20ms).
|
||||
* ISO 15693-3 write commands require a longer FWT than reads to account for
|
||||
* EEPROM programming delays before the tag responds. 20ms covers all known tags. */
|
||||
#define ISO15693_3_FDT_WRITE_POLL_FC (271200U)
|
||||
|
||||
#define ISO15693_3_REQ_FLAG_SUBCARRIER_1 (0U << 0)
|
||||
#define ISO15693_3_REQ_FLAG_SUBCARRIER_2 (1U << 0)
|
||||
#define ISO15693_3_REQ_FLAG_DATA_RATE_LO (0U << 1)
|
||||
|
||||
@@ -176,6 +176,25 @@ Iso15693_3Error
|
||||
return ret;
|
||||
}
|
||||
|
||||
Iso15693_3Error iso15693_3_write_block_response_parse(const BitBuffer* buf) {
|
||||
Iso15693_3Error ret = Iso15693_3ErrorNone;
|
||||
|
||||
do {
|
||||
if(iso15693_3_error_response_parse(&ret, buf)) break;
|
||||
|
||||
typedef struct {
|
||||
uint8_t flags;
|
||||
} WriteBlockResponseLayout;
|
||||
|
||||
if(bit_buffer_get_size_bytes(buf) != sizeof(WriteBlockResponseLayout)) {
|
||||
ret = Iso15693_3ErrorUnexpectedResponse;
|
||||
break;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Iso15693_3Error iso15693_3_get_block_security_response_parse(
|
||||
uint8_t* data,
|
||||
uint16_t block_count,
|
||||
|
||||
@@ -28,6 +28,8 @@ Iso15693_3Error
|
||||
Iso15693_3Error
|
||||
iso15693_3_read_block_response_parse(uint8_t* data, uint8_t block_size, const BitBuffer* buf);
|
||||
|
||||
Iso15693_3Error iso15693_3_write_block_response_parse(const BitBuffer* buf);
|
||||
|
||||
Iso15693_3Error iso15693_3_get_block_security_response_parse(
|
||||
uint8_t* data,
|
||||
uint16_t block_count,
|
||||
|
||||
@@ -13,6 +13,14 @@ extern "C" {
|
||||
*/
|
||||
typedef struct Iso15693_3Poller Iso15693_3Poller;
|
||||
|
||||
/**
|
||||
* @brief Get the Iso15693_3 data accumulated by the poller.
|
||||
*
|
||||
* @param[in] instance pointer to the Iso15693_3Poller instance.
|
||||
* @return pointer to the Iso15693_3Data structure filled during activation.
|
||||
*/
|
||||
const Iso15693_3Data* iso15693_3_poller_get_data(Iso15693_3Poller* instance);
|
||||
|
||||
/**
|
||||
* @brief Enumeration of possible Iso15693_3 poller event types.
|
||||
*/
|
||||
@@ -144,6 +152,40 @@ Iso15693_3Error iso15693_3_poller_get_blocks_security(
|
||||
uint8_t* data,
|
||||
uint16_t block_count);
|
||||
|
||||
/**
|
||||
* @brief Write a single Iso15693_3 block.
|
||||
*
|
||||
* Must ONLY be used inside the callback function.
|
||||
*
|
||||
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||
* @param[in] data pointer to the buffer containing the data to write.
|
||||
* @param[in] block_number block number to write.
|
||||
* @param[in] block_size size of the block in bytes.
|
||||
* @return Iso15693_3ErrorNone on success, an error code on failure.
|
||||
*/
|
||||
Iso15693_3Error iso15693_3_poller_write_block(
|
||||
Iso15693_3Poller* instance,
|
||||
const uint8_t* data,
|
||||
uint8_t block_number,
|
||||
uint8_t block_size);
|
||||
|
||||
/**
|
||||
* @brief Write multiple consecutive Iso15693_3 blocks.
|
||||
*
|
||||
* Must ONLY be used inside the callback function.
|
||||
*
|
||||
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||
* @param[in] data pointer to the buffer containing the data to write.
|
||||
* @param[in] block_count number of blocks to write.
|
||||
* @param[in] block_size size of each block in bytes.
|
||||
* @return Iso15693_3ErrorNone on success, an error code on failure.
|
||||
*/
|
||||
Iso15693_3Error iso15693_3_poller_write_blocks(
|
||||
Iso15693_3Poller* instance,
|
||||
const uint8_t* data,
|
||||
uint16_t block_count,
|
||||
uint8_t block_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -234,6 +234,57 @@ Iso15693_3Error iso15693_3_poller_read_blocks(
|
||||
return ret;
|
||||
}
|
||||
|
||||
Iso15693_3Error iso15693_3_poller_write_block(
|
||||
Iso15693_3Poller* instance,
|
||||
const uint8_t* data,
|
||||
uint8_t block_number,
|
||||
uint8_t block_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
|
||||
bit_buffer_reset(instance->tx_buffer);
|
||||
bit_buffer_reset(instance->rx_buffer);
|
||||
|
||||
bit_buffer_append_byte(
|
||||
instance->tx_buffer, ISO15693_3_REQ_FLAG_SUBCARRIER_1 | ISO15693_3_REQ_FLAG_DATA_RATE_HI);
|
||||
bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_CMD_WRITE_BLOCK);
|
||||
bit_buffer_append_byte(instance->tx_buffer, block_number);
|
||||
bit_buffer_append_bytes(instance->tx_buffer, data, block_size);
|
||||
|
||||
Iso15693_3Error ret;
|
||||
|
||||
do {
|
||||
ret = iso15693_3_poller_send_frame(
|
||||
instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_WRITE_POLL_FC);
|
||||
if(ret != Iso15693_3ErrorNone) break;
|
||||
|
||||
ret = iso15693_3_write_block_response_parse(instance->rx_buffer);
|
||||
} while(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Iso15693_3Error iso15693_3_poller_write_blocks(
|
||||
Iso15693_3Poller* instance,
|
||||
const uint8_t* data,
|
||||
uint16_t block_count,
|
||||
uint8_t block_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
furi_assert(block_count);
|
||||
furi_assert(block_size);
|
||||
|
||||
Iso15693_3Error ret = Iso15693_3ErrorNone;
|
||||
|
||||
for(uint32_t i = 0; i < block_count; ++i) {
|
||||
ret = iso15693_3_poller_write_block(
|
||||
instance, &data[block_size * i], (uint8_t)i, block_size);
|
||||
if(ret != Iso15693_3ErrorNone) break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Iso15693_3Error iso15693_3_poller_get_blocks_security(
|
||||
Iso15693_3Poller* instance,
|
||||
uint8_t* data,
|
||||
|
||||
@@ -33,8 +33,6 @@ struct Iso15693_3Poller {
|
||||
void* context;
|
||||
};
|
||||
|
||||
const Iso15693_3Data* iso15693_3_poller_get_data(Iso15693_3Poller* instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -118,6 +118,40 @@ SlixError slix_poller_set_password(
|
||||
SlixPassword password,
|
||||
SlixRandomNumber random_number);
|
||||
|
||||
/**
|
||||
* @brief Write a single block to a Slix card.
|
||||
*
|
||||
* Must ONLY be used inside the callback function.
|
||||
*
|
||||
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||
* @param[in] data pointer to the buffer containing the data to write.
|
||||
* @param[in] block_number block number to write.
|
||||
* @param[in] block_size size of the block in bytes.
|
||||
* @return SlixErrorNone on success, an error code on failure.
|
||||
*/
|
||||
SlixError slix_poller_write_block(
|
||||
SlixPoller* instance,
|
||||
const uint8_t* data,
|
||||
uint8_t block_number,
|
||||
uint8_t block_size);
|
||||
|
||||
/**
|
||||
* @brief Write multiple consecutive blocks to a Slix card.
|
||||
*
|
||||
* Must ONLY be used inside the callback function.
|
||||
*
|
||||
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||
* @param[in] data pointer to the buffer containing the data to write.
|
||||
* @param[in] block_count number of blocks to write.
|
||||
* @param[in] block_size size of each block in bytes.
|
||||
* @return SlixErrorNone on success, an error code on failure.
|
||||
*/
|
||||
SlixError slix_poller_write_blocks(
|
||||
SlixPoller* instance,
|
||||
const uint8_t* data,
|
||||
uint16_t block_count,
|
||||
uint8_t block_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -128,3 +128,31 @@ SlixError slix_poller_set_password(
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
SlixError slix_poller_write_block(
|
||||
SlixPoller* instance,
|
||||
const uint8_t* data,
|
||||
uint8_t block_number,
|
||||
uint8_t block_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
|
||||
const Iso15693_3Error error =
|
||||
iso15693_3_poller_write_block(instance->iso15693_3_poller, data, block_number, block_size);
|
||||
return slix_process_iso15693_3_error(error);
|
||||
}
|
||||
|
||||
SlixError slix_poller_write_blocks(
|
||||
SlixPoller* instance,
|
||||
const uint8_t* data,
|
||||
uint16_t block_count,
|
||||
uint8_t block_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(data);
|
||||
furi_assert(block_count);
|
||||
furi_assert(block_size);
|
||||
|
||||
const Iso15693_3Error error =
|
||||
iso15693_3_poller_write_blocks(instance->iso15693_3_poller, data, block_count, block_size);
|
||||
return slix_process_iso15693_3_error(error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user