Skip to content

Commit cb7faee

Browse files
committed
feat(nfc): add RF configuration service
1 parent d836cb1 commit cb7faee

2 files changed

Lines changed: 218 additions & 0 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* @file nfc_rf.h
3+
* @brief RF layer configuration (Phase 2): bitrate, modulation, parity, timing.
4+
*/
5+
#ifndef NFC_RF_H
6+
#define NFC_RF_H
7+
8+
#include <stdint.h>
9+
#include <stdbool.h>
10+
#include <stddef.h>
11+
#include "highboy_nfc_error.h"
12+
13+
typedef enum {
14+
NFC_RF_TECH_A = 0,
15+
NFC_RF_TECH_B,
16+
NFC_RF_TECH_F,
17+
NFC_RF_TECH_V,
18+
} nfc_rf_tech_t;
19+
20+
typedef enum {
21+
NFC_RF_BR_106 = 0,
22+
NFC_RF_BR_212,
23+
NFC_RF_BR_424,
24+
NFC_RF_BR_848,
25+
NFC_RF_BR_V_LOW, /* NFC-V low data rate (6.62 kbps RX / 1.65 kbps TX) */
26+
NFC_RF_BR_V_HIGH, /* NFC-V high data rate (26.48 kbps) */
27+
} nfc_rf_bitrate_t;
28+
29+
typedef struct {
30+
nfc_rf_tech_t tech;
31+
nfc_rf_bitrate_t tx_rate;
32+
nfc_rf_bitrate_t rx_rate;
33+
uint8_t am_mod_percent; /* 0 = keep current */
34+
bool tx_parity; /* ISO14443A: generate parity */
35+
bool rx_raw_parity; /* ISO14443A: receive parity bits in FIFO (no check) */
36+
uint32_t guard_time_us; /* optional delay before TX */
37+
uint32_t fdt_min_us; /* optional minimum FDT */
38+
bool validate_fdt; /* log warning if FDT < min */
39+
} nfc_rf_config_t;
40+
41+
/** Apply RF configuration for a given technology. */
42+
hb_nfc_err_t nfc_rf_apply(const nfc_rf_config_t* cfg);
43+
44+
/** Set TX/RX bitrate (A/B/F). */
45+
hb_nfc_err_t nfc_rf_set_bitrate(nfc_rf_bitrate_t tx, nfc_rf_bitrate_t rx);
46+
47+
/** Set raw BIT_RATE register (advanced use). */
48+
hb_nfc_err_t nfc_rf_set_bitrate_raw(uint8_t value);
49+
50+
/** Set AM modulation index in percent (5..40). */
51+
hb_nfc_err_t nfc_rf_set_am_modulation(uint8_t percent);
52+
53+
/** ISO14443A parity control. */
54+
hb_nfc_err_t nfc_rf_set_parity(bool tx_parity, bool rx_raw_parity);
55+
56+
/** Configure timing (guard time + FDT validation). */
57+
void nfc_rf_set_timing(uint32_t guard_time_us, uint32_t fdt_min_us, bool validate_fdt);
58+
59+
/** Returns last measured FDT in microseconds. */
60+
uint32_t nfc_rf_get_last_fdt_us(void);
61+
62+
#endif
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/**
2+
* @file nfc_rf.c
3+
* @brief RF layer configuration (Phase 2).
4+
*/
5+
#include "nfc_rf.h"
6+
7+
#include "st25r3916_core.h"
8+
#include "st25r3916_reg.h"
9+
#include "st25r3916_cmd.h"
10+
#include "hb_nfc_spi.h"
11+
#include "nfc_poller.h"
12+
13+
#include "esp_log.h"
14+
15+
static const char* TAG = "nfc_rf";
16+
17+
static uint8_t bitrate_code(nfc_rf_bitrate_t br)
18+
{
19+
switch (br) {
20+
case NFC_RF_BR_106: return 0x00;
21+
case NFC_RF_BR_212: return 0x01;
22+
case NFC_RF_BR_424: return 0x02;
23+
case NFC_RF_BR_848: return 0x03;
24+
default: return 0xFF;
25+
}
26+
}
27+
28+
hb_nfc_err_t nfc_rf_set_bitrate(nfc_rf_bitrate_t tx, nfc_rf_bitrate_t rx)
29+
{
30+
uint8_t txc = bitrate_code(tx);
31+
uint8_t rxc = bitrate_code(rx);
32+
if (txc == 0xFF || rxc == 0xFF) return HB_NFC_ERR_PARAM;
33+
34+
uint8_t reg = (uint8_t)((txc << 4) | (rxc & 0x03U));
35+
return hb_spi_reg_write(REG_BIT_RATE, reg);
36+
}
37+
38+
hb_nfc_err_t nfc_rf_set_bitrate_raw(uint8_t value)
39+
{
40+
return hb_spi_reg_write(REG_BIT_RATE, value);
41+
}
42+
43+
static uint8_t am_mod_code_from_percent(uint8_t percent)
44+
{
45+
static const uint8_t tbl_percent[16] = {
46+
5, 6, 7, 8, 9, 10, 11, 12,
47+
13, 14, 15, 17, 19, 22, 26, 40
48+
};
49+
50+
uint8_t best = 0;
51+
uint8_t best_diff = 0xFF;
52+
for (uint8_t i = 0; i < 16; i++) {
53+
uint8_t p = tbl_percent[i];
54+
uint8_t diff = (p > percent) ? (p - percent) : (percent - p);
55+
if (diff < best_diff) {
56+
best_diff = diff;
57+
best = i;
58+
}
59+
}
60+
return best;
61+
}
62+
63+
hb_nfc_err_t nfc_rf_set_am_modulation(uint8_t percent)
64+
{
65+
if (percent == 0) return HB_NFC_OK; /* keep current */
66+
67+
uint8_t mod = am_mod_code_from_percent(percent);
68+
uint8_t reg = 0;
69+
if (hb_spi_reg_read(REG_TX_DRIVER, &reg) != HB_NFC_OK) return HB_NFC_ERR_INTERNAL;
70+
71+
reg = (uint8_t)((reg & 0x0FU) | ((mod & 0x0FU) << 4));
72+
return hb_spi_reg_write(REG_TX_DRIVER, reg);
73+
}
74+
75+
hb_nfc_err_t nfc_rf_set_parity(bool tx_parity, bool rx_raw_parity)
76+
{
77+
uint8_t v = 0;
78+
if (hb_spi_reg_read(REG_ISO14443A, &v) != HB_NFC_OK) return HB_NFC_ERR_INTERNAL;
79+
80+
if (tx_parity) v &= (uint8_t)~ISO14443A_NO_TX_PAR;
81+
else v |= ISO14443A_NO_TX_PAR;
82+
83+
if (rx_raw_parity) v |= ISO14443A_NO_RX_PAR;
84+
else v &= (uint8_t)~ISO14443A_NO_RX_PAR;
85+
86+
return hb_spi_reg_write(REG_ISO14443A, v);
87+
}
88+
89+
void nfc_rf_set_timing(uint32_t guard_time_us, uint32_t fdt_min_us, bool validate_fdt)
90+
{
91+
nfc_poller_set_timing(guard_time_us, fdt_min_us, validate_fdt);
92+
}
93+
94+
uint32_t nfc_rf_get_last_fdt_us(void)
95+
{
96+
return nfc_poller_get_last_fdt_us();
97+
}
98+
99+
hb_nfc_err_t nfc_rf_apply(const nfc_rf_config_t* cfg)
100+
{
101+
if (!cfg) return HB_NFC_ERR_PARAM;
102+
103+
hb_nfc_err_t err = HB_NFC_OK;
104+
105+
switch (cfg->tech) {
106+
case NFC_RF_TECH_A:
107+
err = st25r_set_mode_nfca();
108+
if (err != HB_NFC_OK) return err;
109+
err = nfc_rf_set_bitrate(cfg->tx_rate, cfg->rx_rate);
110+
if (err != HB_NFC_OK) return err;
111+
err = nfc_rf_set_parity(cfg->tx_parity, cfg->rx_raw_parity);
112+
if (err != HB_NFC_OK) return err;
113+
break;
114+
case NFC_RF_TECH_B:
115+
hb_spi_reg_write(REG_MODE, MODE_POLL_NFCB);
116+
hb_spi_reg_write(REG_ISO14443B, 0x00U);
117+
hb_spi_reg_write(REG_ISO14443B_FELICA, 0x00U);
118+
err = nfc_rf_set_bitrate(cfg->tx_rate, cfg->rx_rate);
119+
if (err != HB_NFC_OK) return err;
120+
break;
121+
case NFC_RF_TECH_F:
122+
hb_spi_reg_write(REG_MODE, MODE_POLL_NFCF);
123+
hb_spi_reg_write(REG_ISO14443B_FELICA, 0x00U);
124+
err = nfc_rf_set_bitrate(cfg->tx_rate, cfg->rx_rate);
125+
if (err != HB_NFC_OK) return err;
126+
break;
127+
case NFC_RF_TECH_V:
128+
hb_spi_reg_write(REG_MODE, MODE_POLL_NFCV);
129+
hb_spi_reg_write(REG_ISO14443B, 0x00U);
130+
hb_spi_reg_write(REG_ISO14443B_FELICA, 0x00U);
131+
if (cfg->tx_rate == NFC_RF_BR_V_HIGH && cfg->rx_rate == NFC_RF_BR_V_HIGH) {
132+
err = nfc_rf_set_bitrate_raw(0x00U); /* NFC-V high data rate */
133+
} else if (cfg->tx_rate == NFC_RF_BR_V_LOW && cfg->rx_rate == NFC_RF_BR_V_LOW) {
134+
err = nfc_rf_set_bitrate_raw(0x01U); /* NFC-V low data rate (best-effort) */
135+
} else {
136+
err = HB_NFC_ERR_PARAM;
137+
}
138+
if (err != HB_NFC_OK) return err;
139+
break;
140+
default:
141+
return HB_NFC_ERR_PARAM;
142+
}
143+
144+
if (cfg->am_mod_percent > 0) {
145+
err = nfc_rf_set_am_modulation(cfg->am_mod_percent);
146+
if (err != HB_NFC_OK) return err;
147+
}
148+
149+
nfc_rf_set_timing(cfg->guard_time_us, cfg->fdt_min_us, cfg->validate_fdt);
150+
151+
ESP_LOGI(TAG, "RF cfg: tech=%d tx=%d rx=%d am=%u%% guard=%uus fdt=%uus",
152+
(int)cfg->tech, (int)cfg->tx_rate, (int)cfg->rx_rate,
153+
cfg->am_mod_percent, (unsigned)cfg->guard_time_us,
154+
(unsigned)cfg->fdt_min_us);
155+
return HB_NFC_OK;
156+
}

0 commit comments

Comments
 (0)