Skip to content

Commit f1d8ada

Browse files
committed
Merge branch 'main' into feat/lf-psk-indala
# Conflicts: # firmware/application/Makefile # firmware/application/src/app_cmd.c # firmware/application/src/rfid/nfctag/lf/lf_tag_em.c # firmware/application/src/rfid/nfctag/lf/lf_tag_em.h # firmware/application/src/rfid/nfctag/lf/protocols/t55xx.h # firmware/application/src/rfid/nfctag/tag_base_type.h # firmware/application/src/rfid/nfctag/tag_emulation.c # firmware/application/src/rfid/reader/lf/lf_reader_main.h
2 parents dd39009 + 6d30d33 commit f1d8ada

File tree

18 files changed

+1129
-32
lines changed

18 files changed

+1129
-32
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ All notable changes to this project will be documented in this file.
33
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
44

55
## [unreleased][unreleased]
6+
- Added PAC/Stanley LF protocol support: read, emulate and T55xx clone (@kevihiiin, @danieltwagner)
67
- Fix firmware application USB serial number (@taichunmin)
78
- Added ioProx LF protocol support (read, emulate and T55xx clone)
9+
- Added `hf mfu nfcimport` to import Flipper Zero `.nfc` files into MFU/NTAG emulator slots, with `--amiibo` flag for automatic PWD/PACK derivation (@fmuk)
810
- Added commands to dump and clone Mifare tags
911
- Fix bad missing tools warning (@suut)
1012
- Fix for FAST_READ command for nfc - mf0 tags

firmware/application/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ SRC_FILES += \
3737
$(PROJ_DIR)/rfid/nfctag/lf/utils/pskdemod.c \
3838
$(PROJ_DIR)/rfid/nfctag/lf/protocols/em410x.c \
3939
$(PROJ_DIR)/rfid/nfctag/lf/protocols/hidprox.c \
40+
$(PROJ_DIR)/rfid/nfctag/lf/protocols/pac.c \
4041
$(PROJ_DIR)/rfid/nfctag/lf/protocols/indala.c \
4142
$(PROJ_DIR)/rfid/nfctag/lf/protocols/ioprox.c \
4243
$(PROJ_DIR)/rfid/nfctag/lf/protocols/viking.c \
@@ -350,6 +351,7 @@ ifeq (${CURRENT_DEVICE_TYPE}, ${CHAMELEON_ULTRA})
350351
$(PROJ_DIR)/rfid/reader/lf/lf_reader_main.c \
351352
$(PROJ_DIR)/rfid/reader/lf/lf_t55xx_data.c \
352353
$(PROJ_DIR)/rfid/reader/lf/lf_hidprox_data.c \
354+
$(PROJ_DIR)/rfid/reader/lf/lf_pac_data.c \
353355
$(PROJ_DIR)/rfid/reader/lf/lf_ioprox_data.c \
354356
$(PROJ_DIR)/rfid/reader/lf/lf_viking_data.c \
355357
$(PROJ_DIR)/rfid/reader/lf/lf_psk_reader.c \

firmware/application/src/app_cmd.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,15 @@ static data_frame_tx_t *cmd_processor_viking_scan(uint16_t cmd, uint16_t status,
809809
return data_frame_make(cmd, STATUS_LF_TAG_OK, sizeof(card_buffer), card_buffer);
810810
}
811811

