NFC refactoring (#3050)

"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.

Starring:

- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer

Supporting roles:

- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance

Special thanks:

@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
This commit is contained in:
gornekich
2023-10-24 07:08:09 +04:00
committed by GitHub
parent 35c903494c
commit d92b0a82cc
514 changed files with 41488 additions and 68125 deletions

81
lib/drivers/st25r3916.c Normal file
View File

@@ -0,0 +1,81 @@
#include "st25r3916.h"
#include <furi.h>
void st25r3916_mask_irq(FuriHalSpiBusHandle* handle, uint32_t mask) {
furi_assert(handle);
uint8_t irq_mask_regs[4] = {
mask & 0xff,
(mask >> 8) & 0xff,
(mask >> 16) & 0xff,
(mask >> 24) & 0xff,
};
st25r3916_write_burst_regs(handle, ST25R3916_REG_IRQ_MASK_MAIN, irq_mask_regs, 4);
}
uint32_t st25r3916_get_irq(FuriHalSpiBusHandle* handle) {
furi_assert(handle);
uint8_t irq_regs[4] = {};
uint32_t irq = 0;
st25r3916_read_burst_regs(handle, ST25R3916_REG_IRQ_MASK_MAIN, irq_regs, 4);
// FURI_LOG_I(
// "Mask Irq", "%02X %02X %02X %02X", irq_regs[0], irq_regs[1], irq_regs[2], irq_regs[3]);
st25r3916_read_burst_regs(handle, ST25R3916_REG_IRQ_MAIN, irq_regs, 4);
irq = (uint32_t)irq_regs[0];
irq |= (uint32_t)irq_regs[1] << 8;
irq |= (uint32_t)irq_regs[2] << 16;
irq |= (uint32_t)irq_regs[3] << 24;
// FURI_LOG_I("iRQ", "%02X %02X %02X %02X", irq_regs[0], irq_regs[1], irq_regs[2], irq_regs[3]);
return irq;
}
void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t bits) {
furi_assert(handle);
furi_assert(buff);
size_t bytes = (bits + 7) / 8;
st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES2, (uint8_t)(bits & 0xFFU));
st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES1, (uint8_t)((bits >> 8) & 0xFFU));
st25r3916_reg_write_fifo(handle, buff, bytes);
}
bool st25r3916_read_fifo(
FuriHalSpiBusHandle* handle,
uint8_t* buff,
size_t buff_size,
size_t* buff_bits) {
furi_assert(handle);
furi_assert(buff);
bool read_success = false;
do {
uint8_t fifo_status[2] = {};
st25r3916_read_burst_regs(handle, ST25R3916_REG_FIFO_STATUS1, fifo_status, 2);
size_t bytes = ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >>
ST25R3916_REG_FIFO_STATUS2_fifo_b_shift) |
fifo_status[0];
uint8_t bits =
((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) >>
ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift);
if(bytes == 0) break;
if(bytes > buff_size) break;
st25r3916_reg_read_fifo(handle, buff, bytes);
if(bits) {
*buff_bits = (bytes - 1) * 8 + bits;
} else {
*buff_bits = bytes * 8;
}
read_success = true;
} while(false);
return read_success;
}

113
lib/drivers/st25r3916.h Normal file
View File

@@ -0,0 +1,113 @@
#pragma once
#include "st25r3916_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ST25R3916_IRQ_MASK_ALL (uint32_t)(0xFFFFFFFFUL) /** All ST25R3916 interrupt sources */
#define ST25R3916_IRQ_MASK_NONE (uint32_t)(0x00000000UL) /**No ST25R3916 interrupt source */
/** Main interrupt register */
#define ST25R3916_IRQ_MASK_OSC (uint32_t)(0x00000080U) /** ST25R3916 oscillator stable interrupt */
#define ST25R3916_IRQ_MASK_FWL (uint32_t)(0x00000040U) /** ST25R3916 FIFO water level interrupt */
#define ST25R3916_IRQ_MASK_RXS (uint32_t)(0x00000020U) /** ST25R3916 start of receive interrupt */
#define ST25R3916_IRQ_MASK_RXE (uint32_t)(0x00000010U) /** ST25R3916 end of receive interrupt */
#define ST25R3916_IRQ_MASK_TXE \
(uint32_t)(0x00000008U) /** ST25R3916 end of transmission interrupt */
#define ST25R3916_IRQ_MASK_COL (uint32_t)(0x00000004U) /** ST25R3916 bit collision interrupt */
#define ST25R3916_IRQ_MASK_RX_REST \
(uint32_t)(0x00000002U) /** ST25R3916 automatic reception restart interrupt */
#define ST25R3916_IRQ_MASK_RFU (uint32_t)(0x00000001U) /** ST25R3916 RFU interrupt */
/** Timer and NFC interrupt register */
#define ST25R3916_IRQ_MASK_DCT \
(uint32_t)(0x00008000U) /** ST25R3916 termination of direct command interrupt. */
#define ST25R3916_IRQ_MASK_NRE \
(uint32_t)(0x00004000U) /** ST25R3916 no-response timer expired interrupt */
#define ST25R3916_IRQ_MASK_GPE \
(uint32_t)(0x00002000U) /** ST25R3916 general purpose timer expired interrupt */
#define ST25R3916_IRQ_MASK_EON (uint32_t)(0x00001000U) /** ST25R3916 external field on interrupt */
#define ST25R3916_IRQ_MASK_EOF \
(uint32_t)(0x00000800U) /** ST25R3916 external field off interrupt */
#define ST25R3916_IRQ_MASK_CAC \
(uint32_t)(0x00000400U) /** ST25R3916 collision during RF collision avoidance */
#define ST25R3916_IRQ_MASK_CAT \
(uint32_t)(0x00000200U) /** ST25R3916 minimum guard time expired interrupt */
#define ST25R3916_IRQ_MASK_NFCT \
(uint32_t)(0x00000100U) /** ST25R3916 initiator bit rate recognised interrupt */
/** Error and wake-up interrupt register */
#define ST25R3916_IRQ_MASK_CRC (uint32_t)(0x00800000U) /** ST25R3916 CRC error interrupt */
#define ST25R3916_IRQ_MASK_PAR (uint32_t)(0x00400000U) /** ST25R3916 parity error interrupt */
#define ST25R3916_IRQ_MASK_ERR2 \
(uint32_t)(0x00200000U) /** ST25R3916 soft framing error interrupt */
#define ST25R3916_IRQ_MASK_ERR1 \
(uint32_t)(0x00100000U) /** ST25R3916 hard framing error interrupt */
#define ST25R3916_IRQ_MASK_WT (uint32_t)(0x00080000U) /** ST25R3916 wake-up interrupt */
#define ST25R3916_IRQ_MASK_WAM \
(uint32_t)(0x00040000U) /** ST25R3916 wake-up due to amplitude interrupt */
#define ST25R3916_IRQ_MASK_WPH \
(uint32_t)(0x00020000U) /** ST25R3916 wake-up due to phase interrupt */
#define ST25R3916_IRQ_MASK_WCAP \
(uint32_t)(0x00010000U) /** ST25R3916 wake-up due to capacitance measurement */
/** Passive Target Interrupt Register */
#define ST25R3916_IRQ_MASK_PPON2 \
(uint32_t)(0x80000000U) /** ST25R3916 PPON2 Field on waiting Timer interrupt */
#define ST25R3916_IRQ_MASK_SL_WL \
(uint32_t)(0x40000000U) /** ST25R3916 Passive target slot number water level interrupt */
#define ST25R3916_IRQ_MASK_APON \
(uint32_t)(0x20000000U) /** ST25R3916 Anticollision done and Field On interrupt */
#define ST25R3916_IRQ_MASK_RXE_PTA \
(uint32_t)(0x10000000U) /** ST25R3916 RXE with an automatic response interrupt */
#define ST25R3916_IRQ_MASK_WU_F \
(uint32_t)(0x08000000U) /** ST25R3916 212/424b/s Passive target interrupt: Active */
#define ST25R3916_IRQ_MASK_RFU2 (uint32_t)(0x04000000U) /** ST25R3916 RFU2 interrupt */
#define ST25R3916_IRQ_MASK_WU_A_X \
(uint32_t)(0x02000000U) /** ST25R3916 106kb/s Passive target state interrupt: Active* */
#define ST25R3916_IRQ_MASK_WU_A \
(uint32_t)(0x01000000U) /** ST25R3916 106kb/s Passive target state interrupt: Active */
/** Mask st25r3916 interrupts
*
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param mask - mask of interrupts to be disabled
*/
void st25r3916_mask_irq(FuriHalSpiBusHandle* handle, uint32_t mask);
/** Get st25r3916 interrupts
*
* @param handle - pointer to FuriHalSpiBusHandle instance
*
* @return received interrupts
*/
uint32_t st25r3916_get_irq(FuriHalSpiBusHandle* handle);
/** Write FIFO
*
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param buff - buffer to write to FIFO
* @param bits - number of bits to write
*/
void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t bits);
/** Read FIFO
*
* @param handle - pointer to FuriHalSpiBusHandle instance
* @param buff - buffer to read from FIFO
* @param buff_size - buffer size n bytes
* @param buff_bits - pointer to number of bits read
*
* @return true if read success, false otherwise
*/
bool st25r3916_read_fifo(
FuriHalSpiBusHandle* handle,
uint8_t* buff,
size_t buff_size,
size_t* buff_bits);
#ifdef __cplusplus
}
#endif