812+
static data_frame_tx_t *cmd_processor_pac_scan(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
813+
uint8_t card_id[8] = {0x00};
814+
status = scan_pac(card_id);
815+
if (status != STATUS_LF_TAG_OK) {
816+
return data_frame_make(cmd, status, 0, NULL);
817+
}
818+
return data_frame_make(cmd, STATUS_LF_TAG_OK, sizeof(card_id), card_id);
819+
}
820+
812821
static data_frame_tx_t *cmd_processor_viking_write_to_t55xx(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
813822
typedef struct {
814823
uint8_t id[4];
@@ -824,6 +833,20 @@ static data_frame_tx_t *cmd_processor_viking_write_to_t55xx(uint16_t cmd, uint16
824833
return data_frame_make(cmd, status, 0, NULL);
825834
}
826835

836+
static data_frame_tx_t *cmd_processor_pac_write_to_t55xx(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
837+
typedef struct {
838+
uint8_t id[LF_PAC_TAG_ID_SIZE];
839+
uint8_t new_key[4];
840+
uint8_t old_keys[4];
841+
} PACKED payload_t;
842+
payload_t *payload = (payload_t *)data;
843+
if (length < sizeof(payload_t) || (length - offsetof(payload_t, old_keys)) % sizeof(payload->old_keys) != 0) {
844+
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
845+
}
846+
status = write_pac_to_t55xx(payload->id, payload->new_key, payload->old_keys, (length - offsetof(payload_t, old_keys)) / sizeof(payload->old_keys));
847+
return data_frame_make(cmd, status, 0, NULL);
848+
}
849+
827850
static data_frame_tx_t *cmd_processor_indala_scan(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
828851
uint8_t card_buffer[LF_INDALA_TAG_ID_SIZE] = {0x00};
829852
status = scan_indala(card_buffer);
@@ -1102,6 +1125,26 @@ static data_frame_tx_t *cmd_processor_viking_get_emu_id(uint16_t cmd, uint16_t s
11021125
return data_frame_make(cmd, STATUS_SUCCESS, LF_VIKING_TAG_ID_SIZE, buffer->buffer);
11031126
}
11041127

1128+
static data_frame_tx_t *cmd_processor_pac_set_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
1129+
if (length != LF_PAC_TAG_ID_SIZE) {
1130+
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
1131+
}
1132+
tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_PAC);
1133+
memcpy(buffer->buffer, data, LF_PAC_TAG_ID_SIZE);
1134+
tag_emulation_load_by_buffer(TAG_TYPE_PAC, false);
1135+
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
1136+
}
1137+
1138+
static data_frame_tx_t *cmd_processor_pac_get_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
1139+
tag_slot_specific_type_t tag_types;
1140+
tag_emulation_get_specific_types_by_slot(tag_emulation_get_slot(), &tag_types);
1141+
if (tag_types.tag_lf != TAG_TYPE_PAC) {
1142+
return data_frame_make(cmd, STATUS_PAR_ERR, 0, data);
1143+
}
1144+
tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_PAC);
1145+
return data_frame_make(cmd, STATUS_SUCCESS, LF_PAC_TAG_ID_SIZE, buffer->buffer);
1146+
}
1147+
11051148
static data_frame_tx_t *cmd_processor_indala_set_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
11061149
if (length != LF_INDALA_TAG_ID_SIZE) {
11071150
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
@@ -1965,6 +2008,8 @@ static cmd_data_map_t m_data_cmd_map[] = {
19652008
{ DATA_CMD_VIKING_WRITE_TO_T55XX, before_reader_run, cmd_processor_viking_write_to_t55xx, NULL },
19662009
{ DATA_CMD_IOPROX_SCAN, before_reader_run, cmd_processor_ioprox_scan, NULL },
19672010
{ DATA_CMD_IOPROX_WRITE_TO_T55XX, before_reader_run, cmd_processor_ioprox_write_to_t55xx, NULL },
2011+
{ DATA_CMD_PAC_SCAN, before_reader_run, cmd_processor_pac_scan, NULL },
2012+
{ DATA_CMD_PAC_WRITE_TO_T55XX, before_reader_run, cmd_processor_pac_write_to_t55xx, NULL },
19682013
{ DATA_CMD_INDALA_SCAN, before_reader_run, cmd_processor_indala_scan, NULL },
19692014
{ DATA_CMD_INDALA_WRITE_TO_T55XX, before_reader_run, cmd_processor_indala_write_to_t55xx, NULL },
19702015
{ DATA_CMD_ADC_GENERIC_READ, before_reader_run, cmd_processor_generic_read, NULL },
@@ -2032,6 +2077,8 @@ static cmd_data_map_t m_data_cmd_map[] = {
20322077
{ DATA_CMD_IOPROX_GET_EMU_ID, NULL, cmd_processor_ioprox_get_emu_id, NULL },
20332078
{ DATA_CMD_VIKING_SET_EMU_ID, NULL, cmd_processor_viking_set_emu_id, NULL },
20342079
{ DATA_CMD_VIKING_GET_EMU_ID, NULL, cmd_processor_viking_get_emu_id, NULL },
2080+
{ DATA_CMD_PAC_SET_EMU_ID, NULL, cmd_processor_pac_set_emu_id, NULL },
2081+
{ DATA_CMD_PAC_GET_EMU_ID, NULL, cmd_processor_pac_get_emu_id, NULL },
20352082
{ DATA_CMD_INDALA_SET_EMU_ID, NULL, cmd_processor_indala_set_emu_id, NULL },
20362083
{ DATA_CMD_INDALA_GET_EMU_ID, NULL, cmd_processor_indala_get_emu_id, NULL },
20372084
};

firmware/application/src/data_cmd.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494
#define DATA_CMD_EM410X_ELECTRA_WRITE_TO_T55XX (3006)
9595
#define DATA_CMD_HIDPROX_SCAN (3002)
9696
#define DATA_CMD_HIDPROX_WRITE_TO_T55XX (3003)
97+
#define DATA_CMD_PAC_SCAN (3014)
98+
#define DATA_CMD_PAC_WRITE_TO_T55XX (3015)
9799
#define DATA_CMD_VIKING_SCAN (3004)
98100
#define DATA_CMD_VIKING_WRITE_TO_T55XX (3005)
99101
#define DATA_CMD_ADC_GENERIC_READ (3009)
@@ -173,6 +175,8 @@
173175
#define DATA_CMD_HIDPROX_GET_EMU_ID (5003)
174176
#define DATA_CMD_VIKING_SET_EMU_ID (5004)
175177
#define DATA_CMD_VIKING_GET_EMU_ID (5005)
178+
#define DATA_CMD_PAC_SET_EMU_ID (5006)
179+
#define DATA_CMD_PAC_GET_EMU_ID (5007)
176180
#define DATA_CMD_IOPROX_SET_EMU_ID (5008)
177181
#define DATA_CMD_IOPROX_GET_EMU_ID (5009)
178182
#define DATA_CMD_INDALA_SET_EMU_ID (5026)

firmware/application/src/rfid/nfctag/lf/lf_tag_em.c

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
#include "fds_util.h"
88
#include "nrf_gpio.h"
99
#include "nrfx_gpiote.h"
10+
#include "nrf_soc.h"
1011
#include "nrfx_lpcomp.h"
1112
#include "nrfx_ppi.h"
1213
#include "nrfx_pwm.h"
1314
#include "nrfx_timer.h"
1415
#include "protocols/em410x.h"
1516
#include "protocols/hidprox.h"
16-
#include "protocols/indala.h"
1717
#include "protocols/ioprox.h"
18+
#include "protocols/pac.h"
19+
#include "protocols/indala.h"
1820
#include "protocols/viking.h"
1921
#include "syssleep.h"
2022
#include "tag_emulation.h"
@@ -361,6 +363,23 @@ static void psk_build_pattern(const nrf_pwm_sequence_t *seq) {
361363
}
362364

363365
static void lf_sense_enable(void) {
366+
// PWM bit timing divides HFCLK by a fixed ratio. On HFINT (64 MHz RC,
367+
// ±1.5% at 25°C after factory trim, wider over temperature) this gives a
368+
// chip-to-chip spread that NRZ readers — which see cumulative error across
369+
// runs of same-polarity bits with no intra-run resync — reject even when
370+
// Manchester/FSK readers don't. Holding HFXO brings the PWM clock to
371+
// ±40 ppm. We can't lock to the reader's carrier (tag-mode antenna taps
372+
// on this board are envelope-only), so this is as good as it gets.
373+
//
374+
// Paired release in lf_sense_disable(). SD reference-counts HFXO requests,
375+
// so this coexists with BLE. Both functions run from thread context
376+
// (tag_mode_enter/tag_emulation_sense_end) where SVCs are safe.
377+
sd_clock_hfclk_request();
378+
uint32_t hfclk_running = 0;
379+
while (!hfclk_running) {
380+
sd_clock_hfclk_is_running(&hfclk_running);
381+
}
382+
364383
lpcomp_init();
365384
if (is_psk_tag_type(m_tag_type)) {
366385
psk_timer_init();
@@ -381,6 +400,7 @@ static void lf_sense_disable(void) {
381400
nrfx_lpcomp_uninit();
382401
m_pwm_seq = NULL;
383402
m_is_lf_emulating = false;
403+
sd_clock_hfclk_release();
384404
}
385405

386406
static enum {
@@ -464,6 +484,15 @@ int lf_tag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) {
464484
return LF_VIKING_TAG_ID_SIZE;
465485
}
466486

487+
if (type == TAG_TYPE_PAC && buffer->length >= LF_PAC_TAG_ID_SIZE) {
488+
m_tag_type = type;
489+
void *codec = pac.alloc();
490+
m_pwm_seq = pac.modulator(codec, buffer->buffer);
491+
pac.free(codec);
492+
NRF_LOG_INFO("load lf pac data finish.");
493+
return LF_PAC_TAG_ID_SIZE;
494+
}
495+
467496
// PSK protocols: build PWM sequence then convert to timer pattern
468497
if (type == TAG_TYPE_INDALA && buffer->length >= LF_INDALA_TAG_ID_SIZE) {
469498
m_tag_type = type;
@@ -474,6 +503,7 @@ int lf_tag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) {
474503
NRF_LOG_INFO("load lf indala data finish.");
475504
return LF_INDALA_TAG_ID_SIZE;
476505
}
506+
477507
NRF_LOG_ERROR("no valid data exists in buffer for tag type: %d.", type);
478508
return 0;
479509
}
@@ -528,15 +558,6 @@ int lf_tag_viking_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffe
528558
return m_tag_type == TAG_TYPE_VIKING ? LF_VIKING_TAG_ID_SIZE : 0;
529559
}
530560

531-
/** @brief Id card deposit card number before callback
532-
* @param type Refined tag type
533-
* @param buffer Data buffer
534-
* @return The length of the data that needs to be saved is that it does not save when 0
535-
*/
536-
int lf_tag_indala_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) {
537-
return m_tag_type == TAG_TYPE_INDALA ? LF_INDALA_TAG_ID_SIZE : 0;
538-
}
539-
540561
bool lf_tag_data_factory(uint8_t slot, tag_specific_type_t tag_type, uint8_t *tag_id, uint16_t length) {
541562
// write data to flash
542563
tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type);
@@ -606,6 +627,20 @@ bool lf_tag_viking_data_factory(uint8_t slot, tag_specific_type_t tag_type) {
606627
return lf_tag_data_factory(slot, tag_type, tag_id, sizeof(tag_id));
607628
}
608629

630+
int lf_tag_pac_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) {
631+
return m_tag_type == TAG_TYPE_PAC ? LF_PAC_TAG_ID_SIZE : 0;
632+
}
633+
634+
bool lf_tag_pac_data_factory(uint8_t slot, tag_specific_type_t tag_type) {
635+
// default id: 8 ASCII bytes
636+
uint8_t tag_id[8] = {'C', 'A', 'R', 'D', '0', '0', '0', '1'};
637+
return lf_tag_data_factory(slot, tag_type, tag_id, sizeof(tag_id));
638+
}
639+
640+
int lf_tag_indala_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) {
641+
return m_tag_type == TAG_TYPE_INDALA ? LF_INDALA_TAG_ID_SIZE : 0;
642+
}
643+
609644
/** @brief Id card deposit card number before callback
610645
* @param slot Card slot number
611646
* @param tag_type Refined tag type

firmware/application/src/rfid/nfctag/lf/lf_tag_em.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LF_IOPROX_TAG_ID_SIZE 16
1111
#define LF_HIDPROX_TAG_ID_SIZE 13
1212
#define LF_VIKING_TAG_ID_SIZE 4
13+
#define LF_PAC_TAG_ID_SIZE 8
1314
#define LF_INDALA_TAG_ID_SIZE 8
1415

1516
void lf_tag_125khz_sense_switch(bool enable);
@@ -22,6 +23,8 @@ int lf_tag_ioprox_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffe
2223
bool lf_tag_ioprox_data_factory(uint8_t slot, tag_specific_type_t tag_type);
2324
int lf_tag_viking_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer);
2425
bool lf_tag_viking_data_factory(uint8_t slot, tag_specific_type_t tag_type);
26+
int lf_tag_pac_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer);
27+
bool lf_tag_pac_data_factory(uint8_t slot, tag_specific_type_t tag_type);
2528
int lf_tag_indala_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer);
2629
bool lf_tag_indala_data_factory(uint8_t slot, tag_specific_type_t tag_type);
2730
bool is_lf_field_exists(void);

0 commit comments

Comments
 (0)