257
lib/drivers/st25r3916_reg.c Normal file
View File

@@ -0,0 +1,257 @@
#include "st25r3916_reg.h"
#include <furi.h>
#define ST25R3916_WRITE_MODE \
(0U << 6) /*!< ST25R3916 Operation Mode: Write */
#define ST25R3916_READ_MODE \
(1U << 6) /*!< ST25R3916 Operation Mode: Read */
#define ST25R3916_CMD_MODE \
(3U << 6) /*!< ST25R3916 Operation Mode: Direct Command */
#define ST25R3916_FIFO_LOAD \
(0x80U) /*!< ST25R3916 Operation Mode: FIFO Load */
#define ST25R3916_FIFO_READ \
(0x9FU) /*!< ST25R3916 Operation Mode: FIFO Read */
#define ST25R3916_PT_A_CONFIG_LOAD \
(0xA0U) /*!< ST25R3916 Operation Mode: Passive Target Memory A-Config Load */
#define ST25R3916_PT_F_CONFIG_LOAD \
(0xA8U) /*!< ST25R3916 Operation Mode: Passive Target Memory F-Config Load */
#define ST25R3916_PT_TSN_DATA_LOAD \
(0xACU) /*!< ST25R3916 Operation Mode: Passive Target Memory TSN Load */
#define ST25R3916_PT_MEM_READ \
(0xBFU) /*!< ST25R3916 Operation Mode: Passive Target Memory Read */
#define ST25R3916_CMD_LEN \
(1U) /*!< ST25R3916 CMD length */
#define ST25R3916_FIFO_DEPTH (512U)
#define ST25R3916_BUF_LEN \
(ST25R3916_CMD_LEN + \
ST25R3916_FIFO_DEPTH) /*!< ST25R3916 communication buffer: CMD + FIFO length */
static void st25r3916_reg_tx_byte(FuriHalSpiBusHandle* handle, uint8_t byte) {
uint8_t val = byte;
furi_hal_spi_bus_tx(handle, &val, 1, 5);
}
void st25r3916_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val) {
furi_assert(handle);
st25r3916_read_burst_regs(handle, reg, val, 1);
}
void st25r3916_read_burst_regs(
FuriHalSpiBusHandle* handle,
uint8_t reg_start,
uint8_t* values,
uint8_t length) {
furi_assert(handle);
furi_assert(values);
furi_assert(length);
furi_hal_gpio_write(handle->cs, false);
if(reg_start & ST25R3916_SPACE_B) {
// Send direct command first
st25r3916_reg_tx_byte(handle, ST25R3916_CMD_SPACE_B_ACCESS);
}
st25r3916_reg_tx_byte(handle, (reg_start & ~ST25R3916_SPACE_B) | ST25R3916_READ_MODE);
furi_hal_spi_bus_rx(handle, values, length, 5);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val) {
furi_assert(handle);
uint8_t reg_val = val;
st25r3916_write_burst_regs(handle, reg, &reg_val, 1);
}
void st25r3916_write_burst_regs(
FuriHalSpiBusHandle* handle,
uint8_t reg_start,
const uint8_t* values,
uint8_t length) {
furi_assert(handle);
furi_assert(values);
furi_assert(length);
furi_hal_gpio_write(handle->cs, false);
if(reg_start & ST25R3916_SPACE_B) {
// Send direct command first
st25r3916_reg_tx_byte(handle, ST25R3916_CMD_SPACE_B_ACCESS);
}
st25r3916_reg_tx_byte(handle, (reg_start & ~ST25R3916_SPACE_B) | ST25R3916_WRITE_MODE);
furi_hal_spi_bus_tx(handle, values, length, 5);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t length) {
furi_assert(handle);
furi_assert(buff);
furi_assert(length);
furi_assert(length <= ST25R3916_FIFO_DEPTH);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_FIFO_LOAD);
furi_hal_spi_bus_tx(handle, buff, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length) {
furi_assert(handle);
furi_assert(buff);
furi_assert(length);
furi_assert(length <= ST25R3916_FIFO_DEPTH);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_FIFO_READ);
furi_hal_spi_bus_rx(handle, buff, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_write_pta_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length) {
furi_assert(handle);
furi_assert(values);
furi_assert(length);
furi_assert(length <= ST25R3916_PTM_LEN);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_PT_A_CONFIG_LOAD);
furi_hal_spi_bus_tx(handle, values, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length) {
furi_assert(handle);
furi_assert(buff);
furi_assert(length);
furi_assert(length <= ST25R3916_PTM_LEN);
uint8_t tmp_buff[ST25R3916_PTM_LEN + 1];
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_PT_MEM_READ);
furi_hal_spi_bus_rx(handle, tmp_buff, length + 1, 200);
furi_hal_gpio_write(handle->cs, true);
memcpy(buff, tmp_buff + 1, length);
}
void st25r3916_write_ptf_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length) {
furi_assert(handle);
furi_assert(values);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_PT_F_CONFIG_LOAD);
furi_hal_spi_bus_tx(handle, values, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_write_pttsn_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length) {
furi_assert(handle);
furi_assert(buff);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_PT_TSN_DATA_LOAD);
furi_hal_spi_bus_tx(handle, buff, length, 200);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_direct_cmd(FuriHalSpiBusHandle* handle, uint8_t cmd) {
furi_assert(handle);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, cmd | ST25R3916_CMD_MODE);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_read_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val) {
furi_assert(handle);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_CMD_TEST_ACCESS);
st25r3916_reg_tx_byte(handle, reg | ST25R3916_READ_MODE);
furi_hal_spi_bus_rx(handle, val, 1, 5);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_write_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val) {
furi_assert(handle);
furi_hal_gpio_write(handle->cs, false);
st25r3916_reg_tx_byte(handle, ST25R3916_CMD_TEST_ACCESS);
st25r3916_reg_tx_byte(handle, reg | ST25R3916_WRITE_MODE);
furi_hal_spi_bus_tx(handle, &val, 1, 5);
furi_hal_gpio_write(handle->cs, true);
}
void st25r3916_clear_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t clr_mask) {
furi_assert(handle);
uint8_t reg_val = 0;
st25r3916_read_reg(handle, reg, &reg_val);
if((reg_val & ~clr_mask) != reg_val) {
reg_val &= ~clr_mask;
st25r3916_write_reg(handle, reg, reg_val);
}
}
void st25r3916_set_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t set_mask) {
furi_assert(handle);
uint8_t reg_val = 0;
st25r3916_read_reg(handle, reg, &reg_val);
if((reg_val | set_mask) != reg_val) {
reg_val |= set_mask;
st25r3916_write_reg(handle, reg, reg_val);
}
}
void st25r3916_change_reg_bits(
FuriHalSpiBusHandle* handle,
uint8_t reg,
uint8_t mask,
uint8_t value) {
furi_assert(handle);
st25r3916_modify_reg(handle, reg, mask, (mask & value));
}
void st25r3916_modify_reg(
FuriHalSpiBusHandle* handle,
uint8_t reg,
uint8_t clr_mask,
uint8_t set_mask) {
furi_assert(handle);
uint8_t reg_val = 0;
uint8_t new_val = 0;
st25r3916_read_reg(handle, reg, &reg_val);
new_val = (reg_val & ~clr_mask) | set_mask;
if(new_val != reg_val) {
st25r3916_write_reg(handle, reg, new_val);
}
}
void st25r3916_change_test_reg_bits(
FuriHalSpiBusHandle* handle,
uint8_t reg,
uint8_t mask,
uint8_t value) {
furi_assert(handle);
uint8_t reg_val = 0;
uint8_t new_val = 0;
st25r3916_read_test_reg(handle, reg, &reg_val);
new_val = (reg_val & ~mask) | (mask & value);
if(new_val != reg_val) {
st25r3916_write_test_reg(handle, reg, new_val);
}
}
bool st25r3916_check_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t mask, uint8_t val) {
furi_assert(handle);
uint8_t reg_val = 0;
st25r3916_read_reg(handle, reg, &reg_val);
return ((reg_val & mask) == val);
}

1144
lib/drivers/st25r3916_reg.h Normal file

File diff suppressed because it is too large Load Diff