From 098e0a914b206900f7ea7ae7265486c4349ab644 Mon Sep 17 00:00:00 2001 From: TeCHiScy <741195+TeCHiScy@users.noreply.github.com> Date: Mon, 4 Aug 2025 13:01:53 +0800 Subject: [PATCH] feat: add lf HIDProx read, t55xx write, emulate function (#267) * feat: add lf HIDProx read, t55xx write, emulate function code quaility: - consistance: simulation -> emulation, label -> tag - machine translated unreadable comments are made native logic: - newly added cli command includes: `lf hid prox read`, `lf hid prox write`, `lf hid prox econfig` - machester demodulator is simplified - various wiegand formats of HIDProx are supported - goertzel algorithm is used in HIDProx FSK demod - lf read is refactored using stream/feed pattern to boost scan speed - t55xx write is refactored to share same logic between em410x & HIDProx - lf emulating is refactored to use PWM peripheral, allowing more card type to be added closes: #212, #210 * chore: remove not implemented wiegand format comments * fix: build ci * fix: build ci * fix: build ci * fix: build ci --- firmware/application/Makefile | 10 +- firmware/application/src/app_cmd.c | 72 +- firmware/application/src/app_main.c | 8 +- firmware/application/src/app_status.h | 2 + firmware/application/src/bsp/bsp_delay.c | 14 +- firmware/application/src/bsp/bsp_delay.h | 1 - firmware/application/src/data_cmd.h | 4 + firmware/application/src/rfid/byte_mirror.c | 37 + firmware/application/src/rfid/byte_mirror.h | 17 + firmware/application/src/rfid/hex_utils.c | 28 +- firmware/application/src/rfid/hex_utils.h | 5 +- .../application/src/rfid/nfctag/hf/nfc_14a.c | 52 +- .../src/rfid/nfctag/hf/nfc_mf0_ntag.c | 4 +- .../application/src/rfid/nfctag/hf/nfc_mf1.c | 10 +- .../src/rfid/nfctag/lf/lf_tag_em.c | 489 ++++------ .../src/rfid/nfctag/lf/lf_tag_em.h | 22 +- .../src/rfid/nfctag/lf/protocols/em410x.c | 280 ++++++ .../src/rfid/nfctag/lf/protocols/em410x.h | 12 + .../src/rfid/nfctag/lf/protocols/hidprox.c | 239 +++++ .../src/rfid/nfctag/lf/protocols/hidprox.h | 33 + .../src/rfid/nfctag/lf/protocols/protocols.h | 31 + .../src/rfid/nfctag/lf/protocols/t55xx.h | 65 ++ .../src/rfid/nfctag/lf/protocols/wiegand.c | 856 ++++++++++++++++++ .../src/rfid/nfctag/lf/protocols/wiegand.h | 88 ++ .../rfid/nfctag/lf/utils/circular_buffer.c | 51 ++ .../rfid/nfctag/lf/utils/circular_buffer.h | 28 + .../src/rfid/nfctag/lf/utils/fskdemod.c | 46 + .../src/rfid/nfctag/lf/utils/fskdemod.h | 25 + .../src/rfid/nfctag/lf/utils/manchester.c | 51 ++ .../src/rfid/nfctag/lf/utils/manchester.h | 15 + .../src/rfid/nfctag/tag_base_type.h | 61 +- .../src/rfid/nfctag/tag_emulation.c | 290 +++--- .../src/rfid/nfctag/tag_emulation.h | 59 +- .../src/rfid/nfctag/tag_persistence.c | 3 +- .../src/rfid/nfctag/tag_persistence.h | 2 +- .../application/src/rfid/reader/hf/rc522.h | 2 +- .../src/rfid/reader/lf/data_utils.c | 110 --- .../src/rfid/reader/lf/data_utils.h | 32 - .../src/rfid/reader/lf/lf_125khz_radio.c | 300 ++++-- .../src/rfid/reader/lf/lf_125khz_radio.h | 5 +- .../src/rfid/reader/lf/lf_em410x_data.c | 435 ++------- .../src/rfid/reader/lf/lf_em410x_data.h | 28 +- .../src/rfid/reader/lf/lf_hidprox_data.c | 71 ++ .../src/rfid/reader/lf/lf_hidprox_data.h | 19 + .../src/rfid/reader/lf/lf_reader_data.c | 41 +- .../src/rfid/reader/lf/lf_reader_data.h | 10 +- .../src/rfid/reader/lf/lf_reader_main.c | 168 ++-- .../src/rfid/reader/lf/lf_reader_main.h | 21 +- .../src/rfid/reader/lf/lf_t55xx_data.c | 290 ++---- .../src/rfid/reader/lf/lf_t55xx_data.h | 20 - firmware/application/src/rfid_main.c | 8 +- firmware/application/src/rfid_main.h | 19 +- firmware/application/src/utils/syssleep.c | 4 +- .../block_dev/empty/nrf_block_dev_empty.c | 8 +- .../block_dev/qspi/nrf_block_dev_qspi.c | 2 +- .../block_dev/ram/nrf_block_dev_ram.c | 6 +- software/script/chameleon_cli_unit.py | 245 ++++- software/script/chameleon_cmd.py | 73 +- software/script/chameleon_enum.py | 158 +++- software/src/HardnestedRecovery/cmdhfmfhard.c | 2 +- 60 files changed, 3364 insertions(+), 1723 deletions(-) create mode 100644 firmware/application/src/rfid/byte_mirror.c create mode 100644 firmware/application/src/rfid/byte_mirror.h create mode 100644 firmware/application/src/rfid/nfctag/lf/protocols/em410x.c create mode 100644 firmware/application/src/rfid/nfctag/lf/protocols/em410x.h create mode 100644 firmware/application/src/rfid/nfctag/lf/protocols/hidprox.c create mode 100644 firmware/application/src/rfid/nfctag/lf/protocols/hidprox.h create mode 100644 firmware/application/src/rfid/nfctag/lf/protocols/protocols.h create mode 100644 firmware/application/src/rfid/nfctag/lf/protocols/t55xx.h create mode 100644 firmware/application/src/rfid/nfctag/lf/protocols/wiegand.c create mode 100644 firmware/application/src/rfid/nfctag/lf/protocols/wiegand.h create mode 100644 firmware/application/src/rfid/nfctag/lf/utils/circular_buffer.c create mode 100644 firmware/application/src/rfid/nfctag/lf/utils/circular_buffer.h create mode 100644 firmware/application/src/rfid/nfctag/lf/utils/fskdemod.c create mode 100644 firmware/application/src/rfid/nfctag/lf/utils/fskdemod.h create mode 100644 firmware/application/src/rfid/nfctag/lf/utils/manchester.c create mode 100644 firmware/application/src/rfid/nfctag/lf/utils/manchester.h delete mode 100644 firmware/application/src/rfid/reader/lf/data_utils.c delete mode 100644 firmware/application/src/rfid/reader/lf/data_utils.h create mode 100644 firmware/application/src/rfid/reader/lf/lf_hidprox_data.c create mode 100644 firmware/application/src/rfid/reader/lf/lf_hidprox_data.h delete mode 100644 firmware/application/src/rfid/reader/lf/lf_t55xx_data.h diff --git a/firmware/application/Makefile b/firmware/application/Makefile index b6596af..a9912fb 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -18,6 +18,7 @@ SRC_FILES += \ $(PROJ_DIR)/bsp/bsp_delay.c \ $(PROJ_DIR)/bsp/bsp_time.c \ $(PROJ_DIR)/bsp/bsp_wdt.c \ + $(PROJ_DIR)/rfid/byte_mirror.c \ $(PROJ_DIR)/rfid/crc_utils.c \ $(PROJ_DIR)/rfid/hex_utils.c \ $(PROJ_DIR)/rfid/mf1_crapto1.c \ @@ -30,6 +31,12 @@ SRC_FILES += \ $(PROJ_DIR)/rfid/nfctag/hf/nfc_mf1.c \ $(PROJ_DIR)/rfid/nfctag/hf/nfc_mf0_ntag.c \ $(PROJ_DIR)/rfid/nfctag/lf/lf_tag_em.c \ + $(PROJ_DIR)/rfid/nfctag/lf/utils/fskdemod.c \ + $(PROJ_DIR)/rfid/nfctag/lf/utils/circular_buffer.c \ + $(PROJ_DIR)/rfid/nfctag/lf/utils/manchester.c \ + $(PROJ_DIR)/rfid/nfctag/lf/protocols/em410x.c \ + $(PROJ_DIR)/rfid/nfctag/lf/protocols/hidprox.c \ + $(PROJ_DIR)/rfid/nfctag/lf/protocols/wiegand.c \ $(PROJ_DIR)/utils/dataframe.c \ $(PROJ_DIR)/utils/delayed_reset.c \ $(PROJ_DIR)/utils/fds_util.c \ @@ -174,6 +181,7 @@ INC_FOLDERS += \ ${PROJ_DIR}/rfid/nfctag/ \ ${PROJ_DIR}/rfid/nfctag/hf \ ${PROJ_DIR}/rfid/nfctag/lf \ + ${PROJ_DIR}/rfid/nfctag/lf/utils \ $(SDK_ROOT)/components/nfc/ndef/generic/message \ $(SDK_ROOT)/components/nfc/t2t_lib \ $(SDK_ROOT)/components/nfc/t4t_parser/hl_detection_procedure \ @@ -329,12 +337,12 @@ ifeq (${CURRENT_DEVICE_TYPE}, ${CHAMELEON_ULTRA}) SRC_FILES +=\ $(PROJ_DIR)/rfid/reader/hf/mf1_toolbox.c \ $(PROJ_DIR)/rfid/reader/hf/rc522.c \ - $(PROJ_DIR)/rfid/reader/lf/data_utils.c \ $(PROJ_DIR)/rfid/reader/lf/lf_125khz_radio.c \ $(PROJ_DIR)/rfid/reader/lf/lf_em410x_data.c \ $(PROJ_DIR)/rfid/reader/lf/lf_reader_data.c \ $(PROJ_DIR)/rfid/reader/lf/lf_reader_main.c \ $(PROJ_DIR)/rfid/reader/lf/lf_t55xx_data.c \ + $(PROJ_DIR)/rfid/reader/lf/lf_hidprox_data.c \ INC_FOLDERS +=\ ${PROJ_DIR}/rfid/reader/ \ diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index b9d83e6..d4ba55e 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -5,7 +5,6 @@ #include "rfid_main.h" #include "ble_main.h" #include "syssleep.h" -#include "tag_emulation.h" #include "hex_utils.h" #include "data_cmd.h" #include "app_cmd.h" @@ -603,17 +602,32 @@ static data_frame_tx_t *cmd_processor_mf1_manipulate_value_block(uint16_t cmd, u } static data_frame_tx_t *cmd_processor_em410x_scan(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { - uint8_t id_buffer[5] = { 0x00 }; - status = PcdScanEM410X(id_buffer); + uint8_t card_buffer[16] = { 0x00 }; + status = scan_em410x(card_buffer); if (status != STATUS_LF_TAG_OK) { return data_frame_make(cmd, status, 0, NULL); } - return data_frame_make(cmd, STATUS_LF_TAG_OK, sizeof(id_buffer), id_buffer); + return data_frame_make(cmd, STATUS_LF_TAG_OK, sizeof(card_buffer), card_buffer); } -static data_frame_tx_t *cmd_processor_em410x_write_to_t55XX(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { +static data_frame_tx_t *cmd_processor_em410x_write_to_t55xx(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { typedef struct { uint8_t id[5]; + uint8_t new_key[4]; + uint8_t old_keys[4]; // we can have more than one... struct just to compute offsets with min 1 key + } PACKED payload_t; + payload_t *payload = (payload_t *)data; + if (length < sizeof(payload_t) || (length - offsetof(payload_t, old_keys)) % sizeof(payload->old_keys) != 0) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); + } + + status = write_em410x_to_t55xx(payload->id, payload->new_key, payload->old_keys, (length - offsetof(payload_t, old_keys)) / sizeof(payload->old_keys)); + return data_frame_make(cmd, status, 0, NULL); +} + +static data_frame_tx_t *cmd_processor_hidprox_write_to_t55xx(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + typedef struct { + uint8_t id[13]; uint8_t old_key[4]; uint8_t new_keys[4]; // we can have more than one... struct just to compute offsets with min 1 key } PACKED payload_t; @@ -622,10 +636,24 @@ static data_frame_tx_t *cmd_processor_em410x_write_to_t55XX(uint16_t cmd, uint16 return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); } - status = PcdWriteT55XX(payload->id, payload->old_key, payload->new_keys, (length - offsetof(payload_t, new_keys)) / sizeof(payload->new_keys)); + uint8_t format = payload->id[0]; + uint32_t fc = bytes_to_num(payload->id+1, 4); + uint64_t cn = payload->id[5]; + cn = (cn << 32) | (bytes_to_num(payload->id+6, 4)); + uint32_t il = payload->id[10]; + uint32_t oem = bytes_to_num(payload->id+11, 2); + status = write_hidprox_to_t55xx(format, fc, cn, il, oem, payload->old_key, payload->new_keys, (length - offsetof(payload_t, new_keys)) / sizeof(payload->new_keys)); return data_frame_make(cmd, status, 0, NULL); } +static data_frame_tx_t *cmd_processor_hidprox_scan(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + uint8_t card_data[16] = { 0x00 }; + status = scan_hidprox(card_data, data[0]); + if (status != STATUS_LF_TAG_OK) { + return data_frame_make(cmd, status, 0, NULL); + } + return data_frame_make(cmd, STATUS_LF_TAG_OK, sizeof(card_data), card_data); +} #endif @@ -767,12 +795,30 @@ static data_frame_tx_t *cmd_processor_em410x_get_emu_id(uint16_t cmd, uint16_t s tag_slot_specific_type_t tag_types; tag_emulation_get_specific_types_by_slot(tag_emulation_get_slot(), &tag_types); if (tag_types.tag_lf != TAG_TYPE_EM410X) { - return data_frame_make(cmd, STATUS_PAR_ERR, 0, data); // no data in slot, don't send garbage + return data_frame_make(cmd, STATUS_PAR_ERR, 0, data); // no data in slot, don't send garbage } tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_EM410X); - uint8_t responseData[LF_EM410X_TAG_ID_SIZE]; - memcpy(responseData, buffer->buffer, LF_EM410X_TAG_ID_SIZE); - return data_frame_make(cmd, STATUS_SUCCESS, LF_EM410X_TAG_ID_SIZE, responseData); + return data_frame_make(cmd, STATUS_SUCCESS, LF_EM410X_TAG_ID_SIZE, buffer->buffer); +} + +static data_frame_tx_t *cmd_processor_hidprox_set_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + if (length != LF_HIDPROX_TAG_ID_SIZE) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); + } + tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_HID_PROX); + memcpy(buffer->buffer, data, LF_HIDPROX_TAG_ID_SIZE); + tag_emulation_load_by_buffer(TAG_TYPE_HID_PROX, false); + return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL); +} + +static data_frame_tx_t *cmd_processor_hidprox_get_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + tag_slot_specific_type_t tag_types; + tag_emulation_get_specific_types_by_slot(tag_emulation_get_slot(), &tag_types); + if (tag_types.tag_lf != TAG_TYPE_HID_PROX) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, data); // no data in slot, don't send garbage + } + tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_HID_PROX); + return data_frame_make(cmd, STATUS_SUCCESS, LF_HIDPROX_TAG_ID_SIZE, buffer->buffer); } static nfc_tag_14a_coll_res_reference_t *get_coll_res_data(bool write) { @@ -1438,7 +1484,9 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_MF1_CHECK_KEYS_ON_BLOCK, before_hf_reader_run, cmd_processor_mf1_check_keys_on_block, after_hf_reader_run }, { DATA_CMD_EM410X_SCAN, before_reader_run, cmd_processor_em410x_scan, NULL }, - { DATA_CMD_EM410X_WRITE_TO_T55XX, before_reader_run, cmd_processor_em410x_write_to_t55XX, NULL }, + { DATA_CMD_EM410X_WRITE_TO_T55XX, before_reader_run, cmd_processor_em410x_write_to_t55xx, NULL }, + { DATA_CMD_HIDPROX_SCAN, before_reader_run, cmd_processor_hidprox_scan, NULL }, + { DATA_CMD_HIDPROX_WRITE_TO_T55XX, before_reader_run, cmd_processor_hidprox_write_to_t55xx, NULL }, #endif @@ -1476,6 +1524,8 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_MF0_NTAG_SET_WRITE_MODE, NULL, cmd_processor_mf0_ntag_set_write_mode, NULL }, { DATA_CMD_EM410X_SET_EMU_ID, NULL, cmd_processor_em410x_set_emu_id, NULL }, { DATA_CMD_EM410X_GET_EMU_ID, NULL, cmd_processor_em410x_get_emu_id, NULL }, + { DATA_CMD_HIDPROX_SET_EMU_ID, NULL, cmd_processor_hidprox_set_emu_id, NULL }, + { DATA_CMD_HIDPROX_GET_EMU_ID, NULL, cmd_processor_hidprox_get_emu_id, NULL }, }; data_frame_tx_t *cmd_processor_get_device_capabilities(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { diff --git a/firmware/application/src/app_main.c b/firmware/application/src/app_main.c index ca77335..be85917 100644 --- a/firmware/application/src/app_main.c +++ b/firmware/application/src/app_main.c @@ -363,7 +363,7 @@ static void system_off_enter(void) { // Set the reason for Reset. After restarting, you need to get this reason to avoid misjudgment from the source of wake up. sd_power_gpregret_clr(1, GPREGRET_CLEAR_VALUE_DEFAULT); sd_power_gpregret_set(1, RESET_ON_LF_FIELD_EXISTS_Msk); - // Trigger the RESET awakening system, restart the simulation process + // Trigger the RESET awakening system, restart the emulation process nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_RESET); return; }; @@ -453,7 +453,7 @@ static void check_wakeup_src(void) { } } - // It is currently the wake -up system of the simulation card event, we can make the strong lights on the field first + // It is currently the wake-up system of the emulation card event, we can make the strong lights on the field first TAG_FIELD_LED_ON(); uint8_t animation_config = settings_get_animation_config(); @@ -611,7 +611,7 @@ static void btn_fn_copy_ic_uid(void) { switch (tag_types.tag_lf) { case TAG_TYPE_EM410X: - status = PcdScanEM410X(id_buffer); + status = scan_em410x(id_buffer); if (status == STATUS_LF_TAG_OK) { tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_EM410X); @@ -853,7 +853,7 @@ int main(void) { on_data_frame_complete(on_data_frame_received); check_wakeup_src(); // Detect wake-up source and decide BLE broadcast and subsequent hibernation action according to the wake-up source - tag_mode_enter(); // Enter card simulation mode by default + tag_mode_enter(); // Enter card emulation mode by default // usbd event listener APP_ERROR_CHECK(app_usbd_power_events_enable()); diff --git a/firmware/application/src/app_status.h b/firmware/application/src/app_status.h index 0716dbf..58097ac 100644 --- a/firmware/application/src/app_status.h +++ b/firmware/application/src/app_status.h @@ -20,6 +20,8 @@ ///////////////////////////////////////////////////////////////////// #define STATUS_LF_TAG_OK (0x40) // Some of the low -frequency cards are successful! #define STATUS_EM410X_TAG_NO_FOUND (0x41) // Can't search for valid EM410X tags +#define STATUS_LF_TAG_NO_FOUND (0x42) // Can't search for valid LF tag +#define STATUS_HIDPROX_TAG_NO_FOUND (0x43) // Can't search for valid HIDProx tags ///////////////////////////////////////////////////////////////////// diff --git a/firmware/application/src/bsp/bsp_delay.c b/firmware/application/src/bsp/bsp_delay.c index 07dccf6..c3f60a3 100644 --- a/firmware/application/src/bsp/bsp_delay.c +++ b/firmware/application/src/bsp/bsp_delay.c @@ -1,20 +1,16 @@ #include "bsp_delay.h" + #include "bsp_time.h" #include "nrf_delay.h" - -//Initialized delay function -void bsp_delay_init(void) { -} - -//Delay NMS -//Pay attention to the range of NMS +// Delay NMS +// Pay attention to the range of NMS void bsp_delay_ms(uint16_t nms) { nrf_delay_us(nms * 1000); } -//Delay NUS -//NUS is the number of US numbers to be delayed. +// Delay NUS +// NUS is the number of US numbers to be delayed. void bsp_delay_us(uint32_t nus) { nrf_delay_us(nus); } diff --git a/firmware/application/src/bsp/bsp_delay.h b/firmware/application/src/bsp/bsp_delay.h index d6aa307..c6e590d 100644 --- a/firmware/application/src/bsp/bsp_delay.h +++ b/firmware/application/src/bsp/bsp_delay.h @@ -7,7 +7,6 @@ extern "C" { #endif -void bsp_delay_init(void); void bsp_delay_ms(uint16_t nms); void bsp_delay_us(uint32_t nus); diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index 1df66de..65ea385 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -84,6 +84,8 @@ // #define DATA_CMD_EM410X_SCAN (3000) #define DATA_CMD_EM410X_WRITE_TO_T55XX (3001) +#define DATA_CMD_HIDPROX_SCAN (3002) +#define DATA_CMD_HIDPROX_WRITE_TO_T55XX (3003) // // ****************************************************************** @@ -140,5 +142,7 @@ // ****************************************************************** #define DATA_CMD_EM410X_SET_EMU_ID (5000) #define DATA_CMD_EM410X_GET_EMU_ID (5001) +#define DATA_CMD_HIDPROX_SET_EMU_ID (5002) +#define DATA_CMD_HIDPROX_GET_EMU_ID (5003) #endif diff --git a/firmware/application/src/rfid/byte_mirror.c b/firmware/application/src/rfid/byte_mirror.c new file mode 100644 index 0000000..aa750cd --- /dev/null +++ b/firmware/application/src/rfid/byte_mirror.c @@ -0,0 +1,37 @@ +#include "byte_mirror.h" + +// Byte mirror +const uint8_t byte_mirror[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; \ No newline at end of file diff --git a/firmware/application/src/rfid/byte_mirror.h b/firmware/application/src/rfid/byte_mirror.h new file mode 100644 index 0000000..0355489 --- /dev/null +++ b/firmware/application/src/rfid/byte_mirror.h @@ -0,0 +1,17 @@ +#ifndef __BYTE_MIRROR_H__ +#define __BYTE_MIRROR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const uint8_t byte_mirror[256]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/application/src/rfid/hex_utils.c b/firmware/application/src/rfid/hex_utils.c index 108089c..d2a4756 100644 --- a/firmware/application/src/rfid/hex_utils.c +++ b/firmware/application/src/rfid/hex_utils.c @@ -1,14 +1,13 @@ #include "hex_utils.h" - /** -* @brief : Convert the large number to the hex byte array -* @param :n : The value of the conversion -* @param :len : The byte length of the value after the conversion is stored -* @param :dest : Caps that store conversion results -* @retval : none -* -*/ + * @brief Convert the large number to the hex byte array + * @param n : The value of the conversion + * @param len : The byte length of the value after the conversion is stored + * @param dest : Caps that store conversion results + * @retval none + * + */ void num_to_bytes(uint64_t n, uint8_t len, uint8_t *dest) { while (len--) { dest[len] = (uint8_t)n; @@ -17,12 +16,12 @@ void num_to_bytes(uint64_t n, uint8_t len, uint8_t *dest) { } /** -* @brief : Convert byte array to large number -* @param :len : The byte length of the buffer of the value of the value -* @param :src : Byte buffer stored in the numerical -* @retval : Converting result -* -*/ + * @brief Convert byte array to large number + * @param len : The byte length of the buffer of the value of the value + * @param src : Byte buffer stored in the numerical + * @retval Converting result + * + */ uint64_t bytes_to_num(uint8_t *src, uint8_t len) { uint64_t num = 0; while (len--) { @@ -31,4 +30,3 @@ uint64_t bytes_to_num(uint8_t *src, uint8_t len) { } return num; } - diff --git a/firmware/application/src/rfid/hex_utils.h b/firmware/application/src/rfid/hex_utils.h index fc96110..a01e43a 100644 --- a/firmware/application/src/rfid/hex_utils.h +++ b/firmware/application/src/rfid/hex_utils.h @@ -1,9 +1,8 @@ -#ifndef __HEX_UTILS_H -#define __HEX_UTILS_H +#ifndef __HEX_UTILS_H__ +#define __HEX_UTILS_H__ #include -// num & bytes void num_to_bytes(uint64_t n, uint8_t len, uint8_t *dest); uint64_t bytes_to_num(uint8_t *src, uint8_t len); diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_14a.c b/firmware/application/src/rfid/nfctag/hf/nfc_14a.c index d1cd700..043f0e4 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_14a.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_14a.c @@ -11,6 +11,7 @@ NRF_LOG_MODULE_REGISTER(); #include "hex_utils.h" #include "crc_utils.h" #include "nfc_mf1.h" +#include "byte_mirror.h" #include "rfid_main.h" #include "syssleep.h" @@ -46,42 +47,6 @@ nfc_tag_14a_handler_t m_tag_handler = { .get_coll_res = NULL, // Obtain packaging of anti -conflict resources of labels }; -// Byte mirror -const uint8_t ByteMirror[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, -}; - // RATS FSDI length check table const uint16_t ats_fsdi_table[] = { // 0 - 8 @@ -90,9 +55,8 @@ const uint16_t ats_fsdi_table[] = { 256, 256, 256, 256, 256, 256, 256, }; - // Whether it is responding to -static volatile bool m_is_responded = false; +static volatile bool m_is_responded = false; // Receiving buffer static uint8_t m_nfc_rx_buffer[MAX_NFC_RX_BUFFER_SIZE] = { 0x00 }; static uint8_t m_nfc_tx_buffer[MAX_NFC_TX_BUFFER_SIZE] = { 0x00 }; @@ -184,16 +148,16 @@ uint8_t nfc_tag_14a_wrap_frame(const uint8_t *pbtTx, const size_t szTxBits, cons for (uiBitPos = 0; uiBitPos < 8; uiBitPos++) { // Copy as much data that fits in the frame byte - btData = ByteMirror[pbtTx[uiDataPos]]; + btData = byte_mirror[pbtTx[uiDataPos]]; btFrame |= (btData >> uiBitPos); // Save this frame byte - *pbtFrame = ByteMirror[btFrame]; + *pbtFrame = byte_mirror[btFrame]; // Set the remaining bits of the date in the new frame byte and append the parity bit btFrame = (btData << (8 - uiBitPos)); btFrame |= ((pbtTxPar[uiDataPos] & 0x01) << (7 - uiBitPos)); // Backup the frame bits we have so far pbtFrame++; - *pbtFrame = ByteMirror[btFrame]; + *pbtFrame = byte_mirror[btFrame]; // Increase the data (without parity bit) position uiDataPos++; // Test if we are done @@ -242,11 +206,11 @@ uint8_t nfc_tag_14a_unwrap_frame(const uint8_t *pbtFrame, const size_t szFrameBi // This process is the reverse of WrapFrame(), look there for more info while (1) { for (uiBitPos = 0; uiBitPos < 8; uiBitPos++) { - btFrame = ByteMirror[pbtFramePos[uiDataPos]]; + btFrame = byte_mirror[pbtFramePos[uiDataPos]]; btData = (btFrame << uiBitPos); - btFrame = ByteMirror[pbtFramePos[uiDataPos + 1]]; + btFrame = byte_mirror[pbtFramePos[uiDataPos + 1]]; btData |= (btFrame >> (8 - uiBitPos)); - pbtRx[uiDataPos] = ByteMirror[btData]; + pbtRx[uiDataPos] = byte_mirror[btData]; if (pbtRxPar != NULL) pbtRxPar[uiDataPos] = ((btFrame >> (7 - uiBitPos)) & 0x01); // Increase the data (without parity bit) position diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c index cadcaed..bd4aa41 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c @@ -130,7 +130,7 @@ static nfc_tag_mf0_ntag_information_t *m_tag_information = NULL; static nfc_tag_14a_coll_res_reference_t m_shadow_coll_res; //Define and use MF0/NTAG special communication buffer static nfc_tag_mf0_ntag_tx_buffer_t m_tag_tx_buffer; -// Save the specific type of MF0/NTAG currently being simulated +// Save the specific type of MF0/NTAG currently being emulated static tag_specific_type_t m_tag_type; static bool m_tag_authenticated = false; static bool m_did_first_read = false; @@ -1086,7 +1086,7 @@ int nfc_tag_mf0_ntag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *bu if (buffer->length >= info_size) { // Convert the data buffer to MF0/NTAG structure type m_tag_information = (nfc_tag_mf0_ntag_information_t *)buffer->buffer; - // The specific type of MF0/NTAG tag that is simulated by the cache + // The specific type of MF0/NTAG tag that is emulated by the cache m_tag_type = type; // Register 14A communication management interface nfc_tag_14a_handler_t handler_for_14a = { diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c index 0277692..3ae6164 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c @@ -188,7 +188,7 @@ static nfc_tag_14a_coll_res_reference_t m_shadow_coll_res; static nfc_tag_mf1_trailer_info_t *m_tag_trailer_info = NULL; // Define and use MF1 special communication buffer static nfc_tag_mf1_tx_buffer_t m_tag_tx_buffer; -//Save the specific type of MF1 currently being simulated +//Save the specific type of MF1 currently being emulated static tag_specific_type_t m_tag_type; // Fast simulate is enable, we use internal crypto1 instance from 'mf1_crypto1.c' @@ -500,7 +500,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { BlockEnd = BlockStart + 4 - 1; } - // The type of current simulation card is not enough to support the access of the card reader + // The type of current emulation card is not enough to support the access of the card reader if (check_block_max_overflow(BlockAuth)) { break; } @@ -805,7 +805,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { BlockEnd = BlockStart + 4 - 1; } - // The type of current simulation card is not enough to support the access of the card reader + // The type of current emulation card is not enough to support the access of the card reader if (check_block_max_overflow(BlockAuth)) { break; } @@ -1016,7 +1016,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { * @brief Provide the necessary anti -conflict resources for the MiFare label (only pointer provides pointers) */ nfc_tag_14a_coll_res_reference_t *get_mifare_coll_res() { - //According to the current interoperability configuration, selectively return the configuration data to selectively, assuming that the data interoperability is turned on, then we also need to ensure that the current simulation card is 4BYTE + //According to the current interoperability configuration, selectively return the configuration data to selectively, assuming that the data interoperability is turned on, then we also need to ensure that the current emulation card is 4BYTE if (m_tag_information->config.use_mf1_coll_res && m_tag_information->res_coll.size == NFC_TAG_14A_UID_SINGLE_SIZE) { // Manufacturer information obtained by the data area nfc_tag_mf1_factory_info_t *block0_factory_info = (nfc_tag_mf1_factory_info_t *)m_tag_information->memory[0]; @@ -1102,7 +1102,7 @@ int nfc_tag_mf1_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) if (buffer->length >= info_size) { //Convert the data buffer to MF1 structure type m_tag_information = (nfc_tag_mf1_information_t *)buffer->buffer; - // The specific type of MF1 that is simulated by the cache + // The specific type of MF1 that is emulated by the cache m_tag_type = type; // Register 14A communication management interface nfc_tag_14a_handler_t handler_for_14a = { diff --git a/firmware/application/src/rfid/nfctag/lf/lf_tag_em.c b/firmware/application/src/rfid/nfctag/lf/lf_tag_em.c index ffdf520..a0bc16e 100644 --- a/firmware/application/src/rfid/nfctag/lf/lf_tag_em.c +++ b/firmware/application/src/rfid/nfctag/lf/lf_tag_em.c @@ -1,15 +1,17 @@ +#include "lf_tag_em.h" + #include -#include "lf_tag_em.h" +#include "bsp_delay.h" +#include "fds_util.h" +#include "nrf_gpio.h" +#include "nrfx_lpcomp.h" +#include "nrfx_pwm.h" +#include "protocols/em410x.h" +#include "protocols/hidprox.h" #include "syssleep.h" #include "tag_emulation.h" -#include "fds_util.h" #include "tag_persistence.h" -#include "bsp_delay.h" - -#include "nrf_gpio.h" -#include "nrf_drv_timer.h" -#include "nrf_drv_lpcomp.h" #define NRF_LOG_MODULE_NAME tag_em410x #include "nrf_log.h" @@ -17,265 +19,40 @@ #include "nrf_log_default_backends.h" NRF_LOG_MODULE_REGISTER(); - -// Get the specified position bit -#define GETBIT(v, bit) ((v >> bit) & 0x01) -// Antenna control -#define ANT_TO_MOD() nrf_gpio_pin_set(LF_MOD) -#define ANT_NO_MOD() nrf_gpio_pin_clear(LF_MOD) - +#define ANT_NO_MOD() nrf_gpio_pin_clear(LF_MOD) +#define LF_125KHZ_BROADCAST_MAX (10) // Whether the USB light effect is allowed to enable extern bool g_usb_led_marquee_enable; -// Bit data carrying 64 -bit ID number -static uint64_t m_id_bit_data = 0; -// The bit position of the card ID currently sent -static uint8_t m_bit_send_position; -// Whether to send the first edge -static bool m_is_send_first_edge; -// The current broadcast ID number is 33ms every few times, and can be broadcast about 30 times a second -static uint8_t m_send_id_count; // Whether it is currently in the low -frequency card number of broadcasting static volatile bool m_is_lf_emulating = false; -// The timer of the delivery card number, we use the timer 3 -const nrfx_timer_t m_timer_send_id = NRFX_TIMER_INSTANCE(3); -// Cache label type +// Cache tag type static tag_specific_type_t m_tag_type = TAG_TYPE_UNDEFINED; -/** - * @brief Convert the card number of EM410X to the memory layout of U64 and calculate the puppet school inspection - * According to the instructions of the manual, EM4100 is sufficient to accommodate U64 - */ -uint64_t em410x_id_to_memory64(uint8_t id[5]) { - //Union, what you see is obtained - union { - uint64_t u64; - struct { - // 9 header bits - uint8_t h00: 1; - uint8_t h01: 1; - uint8_t h02: 1; - uint8_t h03: 1; - uint8_t h04: 1; - uint8_t h05: 1; - uint8_t h06: 1; - uint8_t h07: 1; - uint8_t h08: 1; - // 8 version bits and 2 bit parity - uint8_t d00: 1; - uint8_t d01: 1; - uint8_t d02: 1; - uint8_t d03: 1; - uint8_t p0: 1; - uint8_t d10: 1; - uint8_t d11: 1; - uint8_t d12: 1; - uint8_t d13: 1; - uint8_t p1: 1; - // 32 data bits and 8 bit parity - uint8_t d20: 1; - uint8_t d21: 1; - uint8_t d22: 1; - uint8_t d23: 1; - uint8_t p2: 1; - uint8_t d30: 1; - uint8_t d31: 1; - uint8_t d32: 1; - uint8_t d33: 1; - uint8_t p3: 1; - uint8_t d40: 1; - uint8_t d41: 1; - uint8_t d42: 1; - uint8_t d43: 1; - uint8_t p4: 1; - uint8_t d50: 1; - uint8_t d51: 1; - uint8_t d52: 1; - uint8_t d53: 1; - uint8_t p5: 1; - uint8_t d60: 1; - uint8_t d61: 1; - uint8_t d62: 1; - uint8_t d63: 1; - uint8_t p6: 1; - uint8_t d70: 1; - uint8_t d71: 1; - uint8_t d72: 1; - uint8_t d73: 1; - uint8_t p7: 1; - uint8_t d80: 1; - uint8_t d81: 1; - uint8_t d82: 1; - uint8_t d83: 1; - uint8_t p8: 1; - uint8_t d90: 1; - uint8_t d91: 1; - uint8_t d92: 1; - uint8_t d93: 1; - uint8_t p9: 1; - // 5 bit end. - uint8_t pc0: 1; - uint8_t pc1: 1; - uint8_t pc2: 1; - uint8_t pc3: 1; - uint8_t s0: 1; - } bit; - } memory; +// The pwm to broadcast FSK2a modulated card id +const nrfx_pwm_t m_broadcast = NRFX_PWM_INSTANCE(0); +const nrf_pwm_sequence_t *m_pwm_seq = NULL; - // Okay, it's the most critical time at present, and now you need to assign and calculate the Qiqi school inspection - // 1. First assign the front guide code - memory.bit.h00 = memory.bit.h01 = memory.bit.h02 = - memory.bit.h03 = memory.bit.h04 = memory.bit.h05 = - memory.bit.h06 = memory.bit.h07 = memory.bit.h08 = 1; - //2. Assign the 8bit version or custom ID - memory.bit.d00 = GETBIT(id[0], 7); - memory.bit.d01 = GETBIT(id[0], 6); - memory.bit.d02 = GETBIT(id[0], 5); - memory.bit.d03 = GETBIT(id[0], 4); - memory.bit.p0 = memory.bit.d00 ^ memory.bit.d01 ^ memory.bit.d02 ^ memory.bit.d03; - memory.bit.d10 = GETBIT(id[0], 3); - memory.bit.d11 = GETBIT(id[0], 2); - memory.bit.d12 = GETBIT(id[0], 1); - memory.bit.d13 = GETBIT(id[0], 0); - memory.bit.p1 = memory.bit.d10 ^ memory.bit.d11 ^ memory.bit.d12 ^ memory.bit.d13; - // 3. Assign the data of 32Bit - // -byte1 - memory.bit.d20 = GETBIT(id[1], 7); - memory.bit.d21 = GETBIT(id[1], 6); - memory.bit.d22 = GETBIT(id[1], 5); - memory.bit.d23 = GETBIT(id[1], 4); - memory.bit.p2 = memory.bit.d20 ^ memory.bit.d21 ^ memory.bit.d22 ^ memory.bit.d23; - memory.bit.d30 = GETBIT(id[1], 3); - memory.bit.d31 = GETBIT(id[1], 2); - memory.bit.d32 = GETBIT(id[1], 1); - memory.bit.d33 = GETBIT(id[1], 0); - memory.bit.p3 = memory.bit.d30 ^ memory.bit.d31 ^ memory.bit.d32 ^ memory.bit.d33; - // - byte2 - memory.bit.d40 = GETBIT(id[2], 7); - memory.bit.d41 = GETBIT(id[2], 6); - memory.bit.d42 = GETBIT(id[2], 5); - memory.bit.d43 = GETBIT(id[2], 4); - memory.bit.p4 = memory.bit.d40 ^ memory.bit.d41 ^ memory.bit.d42 ^ memory.bit.d43; - memory.bit.d50 = GETBIT(id[2], 3); - memory.bit.d51 = GETBIT(id[2], 2); - memory.bit.d52 = GETBIT(id[2], 1); - memory.bit.d53 = GETBIT(id[2], 0); - memory.bit.p5 = memory.bit.d50 ^ memory.bit.d51 ^ memory.bit.d52 ^ memory.bit.d53; - // - byte3 - memory.bit.d60 = GETBIT(id[3], 7); - memory.bit.d61 = GETBIT(id[3], 6); - memory.bit.d62 = GETBIT(id[3], 5); - memory.bit.d63 = GETBIT(id[3], 4); - memory.bit.p6 = memory.bit.d60 ^ memory.bit.d61 ^ memory.bit.d62 ^ memory.bit.d63; - memory.bit.d70 = GETBIT(id[3], 3); - memory.bit.d71 = GETBIT(id[3], 2); - memory.bit.d72 = GETBIT(id[3], 1); - memory.bit.d73 = GETBIT(id[3], 0); - memory.bit.p7 = memory.bit.d70 ^ memory.bit.d71 ^ memory.bit.d72 ^ memory.bit.d73; - // - byte4 - memory.bit.d80 = GETBIT(id[4], 7); - memory.bit.d81 = GETBIT(id[4], 6); - memory.bit.d82 = GETBIT(id[4], 5); - memory.bit.d83 = GETBIT(id[4], 4); - memory.bit.p8 = memory.bit.d80 ^ memory.bit.d81 ^ memory.bit.d82 ^ memory.bit.d83; - memory.bit.d90 = GETBIT(id[4], 3); - memory.bit.d91 = GETBIT(id[4], 2); - memory.bit.d92 = GETBIT(id[4], 1); - memory.bit.d93 = GETBIT(id[4], 0); - memory.bit.p9 = memory.bit.d90 ^ memory.bit.d91 ^ memory.bit.d92 ^ memory.bit.d93; - // 4. Calculate the vertical puppet verification - memory.bit.pc0 = memory.bit.d00 ^ memory.bit.d10 ^ memory.bit.d20 ^ memory.bit.d30 ^ memory.bit.d40 ^ memory.bit.d50 ^ memory.bit.d60 ^ memory.bit.d70 ^ memory.bit.d80 ^ memory.bit.d90; - memory.bit.pc1 = memory.bit.d01 ^ memory.bit.d11 ^ memory.bit.d21 ^ memory.bit.d31 ^ memory.bit.d41 ^ memory.bit.d51 ^ memory.bit.d61 ^ memory.bit.d71 ^ memory.bit.d81 ^ memory.bit.d91; - memory.bit.pc2 = memory.bit.d02 ^ memory.bit.d12 ^ memory.bit.d22 ^ memory.bit.d32 ^ memory.bit.d42 ^ memory.bit.d52 ^ memory.bit.d62 ^ memory.bit.d72 ^ memory.bit.d82 ^ memory.bit.d92; - memory.bit.pc3 = memory.bit.d03 ^ memory.bit.d13 ^ memory.bit.d23 ^ memory.bit.d33 ^ memory.bit.d43 ^ memory.bit.d53 ^ memory.bit.d63 ^ memory.bit.d73 ^ memory.bit.d83 ^ memory.bit.d93; - //5. Set the position of the last EOF, this wave of conversion is over - memory.bit.s0 = 0; - //Return to the U64 data in the combination, this is the data we finally need, - // In the later stage analog card, just take out each bit to send it - return memory.u64; +static void lf_field_lost(void) { + // Open the incident interruption, so that the next event can be in and out normally + g_is_tag_emulating = false; // Reset the flag in the emulation + m_is_lf_emulating = false; + TAG_FIELD_LED_OFF() // Make sure the indicator light of the LF field status + NRF_LPCOMP->INTENSET = LPCOMP_INTENCLR_CROSS_Msk | LPCOMP_INTENCLR_UP_Msk | LPCOMP_INTENCLR_DOWN_Msk | LPCOMP_INTENCLR_READY_Msk; + // call sleep_timer_start *after* unsetting g_is_tag_emulating + sleep_timer_start(SLEEP_DELAY_MS_FIELD_125KHZ_LOST); // Start the timer to enter the sleep + NRF_LOG_INFO("LF FIELD LOST"); } /** -* @brief Judgment field status + * @brief Judge field status */ bool lf_is_field_exists(void) { - nrf_drv_lpcomp_enable(); - bsp_delay_us(30); // Display for a period of time and sampling to avoid misjudgment - nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_SAMPLE); //Trigger a sampling - return nrf_lpcomp_result_get() == 1; //Determine the sampling results of the LF field status -} - -void timer_ce_handler(nrf_timer_event_t event_type, void *p_context) { - bool mod; - switch (event_type) { - // Because we are configured using the CC channel 2, the event recovers - // Detect nrf_timer_event_compare0 event in the function - case NRF_TIMER_EVENT_COMPARE2: { - if (m_is_send_first_edge) { - if (GETBIT(m_id_bit_data, m_bit_send_position)) { - // The first edge of the send 1 - ANT_TO_MOD(); - mod = true; - } else { - // The first edge of the send 0 - ANT_NO_MOD(); - mod = false; - } - m_is_send_first_edge = false; //The second edge is sent next time - } else { - if (GETBIT(m_id_bit_data, m_bit_send_position)) { - // Send the second edge of 1 - ANT_NO_MOD(); - mod = false; - } else { - //The second edge of the send 0 - ANT_TO_MOD(); - mod = true; - } - m_is_send_first_edge = true; //The first edge of the next sends next time - } - - // measure field only during no-mod half of last bit of last broadcast - if ((! mod) && - (m_bit_send_position + 1 >= LF_125KHZ_EM410X_BIT_SIZE) && - (m_send_id_count + 1 >= LF_125KHZ_BROADCAST_MAX)) { - nrfx_timer_disable(&m_timer_send_id); // Close the timer of the broadcast venue - // We don't need any events, but only need to detect the state of the field - NRF_LPCOMP->INTENCLR = LPCOMP_INTENCLR_CROSS_Msk | LPCOMP_INTENCLR_UP_Msk | LPCOMP_INTENCLR_DOWN_Msk | LPCOMP_INTENCLR_READY_Msk; - if (lf_is_field_exists()) { - nrf_drv_lpcomp_disable(); - nrfx_timer_enable(&m_timer_send_id); // Open the timer of the broadcaster and continue to simulate - } else { - // Open the incident interruption, so that the next event can be in and out normally - g_is_tag_emulating = false; // Reset the flag in the simulation - m_is_lf_emulating = false; - TAG_FIELD_LED_OFF() // Make sure the indicator light of the LF field status - NRF_LPCOMP->INTENSET = LPCOMP_INTENCLR_CROSS_Msk | LPCOMP_INTENCLR_UP_Msk | LPCOMP_INTENCLR_DOWN_Msk | LPCOMP_INTENCLR_READY_Msk; - // call sleep_timer_start *after* unsetting g_is_tag_emulating - sleep_timer_start(SLEEP_DELAY_MS_FIELD_125KHZ_LOST); // Start the timer to enter the sleep - NRF_LOG_INFO("LF FIELD LOST"); - } - } - - if (m_is_send_first_edge == true) { // The first edge of the next sends next time - if (++m_bit_send_position >= LF_125KHZ_EM410X_BIT_SIZE) { - m_bit_send_position = 0; // The broadcast is successful once, and the BIT position is zero - if (!lf_is_field_exists()) { // To avoid stopping sending when the reader field is present - m_send_id_count++; - } - if (m_send_id_count >= LF_125KHZ_BROADCAST_MAX) { - m_send_id_count = 0; //The number of broadcasts reaches the upper limit, re -identifies the status of the field and re -statistically count the number of broadcast times - } - } - } - break; - } - default: { - // Nothing to do. - break; - } - } + nrfx_lpcomp_enable(); + bsp_delay_us(30); // Display for a period of time and sampling to avoid misjudgment + nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_SAMPLE); + return nrf_lpcomp_result_get() == 1; // Determine the sampling results of the LF field status } /** @@ -287,66 +64,91 @@ void timer_ce_handler(nrf_timer_event_t event_type, void *p_context) { * priority is set to APP_IRQ_PRIORITY_HIGH). */ static void lpcomp_event_handler(nrf_lpcomp_event_t event) { - // Only when the low -frequency simulation is not launched, and the analog card is started - if (!m_is_lf_emulating && event == NRF_LPCOMP_EVENT_UP) { - // Turn off dormant delay - sleep_timer_stop(); - // Close the comparator - nrf_drv_lpcomp_disable(); + // Only when the lf -frequency emulation is not launched, and the analog card is started + if (m_is_lf_emulating || event != NRF_LPCOMP_EVENT_UP) { + return; + } - // Set the simulation status logo bit - m_is_lf_emulating = true; - g_is_tag_emulating = true; + sleep_timer_stop(); // turn off dormant delay + nrfx_lpcomp_disable(); - // Simulation card status should be turned off the USB light effect - g_usb_led_marquee_enable = false; + // set the emulation status logo bit + m_is_lf_emulating = true; + g_is_tag_emulating = true; + // turn off USB light effect when emulating cards + g_usb_led_marquee_enable = false; - // LED status update - set_slot_light_color(RGB_BLUE); - TAG_FIELD_LED_ON() + // LED status update + set_slot_light_color(RGB_BLUE); + TAG_FIELD_LED_ON() - //In any case, every time the state finds changes, you need to reset the BIT location of the sending - m_send_id_count = 0; - m_bit_send_position = 0; - m_is_send_first_edge = true; + // use precise hardware timer to broadcast card id + nrfx_pwm_simple_playback(&m_broadcast, m_pwm_seq, LF_125KHZ_BROADCAST_MAX, NRFX_PWM_FLAG_STOP); - // openThePreciseHardwareTimerToTheBroadcastCardNumber - nrfx_timer_enable(&m_timer_send_id); + NRF_LOG_INFO("LF FIELD DETECTED"); +} - NRF_LOG_INFO("LF FIELD DETECTED"); +static void lpcomp_init(void) { + nrfx_lpcomp_config_t cfg = NRFX_LPCOMP_DEFAULT_CONFIG; + cfg.input = LF_RSSI; + cfg.hal.reference = NRF_LPCOMP_REF_SUPPLY_1_16; + cfg.hal.detection = NRF_LPCOMP_DETECT_UP; + cfg.hal.hyst = NRF_LPCOMP_HYST_50mV; + + ret_code_t err_code = nrfx_lpcomp_init(&cfg, lpcomp_event_handler); + APP_ERROR_CHECK(err_code); +} + +static void pwm_handler(nrfx_pwm_evt_type_t event_type) { + if (event_type != NRFX_PWM_EVT_STOPPED) { + return; + } + + // after last broadcast, force NO_MOD on antenna to measure field. + ANT_NO_MOD(); + bsp_delay_ms(1); + // We don't need any events, but only need to detect the state of the field + NRF_LPCOMP->INTENCLR = LPCOMP_INTENCLR_CROSS_Msk | LPCOMP_INTENCLR_UP_Msk | LPCOMP_INTENCLR_DOWN_Msk | LPCOMP_INTENCLR_READY_Msk; + if (lf_is_field_exists()) { + nrfx_lpcomp_disable(); + nrfx_pwm_simple_playback(&m_broadcast, m_pwm_seq, LF_125KHZ_BROADCAST_MAX, NRFX_PWM_FLAG_STOP); + } else { + lf_field_lost(); } } +static void pwm_init(void) { + nrfx_pwm_config_t cfg = NRFX_PWM_DEFAULT_CONFIG; + cfg.output_pins[0] = LF_MOD; + for (uint8_t i = 1; i < NRF_PWM_CHANNEL_COUNT; i++) { + cfg.output_pins[i] = NRFX_PWM_PIN_NOT_USED; + } + cfg.irq_priority = APP_IRQ_PRIORITY_LOW; + cfg.base_clock = NRF_PWM_CLK_125kHz; + cfg.count_mode = NRF_PWM_MODE_UP; + cfg.load_mode = NRF_PWM_LOAD_WAVE_FORM; + cfg.step_mode = NRF_PWM_STEP_AUTO; + + nrfx_err_t err_code = nrfx_pwm_init(&m_broadcast, &cfg, pwm_handler); + APP_ERROR_CHECK(err_code); +} + static void lf_sense_enable(void) { - ret_code_t err_code; - - nrf_drv_lpcomp_config_t config = NRF_DRV_LPCOMP_DEFAULT_CONFIG; - config.hal.reference = NRF_LPCOMP_REF_SUPPLY_1_16; - config.input = LF_RSSI; - config.hal.detection = NRF_LPCOMP_DETECT_UP; - config.hal.hyst = NRF_LPCOMP_HYST_50mV; - - err_code = nrf_drv_lpcomp_init(&config, lpcomp_event_handler); - APP_ERROR_CHECK(err_code); - - // TAG id broadcast - nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG; - err_code = nrfx_timer_init(&m_timer_send_id, &timer_cfg, timer_ce_handler); - APP_ERROR_CHECK(err_code); - nrfx_timer_extended_compare(&m_timer_send_id, NRF_TIMER_CC_CHANNEL2, nrfx_timer_us_to_ticks(&m_timer_send_id, LF_125KHZ_EM410X_BIT_CLOCK), NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK, true); - - if (lf_is_field_exists() && !m_is_lf_emulating) { + lpcomp_init(); + pwm_init(); // use precise hardware timer to broadcast card id + if (lf_is_field_exists()) { lpcomp_event_handler(NRF_LPCOMP_EVENT_UP); } } static void lf_sense_disable(void) { - nrfx_timer_uninit(&m_timer_send_id); //counterInitializationTimer - nrfx_lpcomp_uninit(); //antiInitializationComparator - m_is_lf_emulating = false; //setAsNonSimulatedState + nrfx_pwm_uninit(&m_broadcast); + nrfx_lpcomp_uninit(); + m_pwm_seq = NULL; + m_is_lf_emulating = false; } -static enum { +static enum { LF_SENSE_STATE_NONE, LF_SENSE_STATE_DISABLE, LF_SENSE_STATE_ENABLE, @@ -356,18 +158,18 @@ static enum { * @brief switchLfFieldInductionToEnableTheState */ void lf_tag_125khz_sense_switch(bool enable) { - // initializationModulationFootIsOutput + // init modulation PIN as output PIN nrf_gpio_cfg_output(LF_MOD); - //theDefaultIsNotShortCircuitAntenna (shortCircuitWillCauseRssiToBeUnableToJudge) + // turn off mod, otherwise its hard to judge RSSI ANT_NO_MOD(); - //forTheFirstTimeOrDisabled,OnlyInitializationIsAllowed + // forTheFirstTimeOrDisabled,OnlyInitializationIsAllowed if (m_lf_sense_state == LF_SENSE_STATE_NONE || m_lf_sense_state == LF_SENSE_STATE_DISABLE) { if (enable) { m_lf_sense_state = LF_SENSE_STATE_ENABLE; lf_sense_enable(); } - } else { // inOtherCases,OnlyAntiInitializationIsAllowed + } else { // inOtherCases,OnlyAntiInitializationIsAllowed if (!enable) { m_lf_sense_state = LF_SENSE_STATE_DISABLE; lf_sense_disable(); @@ -375,51 +177,62 @@ void lf_tag_125khz_sense_switch(bool enable) { } } -/** @brief EM410X load data - * @param type Refined label type +/** @brief lf card load data + * @param type Refined tag type * @param buffer Data buffer */ -int lf_tag_em410x_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) { - //Make sure that external capacity is enough to convert to an information structure - if (buffer->length >= LF_EM410X_TAG_ID_SIZE) { - // The ID card number is directly converted here as the corresponding BIT data stream +int lf_tag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) { + // ensure buffer size is large enough for specific tag type, + // so that tag data (e.g., card numbers) can be converted to corresponding pwm sequence here. + if (type == TAG_TYPE_EM410X && buffer->length >= LF_EM410X_TAG_ID_SIZE) { m_tag_type = type; - m_id_bit_data = em410x_id_to_memory64(buffer->buffer); - NRF_LOG_INFO("LF Em410x data load finish."); - } else { - NRF_LOG_ERROR("LF_EM410X_TAG_ID_SIZE too big."); + void *codec = em410x_64.alloc(); + m_pwm_seq = em410x_64.modulator(codec, buffer->buffer); + em410x_64.free(codec); + NRF_LOG_INFO("load lf em410x data finish."); + return LF_EM410X_TAG_ID_SIZE; } - return LF_EM410X_TAG_ID_SIZE; + + if (type == TAG_TYPE_HID_PROX && buffer->length >= LF_HIDPROX_TAG_ID_SIZE) { + m_tag_type = type; + void *codec = hidprox.alloc(); + m_pwm_seq = hidprox.modulator(codec, buffer->buffer); + hidprox.free(codec); + NRF_LOG_INFO("load lf hidprox data finish."); + return LF_HIDPROX_TAG_ID_SIZE; + } + NRF_LOG_ERROR("no valid data exists in buffer for tag type: %d.", type); + return 0; } /** @brief Id card deposit card number before callback - * @param type Refined label type + * @param type Refined tag type * @param buffer Data buffer * @return The length of the data that needs to be saved is that it does not save when 0 */ int lf_tag_em410x_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) { - // Make sure to load this label before allowing saving - if (m_tag_type != TAG_TYPE_UNDEFINED) { - // Just save the original card package directly - return LF_EM410X_TAG_ID_SIZE; - } else { - return 0; - } + // Make sure to load this tag before allowing saving + // Just save the original card package directly + return m_tag_type == TAG_TYPE_EM410X ? LF_EM410X_TAG_ID_SIZE : 0; } /** @brief Id card deposit card number before callback - * @param slot Card slot number - * @param tag_type Refined label type - * @return Whether the format is successful, if the formatting is successful, it will return to True, otherwise False will be returned + * @param type Refined tag type + * @param buffer Data buffer + * @return The length of the data that needs to be saved is that it does not save when 0 */ -bool lf_tag_em410x_data_factory(uint8_t slot, tag_specific_type_t tag_type) { - // default id, must to align(4), more word... - uint8_t tag_id[5] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x88 }; - // Write the data in Flash +int lf_tag_hidprox_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) { + // Make sure to load this tag before allowing saving + // Just save the original card package directly + return m_tag_type == TAG_TYPE_HID_PROX ? LF_HIDPROX_TAG_ID_SIZE : 0; +} + +bool lf_tag_data_factory(uint8_t slot, tag_specific_type_t tag_type, uint8_t *tag_id, uint16_t length) { + // write data to flash tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); - fds_slot_record_map_t map_info; // Get the special card slot FDS record information + fds_slot_record_map_t map_info; // Get the special card slot FDS record information get_fds_map_by_slot_sense_type_for_dump(slot, sense_type, &map_info); - //Call the blocked FDS to write the function, and write the data of the specified field type of the card slot into the Flash + // Call the blocked FDS to write the function, and write the data of the specified field type of the card slot into the Flash bool ret = fds_write_sync(map_info.id, map_info.key, sizeof(tag_id), (uint8_t *)tag_id); if (ret) { NRF_LOG_INFO("Factory slot data success."); @@ -428,3 +241,25 @@ bool lf_tag_em410x_data_factory(uint8_t slot, tag_specific_type_t tag_type) { } return ret; } + +/** @brief Id card deposit card number before callback + * @param slot Card slot number + * @param tag_type Refined tag type + * @return Whether the format is successful, if the formatting is successful, it will return to True, otherwise False will be returned + */ +bool lf_tag_em410x_data_factory(uint8_t slot, tag_specific_type_t tag_type) { + // default id, must to align(4), more word... + uint8_t tag_id[5] = {0xDE, 0xAD, 0xBE, 0xEF, 0x88}; + return lf_tag_data_factory(slot, tag_type, tag_id, sizeof(tag_id)); +} + +/** @brief Id card deposit card number before callback + * @param slot Card slot number + * @param tag_type Refined tag type + * @return Whether the format is successful, if the formatting is successful, it will return to True, otherwise False will be returned + */ +bool lf_tag_hidprox_data_factory(uint8_t slot, tag_specific_type_t tag_type) { + // default id, must to align(4), more word... + uint8_t tag_id[13] = {0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x51, 0x45, 0x00, 0x00, 0x00}; + return lf_tag_data_factory(slot, tag_type, tag_id, sizeof(tag_id)); +} diff --git a/firmware/application/src/rfid/nfctag/lf/lf_tag_em.h b/firmware/application/src/rfid/nfctag/lf/lf_tag_em.h index 62abe86..0ae3dc3 100644 --- a/firmware/application/src/rfid/nfctag/lf/lf_tag_em.h +++ b/firmware/application/src/rfid/nfctag/lf/lf_tag_em.h @@ -1,25 +1,17 @@ -#ifndef __LF_TAG_H -#define __LF_TAG_H +#pragma once #include + #include "rfid_main.h" #include "tag_emulation.h" - -/** - * Low -frequency analog card adjustment Manchester signal - * The definition of the packaging tool macro only needs to be modulated 0 and 1 - */ -#define LF_125KHZ_EM410X_BIT_SIZE 64 -#define LF_125KHZ_BROADCAST_MAX 10 // 32.768ms once, about 31 times in one second -#define LF_125KHZ_EM410X_BIT_CLOCK 256 -#define LF_EM410X_TAG_ID_SIZE 5 - +#define LF_EM410X_TAG_ID_SIZE 5 +#define LF_HIDPROX_TAG_ID_SIZE 13 void lf_tag_125khz_sense_switch(bool enable); -int lf_tag_em410x_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer); +int lf_tag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer); int lf_tag_em410x_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer); bool lf_tag_em410x_data_factory(uint8_t slot, tag_specific_type_t tag_type); +int lf_tag_hidprox_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer); +bool lf_tag_hidprox_data_factory(uint8_t slot, tag_specific_type_t tag_type); bool lf_is_field_exists(void); - -#endif diff --git a/firmware/application/src/rfid/nfctag/lf/protocols/em410x.c b/firmware/application/src/rfid/nfctag/lf/protocols/em410x.c new file mode 100644 index 0000000..cf7d543 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/protocols/em410x.c @@ -0,0 +1,280 @@ +#include "em410x.h" + +#include +#include + +#include "em410x.h" +#include "nordic_common.h" +#include "nrf_pwm.h" +#include "parity.h" +#include "protocols.h" +#include "t55xx.h" +#include "tag_base_type.h" +#include "utils/manchester.h" + +#define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1) + +#define EM_RAW_SIZE (64) +#define EM_DATA_SIZE (5) +#define EM_ROW_COUNT (10) +#define EM_COLUMN_COUNT (4) +#define EM_HEADER (0x1ff) // 9 bits of 1 + +#define EM_T55XX_BLOCK_COUNT (3) + +#define EM_READ_TIME1_BASE (0x40) +#define EM_READ_TIME2_BASE (0x60) +#define EM_READ_TIME3_BASE (0x80) +#define EM_READ_JITTER_TIME_BASE (0x10) + +#define NRF_LOG_MODULE_NAME em4100 +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_log_default_backends.h" +NRF_LOG_MODULE_REGISTER(); + +static nrf_pwm_values_wave_form_t m_em410x_pwm_seq_vals[EM_RAW_SIZE] = {}; + +nrf_pwm_sequence_t const m_em410x_pwm_seq = { + .values.p_wave_form = m_em410x_pwm_seq_vals, + .length = NRF_PWM_VALUES_LENGTH(m_em410x_pwm_seq_vals), + .repeats = 0, + .end_delay = 0, +}; + +const protocol *em410x_protocols[] = { + &em410x_64, + &em410x_32, + &em410x_16, +}; + +size_t em410x_protocols_size = ARRAY_SIZE(em410x_protocols); + +typedef struct { + uint8_t data[EM_DATA_SIZE]; + uint64_t raw; + uint8_t raw_length; + manchester *modem; +} em410x_codec; + +uint64_t em410x_raw_data(uint8_t *uid) { + uint64_t raw = EM_HEADER; + uint8_t pc = 0x00; // column parity + // 10 rows, each row is 4 bits data + 1 bit parity + for (int8_t i = 0; i < EM_ROW_COUNT; i++) { + uint8_t data; + if (i % 2) { + data = uid[i >> 1] & 0x0f; + } else { + data = (uid[i >> 1] >> EM_COLUMN_COUNT) & 0x0f; + } + pc ^= data; + raw = (raw << EM_COLUMN_COUNT) | data; + raw <<= 1; + if (!oddparity8(data)) { + raw |= 0x01; // row parity bit + } + } + raw = (raw << EM_COLUMN_COUNT) | pc; // column parity + raw <<= 1; // stop bit + return raw; +} + +bool em410x_get_time(uint16_t divisor, uint8_t interval, uint8_t base) { + return interval >= (base - EM_READ_JITTER_TIME_BASE) / divisor && + interval <= (base + EM_READ_JITTER_TIME_BASE) / divisor; +} + +uint8_t em410x_period(uint16_t divisor, uint8_t interval) { + if (em410x_get_time(divisor, interval, EM_READ_TIME1_BASE)) { + return 0; + } + if (em410x_get_time(divisor, interval, EM_READ_TIME2_BASE)) { + return 1; + } + if (em410x_get_time(divisor, interval, EM_READ_TIME3_BASE)) { + return 2; + } + return 3; +} + +uint8_t em410x_64_period(uint8_t interval) { + return em410x_period(1, interval); // clock_per_bit = 64, divisor = 1 +} + +uint8_t em410x_32_period(uint8_t interval) { + return em410x_period(2, interval); // clock_per_bit = 32, divisor = 2 +} + +uint8_t em410x_16_period(uint8_t interval) { + return em410x_period(4, interval); // clock_per_bit = 16, divisor = 4 +} + +em410x_codec *em410x_64_alloc(void) { + em410x_codec *codec = malloc(sizeof(em410x_codec)); + codec->modem = malloc(sizeof(manchester)); + codec->modem->rp = em410x_64_period; + return codec; +}; + +em410x_codec *em410x_32_alloc(void) { + em410x_codec *codec = malloc(sizeof(em410x_codec)); + codec->modem = malloc(sizeof(manchester)); + codec->modem->rp = em410x_32_period; + return codec; +}; + +em410x_codec *em410x_16_alloc(void) { + em410x_codec *codec = malloc(sizeof(em410x_codec)); + codec->modem = malloc(sizeof(manchester)); + codec->modem->rp = em410x_16_period; + return codec; +}; + +void em410x_free(em410x_codec *d) { + if (d->modem) { + free(d->modem); + d->modem = NULL; + } + free(d); +}; + +uint8_t *em410x_get_data(em410x_codec *d) { return d->data; }; + +void em410x_decoder_start(em410x_codec *d, uint8_t format) { + memset(d->data, 0, EM_DATA_SIZE); + d->raw = 0; + d->raw_length = 0; + manchester_reset(d->modem); +}; + +bool em410x_decode_feed(em410x_codec *d, bool bit) { + d->raw <<= 1; + d->raw_length++; + if (bit) { + d->raw |= 0x01; + } + if (d->raw_length < EM_RAW_SIZE) { + return false; + } + + // check header + uint8_t v = (d->raw >> (EM_RAW_SIZE - 8)) & 0xff; + if (v != 0xff) { + return false; + } + v = (d->raw >> (EM_RAW_SIZE - 9)) & 0xff; + if (v != 0xff) { + return false; + } + + // check stop bit + if (d->raw & 0x01) { + return false; + } + + uint8_t pc = 0; + for (int i = 0; i < EM_ROW_COUNT + 1; i++) { + uint8_t row = d->raw >> (EM_RAW_SIZE - 9 - (i + 1) * EM_BITS_PER_ROW_COUNT) & 0x1f; + uint8_t data = (row >> 1) & 0x0f; + pc ^= data; + if (i == 10) { + break; + } + + if (!oddparity8(row)) { // row parity + return false; + } + + if (i % 2) { + d->data[i >> 1] |= data; + } else { + d->data[i >> 1] = data << 4; + } + } + return pc == 0x00; // column parity +} + +bool em410x_decoder_feed(em410x_codec *d, uint16_t interval) { + bool bits[2] = {0}; + int8_t bitlen = 0; + manchester_feed(d->modem, (uint8_t)interval, bits, &bitlen); + if (bitlen == -1) { + d->raw = 0; + d->raw_length = 0; + return false; + } + for (int i = 0; i < bitlen; i++) { + if (em410x_decode_feed(d, bits[i])) { + return true; + } + } + return false; +}; + +const nrf_pwm_sequence_t *em410x_modulator(em410x_codec *d, uint8_t *buf) { + uint64_t lo = em410x_raw_data(buf); + for (int i = 0; i < EM_RAW_SIZE; i++) { + uint16_t msb = 0x00; + if (IS_SET(lo, EM_RAW_SIZE - i - 1)) { + msb = (1 << 15); + } + m_em410x_pwm_seq_vals[i].channel_0 = msb | 32; + m_em410x_pwm_seq_vals[i].counter_top = 64; + } + return &m_em410x_pwm_seq; +}; + +// EM-Micro, EM410x/64 (std) +const protocol em410x_64 = { + .tag_type = TAG_TYPE_EM410X_64, + .data_size = EM_DATA_SIZE, + .alloc = (codec_alloc)em410x_64_alloc, + .free = (codec_free)em410x_free, + .get_data = (codec_get_data)em410x_get_data, + .modulator = (modulator)em410x_modulator, + .decoder = + { + .start = (decoder_start)em410x_decoder_start, + .feed = (decoder_feed)em410x_decoder_feed, + }, +}; + +// EM-Micro, EM410x/32 +const protocol em410x_32 = { + .tag_type = TAG_TYPE_EM410X_32, + .data_size = EM_DATA_SIZE, + .alloc = (codec_alloc)em410x_32_alloc, + .free = (codec_free)em410x_free, + .get_data = (codec_get_data)em410x_get_data, + .modulator = (modulator)em410x_modulator, + .decoder = + { + .start = (decoder_start)em410x_decoder_start, + .feed = (decoder_feed)em410x_decoder_feed, + }, +}; + +// EM-Micro, EM410x/16 +const protocol em410x_16 = { + .tag_type = TAG_TYPE_EM410X_16, + .data_size = EM_DATA_SIZE, + .alloc = (codec_alloc)em410x_16_alloc, + .free = (codec_free)em410x_free, + .get_data = (codec_get_data)em410x_get_data, + .modulator = (modulator)em410x_modulator, + .decoder = + { + .start = (decoder_start)em410x_decoder_start, + .feed = (decoder_feed)em410x_decoder_feed, + }, +}; + +// Encode EM410X card number to T55xx blocks. +uint8_t em410x_t55xx_writer(uint8_t *uid, uint32_t *blks) { + uint64_t raw = em410x_raw_data(uid); + blks[0] = T5577_EM410X_64_CONFIG; + blks[1] = raw >> 32; + blks[2] = raw & 0xffffffff; + return EM_T55XX_BLOCK_COUNT; +} \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/lf/protocols/em410x.h b/firmware/application/src/rfid/nfctag/lf/protocols/em410x.h new file mode 100644 index 0000000..074fb3a --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/protocols/em410x.h @@ -0,0 +1,12 @@ +#pragma once + +#include "protocols.h" + +extern const protocol em410x_64; +extern const protocol em410x_32; +extern const protocol em410x_16; + +extern const protocol* em410x_protocols[]; +extern size_t em410x_protocols_size; + +uint8_t em410x_t55xx_writer(uint8_t* uid, uint32_t* blks); \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/lf/protocols/hidprox.c b/firmware/application/src/rfid/nfctag/lf/protocols/hidprox.c new file mode 100644 index 0000000..9d86a69 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/protocols/hidprox.c @@ -0,0 +1,239 @@ +#include "hidprox.h" + +#include +#include + +#include "hex_utils.h" +#include "nordic_common.h" +#include "parity.h" +#include "protocols.h" +#include "t55xx.h" +#include "tag_base_type.h" +#include "wiegand.h" + +#define HIDPROX_SOF (0x1d) +#define HIDPROX_T55XX_BLOCK_COUNT (4) +#define DEMOD_BUFFER_SIZE (32) +#define HIDPROX_RAW_SIZE (96) + +#define LF_FSK2a_PWM_LO_FREQ_LOOP (5) +#define LF_FSK2a_PWM_LO_FREQ_TOP_VALUE (10) +#define LF_FSK2a_PWM_HI_FREQ_LOOP (6) +#define LF_FSK2a_PWM_HI_FREQ_TOP_VALUE (8) + +static nrf_pwm_values_wave_form_t m_hidprox_pwm_seq_vals[HIDPROX_RAW_SIZE * 6] = {}; + +nrf_pwm_sequence_t m_hidprox_pwm_seq = { + .values.p_wave_form = m_hidprox_pwm_seq_vals, + .length = NRF_PWM_VALUES_LENGTH(m_hidprox_pwm_seq_vals), + .repeats = 0, + .end_delay = 0, +}; + +void decoder_reset(hidprox_codec *d) { + d->sof = 0; + d->state = STATE_SOF; + d->raw = 0; + d->raw_length = 0; + d->bit = false; +} + +void hidprox_decoder_start(hidprox_codec *d, uint8_t format_hint) { + memset(d->data, 0, HIDPROX_DATA_SIZE); + decoder_reset(d); + d->format_hint = format_hint; +} + +hidprox_codec *hidprox_codec_alloc(void) { + hidprox_codec *d = malloc(sizeof(hidprox_codec)); + d->card = NULL; + d->modem = fsk_alloc(); + return d; +} + +void hidprox_codec_free(hidprox_codec *d) { + if (d->modem) { + fsk_free(d->modem); + d->modem = NULL; + } + if (d->card) { + free(d->card); + d->card = NULL; + } + free(d); +} + +// ref: https://github.com/RfidResearchGroup/proxmark3/blob/810eaeac250f35eca8819aa9c23cb57c5276b3e6/client/src/wiegand_formatutils.c#L131 +static uint8_t hidprox_codec_get_length(hidprox_codec *d) { + //! TODO direct XOR check + if (!(d->raw >> 37) && 0x01) { + return 37; + } + uint16_t bits = (d->raw >> 26) & 0x7ff; + uint8_t length = 25; + while (bits) { + bits >>= 1; + length++; + } + return length; +} + +uint8_t *hidprox_get_data(hidprox_codec *d) { + if (d->card == NULL) { + return d->data; + } + // total 13 bytes + d->data[0] = d->card->format; + num_to_bytes(d->card->facility_code, 4, d->data + 1); // 4 bytes + num_to_bytes(d->card->card_number, 5, d->data + 5); // 5 bytes + num_to_bytes(d->card->issue_level, 1, d->data + 10); // 1 bytes + num_to_bytes(d->card->oem, 2, d->data + 11); // 2 bytes + return d->data; +}; + +bool hidprox_decode_feed(hidprox_codec *d, bool bit) { + if (d->state == STATE_SOF) { + d->sof <<= 1; + if (bit) { + SET_BIT(d->sof, 0); + } + if (d->sof == HIDPROX_SOF) { // found start of frame + d->state = STATE_DATA_LO; + } + return false; + } + + if (d->state == STATE_DATA_LO) { + d->bit = bit; + d->state = STATE_DATA_HI; + return false; + } + + if (d->state == STATE_DATA_HI) { + if (bit == d->bit) { // invalid manchester bit + decoder_reset(d); + return false; + } + + d->raw <<= 1; + d->raw_length++; + if (d->bit && !bit) { + SET_BIT(d->raw, 0); + } + + if (d->raw_length < 44) { + d->state = STATE_DATA_LO; + return false; + } + + d->state = STATE_DONE; + + uint8_t length = hidprox_codec_get_length(d); + wiegand_card_t *card = unpack(d->format_hint, length, 0, d->raw); + if (card == NULL) { + decoder_reset(d); + return false; + } + d->card = card; + return true; + } + + return false; +} + +bool hidprox_decoder_feed(hidprox_codec *d, uint16_t val) { + bool bit = false; + if (!fsk_feed(d->modem, val, &bit)) { + return false; + } + return hidprox_decode_feed(d, bit); +} + +void hidprox_raw_data(wiegand_card_t *card, uint32_t *hi, uint32_t *mid, uint32_t *bot) { + *hi = 0; + *mid = 0; + *bot = 0; + uint64_t data = pack(card); + if (data == 0) { + return; + } + *hi = HIDPROX_SOF; + for (uint8_t i = 0; i < 44; i++) { + uint32_t *blk; + if (i < 12) { + blk = hi; + } else if (i < 28) { + blk = mid; + } else { + blk = bot; + } + *blk <<= 2; + if ((data >> (43 - i)) & 0x01) { + *blk |= 0x02; + } else { + *blk |= 0x01; + } + } +} + +// fsk2a modulator +const nrf_pwm_sequence_t *hidprox_modulator(hidprox_codec *d, uint8_t *buf) { + uint64_t cn = buf[5]; + cn = (cn << 32) | (bytes_to_num(buf + 6, 4)); + wiegand_card_t card = { + .facility_code = bytes_to_num(buf + 1, 4), + .card_number = cn, + .issue_level = buf[10], + .oem = bytes_to_num(buf + 11, 2), + .format = buf[0], + }; + + uint32_t hi, mid, bot; + hidprox_raw_data(&card, &hi, &mid, &bot); + int k = 0; + for (int i = 0; i < HIDPROX_RAW_SIZE; i++) { + bool bit = false; + if (i < 32) { + bit = (hi >> (31 - i)) & 1; + } else if (i < 64) { + bit = (mid >> (63 - i)) & 1; + } else { + bit = (bot >> (95 - i)) & 1; + } + if (!bit) { + for (int j = 0; j < LF_FSK2a_PWM_HI_FREQ_LOOP; j++) { + m_hidprox_pwm_seq_vals[k].channel_0 = LF_FSK2a_PWM_HI_FREQ_TOP_VALUE / 2; + m_hidprox_pwm_seq_vals[k].counter_top = LF_FSK2a_PWM_HI_FREQ_TOP_VALUE; + k++; + } + } else { + for (int j = 0; j < LF_FSK2a_PWM_LO_FREQ_LOOP; j++) { + m_hidprox_pwm_seq_vals[k].channel_0 = LF_FSK2a_PWM_LO_FREQ_TOP_VALUE / 2; + m_hidprox_pwm_seq_vals[k].counter_top = LF_FSK2a_PWM_LO_FREQ_TOP_VALUE; + k++; + } + } + } + m_hidprox_pwm_seq.length = k * 4; + return &m_hidprox_pwm_seq; +}; + +const protocol hidprox = { + .tag_type = TAG_TYPE_HID_PROX, + .data_size = HIDPROX_DATA_SIZE, + .alloc = (codec_alloc)hidprox_codec_alloc, + .free = (codec_free)hidprox_codec_free, + .get_data = (codec_get_data)hidprox_get_data, + .modulator = (modulator)hidprox_modulator, + .decoder = + { + .start = (decoder_start)hidprox_decoder_start, + .feed = (decoder_feed)hidprox_decoder_feed, + }, +}; + +uint8_t hidprox_t55xx_writer(wiegand_card_t *card, uint32_t *blks) { + blks[0] = T5577_HIDPROX_CONFIG; + hidprox_raw_data(card, &blks[1], &blks[2], &blks[3]); + return HIDPROX_T55XX_BLOCK_COUNT; +} \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/lf/protocols/hidprox.h b/firmware/application/src/rfid/nfctag/lf/protocols/hidprox.h new file mode 100644 index 0000000..8306954 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/protocols/hidprox.h @@ -0,0 +1,33 @@ +#pragma once + +#include "protocols.h" +#include "utils/fskdemod.h" +#include "wiegand.h" + +#define HIDPROX_DATA_SIZE (16) + +typedef enum { + STATE_SOF, + STATE_DATA_LO, + STATE_DATA_HI, + STATE_DONE, +} hidprox_codec_state_t; + +typedef struct { + uint8_t data[HIDPROX_DATA_SIZE]; + + bool bit; + uint8_t sof; + uint64_t raw; + uint8_t raw_length; + + fsk_t *modem; + hidprox_codec_state_t state; + + uint8_t format_hint; + wiegand_card_t *card; +} hidprox_codec; + +extern const protocol hidprox; + +uint8_t hidprox_t55xx_writer(wiegand_card_t *card, uint32_t *blks); \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/lf/protocols/protocols.h b/firmware/application/src/rfid/nfctag/lf/protocols/protocols.h new file mode 100644 index 0000000..6bab966 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/protocols/protocols.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +#include "nrf_pwm.h" + +typedef void* (*codec_alloc)(void); +typedef void (*codec_free)(void* codec); +typedef uint8_t* (*codec_get_data)(void* codec); + +typedef void (*decoder_start)(void* codec, uint8_t format); +typedef bool (*decoder_feed)(void* codec, uint16_t val); + +typedef nrf_pwm_sequence_t* (*modulator)(void* d, uint8_t* buf); + +typedef struct { + decoder_start start; + decoder_feed feed; +} decoder_t; + +typedef struct { + uint16_t tag_type; + const size_t data_size; + codec_alloc alloc; + codec_free free; + codec_get_data get_data; + decoder_t decoder; + modulator modulator; +} protocol; diff --git a/firmware/application/src/rfid/nfctag/lf/protocols/t55xx.h b/firmware/application/src/rfid/nfctag/lf/protocols/t55xx.h new file mode 100644 index 0000000..788d93f --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/protocols/t55xx.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define T5577_BLOCK_COUNT 8 + +// t5577 block 0 definitions, thanks proxmark3! +#define T5577_POR_DELAY 0x00000001 +#define T5577_ST_TERMINATOR 0x00000008 +#define T5577_PWD 0x00000010 +#define T5577_MAXBLOCK_SHIFT 5 +#define T5577_AOR 0x00000200 +#define T5577_PSKCF_RF_2 0 +#define T5577_PSKCF_RF_4 0x00000400 +#define T5577_PSKCF_RF_8 0x00000800 +#define T5577_MODULATION_DIRECT 0 +#define T5577_MODULATION_PSK1 0x00001000 +#define T5577_MODULATION_PSK2 0x00002000 +#define T5577_MODULATION_PSK3 0x00003000 +#define T5577_MODULATION_FSK1 0x00004000 +#define T5577_MODULATION_FSK2 0x00005000 +#define T5577_MODULATION_FSK1a 0x00006000 +#define T5577_MODULATION_FSK2a 0x00007000 +#define T5577_MODULATION_MANCHESTER 0x00008000 +#define T5577_MODULATION_BIPHASE 0x00010000 +#define T5577_MODULATION_DIPHASE 0x00018000 +#define T5577_X_MODE 0x00020000 +#define T5577_BITRATE_RF_8 0 +#define T5577_BITRATE_RF_16 0x00040000 +#define T5577_BITRATE_RF_32 0x00080000 +#define T5577_BITRATE_RF_40 0x000C0000 +#define T5577_BITRATE_RF_50 0x00100000 +#define T5577_BITRATE_RF_64 0x00140000 +#define T5577_BITRATE_RF_100 0x00180000 +#define T5577_BITRATE_RF_128 0x001C0000 +#define T5577_TESTMODE_DISABLED 0x60000000 + +#define T5577_OPCODE_RESET 0x00 +#define T5577_OPCODE_PAGE0 0x02 +#define T5577_OPCODE_PAGE1 0x03 +#define T5577_EM410X_64_CONFIG ( \ + T5577_BITRATE_RF_64 | \ + T5577_MODULATION_MANCHESTER | \ + T5577_PWD | \ + (2 << T5577_MAXBLOCK_SHIFT)) + +#define T5577_HIDPROX_CONFIG ( \ + T5577_BITRATE_RF_50 | \ + T5577_MODULATION_FSK2a | \ + T5577_PWD | \ + (3 << T5577_MAXBLOCK_SHIFT)) + +void t55xx_write_data(uint32_t passwd, uint32_t *blks, uint8_t blk_count); +void t55xx_reset_passwd(uint32_t old_passwd, uint32_t new_passwd); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/lf/protocols/wiegand.c b/firmware/application/src/rfid/nfctag/lf/protocols/wiegand.c new file mode 100644 index 0000000..025120d --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/protocols/wiegand.c @@ -0,0 +1,856 @@ +#include "wiegand.h" + +#include +#include +#include + +#include "nordic_common.h" +#include "parity.h" + +#define PREAMBLE_26BIT (0x801) +#define PREAMBLE_27BIT (0x401) +#define PREAMBLE_28BIT (0x201) +#define PREAMBLE_29BIT (0x101) +#define PREAMBLE_30BIT (0x081) +#define PREAMBLE_31BIT (0x041) +#define PREAMBLE_32BIT (0x021) +#define PREAMBLE_33BIT (0x011) +#define PREAMBLE_34BIT (0x009) +#define PREAMBLE_35BIT (0x005) +#define PREAMBLE_36BIT (0x003) + +/**@brief Set a bit in the uint64 word. + * + * @param[in] W Word whose bit is being set. + * @param[in] B Bit number in the word to be set. + */ +#define SET_BIT64(W, B) ((W) |= (uint64_t)(1ULL << (B))) + +// if (!validate_card_limit(format_idx, card)) return false; + +const uint8_t indasc27_fc_map[13] = {4, 14, 2, 10, 16, 18, 7, 19, 26, 21, 20, 22, 17}; +const uint8_t indasc27_cn_map[14] = {3, 15, 5, 8, 24, 1, 13, 6, 9, 12, 11, 23, 25, 0}; + +const uint8_t tecom27_fc_map[11] = {24, 23, 12, 16, 20, 8, 4, 3, 2, 7, 11}; +const uint8_t tecom27_cn_map[16] = {21, 22, 15, 18, 19, 1, 5, 9, 10, 6, 0, 17, 14, 13, 25, 26}; + +wiegand_card_t *wiegand_card_alloc() { + wiegand_card_t *card = (wiegand_card_t *)malloc(sizeof(wiegand_card_t)); + memset(card, 0, sizeof(wiegand_card_t)); + return card; +} + +static uint64_t get_nonlinear_fields(uint64_t n, const uint8_t *map, size_t size) { + uint64_t bits = 0x0; + for (int i = 0; (i < size) && (n > 0); i++) { + if (n & 0x01) { + bits |= 1ULL << map[i]; + } + n >>= 1; + } + return bits; +} + +static uint64_t pack_nonlinear( + wiegand_card_t *card, + const uint8_t *fc_map, size_t fc_map_size, + const uint8_t *cn_map, size_t cn_map_size) { + uint64_t bits = PREAMBLE_27BIT; + bits <<= 27; + bits |= get_nonlinear_fields(card->facility_code, fc_map, fc_map_size); + bits |= get_nonlinear_fields(card->card_number, cn_map, cn_map_size); + return bits; +} + +static wiegand_card_t *unpack_nonlinear( + uint64_t hi, uint64_t lo, + const uint8_t *fc_map, size_t fc_map_size, + const uint8_t *cn_map, size_t cn_map_size) { + wiegand_card_t *d = wiegand_card_alloc(); + for (int i = fc_map_size - 1; i >= 0; i--) { + d->facility_code <<= 1; + if (IS_SET(lo, fc_map[i])) { + d->facility_code |= 0x1; + } + } + for (int i = cn_map_size - 1; i >= 0; i--) { + d->card_number <<= 1; + if (IS_SET(lo, cn_map[i])) { + d->card_number |= 0x1; + } + } + return d; +} + +static uint64_t pack_h10301(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_26BIT; + bits <<= 1; // even parity bit + bits = (bits << 8) | (card->facility_code & 0xff); + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 1; // odd parity bit + if (oddparity32((bits >> 1) & 0xfff)) { + SET_BIT64(bits, 0); + } + if (evenparity32((bits >> 13) & 0xfff)) { + SET_BIT64(bits, 25); + } + return bits; +} + +static wiegand_card_t *unpack_h10301(uint64_t hi, uint64_t lo) { + if (!((IS_SET(lo, 0) == oddparity32((lo >> 1) & 0xfff)) && + (IS_SET(lo, 25) == evenparity32((lo >> 13) & 0xfff)))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 17) & 0xff; + d->card_number = (lo >> 1) & 0xffff; + return d; +} + +static uint64_t pack_ind26(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_26BIT; + bits <<= 1; // even parity bit + + bits = (bits << 12) | (card->facility_code & 0xfff); + bits = (bits << 12) | (card->card_number & 0xfff); + + uint8_t odd_parity = oddparity32(bits & 0xfff); + bits <<= 1; // odd parity bit + if (odd_parity) { + bits |= 0x01; + } + uint8_t even_parity = evenparity32((bits >> 13) & 0xfff); + if (even_parity) { + bits |= 0x2000000; + } + return bits; +} + +static wiegand_card_t *unpack_ind26(uint64_t hi, uint64_t lo) { + uint32_t odd = (lo >> 1) & 0xfff; // 32..43 + uint8_t odd_parity = lo & 0x01; // 44 + uint32_t even = (lo >> 13) & 0xfff; // 19..31 + uint8_t even_parity = (lo >> 25) & 0x01; // 18 + if (!(oddparity32(odd) == odd_parity) && (evenparity32(even) == even_parity)) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->card_number = (lo >> 1) & 0xfff; + d->facility_code = (lo >> 13) & 0xfff; + return d; +} + +static uint64_t pack_ind27(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_27BIT; + bits = (bits << 13) | (card->facility_code & 0x1fff); + bits = (bits << 14) | (card->card_number & 0x3fff); + return bits; +} + +static wiegand_card_t *unpack_ind27(uint64_t hi, uint64_t lo) { + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 14) & 0x1fff; + d->card_number = (lo >> 0) & 0x3fff; + return d; +} + +static uint64_t pack_indasc27(wiegand_card_t *card) { + return pack_nonlinear(card, indasc27_fc_map, sizeof(indasc27_fc_map), indasc27_cn_map, sizeof(indasc27_cn_map)); +} + +static wiegand_card_t *unpack_indasc27(uint64_t hi, uint64_t lo) { + return unpack_nonlinear(hi, lo, indasc27_fc_map, sizeof(indasc27_fc_map), indasc27_cn_map, sizeof(indasc27_cn_map)); +} + +static uint64_t pack_tecom27(wiegand_card_t *card) { + return pack_nonlinear(card, tecom27_fc_map, sizeof(tecom27_fc_map), tecom27_cn_map, sizeof(tecom27_cn_map)); +} + +static wiegand_card_t *unpack_tecom27(uint64_t hi, uint64_t lo) { + return unpack_nonlinear(hi, lo, tecom27_fc_map, sizeof(tecom27_fc_map), tecom27_cn_map, sizeof(tecom27_cn_map)); +} + +static uint64_t pack_2804w(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_28BIT; + bits <<= 4; + bits = (bits << 8) | (card->facility_code & 0xff); + bits = (bits << 15) | (card->card_number & 0x7fff); + bits <<= 1; // parity bit + if (oddparity32(bits & 0xDB6DB6)) { + SET_BIT64(bits, 25); + } + if (evenparity32((bits >> 14) & 0x1fff)) { + SET_BIT64(bits, 27); + } + if (oddparity32((bits >> 1) & 0x7ffffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_2804w(uint64_t hi, uint64_t lo) { + if (!(((lo >> 27) & 0x1) == (evenparity32((lo >> 14) & 0x1fff)) && + (((lo >> 25) & 0x1) == (oddparity32(lo & 0xDB6DB6))) && + (((lo >> 0) & 0x1) == (oddparity32((lo >> 1) & 0x7ffffff))))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 16) & 0xff; + d->card_number = (lo >> 1) & 0x7fff; + return d; +} + +static uint64_t pack_ind29(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_29BIT; + bits = (bits << 13) | (card->facility_code & 0x1fff); + bits = (bits << 16) | (card->card_number & 0xffff); + return bits; +} + +static wiegand_card_t *unpack_ind29(uint64_t hi, uint64_t lo) { + wiegand_card_t *d = wiegand_card_alloc(); + d->card_number = (lo >> 0) & 0xffff; + d->facility_code = (lo >> 16) & 0x1fff; + return d; +} + +static uint64_t pack_atsw30(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_30BIT; + bits <<= 1; + bits = (bits << 12) | (card->facility_code & 0xfff); + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 1; + if (evenparity32((bits >> 17) & 0xfff)) { + SET_BIT64(bits, 29); + } + if (oddparity32((bits >> 1) & 0xffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_atsw30(uint64_t hi, uint64_t lo) { + if (!(IS_SET(lo, 29) == evenparity32((lo >> 17) & 0xfff) && + IS_SET(lo, 0) == oddparity32((lo >> 1) & 0xffff))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 17) & 0xfff; + d->card_number = (lo >> 1) & 0xffff; + return d; +} + +static uint64_t pack_adt31(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_31BIT; + bits <<= 1; // parity bit, unknown + bits = (bits << 4) | (card->facility_code & 0xf); + bits = (bits << 23) | (card->card_number & 0x7fffff); + bits <<= 3; + return bits; +} + +static wiegand_card_t *unpack_adt31(uint64_t hi, uint64_t lo) { + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 26) & 0xf; + d->card_number = (lo >> 3) & 0x7fffff; + return d; +} + +static uint64_t pack_hcp32(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_32BIT; + bits <<= 1; + bits = (bits << 24) | (card->card_number & 0xffffff); + bits <<= 7; + return bits; +} + +static wiegand_card_t *unpack_hcp32(uint64_t hi, uint64_t lo) { + wiegand_card_t *d = wiegand_card_alloc(); + d->card_number = (lo >> 7) & 0xffffff; + return d; +} + +static uint64_t pack_hpp32(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_32BIT; + bits <<= 1; + bits = (bits << 12) | (card->facility_code & 0xfff); + bits = (bits << 19) | (card->card_number & 0x7ffff); + return bits; +} + +static wiegand_card_t *unpack_hpp32(uint64_t hi, uint64_t lo) { + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 19) & 0xfff; + d->card_number = (lo >> 0) & 0x7ffff; + return d; +} + +static uint64_t pack_kastle(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_32BIT; + bits = (bits << 2) | 0x1; // Always 1 + bits = (bits << 5) | (card->issue_level & 0x1f); + bits = (bits << 8) | (card->facility_code & 0xff); + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 1; + if (evenparity32((bits >> 15) & 0xffff)) { + SET_BIT64(bits, 31); // even parity bit + } + if (oddparity32((bits >> 1) & 0x1ffff)) { + SET_BIT64(bits, 0); // odd parity bit + } + return bits; +} + +static wiegand_card_t *unpack_kastle(uint64_t hi, uint64_t lo) { + if (!IS_SET(lo, 30)) { // Always 1 in this format + return NULL; + } + if (!(IS_SET(lo, 31) == evenparity32((lo >> 15) & 0xffff) && + IS_SET(lo, 0) == oddparity32((lo >> 1) & 0x1ffff))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->issue_level = (lo >> 25) & 0x1f; + d->facility_code = (lo >> 17) & 0xff; + d->card_number = (lo >> 1) & 0xffff; + return d; +} + +static uint64_t pack_kantech(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_32BIT; + bits <<= 7; + bits = (bits << 8) | (card->facility_code & 0xff); + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 1; + return bits; +} + +static wiegand_card_t *unpack_kantech(uint64_t hi, uint64_t lo) { + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 17) & 0xff; + d->card_number = (lo >> 1) & 0xffff; + return d; +} + +static uint64_t pack_wie32(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_32BIT; + bits <<= 4; + bits = (bits << 12) | (card->facility_code & 0xfff); + bits = (bits << 16) | (card->card_number & 0xffff); + return bits; +} + +static wiegand_card_t *unpack_wie32(uint64_t hi, uint64_t lo) { + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 16) & 0xfff; + d->card_number = (lo >> 0) & 0xffff; + return d; +} + +static uint64_t pack_d10202(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_33BIT; + bits <<= 1; + bits = (bits << 7) | (card->facility_code & 0x7f); + bits = (bits << 24) | (card->card_number & 0xffffff); + bits <<= 1; + if (evenparity32((bits >> 16) & 0xffff)) { + SET_BIT64(bits, 32); + } + if (oddparity32((bits >> 1) & 0xffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_d10202(uint64_t hi, uint64_t lo) { + if (!((IS_SET(lo, 32) == evenparity32((lo >> 16) & 0xffff)) && + (IS_SET(lo, 0) == oddparity32((lo >> 1) & 0xffff)))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 25) & 0x7f; + d->card_number = (lo >> 1) & 0xffffff; + return d; +} + +static uint64_t pack_h10306(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_34BIT; + bits <<= 1; + bits = (bits << 16) | (card->facility_code & 0xffff); + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 1; + if (evenparity32((bits >> 17) & 0xffff)) { + SET_BIT64(bits, 33); + } + if (oddparity32((bits >> 1) & 0xffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_h10306(uint64_t hi, uint64_t lo) { + if (!((IS_SET(lo, 33) == evenparity32((lo >> 17) & 0xffff)) && + (IS_SET(lo, 0) == oddparity32((lo >> 1) & 0xffff)))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 17) & 0xffff; + d->card_number = (lo >> 1) & 0xffff; + return d; +} + +static uint64_t pack_n10002(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_34BIT; + bits <<= 1; + bits = (bits << 16) | (card->facility_code & 0xffff); + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 1; + if (evenparity32((bits >> 17) & 0xffff)) { + SET_BIT64(bits, 33); + } + if (oddparity32((bits >> 1) & 0xffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_n10002(uint64_t hi, uint64_t lo) { + if (!((IS_SET(lo, 33) == evenparity32((lo >> 17) & 0xffff)) && + (IS_SET(lo, 0) == oddparity32((lo >> 1) & 0xffff)))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 17) & 0xffff; + d->card_number = (lo >> 1) & 0xffff; + return d; +} + +static uint64_t pack_optus(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_34BIT; + bits <<= 1; + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 5; + bits = (bits << 11) | (card->facility_code & 0x7ff); + bits <<= 1; + return bits; +} + +static wiegand_card_t *unpack_optus(uint64_t hi, uint64_t lo) { + wiegand_card_t *d = wiegand_card_alloc(); + d->card_number = (lo >> 17) & 0xffff; + d->facility_code = (lo >> 1) & 0x7ff; + return d; +} + +static uint64_t pack_smartpass(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_34BIT; + bits <<= 1; + bits = (bits << 13) | (card->facility_code & 0x1fff); + bits = (bits << 3) | (card->issue_level & 0x7); + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 1; + return bits; +} + +static wiegand_card_t *unpack_smartpass(uint64_t hi, uint64_t lo) { + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 20) & 0x1fff; + d->issue_level = (lo >> 17) & 0x7; + d->card_number = (lo >> 1) & 0xffff; + return d; +} + +static uint64_t pack_bqt34(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_34BIT; + bits <<= 1; + bits = (bits << 8) | (card->facility_code & 0xff); + bits = (bits << 24) | (card->card_number & 0xffffff); + bits <<= 1; + if (evenparity32((bits >> 17) & 0xffff)) { + SET_BIT64(bits, 33); + } + if (oddparity32((bits >> 1) & 0xffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_bqt34(uint64_t hi, uint64_t lo) { + if (!((IS_SET(lo, 33) == evenparity32((lo >> 17) & 0xffff)) && + (IS_SET(lo, 0) == oddparity32((lo >> 1) & 0xffff)))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 25) & 0xff; + d->card_number = (lo >> 1) & 0xffffff; + return d; +} + +static uint64_t pack_c1k35s(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_35BIT; + bits <<= 2; + bits = (bits << 12) | (card->facility_code & 0xfff); + bits = (bits << 20) | (card->card_number & 0xfffff); + bits <<= 1; // parity bit + if (evenparity32((bits >> 1) & 0xDB6DB6DB)) { + SET_BIT64(bits, 33); + } + if (oddparity32(((bits >> 2) & 0xDB6DB6DB))) { + SET_BIT64(bits, 0); + } + if (oddparity32(((bits >> 32) & 0x3) ^ (bits & 0xFFFFFFFF))) { + SET_BIT64(bits, 34); + } + return bits; +} + +static wiegand_card_t *unpack_c1k35s(uint64_t hi, uint64_t lo) { + if (!(IS_SET(lo, 33) == (evenparity32((lo >> 1) & 0xDB6DB6DB)) && + IS_SET(lo, 0) == (oddparity32((lo >> 2) & 0xDB6DB6DB)) && + IS_SET(lo, 34) == (oddparity32(((lo >> 32) & 0x3) ^ (lo & 0xFFFFFFFF))))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->card_number = (lo >> 1) & 0xfffff; + d->facility_code = (lo >> 21) & 0xfff; + return d; +} + +static uint64_t pack_c15001(wiegand_card_t *card) { + if (card->oem == 0) { + card->oem = 900; + } + uint64_t bits = PREAMBLE_36BIT; + bits <<= 1; + bits = (bits << 10) | (card->oem & 0x3ff); + bits = (bits << 8) | (card->facility_code & 0xff); + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 1; + if (evenparity32((bits >> 18) & 0x1ffff)) { + SET_BIT64(bits, 35); + } + if (oddparity32((bits >> 1) & 0x1ffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_c15001(uint64_t hi, uint64_t lo) { + if (!(IS_SET(lo, 35) == evenparity32((lo >> 18) & 0x1ffff) && + IS_SET(lo, 0) == oddparity32((lo >> 1) & 0x1ffff))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->oem = (lo >> 25) & 0x3ff; + d->facility_code = (lo >> 17) & 0xff; + d->card_number = (lo >> 1) & 0xffff; + return d; +} + +static uint64_t pack_s12906(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_36BIT; + bits <<= 1; + bits = (bits << 8) | (card->facility_code & 0xff); + bits = (bits << 2) | (card->issue_level & 0x3); + bits = (bits << 24) | (card->card_number & 0xffffff); + bits <<= 1; + if (oddparity32((bits >> 18) & 0x1ffff)) { + SET_BIT64(bits, 35); + } + if (oddparity32((bits >> 1) & 0x3ffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_s12906(uint64_t hi, uint64_t lo) { + if (!(IS_SET(lo, 35) == oddparity32((lo >> 18) & 0x1ffff) && + IS_SET(lo, 0) == oddparity32((lo >> 1) & 0x3ffff))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 27) & 0xff; + d->issue_level = (lo >> 25) & 0x3; + d->card_number = (lo >> 1) & 0xffffff; + return d; +} + +static uint64_t pack_sie36(wiegand_card_t *card) { + uint64_t bits = PREAMBLE_36BIT; + bits <<= 1; + bits = (bits << 18) | (card->facility_code & 0x3ffff); + bits = (bits << 16) | (card->card_number & 0xffff); + bits <<= 1; + if (oddparity32((bits & 0xB6DB6DB6) ^ ((bits >> 32) & 0x05))) { + SET_BIT64(bits, 35); + } + if (evenparity32((bits & 0xDB6DB6DA) ^ ((bits >> 32) & 0x06))) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_sie36(uint64_t hi, uint64_t lo) { + if (!(IS_SET(lo, 35) == oddparity32((lo & 0xB6DB6DB6) ^ ((lo >> 32) & 0x05)) && + IS_SET(lo, 0) == evenparity32((lo & 0xDB6DB6DA) ^ ((lo >> 32) & 0x06)))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 17) & 0x3ffff; + d->card_number = (lo >> 1) & 0xffff; + return d; +} + +static uint64_t pack_h10320(wiegand_card_t *card) { + uint64_t bits = 0x01; // first bit is ONE. + // This card is BCD-encoded rather than binary. Set the 4-bit groups independently. + uint64_t n = 10000000; + for (uint32_t i = 0; i < 8; i++) { + bits = (bits << 4) | (((uint64_t)(card->card_number / n) % 10) & 0xf); + n /= 10; + } + bits <<= 4; + if (evenparity32((bits >> 4) & 0x88888888)) { + SET_BIT64(bits, 3); + } + if (oddparity32((bits >> 4) & 0x44444444)) { + SET_BIT64(bits, 2); + } + if (evenparity32((bits >> 4) & 0x22222222)) { + SET_BIT64(bits, 1); + } + if (evenparity32((bits >> 4) & 0x11111111)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_h10320(uint64_t hi, uint64_t lo) { + if (IS_SET(lo, 36) != 1) { + return NULL; + } + + if (!((IS_SET(lo, 3) == evenparity32((lo >> 4) & 0x88888888)) && + (IS_SET(lo, 2) == oddparity32((lo >> 4) & 0x44444444)) && + (IS_SET(lo, 1) == evenparity32((lo >> 4) & 0x22222222)) && + (IS_SET(lo, 0) == evenparity32((lo >> 4) & 0x11111111)))) { + return NULL; + } + + // This card is BCD-encoded rather than binary. Get the 4-bit groups independently. + uint64_t n = 1; + uint64_t cn = 0; + for (uint32_t i = 0; i < 8; i++) { + lo >>= 4; + uint64_t val = lo & 0xf; + if (val > 9) { // violation of BCD; Zero and exit. + return NULL; + } + cn += val * n; + n *= 10; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->card_number = cn; + return d; +} + +static uint64_t pack_h10302(wiegand_card_t *card) { + uint64_t bits = 0x00; + bits <<= 1; + bits = (bits << 35) | (card->card_number & 0x7ffffffff); + bits <<= 1; + if (evenparity32((bits >> 18) & 0x3ffff)) { + SET_BIT64(bits, 36); + } + if (oddparity32((bits >> 1) & 0x3ffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_h10302(uint64_t hi, uint64_t lo) { + if (!(IS_SET(lo, 36) == evenparity32((lo >> 18) & 0x3ffff) && + IS_SET(lo, 0) == oddparity32((lo >> 1) & 0x3ffff))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->card_number = (lo >> 1) & 0x7ffffffff; + return d; +} + +static uint64_t pack_h10304(wiegand_card_t *card) { + uint64_t bits = 0x00; + bits <<= 1; + bits = (bits << 16) | (card->facility_code & 0xffff); + bits = (bits << 19) | (card->card_number & 0x7ffff); + bits <<= 1; + if (evenparity32((bits >> 18) & 0x3ffff)) { + SET_BIT64(bits, 36); + } + if (oddparity32((bits >> 1) & 0x3ffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_h10304(uint64_t hi, uint64_t lo) { + if (!(IS_SET(lo, 36) == evenparity32((lo >> 18) & 0x3ffff) && + IS_SET(lo, 0) == oddparity32((lo >> 1) & 0x3ffff))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 20) & 0xffff; + d->card_number = (lo >> 1) & 0x7ffff; + return d; +} + +static uint64_t pack_p10004(wiegand_card_t *card) { + // unknown parity scheme + uint64_t bits = 0x00; + bits <<= 1; + bits = (bits << 13) | (card->facility_code & 0x1fff); + bits = (bits << 18) | (card->card_number & 0x3ffff); + bits <<= 5; + return bits; +} + +static wiegand_card_t *unpack_p10004(uint64_t hi, uint64_t lo) { + // unknown parity scheme + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 23) & 0x1fff; + d->card_number = (lo >> 5) & 0x3ffff; + return d; +} + +static uint64_t pack_hgeneric37(wiegand_card_t *card) { + uint64_t bits = 0x00; + bits <<= 4; + bits = (bits << 32) | (card->card_number & 0xffffffff); + bits = (bits << 1) | 0x1; // Always 1 + // even1 + if (evenparity32((bits >> 4) & 0x11111111)) { + SET_BIT64(bits, 36); + } + // odd1 + if (oddparity32(bits & 0x44444444)) { + SET_BIT64(bits, 34); + } + // even2 + if (evenparity32(bits & 0x22222222)) { + SET_BIT64(bits, 33); + } + return bits; +} + +static wiegand_card_t *unpack_hgeneric37(uint64_t hi, uint64_t lo) { + if (!IS_SET(lo, 0)) { // Always 1 in this format + return NULL; + } + if (!(IS_SET(lo, 36) == evenparity32((lo >> 4) & 0x11111111) && + IS_SET(lo, 34) == oddparity32(lo & 0x44444444) && + IS_SET(lo, 33) == evenparity32(lo & 0x22222222))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->card_number = (lo >> 1) & 0xffffffff; + return d; +} + +static uint64_t pack_mdi37(wiegand_card_t *card) { + uint64_t bits = 0x00; + bits <<= 3; + bits = (bits << 4) | (card->facility_code & 0xf); + bits = (bits << 29) | (card->card_number & 0x1fffffff); + bits <<= 1; + if (evenparity32((bits >> 18) & 0x3ffff)) { + SET_BIT64(bits, 36); + } + if (oddparity32((bits >> 1) & 0x3ffff)) { + SET_BIT64(bits, 0); + } + return bits; +} + +static wiegand_card_t *unpack_mdi37(uint64_t hi, uint64_t lo) { + if (!(IS_SET(lo, 36) == evenparity32((lo >> 18) & 0x3ffff) && + IS_SET(lo, 0) == oddparity32((lo >> 1) & 0x3ffff))) { + return NULL; + } + wiegand_card_t *d = wiegand_card_alloc(); + d->facility_code = (lo >> 30) & 0xf; + d->card_number = (lo >> 1) & 0x1fffffff; + return d; +} + +// ref: +// https://github.com/TeCHiScy/proxmark3/blob/d83196fb3549f236c0a58a309fdbd89c0487085c/client/src/wiegand_formats.c#L1457 +// https://github.com/Proxmark/proxmark3/blob/master/client/hidcardformats.c +// https://acre.my.site.com/knowledgearticles/s/article/x107 +// https://www.everythingid.com.au/hid-card-formats-i-15?srsltid=AfmBOor2UAGlvB7R6Zmj7B7rtL-LExfBjh7I3ZEyoLLbg7Pk7UbC1za- +static const card_format_table_t formats[] = { + {H10301, pack_h10301, unpack_h10301, 26, {1, 0xFF, 0xFFFF, 0, 0}}, // HID H10301 26-bit + {IND26, pack_ind26, unpack_ind26, 26, {1, 0xFFF, 0xFFF, 0, 0}}, // Indala 26-bit + {IND27, pack_ind27, unpack_ind27, 27, {0, 0x1FFF, 0x3FFF, 0, 0}}, // Indala 27-bit + {INDASC27, pack_indasc27, unpack_indasc27, 27, {0, 0x1FFF, 0x3FFF, 0, 0}}, // Indala ASC 27-bit + {TECOM27, pack_tecom27, unpack_tecom27, 27, {0, 0x7FF, 0xFFFF, 0, 0}}, // Tecom 27-bit + {W2804, pack_2804w, unpack_2804w, 28, {1, 0xFF, 0x7FFF, 0, 0}}, // 2804 Wiegand 28-bit + {IND29, pack_ind29, unpack_ind29, 29, {0, 0x1FFF, 0xFFFF, 0, 0}}, // Indala 29-bit + {ATSW30, pack_atsw30, unpack_atsw30, 30, {1, 0xFFF, 0xFFFF, 0, 0}}, // ATS Wiegand 30-bit + {ADT31, pack_adt31, unpack_adt31, 31, {0, 0xF, 0x7FFFFF, 0, 0}}, // HID ADT 31-bit + {HCP32, pack_hcp32, unpack_hcp32, 32, {0, 0, 0x3FFF, 0, 0}}, // HID Check Point 32-bit + {HPP32, pack_hpp32, unpack_hpp32, 32, {0, 0xFFF, 0x7FFFF, 0, 0}}, // HID Hewlett-Packard 32-bit + {KASTLE, pack_kastle, unpack_kastle, 32, {1, 0xFF, 0xFFFF, 0x1F, 0}}, // Kastle 32-bit + {KANTECH, pack_kantech, unpack_kantech, 32, {0, 0xFF, 0xFFFF, 0, 0}}, // Indala/Kantech KFS 32-bit + {WIE32, pack_wie32, unpack_wie32, 32, {0, 0xFFF, 0xFFFF, 0, 0}}, // Wiegand 32-bit + {D10202, pack_d10202, unpack_d10202, 33, {1, 0x7F, 0xFFFFFF, 0, 0}}, // HID D10202 33-bit + {H10306, pack_h10306, unpack_h10306, 34, {1, 0xFFFF, 0xFFFF, 0, 0}}, // HID H10306 34-bit + {N10002, pack_n10002, unpack_n10002, 34, {1, 0xFFFF, 0xFFFF, 0, 0}}, // Honeywell/Northern N10002 34-bit + {OPTUS34, pack_optus, unpack_optus, 34, {0, 0x3FF, 0xFFFF, 0, 0}}, // Indala Optus 34-bit + {SMP34, pack_smartpass, unpack_smartpass, 34, {0, 0x3FF, 0xFFFF, 0x7, 0}}, // Cardkey Smartpass 34-bit + {BQT34, pack_bqt34, unpack_bqt34, 34, {1, 0xFF, 0xFFFFFF, 0, 0}}, // BQT 34-bit + {C1K35S, pack_c1k35s, unpack_c1k35s, 35, {1, 0xFFF, 0xFFFFF, 0, 0}}, // HID Corporate 1000 35-bit Std + {C15001, pack_c15001, unpack_c15001, 36, {1, 0xFF, 0xFFFF, 0, 0x3FF}}, // HID KeyScan 36-bit + {S12906, pack_s12906, unpack_s12906, 36, {1, 0xFF, 0xFFFFFF, 0x3, 0}}, // HID Simplex 36-bit + {SIE36, pack_sie36, unpack_sie36, 36, {1, 0x3FFFF, 0xFFFF, 0, 0}}, // HID 36-bit Siemens + {H10320, pack_h10320, unpack_h10320, 37, {1, 0, 99999999, 0, 0}}, // HID H10320 37-bit BCD + {H10302, pack_h10302, unpack_h10302, 37, {1, 0, 0x7FFFFFFFF, 0, 0}}, // HID H10302 37-bit huge ID + {H10304, pack_h10304, unpack_h10304, 37, {1, 0xFFFF, 0x7FFFF, 0, 0}}, // HID H10304 37-bit + {P10004, pack_p10004, unpack_p10004, 37, {0, 0x1FFF, 0x3FFFF, 0, 0}}, // HID P10004 37-bit PCSC + {HGEN37, pack_hgeneric37, unpack_hgeneric37, 37, {1, 0, 0xFFFFFFFF, 0, 0}}, // HID Generic 37-bit + {MDI37, pack_mdi37, unpack_mdi37, 37, {1, 0xF, 0x1FFFFFFF, 0, 0}}, // PointGuard MDI 37-bit +}; + +uint64_t pack(wiegand_card_t *card) { + for (int i = 0; i < ARRAY_SIZE(formats); i++) { + if (card->format != formats[i].format) { + continue; + } + if (formats[i].pack == NULL) { + continue; + } + return formats[i].pack(card); + } + return 0; +} + +wiegand_card_t *unpack(uint8_t format_hint, uint8_t length, uint64_t hi, uint64_t lo) { + for (int i = 0; i < ARRAY_SIZE(formats); i++) { + if (format_hint != 0 && format_hint != formats[i].format) { + continue; + } + if (length != formats[i].bits) { + continue; + } + if (formats[i].unpack == NULL) { + continue; + } + wiegand_card_t *card = formats[i].unpack(hi, lo); + if (card == NULL) { + continue; + } + card->format = formats[i].format; + return card; + } + return NULL; +} diff --git a/firmware/application/src/rfid/nfctag/lf/protocols/wiegand.h b/firmware/application/src/rfid/nfctag/lf/protocols/wiegand.h new file mode 100644 index 0000000..8f898cf --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/protocols/wiegand.h @@ -0,0 +1,88 @@ +#pragma once + +#include +#include +#include +#include + +// Structure for packed wiegand messages +// Always align lowest value (last transmitted) bit to ordinal position 0 (lowest valued bit bottom) +typedef struct { + uint8_t length; // number of encoded bits in wiegand message (excluding headers and preamble) + uint64_t hi; // bits in x<<64 positions + uint64_t lo; // lowest ordinal positions +} wiegand_message_t; + +// Structure for unpacked wiegand card, like HID prox +typedef struct { + uint32_t facility_code; + uint64_t card_number; + uint32_t issue_level; + uint32_t oem; + uint8_t format; +} wiegand_card_t; + +typedef struct { + bool has_parity; + uint32_t max_fc; // max facility code + uint64_t max_cn; // max cardNumber + uint32_t max_il; // max issue_level + uint32_t max_oem; // max oem +} card_format_descriptor_t; + +typedef enum { + H10301 = 1, + IND26, + IND27, + INDASC27, + TECOM27, + W2804, + IND29, + ATSW30, + ADT31, + HCP32, + HPP32, + KASTLE, + KANTECH, + WIE32, + D10202, + H10306, + N10002, + OPTUS34, + SMP34, + BQT34, + C1K35S, + C15001, + S12906, + SIE36, + H10320, + H10302, + H10304, + P10004, + HGEN37, + MDI37, + BQT38, + ISCS, + PW39, + P10001, + CASI40, + BC40, + DEFCON32, + H800002, + C1K48S, + AVIG56, + IR56, +} card_format_t; + +// Structure for defined Wiegand card formats available for packing/unpacking +typedef struct { + card_format_t format; + uint64_t (*pack)(wiegand_card_t *card); + wiegand_card_t *(*unpack)(uint64_t hi, uint64_t lo); + uint32_t bits; // number of bits in this format + card_format_descriptor_t fields; +} card_format_table_t; + +extern uint64_t pack(wiegand_card_t *card); +extern wiegand_card_t *unpack(uint8_t format_hint, uint8_t length, uint64_t hi, uint64_t lo); +extern wiegand_card_t *wiegand_card_alloc(); \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/lf/utils/circular_buffer.c b/firmware/application/src/rfid/nfctag/lf/utils/circular_buffer.c new file mode 100644 index 0000000..59b76ca --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/utils/circular_buffer.c @@ -0,0 +1,51 @@ +#include "circular_buffer.h" + +#include +#include + +bool cb_init(circular_buffer *cb, size_t capacity, size_t sz) { + cb->buffer = malloc(capacity * sz); + if (cb->buffer == NULL) { + return false; + } + cb->buffer_end = (char *)cb->buffer + capacity * sz; + cb->capacity = capacity; + cb->count = 0; + cb->sz = sz; + cb->head = cb->buffer; + cb->tail = cb->buffer; + return true; +} + +void cb_free(circular_buffer *cb) { + if (cb != NULL && cb->buffer != NULL) { + free(cb->buffer); + cb->buffer = NULL; + } +} + +bool cb_push_back(circular_buffer *cb, const void *item) { + if (cb->buffer == NULL || cb->count == cb->capacity) { + return false; + } + memcpy(cb->head, item, cb->sz); + cb->head = (char *)cb->head + cb->sz; + if (cb->head == cb->buffer_end) { + cb->head = cb->buffer; + } + cb->count++; + return true; +} + +bool cb_pop_front(circular_buffer *cb, void *item) { + if (cb->buffer == NULL || cb->count == 0) { + return false; + } + memcpy(item, cb->tail, cb->sz); + cb->tail = (char *)cb->tail + cb->sz; + if (cb->tail == cb->buffer_end) { + cb->tail = cb->buffer; + } + cb->count--; + return true; +} \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/lf/utils/circular_buffer.h b/firmware/application/src/rfid/nfctag/lf/utils/circular_buffer.h new file mode 100644 index 0000000..9a670cf --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/utils/circular_buffer.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct circular_buffer { + void *buffer; // data buffer + void *buffer_end; // end of data buffer + size_t capacity; // maximum number of items in the buffer + size_t count; // number of items in the buffer + size_t sz; // size of each item in the buffer + void *head; // pointer to head + void *tail; // pointer to tail +} circular_buffer; + +extern bool cb_init(circular_buffer *cb, size_t capacity, size_t sz); +extern void cb_free(circular_buffer *cb); +extern bool cb_push_back(circular_buffer *cb, const void *item); +extern bool cb_pop_front(circular_buffer *cb, void *item); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/lf/utils/fskdemod.c b/firmware/application/src/rfid/nfctag/lf/utils/fskdemod.c new file mode 100644 index 0000000..7f80f96 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/utils/fskdemod.c @@ -0,0 +1,46 @@ +#include "fskdemod.h" + +#include +#include + +#include "math.h" + +#define PI 3.14159265358979f +#define GOERTZEL(FREQ, SAMPLE_RATE) (2.0 * cos((2.0 * PI * FREQ) / (SAMPLE_RATE))) + +float goertzel_mag(float coef, uint16_t samples[], int n) { + float z1 = 0; + float z2 = 0; + for (int i = 0; i < n; i++) { + float z0 = coef * z1 - z2 + (float)(samples[i]); + z2 = z1; + z1 = z0; + } + return sqrt(z1 * z1 + z2 * z2 - coef * z1 * z2); +} + +void fsk_free(fsk_t *m) { + if (m != NULL) { + free(m); + } +} + +bool fsk_feed(fsk_t *m, uint16_t sample, bool *bit) { + m->samples[m->c++] = sample; + if (m->c < BITRATE) { + return false; + } + float bit0 = goertzel_mag(m->goertzel_fc_8, m->samples, BITRATE); + float bit1 = goertzel_mag(m->goertzel_fc_10, m->samples, BITRATE); + *bit = bit1 > bit0; + m->c = 0; + return true; +} + +fsk_t *fsk_alloc(void) { + fsk_t *m = (fsk_t *)malloc(sizeof(fsk_t)); + m->c = 0; + m->goertzel_fc_8 = GOERTZEL(15625.0f, 125000.0f); + m->goertzel_fc_10 = GOERTZEL(12500.0f, 125000.0f); + return m; +} diff --git a/firmware/application/src/rfid/nfctag/lf/utils/fskdemod.h b/firmware/application/src/rfid/nfctag/lf/utils/fskdemod.h new file mode 100644 index 0000000..fa17d29 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/utils/fskdemod.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BITRATE (50) + +typedef struct { + uint8_t c; + uint16_t samples[BITRATE * 2]; + float goertzel_fc_8; + float goertzel_fc_10; +} fsk_t; + +extern bool fsk_feed(fsk_t *m, uint16_t sample, bool *bit); +extern fsk_t *fsk_alloc(void); +extern void fsk_free(fsk_t *m); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/application/src/rfid/nfctag/lf/utils/manchester.c b/firmware/application/src/rfid/nfctag/lf/utils/manchester.c new file mode 100644 index 0000000..f00acc5 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/utils/manchester.c @@ -0,0 +1,51 @@ +#include "manchester.h" + +#include +#include + +void manchester_reset(manchester *m) { + m->sync = true; +} + +void manchester_feed(manchester *m, uint8_t interval, bool *bits, int8_t *bitlen) { + // after the current interval is processed, is it on the judgment line + uint8_t t = m->rp(interval); + *bitlen = -1; + if (t == 3) { + return; + } + + if (m->sync) { + if (t == 0) { + // 1T, add '0', still sync + *bitlen = 1; + bits[0] = 0; + } else if (t == 1) { + // 1.5T, add '1', switch to non-sync + *bitlen = 1; + bits[0] = 1; + m->sync = false; + } else if (t == 2) { + // 2T, add '10', still sync + *bitlen = 2; + bits[0] = 1; + bits[1] = 0; + } else { + return; + } + } else { + if (t == 0) { + // 1T, add '1', still non-sync + *bitlen = 1; + bits[0] = 1; + } else if (t == 1) { + // 1.5T, add '10', switch to sync + *bitlen = 2; + bits[0] = 1; + bits[1] = 0; + m->sync = true; + } else { + return; + } + } +} diff --git a/firmware/application/src/rfid/nfctag/lf/utils/manchester.h b/firmware/application/src/rfid/nfctag/lf/utils/manchester.h new file mode 100644 index 0000000..202d563 --- /dev/null +++ b/firmware/application/src/rfid/nfctag/lf/utils/manchester.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include + +typedef uint8_t (*period)(uint8_t interval); + +typedef struct { + bool sync; + period rp; +} manchester; + +extern void manchester_reset(manchester *m); +extern void manchester_feed(manchester *m, uint8_t interval, bool *bits, int8_t *bitlen); \ No newline at end of file diff --git a/firmware/application/src/rfid/nfctag/tag_base_type.h b/firmware/application/src/rfid/nfctag/tag_base_type.h index 5e83319..dd5cfe5 100644 --- a/firmware/application/src/rfid/nfctag/tag_base_type.h +++ b/firmware/application/src/rfid/nfctag/tag_base_type.h @@ -1,10 +1,9 @@ #ifndef TAG_BASE_TYPE_H #define TAG_BASE_TYPE_H - // Field sensor type -typedef enum { - //No sense of induction +typedef enum { + // No sense of induction TAG_SENSE_NO, // Low -frequency 125kHz field induction TAG_SENSE_LF, @@ -13,12 +12,11 @@ typedef enum { } tag_sense_type_t; /** - * - *The definition of all types of labels that support analog - * Note that all the defined label type below is the specific type statistics of the application layer refine - * No longer distinguish between high and low frequencies + * The definition of all types of labels that support analog + * Note that all the defined tag type below is the specific type statistics of + * the application layer refine No longer distinguish between high and low + * frequencies */ - typedef enum { TAG_TYPE_UNDEFINED = 0, @@ -35,8 +33,11 @@ typedef enum { //////////// LF //////////// //////// ASK Tag-Talk-First 100 - // EM410x + // EM410x, EM-Micro TAG_TYPE_EM410X = 100, + TAG_TYPE_EM410X_16, + TAG_TYPE_EM410X_32, + TAG_TYPE_EM410X_64, // FDX-B // securakey // gallagher @@ -48,7 +49,7 @@ typedef enum { // Jablotron //////// FSK Tag-Talk-First 200 - // HID Prox + TAG_TYPE_HID_PROX = 200, // ioProx // AWID // Paradox @@ -93,37 +94,29 @@ typedef enum { #define TAG_SPECIFIC_TYPE_OLD2NEW_LF_VALUES \ {OLD_TAG_TYPE_EM410X, TAG_TYPE_EM410X} -#define TAG_SPECIFIC_TYPE_OLD2NEW_HF_VALUES \ - {OLD_TAG_TYPE_MIFARE_Mini, TAG_TYPE_MIFARE_Mini},\ - {OLD_TAG_TYPE_MIFARE_1024, TAG_TYPE_MIFARE_1024},\ - {OLD_TAG_TYPE_MIFARE_2048, TAG_TYPE_MIFARE_2048},\ - {OLD_TAG_TYPE_MIFARE_4096, TAG_TYPE_MIFARE_4096},\ - {OLD_TAG_TYPE_NTAG_213, TAG_TYPE_NTAG_213},\ - {OLD_TAG_TYPE_NTAG_215, TAG_TYPE_NTAG_215},\ - {OLD_TAG_TYPE_NTAG_216, TAG_TYPE_NTAG_216} +#define TAG_SPECIFIC_TYPE_OLD2NEW_HF_VALUES \ + {OLD_TAG_TYPE_MIFARE_Mini, TAG_TYPE_MIFARE_Mini}, \ + {OLD_TAG_TYPE_MIFARE_1024, TAG_TYPE_MIFARE_1024}, \ + {OLD_TAG_TYPE_MIFARE_2048, TAG_TYPE_MIFARE_2048}, \ + {OLD_TAG_TYPE_MIFARE_4096, TAG_TYPE_MIFARE_4096}, \ + {OLD_TAG_TYPE_NTAG_213, TAG_TYPE_NTAG_213}, \ + {OLD_TAG_TYPE_NTAG_215, TAG_TYPE_NTAG_215}, { \ + OLD_TAG_TYPE_NTAG_216, TAG_TYPE_NTAG_216 \ + } #define TAG_SPECIFIC_TYPE_LF_VALUES \ - TAG_TYPE_EM410X + TAG_TYPE_EM410X, TAG_TYPE_HID_PROX -#define TAG_SPECIFIC_TYPE_HF_VALUES \ - TAG_TYPE_MIFARE_Mini,\ - TAG_TYPE_MIFARE_1024,\ - TAG_TYPE_MIFARE_2048,\ - TAG_TYPE_MIFARE_4096,\ - TAG_TYPE_NTAG_213,\ - TAG_TYPE_NTAG_215,\ - TAG_TYPE_NTAG_216,\ - TAG_TYPE_MF0ICU1,\ - TAG_TYPE_MF0ICU2,\ - TAG_TYPE_MF0UL11,\ - TAG_TYPE_MF0UL21,\ - TAG_TYPE_NTAG_210,\ - TAG_TYPE_NTAG_212 +#define TAG_SPECIFIC_TYPE_HF_VALUES \ + TAG_TYPE_MIFARE_Mini, TAG_TYPE_MIFARE_1024, TAG_TYPE_MIFARE_2048, \ + TAG_TYPE_MIFARE_4096, TAG_TYPE_NTAG_213, TAG_TYPE_NTAG_215, \ + TAG_TYPE_NTAG_216, TAG_TYPE_MF0ICU1, TAG_TYPE_MF0ICU2, \ + TAG_TYPE_MF0UL11, TAG_TYPE_MF0UL21, TAG_TYPE_NTAG_210, \ + TAG_TYPE_NTAG_212 typedef struct { tag_specific_type_t tag_hf; tag_specific_type_t tag_lf; } tag_slot_specific_type_t; - #endif diff --git a/firmware/application/src/rfid/nfctag/tag_emulation.c b/firmware/application/src/rfid/nfctag/tag_emulation.c index 9f8d167..b3fe48e 100644 --- a/firmware/application/src/rfid/nfctag/tag_emulation.c +++ b/firmware/application/src/rfid/nfctag/tag_emulation.c @@ -1,14 +1,14 @@ +#include "tag_emulation.h" + #include "crc_utils.h" -#include "nfc_14a.h" -#include "lf_tag_em.h" -#include "nfc_mf1.h" -#include "nfc_mf0_ntag.h" #include "fds_ids.h" #include "fds_util.h" -#include "tag_emulation.h" -#include "tag_persistence.h" +#include "lf_tag_em.h" +#include "nfc_14a.h" +#include "nfc_mf0_ntag.h" +#include "nfc_mf1.h" #include "rgb_marquee.h" - +#include "tag_persistence.h" #define NRF_LOG_MODULE_NAME tag_emu #include "nrf_log.h" @@ -16,15 +16,12 @@ #include "nrf_log_default_backends.h" NRF_LOG_MODULE_REGISTER(); - /* * A card slot can simulate up to two cards at the same time, one ID 125kHz EM410X, and one IC 13.56MHz 14A.(May be able to support more in the future) * When starting, you should start the startup listener on demand (there is no emulated card when there is no data, but you need to monitor the state on demand) * If the retrieved card slot configuration has a specified type of card, then loading the specified type of data should be carried out, and the necessary parameters of initialization should be performed. - * When the on-field entry is detected, in addition to the relevant LED, you also need to start the simulation card according to whether the current data is loaded. - * In the simulation card, all operations should be carried out based on the data loaded in RAM. After the analog card is over, the modified data should be preserved to Flash - * - * + * When the on-field entry is detected, in addition to the relevant LED, you also need to start the emulation card according to whether the current data is loaded. + * In the emulation card, all operations should be carried out based on the data loaded in RAM. After the analog card is over, the modified data should be preserved to Flash * * ...... */ @@ -32,10 +29,10 @@ NRF_LOG_MODULE_REGISTER(); // Is the logo in the analog card? bool g_is_tag_emulating = false; -static tag_specific_type_t tag_specific_type_old2new_lf_values[][2] = { TAG_SPECIFIC_TYPE_OLD2NEW_LF_VALUES }; -static tag_specific_type_t tag_specific_type_old2new_hf_values[][2] = { TAG_SPECIFIC_TYPE_OLD2NEW_HF_VALUES }; -static tag_specific_type_t tag_specific_type_lf_values[] = { TAG_SPECIFIC_TYPE_LF_VALUES }; -static tag_specific_type_t tag_specific_type_hf_values[] = { TAG_SPECIFIC_TYPE_HF_VALUES }; +static tag_specific_type_t tag_specific_type_old2new_lf_values[][2] = {TAG_SPECIFIC_TYPE_OLD2NEW_LF_VALUES}; +static tag_specific_type_t tag_specific_type_old2new_hf_values[][2] = {TAG_SPECIFIC_TYPE_OLD2NEW_HF_VALUES}; +static tag_specific_type_t tag_specific_type_lf_values[] = {TAG_SPECIFIC_TYPE_LF_VALUES}; +static tag_specific_type_t tag_specific_type_hf_values[] = {TAG_SPECIFIC_TYPE_HF_VALUES}; bool is_tag_specific_type_valid(tag_specific_type_t tag_type) { bool valid = false; @@ -50,15 +47,15 @@ bool is_tag_specific_type_valid(tag_specific_type_t tag_type) { // ********************** Specific parameters start ********************** /** - * The label data exists in the information in Flash, and the total length must be aligned by 4 bytes (whole words)!IntersectionIntersection + * Tag data stored in flash. Total length must be aligned by 4 bytes (whole words). */ -static uint8_t m_tag_data_buffer_lf[12]; // Low -frequency card data buffer +static uint8_t m_tag_data_buffer_lf[20]; // LF card data buffer static uint16_t m_tag_data_lf_crc; -static tag_data_buffer_t m_tag_data_lf = { sizeof(m_tag_data_buffer_lf), m_tag_data_buffer_lf, &m_tag_data_lf_crc }; +static tag_data_buffer_t m_tag_data_lf = {sizeof(m_tag_data_buffer_lf), m_tag_data_buffer_lf, &m_tag_data_lf_crc}; -static uint8_t m_tag_data_buffer_hf[4500]; // High -frequency card data buffer +static uint8_t m_tag_data_buffer_hf[4500]; // HF card data buffer static uint16_t m_tag_data_hf_crc; -static tag_data_buffer_t m_tag_data_hf = { sizeof(m_tag_data_buffer_hf), m_tag_data_buffer_hf, &m_tag_data_hf_crc }; +static tag_data_buffer_t m_tag_data_hf = {sizeof(m_tag_data_buffer_hf), m_tag_data_buffer_hf, &m_tag_data_hf_crc}; /** * Eight card slots, each card slot has its own unique configuration @@ -70,14 +67,14 @@ static tag_slot_config_t slotConfig ALIGN_U32 = { // Configuration card slots // See tag_emulation_factory_init for actual tag content .slots = { - { .enabled_hf = true, .enabled_lf = true, .tag_hf = TAG_TYPE_MIFARE_1024, .tag_lf = TAG_TYPE_EM410X, }, // 1 - { .enabled_hf = true, .enabled_lf = false, .tag_hf = TAG_TYPE_MF0ICU1, .tag_lf = TAG_TYPE_UNDEFINED, }, // 2 - { .enabled_hf = false, .enabled_lf = true, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_EM410X, }, // 3 - { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 4 - { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 5 - { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 6 - { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 7 - { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 8 + { .enabled_hf = true, .enabled_lf = true, .tag_hf = TAG_TYPE_MIFARE_1024, .tag_lf = TAG_TYPE_EM410X, }, // 1 + { .enabled_hf = true, .enabled_lf = false, .tag_hf = TAG_TYPE_MF0ICU1, .tag_lf = TAG_TYPE_UNDEFINED, }, // 2 + { .enabled_hf = false, .enabled_lf = true, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_EM410X, }, // 3 + { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 4 + { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 5 + { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 6 + { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 7 + { .enabled_hf = false, .enabled_lf = false, .tag_hf = TAG_TYPE_UNDEFINED, .tag_lf = TAG_TYPE_UNDEFINED, }, // 8 }, }; // The card slot configuration unique CRC, once the slot configuration changes, can be checked by CRC @@ -85,39 +82,38 @@ static uint16_t m_slot_config_crc; // ********************** Specific parameter ends ********************** - /** - * The data of the label is loaded to the RAM and the mapping table of the operation of the regulating notification, + * The data of the tag is loaded to the RAM and the mapping table of the operation of the regulating notification, * The mapping structure is: - * Field -type detailed label type Loading data The notification of the notification of the notification of the notification of the call recovery data before saving the data of the realization data of the function card data + * Field -type detailed tag type Loading data The notification of the notification of the notification of the notification of the call recovery data before saving the data of the realization data of the function card data */ static tag_base_handler_map_t tag_base_map[] = { - // Low -frequency ID card simulation - { TAG_SENSE_LF, TAG_TYPE_EM410X, lf_tag_em410x_data_loadcb, lf_tag_em410x_data_savecb, lf_tag_em410x_data_factory, &m_tag_data_lf }, - // MF1 tag simulation - { TAG_SENSE_HF, TAG_TYPE_MIFARE_Mini, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_MIFARE_1024, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_MIFARE_2048, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_MIFARE_4096, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, - // NTAG tag simulation - { TAG_SENSE_HF, TAG_TYPE_NTAG_210, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_NTAG_212, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_NTAG_213, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_NTAG_215, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_NTAG_216, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, - // MF0 tag simulation - { TAG_SENSE_HF, TAG_TYPE_MF0ICU1, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_MF0ICU2, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_MF0UL11, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, - { TAG_SENSE_HF, TAG_TYPE_MF0UL21, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf }, + // LF tag emulation + {TAG_SENSE_LF, TAG_TYPE_EM410X, lf_tag_data_loadcb, lf_tag_em410x_data_savecb, lf_tag_em410x_data_factory, &m_tag_data_lf}, + {TAG_SENSE_LF, TAG_TYPE_HID_PROX, lf_tag_data_loadcb, lf_tag_hidprox_data_savecb, lf_tag_hidprox_data_factory, &m_tag_data_lf}, + // MF1 tag emulation + {TAG_SENSE_HF, TAG_TYPE_MIFARE_Mini, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_MIFARE_1024, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_MIFARE_2048, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_MIFARE_4096, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf}, + // NTAG tag emulation + {TAG_SENSE_HF, TAG_TYPE_NTAG_210, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_NTAG_212, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_NTAG_213, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_NTAG_215, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_NTAG_216, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf}, + // MF0 tag emulation + {TAG_SENSE_HF, TAG_TYPE_MF0ICU1, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_MF0ICU2, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_MF0UL11, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf}, + {TAG_SENSE_HF, TAG_TYPE_MF0UL21, nfc_tag_mf0_ntag_data_loadcb, nfc_tag_mf0_ntag_data_savecb, nfc_tag_mf0_ntag_data_factory, &m_tag_data_hf}, }; - static void tag_emulation_load_config(void); static void tag_emulation_save_config(void); /** - * accordingToTheSpecifiedDetailedLabelType,ObtainTheImplementationFunctionOfTheDataThatProcessesTheLoadedLoaded + * get the data loader for the specific type of tag */ static tag_datas_loadcb_t get_data_loadcb_from_tag_type(tag_specific_type_t type) { for (int i = 0; i < ARRAY_SIZE(tag_base_map); i++) { @@ -141,7 +137,7 @@ static tag_datas_savecb_t get_data_savecb_from_tag_type(tag_specific_type_t type } /** - * accordingToTheSpecifiedDetailedLabelType,ObtainTheOperationFunctionOfTheDataFactoryInitialized + * get factory data for specific tag type */ static tag_datas_factory_t get_data_factory_from_tag_type(tag_specific_type_t type) { for (int i = 0; i < ARRAY_SIZE(tag_base_map); i++) { @@ -165,7 +161,7 @@ tag_sense_type_t get_sense_type_from_tag_type(tag_specific_type_t type) { } /** - * obtainTheBufferInformationAccordingToTheType + * Get buffer data according to tag type. */ tag_data_buffer_t *get_buffer_by_tag_type(tag_specific_type_t type) { for (int i = 0; i < ARRAY_SIZE(tag_base_map); i++) { @@ -173,22 +169,28 @@ tag_data_buffer_t *get_buffer_by_tag_type(tag_specific_type_t type) { return tag_base_map[i].data_buffer; } } + NRF_LOG_ERROR("no buffer valid for tag type %d.", type); return NULL; } /** -* loadDataFromMemoryToTheSimulationCardData + * Load data from memory to the emulated card data. */ bool tag_emulation_load_by_buffer(tag_specific_type_t tag_type, bool update_crc) { - // theDataHasBeenLoadedToTheBufferArea,AndTheConfigurationOfTheActivatedCardSlotIsNext, //PassTheBufferOfTheSettingOfTheSettingSimulationCardType (highFrequencyCard,LowFrequencyCard)ToIt - tag_datas_loadcb_t fn_loadcb = get_data_loadcb_from_tag_type(tag_type); - if (fn_loadcb == NULL) { //makeSureThatThereIsACorrespondingLoadingProcess - NRF_LOG_INFO("Tag data loader no impl."); + // data has been read to buffer, + // here we load buffer to the emulator to config pwm seq for the activated card slot. + tag_datas_loadcb_t loader = get_data_loadcb_from_tag_type(tag_type); + if (loader == NULL) { + NRF_LOG_INFO("no data loader exists for the tag type."); return false; } - //theCorrespondingImplementation,WeHaveLoadedTheData + tag_data_buffer_t *buffer = get_buffer_by_tag_type(tag_type); - int length = fn_loadcb(tag_type, buffer); + if (buffer == NULL) { + return false; + } + + int length = loader(tag_type, buffer); if (length > 0 && update_crc) { // afterReadingIsCompleted,WeCanSaveACrcOfTheCurrentDataWhenItIsStoredLater,ItCanBeUsedAsAReferenceForChangesComparison calc_14a_crc_lut(buffer->buffer, length, (uint8_t *)buffer->crc); @@ -198,33 +200,37 @@ bool tag_emulation_load_by_buffer(tag_specific_type_t tag_type, bool update_crc) } /** - * loadTheDataAccordingToTheType + * Load card data based on tag type. */ static void load_data_by_tag_type(uint8_t slot, tag_specific_type_t tag_type) { - // maybeTheCardSlotIsNotEnabledToUseTheSimulationOfThisTypeOfLabel,AndSkipTheDataDirectlyToLoadThisData + // maybeTheCardSlotIsNotEnabledToUseTheemulationOfThisTypeOfLabel,AndSkipTheDataDirectlyToLoadThisData if (tag_type == TAG_TYPE_UNDEFINED) { return; } - // getTheSpecialBufferInformation + tag_data_buffer_t *buffer = get_buffer_by_tag_type(tag_type); if (buffer == NULL) { - NRF_LOG_ERROR("No buffer valid!"); return; } + tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); - // getTheSpecialCardSlotFdsRecordInformation + + // get fds record for the card slot fds_slot_record_map_t map_info; get_fds_map_by_slot_sense_type_for_dump(slot, sense_type, &map_info); - // accordingToTheTypeOfTheCardSlotCurrentlyActivated,LoadTheDataOfTheDesignatedFieldToTheBuffer //Tip:IfTheLengthOfTheDataCannotMatchTheLengthOfTheBuffer,ItMayBeCausedByTheFirmwareUpdateAtThisTime,TheDataMustBeDeletedAndRebuilt + + // load data to the buffer according to the card slot currently activated. + // If the length of data does not match the length of the buffer, + // it may be caused by the firmware update at this time, the data must be deleted and rebuilt. uint16_t length = buffer->length; bool ret = fds_read_sync(map_info.id, map_info.key, &length, buffer->buffer); if (false == ret) { - NRF_LOG_INFO("Tag slot data no exists."); + NRF_LOG_INFO("tag slot data no exists."); return; } ret = tag_emulation_load_by_buffer(tag_type, true); if (ret) { - NRF_LOG_INFO("Load tag slot %d, type %d data done.", slot, tag_type); + NRF_LOG_INFO("load tag data in slot %d, type %d done.", slot, tag_type); } } @@ -232,24 +238,25 @@ static void load_data_by_tag_type(uint8_t slot, tag_specific_type_t tag_type) { * Save data according to the type */ static void save_data_by_tag_type(uint8_t slot, tag_specific_type_t tag_type) { - // Maybe the card slot is not enabled to use the simulation of this type of label, and skip it directly to save this data + // Maybe the card slot is not enabled to use the emulation of this type of label, and skip it directly to save this data if (tag_type == TAG_TYPE_UNDEFINED) { return; } + tag_data_buffer_t *buffer = get_buffer_by_tag_type(tag_type); if (buffer == NULL) { - NRF_LOG_ERROR("No buffer valid!"); return; } + // The length of the data to be saved by the user should not exceed the size of the global buffer int data_byte_length = 0; tag_datas_savecb_t fn_savecb = get_data_savecb_from_tag_type(tag_type); - if (fn_savecb == NULL) { //Make sure that there is a real estate process + if (fn_savecb == NULL) { // Make sure that there is a real estate process NRF_LOG_INFO("Tag data saver no impl."); return; - } else { - data_byte_length = fn_savecb(tag_type, buffer); } + + data_byte_length = fn_savecb(tag_type, buffer); // Make sure to save data, we can judge whether the data has changed through CRC if (data_byte_length <= 0) { NRF_LOG_INFO("Tag type %d data no save.", tag_type); @@ -278,7 +285,7 @@ static void save_data_by_tag_type(uint8_t slot, tag_specific_type_t tag_type) { } else { NRF_LOG_ERROR("Save tag slot data error."); } - //After the preservation is completed, the CRC of the BUFFER in the corresponding memory + // After the preservation is completed, the CRC of the BUFFER in the corresponding memory *buffer->crc = crc; } @@ -296,7 +303,7 @@ static void delete_data_by_tag_type(uint8_t slot, tag_sense_type_t sense_type) { } /** - * Load the simulation card data data. Note that loading is just data operation, + * Load the emulation card data data. Note that loading is just data operation, * Start the analog card, please call tag_emulation_sense_run function, otherwise you will not sensor the field event */ void tag_emulation_load_data(void) { @@ -315,7 +322,7 @@ void tag_emulation_save_data(void) { } /** - * @brief Get the type of labeling of the simulation card from the corresponding card slot. + * @brief Get the type of labeling of the emulation card from the corresponding card slot. * * @param slot Card slot * @param tag_type Label @@ -326,27 +333,25 @@ void tag_emulation_get_specific_types_by_slot(uint8_t slot, tag_slot_specific_ty } /** - * Delete the data specified by a card slot, if it is the current activated card slot data, we also need to dynamically close the simulation of this card + * Delete the data specified by a card slot, if it is the current activated card slot data, we also need to dynamically close the emulation of this card */ void tag_emulation_delete_data(uint8_t slot, tag_sense_type_t sense_type) { // delete data delete_data_by_tag_type(slot, sense_type); - //Close the corresponding card type of the corresponding card slot + // Close the corresponding card type of the corresponding card slot switch (sense_type) { case TAG_SENSE_HF: { slotConfig.slots[slot].tag_hf = TAG_TYPE_UNDEFINED; slotConfig.slots[slot].enabled_hf = false; - } - break; + } break; case TAG_SENSE_LF: { slotConfig.slots[slot].tag_lf = TAG_TYPE_UNDEFINED; slotConfig.slots[slot].enabled_lf = false; - } - break; + } break; default: break; } - // If the deleted card slot data is currently activated (being simulated), we also need to make dynamic shutdown + // If the deleted card slot data is currently activated (being emulated), we also need to make dynamic shutdown if (slotConfig.active_slot == slot) { tag_emulation_sense_switch(sense_type, false); } @@ -357,15 +362,13 @@ void tag_emulation_delete_data(uint8_t slot, tag_sense_type_t sense_type) { */ bool tag_emulation_factory_data(uint8_t slot, tag_specific_type_t tag_type) { tag_datas_factory_t factory = get_data_factory_from_tag_type(tag_type); - if (factory != NULL) { - // The process of implementing the data formatting data! - if (factory(slot, tag_type)) { - // If the current data card slot number currently set is the current activated card slot, then we need to update to the memory - if (tag_emulation_get_slot() == slot) { - load_data_by_tag_type(slot, tag_type); - } - return true; + // The process of implementing the data formatting data! + if (factory != NULL && factory(slot, tag_type)) { + // If the current data card slot number currently set is the current activated card slot, then we need to update to the memory + if (tag_emulation_get_slot() == slot) { + load_data_by_tag_type(slot, tag_type); } + return true; } return false; } @@ -403,7 +406,7 @@ void tag_emulation_sense_switch(tag_sense_type_t type, bool enable) { break; case TAG_SENSE_HF: if (enable && (slotConfig.slots[slot].enabled_hf) && - (slotConfig.slots[slot].tag_hf != TAG_TYPE_UNDEFINED)) { + (slotConfig.slots[slot].tag_hf != TAG_TYPE_UNDEFINED)) { nfc_tag_14a_sense_switch(true); } else { nfc_tag_14a_sense_switch(false); @@ -411,7 +414,7 @@ void tag_emulation_sense_switch(tag_sense_type_t type, bool enable) { break; case TAG_SENSE_LF: if (enable && (slotConfig.slots[slot].enabled_lf) && - (slotConfig.slots[slot].tag_lf != TAG_TYPE_UNDEFINED)) { + (slotConfig.slots[slot].tag_lf != TAG_TYPE_UNDEFINED)) { lf_tag_125khz_sense_switch(true); } else { lf_tag_125khz_sense_switch(false); @@ -420,7 +423,6 @@ void tag_emulation_sense_switch(tag_sense_type_t type, bool enable) { } } - static void tag_emulation_migrate_slot_config_v0_to_v8(void) { // Copy old slotConfig content uint8_t tmpbuf[sizeof(slotConfig)]; @@ -430,7 +432,7 @@ static void tag_emulation_migrate_slot_config_v0_to_v8(void) { // Populate new slotConfig struct slotConfig.version = TAG_SLOT_CONFIG_CURRENT_VERSION; slotConfig.active_slot = tmpbuf[0]; - for (uint8_t i = 0; i < ARRAYLEN(slotConfig.slots); i++) { + for (uint8_t i = 0; i < ARRAYLEN(slotConfig.slots); i++) { bool enabled = tmpbuf[4 + (i * 4)] & 1; slotConfig.slots[i].tag_hf = tmpbuf[4 + (i * 4) + 2]; @@ -453,7 +455,6 @@ static void tag_emulation_migrate_slot_config_v0_to_v8(void) { } } - static void tag_emulation_migrate_slot_config(void) { switch (slotConfig.version) { case 0: @@ -481,7 +482,6 @@ static void tag_emulation_migrate_slot_config(void) { } } - /** * Load the emulated card configuration data, note that loading is just a card slot configuration */ @@ -493,7 +493,7 @@ static void tag_emulation_load_config(void) { // After the reading is completed, we will save a BCC of the current configuration. When it is stored later, it can be used as a reference for the contrast between changes. calc_14a_crc_lut((uint8_t *)&slotConfig, sizeof(slotConfig), (uint8_t *)&m_slot_config_crc); NRF_LOG_INFO("Load tag slot config done."); - if (slotConfig.version < TAG_SLOT_CONFIG_CURRENT_VERSION) { // old slotConfig, need to migrate + if (slotConfig.version < TAG_SLOT_CONFIG_CURRENT_VERSION) { // old slotConfig, need to migrate tag_emulation_migrate_slot_config(); } } else { @@ -502,13 +502,13 @@ static void tag_emulation_load_config(void) { } /** - *Save the emulated card configuration data + * Save the emulated card configuration data */ static void tag_emulation_save_config(void) { // We are configured the card slot configuration, and we need to calculate the current card slot configuration CRC code to judge whether the data below is updated uint16_t new_calc_crc; calc_14a_crc_lut((uint8_t *)&slotConfig, sizeof(slotConfig), (uint8_t *)&new_calc_crc); - if (new_calc_crc != m_slot_config_crc) { // Before saving, make sure that the card slot configuration has changed + if (new_calc_crc != m_slot_config_crc) { // Before saving, make sure that the card slot configuration has changed NRF_LOG_INFO("Save tag slot config start."); bool ret = fds_write_sync(FDS_EMULATION_CONFIG_FILE_ID, FDS_EMULATION_CONFIG_RECORD_KEY, sizeof(slotConfig), (uint8_t *)&slotConfig); if (ret) { @@ -523,14 +523,14 @@ static void tag_emulation_save_config(void) { } /** - * Start label simulation + * Start tag emulation */ void tag_emulation_sense_run(void) { tag_emulation_sense_switch_all(true); } /** - * Stop the label simulation. Note that this function will absolutely block NFC -related events, including awakening MCU + * Stop the tag emulation. Note that this function will absolutely block NFC-related events, including awakening MCU * If you still need to be awakened by NFC after the MCU is required, please do not call this function */ void tag_emulation_sense_end(void) { @@ -539,19 +539,19 @@ void tag_emulation_sense_end(void) { } /** - *Initialized label simulation + * Initialized tag emulation */ void tag_emulation_init(void) { - tag_emulation_load_config(); // Configuration of loading the card slot of the simulation card - tag_emulation_load_data(); // Load the data of the emulated card + tag_emulation_load_config(); // Configuration of loading the card slot of the emulation card + tag_emulation_load_data(); // Load the data of the emulated card } /** - *Save the label data (written from RAM to Flash) + * Save the tag data (written from RAM to Flash) */ void tag_emulation_save(void) { - tag_emulation_save_config(); // Save the card slot configuration - tag_emulation_save_data(); // Save card slot data + tag_emulation_save_config(); // Save the card slot configuration + tag_emulation_save_data(); // Save card slot data } /** @@ -565,8 +565,8 @@ uint8_t tag_emulation_get_slot(void) { * Set the currently activated card slot index */ void tag_emulation_set_slot(uint8_t index) { - slotConfig.active_slot = index; // Re -set to the new switched card slot - rgb_marquee_reset(); // force animation color refresh according to new slot + slotConfig.active_slot = index; // Re -set to the new switched card slot + rgb_marquee_reset(); // force animation color refresh according to new slot } /** @@ -574,11 +574,11 @@ void tag_emulation_set_slot(uint8_t index) { */ void tag_emulation_change_slot(uint8_t index, bool sense_disable) { if (sense_disable) { - // Turn off the analog card to avoid triggering the simulation when switching the card slot + // Turn off the analog card to avoid triggering the emulation when switching the card slot tag_emulation_sense_end(); } - tag_emulation_save_data(); // Save the data of the current card, if there is a change, if there is a change - g_is_tag_emulating = false; // Reset the logo position + tag_emulation_save_data(); // Save the data of the current card, in case of there is a change + g_is_tag_emulating = false; // Reset the emulating flag tag_emulation_set_slot(index); // Update the index of the activated card slot tag_emulation_load_data(); // Then reload the data of the card slot if (sense_disable) { @@ -591,54 +591,42 @@ void tag_emulation_change_slot(uint8_t index, bool sense_disable) { * Determine whether the specified card slot is enabled */ bool tag_emulation_slot_is_enabled(uint8_t slot, tag_sense_type_t sense_type) { - switch (sense_type) { - case TAG_SENSE_LF: { - return slotConfig.slots[slot].enabled_lf; - break; - } - case TAG_SENSE_HF: { - return slotConfig.slots[slot].enabled_hf; - break; - } - default: - return false; - break; //Never happen + if (sense_type == TAG_SENSE_LF) { + return slotConfig.slots[slot].enabled_lf; } + if (sense_type == TAG_SENSE_HF) { + return slotConfig.slots[slot].enabled_hf; + } + return false; } /** * Set whether the specified card slot is enabled */ void tag_emulation_slot_set_enable(uint8_t slot, tag_sense_type_t sense_type, bool enable) { - //Set the capacity of the corresponding card slot directly - switch (sense_type) { - case TAG_SENSE_LF: { - slotConfig.slots[slot].enabled_lf = enable; - break; - } - case TAG_SENSE_HF: { - slotConfig.slots[slot].enabled_hf = enable; - break; - } - default: - break; //Never happen + // Set the capacity of the corresponding card slot directly + if (sense_type == TAG_SENSE_LF) { + slotConfig.slots[slot].enabled_lf = enable; + } + if (sense_type == TAG_SENSE_HF) { + slotConfig.slots[slot].enabled_hf = enable; } } /** - *Find the next valid card slot + * Find the next valid card slot */ uint8_t tag_emulation_slot_find_next(uint8_t slot_now) { uint8_t start_slot = (slot_now + 1 == TAG_MAX_SLOT_NUM) ? 0 : slot_now + 1; for (uint8_t i = start_slot;;) { - if (i == slot_now) return slot_now; // No other activated card slots were found after a loop - if (slotConfig.slots[i].enabled_hf || slotConfig.slots[i].enabled_lf) return i; // Check whether the card slot that is currently traversed is enabled, so that the capacity determines that the current card slot is the card slot that can effectively enable capacity + if (i == slot_now) return slot_now; // No other activated card slots were found after a loop + if (slotConfig.slots[i].enabled_hf || slotConfig.slots[i].enabled_lf) return i; // Check whether the card slot that is currently traversed is enabled, so that the capacity determines that the current card slot is the card slot that can effectively enable capacity i++; - if (i == TAG_MAX_SLOT_NUM) { // Continue the next cycle + if (i == TAG_MAX_SLOT_NUM) { // Continue the next cycle i = 0; } } - return slot_now; // If you cannot find it, the specified return value of the pass is returned by default + return slot_now; // If you cannot find it, the specified return value of the pass is returned by default } /** @@ -647,22 +635,22 @@ uint8_t tag_emulation_slot_find_next(uint8_t slot_now) { uint8_t tag_emulation_slot_find_prev(uint8_t slot_now) { uint8_t start_slot = (slot_now == 0) ? (TAG_MAX_SLOT_NUM - 1) : slot_now - 1; for (uint8_t i = start_slot;;) { - if (i == slot_now) return slot_now; //No other activated card slots were found after a loop - if (slotConfig.slots[i].enabled_hf || slotConfig.slots[i].enabled_lf) return i; // Check whether the card slot that is currently traversed is enabled, so that the capacity determines that the current card slot is the card slot that can effectively enable capacity - if (i == 0) { // Continue the next cycle + if (i == slot_now) return slot_now; // No other activated card slots were found after a loop + if (slotConfig.slots[i].enabled_hf || slotConfig.slots[i].enabled_lf) return i; // Check whether the card slot that is currently traversed is enabled, so that the capacity determines that the current card slot is the card slot that can effectively enable capacity + if (i == 0) { // Continue the next cycle i = TAG_MAX_SLOT_NUM - 1; } else { i--; } } - return slot_now; // If you cannot find it, the specified return value of the pass is returned by default + return slot_now; // If you cannot find it, the specified return value of the pass is returned by default } /** *Set the card specified by the specified card slot card slot card type card to the specified type */ void tag_emulation_change_type(uint8_t slot, tag_specific_type_t tag_type) { - tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); + tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); NRF_LOG_INFO("sense type = %d", sense_type); switch (sense_type) { case TAG_SENSE_LF: { @@ -674,10 +662,10 @@ void tag_emulation_change_type(uint8_t slot, tag_specific_type_t tag_type) { break; } default: - break; //Never happen + break; // never happen } NRF_LOG_INFO("tag type = %d", tag_type); - //After the update is completed, we need to notify the relevant data in the update of the memory + // After the update is completed, we need to notify the relevant data in the update of the memory if (sense_type != TAG_SENSE_NO) { load_data_by_tag_type(slot, tag_type); NRF_LOG_INFO("reload data success."); @@ -685,7 +673,7 @@ void tag_emulation_change_type(uint8_t slot, tag_specific_type_t tag_type) { } /** - * @briefThe factory initialization function of the simulation card + * @briefThe factory initialization function of the emulation card * Some data that can be used to initialize the default factory factory */ void tag_emulation_factory_init(void) { diff --git a/firmware/application/src/rfid/nfctag/tag_emulation.h b/firmware/application/src/rfid/nfctag/tag_emulation.h index f17a9c5..1725e0d 100644 --- a/firmware/application/src/rfid/nfctag/tag_emulation.h +++ b/firmware/application/src/rfid/nfctag/tag_emulation.h @@ -1,26 +1,27 @@ #ifndef NFC_TAG_H #define NFC_TAG_H -#include -#include #include -#include "app_util.h" -#include "utils.h" -#include "tag_base_type.h" +#include +#include -//Up to eight card slots -#define TAG_MAX_SLOT_NUM 8 +#include "app_util.h" +#include "tag_base_type.h" +#include "utils.h" + +// Up to eight card slots +#define TAG_MAX_SLOT_NUM 8 extern bool g_is_tag_emulating; -// Label data buffer +// Tag data buffer typedef struct { uint16_t length; uint8_t *buffer; uint16_t *crc; } tag_data_buffer_t; -//Farming impact enable and closed energy switching function +// Farming impact enable and closed energy switching function typedef void (*tag_sense_switch_t)(bool enable); // Flash data is notified to the registrar after loading to RAM typedef int (*tag_datas_loadcb_t)(tag_specific_type_t type, tag_data_buffer_t *buffer); @@ -29,18 +30,18 @@ typedef int (*tag_datas_savecb_t)(tag_specific_type_t type, tag_data_buffer_t *b // Data factory initialization function typedef bool (*tag_datas_factory_t)(uint8_t slot, tag_specific_type_t type); -// The data of the label data loading and the recovery function of the preservation event mapping table +// The data of the tag data loading and the recovery function of the preservation event mapping table typedef struct { - tag_sense_type_t sense_type; - tag_specific_type_t tag_type; - tag_datas_loadcb_t data_on_load; - tag_datas_savecb_t data_on_save; - tag_datas_factory_t data_factory; - tag_data_buffer_t *data_buffer; + tag_sense_type_t sense_type; + tag_specific_type_t tag_type; + tag_datas_loadcb_t data_on_load; + tag_datas_savecb_t data_on_save; + tag_datas_factory_t data_factory; + tag_data_buffer_t *data_buffer; } tag_base_handler_map_t; /** - * The storage configuration of parameters such as the type of card simulated in the card slot + * The storage configuration of parameters such as the type of card emulated in the card slot * This configuration can be preserved by persistently to Flash * 4 bytes a word, keep in mind the entire word alignment */ @@ -49,11 +50,11 @@ typedef struct { #define TAG_SLOT_CONFIG_CURRENT_SIZE 68 typedef struct { - //Basic configuration - uint8_t version; // struct version (U8 so map on old .activated<=7 field) - uint8_t active_slot; // Which slot is currently active - uint32_t : 0; // U32 align - struct { // 4-byte slot config + 2*2-byte tag_specific_types + // Basic configuration + uint8_t version; // struct version (U8 so map on old .activated<=7 field) + uint8_t active_slot; // Which slot is currently active + uint32_t : 0; // U32 align + struct { // 4-byte slot config + 2*2-byte tag_specific_types // Individual slot configuration uint32_t enabled_hf : 1; // Whether to enable the HF card uint32_t enabled_lf : 1; // Whether to enable the LF card @@ -73,12 +74,12 @@ typedef struct { // Use the macro to check the struct size STATIC_ASSERT(sizeof(tag_slot_config_t) == TAG_SLOT_CONFIG_CURRENT_SIZE); -// The most basic simulation card initialization program +// The most basic emulation card initialization program void tag_emulation_init(void); -//Some of the data stored in RAM can be saved to Flash through this interface +// Some of the data stored in RAM can be saved to Flash through this interface void tag_emulation_save(void); -// Starting and ending of the simulation card +// Starting and ending of the emulation card void tag_emulation_sense_run(void); void tag_emulation_sense_end(void); @@ -88,9 +89,9 @@ void tag_emulation_sense_switch(tag_sense_type_t type, bool enable); void tag_emulation_delete_data(uint8_t slot, tag_sense_type_t sense_type); // Initial data of the factory data of the specified card slot into the factory of the specified type of card bool tag_emulation_factory_data(uint8_t slot, tag_specific_type_t tag_type); -// Change the type of the card that is being simulated +// Change the type of the card that is being emulated void tag_emulation_change_type(uint8_t slot, tag_specific_type_t tag_type); -//Load the data from the memory to the simulation card buffer +// Load the data from the memory to the emulation card buffer bool tag_emulation_load_by_buffer(tag_specific_type_t tag_type, bool update_crc); tag_sense_type_t get_sense_type_from_tag_type(tag_specific_type_t type); @@ -106,12 +107,12 @@ void tag_emulation_change_slot(uint8_t index, bool sense_disable); bool tag_emulation_slot_is_enabled(uint8_t slot, tag_sense_type_t sense_type); // Set the card slot to enable void tag_emulation_slot_set_enable(uint8_t slot, tag_sense_type_t sense_type, bool enable); -// Get the simulation card type of the corresponding card slot +// Get the emulation card type of the corresponding card slot void tag_emulation_get_specific_types_by_slot(uint8_t slot, tag_slot_specific_type_t *tag_types); // Initialize some factory data void tag_emulation_factory_init(void); -//In the direction, query any card slot that enable +// In the direction, query any card slot that enable uint8_t tag_emulation_slot_find_next(uint8_t slot_now); uint8_t tag_emulation_slot_find_prev(uint8_t slot_now); bool is_tag_specific_type_valid(tag_specific_type_t tag_type); diff --git a/firmware/application/src/rfid/nfctag/tag_persistence.c b/firmware/application/src/rfid/nfctag/tag_persistence.c index 0703b2f..59c0221 100644 --- a/firmware/application/src/rfid/nfctag/tag_persistence.c +++ b/firmware/application/src/rfid/nfctag/tag_persistence.c @@ -1,4 +1,5 @@ #include "tag_persistence.h" + #include "fds_ids.h" #define NRF_LOG_MODULE_NAME tag_persistence @@ -7,8 +8,6 @@ #include "nrf_log_default_backends.h" NRF_LOG_MODULE_REGISTER(); - - static void get_fds_map_by_slot_auto_inc_id(uint16_t id, uint8_t slot, tag_sense_type_t sense_type, fds_slot_record_map_t *map) { if ((sense_type == TAG_SENSE_NO) || (slot > 7)) { APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM); diff --git a/firmware/application/src/rfid/nfctag/tag_persistence.h b/firmware/application/src/rfid/nfctag/tag_persistence.h index 5ad74f6..06003d2 100644 --- a/firmware/application/src/rfid/nfctag/tag_persistence.h +++ b/firmware/application/src/rfid/nfctag/tag_persistence.h @@ -2,8 +2,8 @@ #define TAG_PERSISTENCE_H #include -#include "tag_base_type.h" +#include "tag_base_type.h" typedef struct { uint16_t key; diff --git a/firmware/application/src/rfid/reader/hf/rc522.h b/firmware/application/src/rfid/reader/hf/rc522.h index 46876c0..64e262b 100644 --- a/firmware/application/src/rfid/reader/hf/rc522.h +++ b/firmware/application/src/rfid/reader/hf/rc522.h @@ -62,7 +62,7 @@ RC522 theDefaultTimerTimeoutConfiguration,ThisValueCanBeAdjustedDynamically,Through PcdSetTimeout function operationStandardM1CardMaximumWaitingTime 25ms weCanIncreaseTimeoutToCompatibleWithSomeDullCards - forExample,SomeBraceletSimulationCards,SuchAsSomeOtherHardwareSimulationCards,SuchAsColorChangingDragons + forExample,SomeBraceletemulationCards,SuchAsSomeOtherHardwareemulationCards,SuchAsColorChangingDragons ifTheTimeoutValueIsTooSmall,YouMayNotBeAbleToReadTheUid (gen1A)Card! */ #define DEF_COM_TIMEOUT 25 diff --git a/firmware/application/src/rfid/reader/lf/data_utils.c b/firmware/application/src/rfid/reader/lf/data_utils.c deleted file mode 100644 index 72e4ded..0000000 --- a/firmware/application/src/rfid/reader/lf/data_utils.c +++ /dev/null @@ -1,110 +0,0 @@ -#include "data_utils.h" -#include - -//Write2BitDataToRaw,DataBStores0Bit,DataaStores1Bit -void writebit(uint8_t *dataa, uint8_t *datab, uint8_t pos, uint8_t adata) { - if (adata >= 4) { - return; - } - static uint8_t aimbyte = 0; - static uint8_t aimbit = 0; - aimbyte = pos / 8; - aimbit = pos % 8; - getbit(adata, 1) ? setbit(dataa[aimbyte], aimbit) : clrbit(dataa[aimbyte], aimbit); - getbit(adata, 0) ? setbit(datab[aimbyte], aimbit) : clrbit(datab[aimbyte], aimbit); -} - -//OutputRaw's2BitCombinationData -uint8_t readbit(uint8_t *dataa, uint8_t *datab, uint8_t pos) { - static uint8_t aimbyte = 0; - static uint8_t aimbit = 0; - aimbyte = pos / 8; - aimbit = pos % 8; - return ( - (getbit(dataa[aimbyte], aimbit) << 1) | - (getbit(datab[aimbyte], aimbit))); -} - -// Write 2bit data to RAW (large -end method, 1st place for each Byte's 8th position), datab deposit 0bit, dataa save 1bit 1bit -void writebit_msb(uint8_t *dataa, uint8_t *datab, uint8_t pos, uint8_t adata) { - if (adata >= 4) { - return; - } - static uint8_t aimbyte = 0; - static uint8_t aimbit = 0; - aimbyte = pos / 8; - aimbit = 7 - (pos % 8); - getbit(adata, 1) ? setbit(dataa[aimbyte], aimbit) : clrbit(dataa[aimbyte], aimbit); - getbit(adata, 0) ? setbit(datab[aimbyte], aimbit) : clrbit(datab[aimbyte], aimbit); -} - -// Output RAW's 2bit combination data (large -end method, No. 1 of the 8th reading data of each byte) -uint8_t readbit_msb(uint8_t *dataa, uint8_t *datab, uint8_t pos) { - static uint8_t aimbyte = 0; - static uint8_t aimbit = 0; - aimbyte = pos / 8; - aimbit = 7 - (pos % 8); - return ( - (getbit(dataa[aimbyte], aimbit) << 1) | - (getbit(datab[aimbyte], aimbit))); -} - -//High and low flip -uint8_t invert_num(uint8_t num) { - uint8_t temp = 0, sh = 0xf; - uint8_t i = 0; - for (i = 0; i < sizeof(uint8_t); i++) { - temp |= (num & (sh << ((sizeof(uint8_t) - 1 - i) << 2))) << ((i << 3) + 4); - temp |= (num & (sh << ((sizeof(uint8_t) + i) << 2))) >> ((i << 3) + 4); - } - num = ((temp << 2) & 0xcccccccccccccccc) | ((temp >> 2) & 0x3333333333333333); - num = ((num << 1) & 0xaaaaaaaaaaaaaaaa) | ((num >> 1) & 0x5555555555555555); - - return num; -} - -//The original data is converted to the HEX character array with a 2x length -void ByteToHexStr(uint8_t *source, uint8_t *dest, uint8_t sourceLen) { - uint8_t i, highByte, lowByte; - - for (i = 0; i < sourceLen; i++) { - highByte = source[i] >> 4; - lowByte = source[i] & 0x0f; - - highByte += 0x30; - - if (highByte > 0x39) - dest[i * 2] = highByte + 0x07; - else - dest[i * 2] = highByte; - - lowByte += 0x30; - if (lowByte > 0x39) - dest[i * 2 + 1] = lowByte + 0x07; - else - dest[i * 2 + 1] = lowByte; - } - return; -} - -void HexStrToByte(uint8_t *source, uint8_t *dest, uint8_t sourceLen) { - uint8_t i, highByte, lowByte; - - for (i = 0; i < sourceLen; i += 2) { - highByte = toupper(source[i]); - lowByte = toupper(source[i + 1]); - - if (highByte > 0x39) - highByte -= 0x37; - else - highByte -= 0x30; - - if (lowByte > 0x39) - lowByte -= 0x37; - else - lowByte -= 0x30; - - dest[i / 2] = (highByte << 4) | lowByte; - } - return; -} diff --git a/firmware/application/src/rfid/reader/lf/data_utils.h b/firmware/application/src/rfid/reader/lf/data_utils.h deleted file mode 100644 index 1463761..0000000 --- a/firmware/application/src/rfid/reader/lf/data_utils.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __DATA_UTILS_H__ -#define __DATA_UTILS_H__ - -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -#define DEBUG_READ_BUFF_CHAR(WATCH, PDATA, LENG) \ - uint8_t (*(WATCH))[(LENG)] = (uint8_t (*)[(LENG)])(PDATA) -#define DEBUG_READ_BREAK(WATCH) (*(WATCH))[0] = (*(WATCH))[0] - -#define setbit(x,y) (x|=(1<> (y)&1) - -void writebit(uint8_t *dataa, uint8_t *datab, uint8_t pos, uint8_t adata); -uint8_t readbit(uint8_t *dataa, uint8_t *datab, uint8_t pos); -void writebit_msb(uint8_t *dataa, uint8_t *datab, uint8_t pos, uint8_t adata); -uint8_t readbit_msb(uint8_t *dataa, uint8_t *datab, uint8_t pos); -uint8_t invert_num(uint8_t num); -void ByteToHexStr(uint8_t *source, uint8_t *dest, uint8_t sourceLen); -void HexStrToByte(uint8_t *source, uint8_t *dest, uint8_t sourceLen); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/firmware/application/src/rfid/reader/lf/lf_125khz_radio.c b/firmware/application/src/rfid/reader/lf/lf_125khz_radio.c index 39f3f4c..4d732ad 100644 --- a/firmware/application/src/rfid/reader/lf/lf_125khz_radio.c +++ b/firmware/application/src/rfid/reader/lf/lf_125khz_radio.c @@ -1,122 +1,136 @@ -#include "nrf_drv_ppi.h" -#include "nrf_drv_timer.h" -#include "nrf_drv_pwm.h" -#include "nrf_drv_clock.h" -#include "nrf_gpio.h" -#include "nrf_drv_gpiote.h" - #include "lf_125khz_radio.h" + #include "lf_reader_data.h" +#include "nrf_gpio.h" +#include "nrfx_clock.h" +#include "nrfx_gpiote.h" +#include "nrfx_ppi.h" +#include "nrfx_pwm.h" +#include "nrfx_saadc.h" +#include "nrfx_timer.h" #include "rfid_main.h" +#define SAADC_BUF_SIZE (2048) +#define SAADC_BUF_COUNT (2) -nrf_drv_pwm_t m_pwm = NRF_DRV_PWM_INSTANCE(0); -nrf_ppi_channel_t m_ppi_channel1; +static nrf_saadc_value_t samples[SAADC_BUF_SIZE][SAADC_BUF_COUNT]; +nrfx_pwm_t m_pwm = NRFX_PWM_INSTANCE(0); +nrf_ppi_channel_t m_ppi_channel; nrfx_timer_t m_timer_lf_reader = NRFX_TIMER_INSTANCE(2); -// At present, only channel 1 is used, so only one channel can be configured -nrf_pwm_values_individual_t m_lf_125khz_pwm_seq_val[] = { { 2, 0, 0, 0}, }; -nrf_pwm_sequence_t const m_lf_125khz_pwm_seq_obj = { - .values.p_individual = m_lf_125khz_pwm_seq_val, - .length = NRF_PWM_VALUES_LENGTH(m_lf_125khz_pwm_seq_val), - .repeats = 0, - .end_delay = 0 -}; -static bool m_is_125khz_radio_init = false; +static void pwm_init(void); +static void saadc_init(void); +static void timer_counter_init(void); +static void gpiote_init(void); +static void pwm_saadc_sample_ppi_init(void); +static void pwm_timer_counter_ppi_init(void); - -/**@brief Low -frequency reading card decrease along the trigger collection event - */ -static void lf_125khz_gpio_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { - // Directly transfer to the event - GPIO_INT0_IRQHandler(); +// Simple function to provide an index to the next input buffer +// Will simply alernate between 0 and 1 when SAADC_BUF_COUNT is 2 +static uint32_t next_free_buf_index(void) { + static uint32_t buffer_index = -1; + buffer_index = (buffer_index + 1) % SAADC_BUF_COUNT; + return buffer_index; } -// Initialize 125kHz signal PWM modulation -void lf_125khz_radio_init(void) { +// At present, only channel 1 is used, so only one channel can be configured +static nrf_pwm_values_individual_t m_lf_125khz_pwm_seq_val[] = { + {2, 0, 0, 0}, +}; + +nrf_pwm_sequence_t const m_lf_125khz_pwm_seq_obj = { + .values.p_individual = m_lf_125khz_pwm_seq_val, + .length = NRF_PWM_VALUES_LENGTH(m_lf_125khz_pwm_seq_val), + .repeats = 0, + .end_delay = 0}; + +typedef enum { + LF_125K_RADIO_MODE_NONE, + LF_125K_RADIO_MODE_SAADC, + LF_125K_RADIO_MODE_GPIOTE, +} lf_125k_radio_mode_t; +static lf_125k_radio_mode_t m_lf_125k_radio_mode = LF_125K_RADIO_MODE_NONE; + +/**@brief Low -frequency reading card decrease along the trigger collection + * event + */ +static void lf_125khz_gpio_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { + // Directly transfer to the event + gpio_int0_irq_handler(); +} + +// initialize 125kHz signal PWM modulation (use saadc, FSK) +void lf_125khz_radio_saadc_init(void) { + if (m_lf_125k_radio_mode == LF_125K_RADIO_MODE_SAADC) { + return; + } + + if (m_lf_125k_radio_mode == LF_125K_RADIO_MODE_GPIOTE) { + lf_125khz_radio_uninit(); + } + + pwm_init(); + saadc_init(); + pwm_saadc_sample_ppi_init(); + m_lf_125k_radio_mode = LF_125K_RADIO_MODE_SAADC; +} + +// initialize 125kHz signal PWM modulation (use gpiote, ASK) +void lf_125khz_radio_gpiote_init(void) { + if (m_lf_125k_radio_mode == LF_125K_RADIO_MODE_GPIOTE) { + return; + } + + if (m_lf_125k_radio_mode == LF_125K_RADIO_MODE_SAADC) { + lf_125khz_radio_uninit(); + } + + pwm_init(); + timer_counter_init(); + pwm_timer_counter_ppi_init(); + gpiote_init(); + m_lf_125k_radio_mode = LF_125K_RADIO_MODE_GPIOTE; +} + +static void gpiote_init(void) { nrfx_err_t err_code; - if (!m_is_125khz_radio_init) { - m_is_125khz_radio_init = true; - - // ****************************************************************** - - // Configure pwm - nrfx_pwm_config_t config = NRFX_PWM_DEFAULT_CONFIG; - config.output_pins[0] = LF_ANT_DRIVER | NRF_DRV_PWM_PIN_INVERTED; - for (uint8_t i = 1; i < NRF_PWM_CHANNEL_COUNT; i++) { - config.output_pins[i] = NRFX_PWM_PIN_NOT_USED; - } - config.irq_priority = APP_IRQ_PRIORITY_LOW; - config.base_clock = (nrf_pwm_clk_t)NRF_PWM_CLK_500kHz; - config.count_mode = (nrf_pwm_mode_t)NRF_PWM_MODE_UP; - config.top_value = (uint16_t)4; - config.load_mode = (nrf_pwm_dec_load_t)NRF_PWM_LOAD_INDIVIDUAL; - config.step_mode = (nrf_pwm_dec_step_t)NRF_PWM_STEP_AUTO; - - // Initialization PWM - err_code = nrfx_pwm_init(&m_pwm, &config, NULL); - APP_ERROR_CHECK(err_code); - - // ****************************************************************** - - // Define the timer configuration structure, and use the default configuration parameter to initialize the structure - nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG; - timer_cfg.mode = NRF_TIMER_MODE_COUNTER; // Use the counter mode - - // Initialized timer - err_code = nrfx_timer_init(&m_timer_lf_reader, &timer_cfg, NULL); - APP_ERROR_CHECK(err_code); - - // Enable timer - nrfx_timer_enable(&m_timer_lf_reader); - - // ****************************************************************** - - // Initialized PPI - err_code = nrf_drv_ppi_init(); - APP_ERROR_CHECK(err_code); - - err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel1); - APP_ERROR_CHECK(err_code); - - err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1, nrf_drv_pwm_event_address_get(&m_pwm, NRF_PWM_EVENT_PWMPERIODEND), nrf_drv_timer_task_address_get(&m_timer_lf_reader, NRF_TIMER_TASK_COUNT)); - APP_ERROR_CHECK(err_code); - - // Enable both configured PPI channels - err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1); - APP_ERROR_CHECK(err_code); - - // ****************************************************************** - - // The LF collection decline is interrupted, and the GPIO is pulled down by default. The trigger method is triggering - nrf_drv_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(false); - err_code = nrf_drv_gpiote_in_init(LF_OA_OUT, &in_config, lf_125khz_gpio_handler); - APP_ERROR_CHECK(err_code); - nrf_drv_gpiote_in_event_enable(LF_OA_OUT, true); - - // ****************************************************************** - } + // The LF collection decline is interrupted, and the GPIO is pulled down + // by default. The trigger method is triggering + nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(false); + err_code = nrfx_gpiote_in_init(LF_OA_OUT, &in_config, lf_125khz_gpio_handler); + APP_ERROR_CHECK(err_code); + nrfx_gpiote_in_event_enable(LF_OA_OUT, true); } // Anti -initialization void lf_125khz_radio_uninit(void) { - if (m_is_125khz_radio_init) { - m_is_125khz_radio_init = false; - nrf_drv_gpiote_in_event_disable(LF_OA_OUT); - nrf_drv_gpiote_in_uninit(LF_OA_OUT); - nrf_drv_ppi_channel_free(m_ppi_channel1); - nrf_drv_ppi_uninit(); - nrfx_timer_uninit(&m_timer_lf_reader); - nrfx_pwm_uninit(&m_pwm); + if (m_lf_125k_radio_mode == LF_125K_RADIO_MODE_NONE) { + return; } + + if (m_lf_125k_radio_mode == LF_125K_RADIO_MODE_SAADC) { + nrfx_ppi_channel_free(m_ppi_channel); + nrfx_saadc_uninit(); + } + + if (m_lf_125k_radio_mode == LF_125K_RADIO_MODE_GPIOTE) { + nrfx_gpiote_in_event_disable(LF_OA_OUT); + nrfx_gpiote_in_uninit(LF_OA_OUT); + nrfx_ppi_channel_free(m_ppi_channel); + nrfx_timer_uninit(&m_timer_lf_reader); + } + + nrfx_ppi_free_all(); // nrf_drv_ppi_uninit(); + nrfx_pwm_uninit(&m_pwm); + m_lf_125k_radio_mode = LF_125K_RADIO_MODE_NONE; } /** * Start the 125kHz broadcast */ void start_lf_125khz_radio(void) { - nrf_drv_pwm_simple_playback(&m_pwm, &m_lf_125khz_pwm_seq_obj, 1, NRF_DRV_PWM_FLAG_LOOP); + nrfx_pwm_simple_playback(&m_pwm, &m_lf_125khz_pwm_seq_obj, 1, NRFX_PWM_FLAG_LOOP); TAG_FIELD_LED_ON(); } @@ -124,6 +138,98 @@ void start_lf_125khz_radio(void) { * Close 125kHz RF broadcast */ void stop_lf_125khz_radio(void) { - nrf_drv_pwm_stop(&m_pwm, true); + nrfx_pwm_stop(&m_pwm, true); TAG_FIELD_LED_OFF(); } + +static void pwm_init(void) { + nrfx_pwm_config_t config = NRFX_PWM_DEFAULT_CONFIG; + config.output_pins[0] = LF_ANT_DRIVER | NRFX_PWM_PIN_INVERTED; + for (uint8_t i = 1; i < NRF_PWM_CHANNEL_COUNT; i++) { + config.output_pins[i] = NRFX_PWM_PIN_NOT_USED; + } + config.irq_priority = APP_IRQ_PRIORITY_LOW; + config.base_clock = (nrf_pwm_clk_t)NRF_PWM_CLK_500kHz; + config.count_mode = (nrf_pwm_mode_t)NRF_PWM_MODE_UP; + config.top_value = (uint16_t)4; + config.load_mode = (nrf_pwm_dec_load_t)NRF_PWM_LOAD_INDIVIDUAL; + config.step_mode = (nrf_pwm_dec_step_t)NRF_PWM_STEP_AUTO; + + nrfx_err_t err_code = nrfx_pwm_init(&m_pwm, &config, NULL); + APP_ERROR_CHECK(err_code); +} + +static void timer_counter_init(void) { + nrfx_err_t err_code; + + nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG; + timer_cfg.mode = NRF_TIMER_MODE_COUNTER; + + err_code = nrfx_timer_init(&m_timer_lf_reader, &timer_cfg, NULL); + APP_ERROR_CHECK(err_code); + + nrfx_timer_enable(&m_timer_lf_reader); +} + +static void pwm_timer_counter_ppi_init() { + nrfx_err_t err_code; + + err_code = nrfx_ppi_channel_alloc(&m_ppi_channel); + APP_ERROR_CHECK(err_code); + + err_code = nrfx_ppi_channel_assign( + m_ppi_channel, + nrfx_pwm_event_address_get(&m_pwm, NRF_PWM_EVENT_PWMPERIODEND), + nrfx_timer_task_address_get(&m_timer_lf_reader, NRF_TIMER_TASK_COUNT)); + APP_ERROR_CHECK(err_code); + + err_code = nrfx_ppi_channel_enable(m_ppi_channel); + APP_ERROR_CHECK(err_code); +} + +// trigger saadc sample task from pwm +static void pwm_saadc_sample_ppi_init(void) { + nrfx_err_t err_code; + + err_code = nrfx_ppi_channel_alloc(&m_ppi_channel); + APP_ERROR_CHECK(err_code); + + err_code = nrfx_ppi_channel_assign( + m_ppi_channel, + nrfx_pwm_event_address_get(&m_pwm, NRF_PWM_EVENT_PWMPERIODEND), + nrf_saadc_task_address_get(NRF_SAADC_TASK_SAMPLE)); + APP_ERROR_CHECK(err_code); + + err_code = nrfx_ppi_channel_enable(m_ppi_channel); + APP_ERROR_CHECK(err_code); +} + +void lf_saadc_event_handler(nrfx_saadc_evt_t const* p_event) { + if (p_event->type == NRFX_SAADC_EVT_DONE) { + ret_code_t err_code; + err_code = nrfx_saadc_buffer_convert(&samples[next_free_buf_index()][0], SAADC_BUF_SIZE); + APP_ERROR_CHECK(err_code); + saadc_irq_handler(p_event->data.done.p_buffer, p_event->data.done.size); + } +} + +static void saadc_init(void) { + nrfx_saadc_uninit(); + + ret_code_t err_code; + + nrfx_saadc_config_t config = NRFX_SAADC_DEFAULT_CONFIG; + err_code = nrfx_saadc_init(&config, lf_saadc_event_handler); + APP_ERROR_CHECK(err_code); + + nrf_saadc_channel_config_t ch_config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5); + ch_config.acq_time = NRF_SAADC_ACQTIME_5US; + err_code = nrfx_saadc_channel_init(0, &ch_config); + APP_ERROR_CHECK(err_code); + + err_code = nrfx_saadc_buffer_convert(&samples[next_free_buf_index()][0], SAADC_BUF_SIZE); + APP_ERROR_CHECK(err_code); + + err_code = nrfx_saadc_buffer_convert(&samples[next_free_buf_index()][0], SAADC_BUF_SIZE); + APP_ERROR_CHECK(err_code); +} \ No newline at end of file diff --git a/firmware/application/src/rfid/reader/lf/lf_125khz_radio.h b/firmware/application/src/rfid/reader/lf/lf_125khz_radio.h index 2d01e2c..4b867eb 100644 --- a/firmware/application/src/rfid/reader/lf/lf_125khz_radio.h +++ b/firmware/application/src/rfid/reader/lf/lf_125khz_radio.h @@ -1,11 +1,10 @@ #ifndef LF_125KHZ_RADIO_H_ #define LF_125KHZ_RADIO_H_ - -void lf_125khz_radio_init(void); +void lf_125khz_radio_gpiote_init(void); +void lf_125khz_radio_saadc_init(void); void lf_125khz_radio_uninit(void); void start_lf_125khz_radio(void); void stop_lf_125khz_radio(void); - #endif diff --git a/firmware/application/src/rfid/reader/lf/lf_em410x_data.c b/firmware/application/src/rfid/reader/lf/lf_em410x_data.c index 537e0f0..f20d8d0 100644 --- a/firmware/application/src/rfid/reader/lf/lf_em410x_data.c +++ b/firmware/application/src/rfid/reader/lf/lf_em410x_data.c @@ -1,12 +1,12 @@ -#ifdef debug410x -#include -#endif - -#include "bsp_time.h" -#include "bsp_delay.h" -#include "lf_reader_data.h" #include "lf_em410x_data.h" + +#include "bsp_delay.h" +#include "bsp_time.h" +#include "circular_buffer.h" #include "lf_125khz_radio.h" +#include "lf_reader_data.h" +#include "protocols/em410x.h" +#include "protocols/protocols.h" #define NRF_LOG_MODULE_NAME em410x #include "nrf_log.h" @@ -14,391 +14,68 @@ #include "nrf_log_default_backends.h" NRF_LOG_MODULE_REGISTER(); +static circular_buffer cb; -static RAWBUF_TYPE_S carddata; -static volatile uint8_t dataindex = 0; //Record changes along the number of times -uint8_t cardbufbyte[CARD_BUF_BYTES_SIZE]; //Card data - -#ifdef debug410x -uint8_t datatest[256] = { 0x00 }; -#endif - - -//Process card data, enter raw Buffer's starting position 2 position (21111 ...) -//After processing the card data, put cardbuf, return 5 normal analysis -//pdata is rawbuffer -uint8_t mcst(RAWBUF_TYPE_S *Pdata) { - uint8_t sync = 1; //After the current interval process is processed, is it on the judgment line - uint8_t cardindex = 0; //Record change number - for (int i = Pdata->startbit; i < RAW_BUF_SIZE * 8; i++) { - uint8_t thisbit = readbit(Pdata->rawa, Pdata->rawb, i); - switch (sync) { - case 1: //Synchronous state - switch (thisbit) { - case 0: //TheSynchronousState1T,Add1Digit0,StillSynchronize - writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); - cardindex++; - break; - case 1: // Synchronous status 1.5T, add 1 digit 1, switch to non -synchronized state - writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); - cardindex++; - sync = 0; - break; - case 2: //Synchronous2T,Add2Digits10,StillSynchronize - writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); - cardindex++; - writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); - cardindex++; - break; - default: - return 0; - } - break; - case 0: //Non -synchronous state - switch (thisbit) { - case 0: //1TInNonSynchronousState,Add1Digit1,StillNonSynchronous - writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); - cardindex++; - break; - case 1: // In non -synchronous status 1.5T, add 2 digits 10, switch to the synchronous state - writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); - cardindex++; - writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); - cardindex++; - sync = 1; - break; - case 2: //The2TOfTheNonSynchronousState,ItIsImpossibleToOccur,ReportAnError - return 0; - default: - return 0; - } - break; - } - if (cardindex >= CARD_BUF_SIZE * 8) - break; +// GPIO interrupt recovery function is used to detect the descending edge +void gpio_int0_cb(void) { + uint32_t cntr = get_lf_counter_value(); + uint16_t val = 0; + if (cntr > 0xff) { + val = 0xff; + } else { + val = cntr & 0xff; } - return 1; + cb_push_back(&cb, &val); + clear_lf_counter_value(); } -//Process card, find school inspection and determine whether it is normal -uint8_t em410x_decoder(uint8_t *pData, uint8_t size, uint8_t *pOut) { - if (size != 8) { - //NRF_LOG_INFO("size err %d!\n", size); - return 0; - } - - // Nrf_log_info ("Start the decoding data! \ N"); - - // The number of iterative data, each time +5 Bit - uint8_t iteration = 0; - // The current merged data storage location - uint8_t merge_pos = 0; - - // Quickly check the head - uint8_t head_check = 1; - for (int i = 0; i < 9; i++) { - head_check &= getbit(pData[i / 8], i % 8); - } - // Quickly school to test the tail - if ((!head_check) || getbit(pData[7], 7)) { - //NRF_LOG_INFO("head or tail err!\n"); - return 0; - } - - // Nrf_log_info ("Terrate head and tail detection pass! \ N"); - - // Check the data of the X -axis first - // X -axis verification, every separate 5 BIT check once, - // After the verification is completed, it is stored to halfbyte - for (int i = 9; i < size * 8 - 5; i += 5) { - uint8_t count_bit_x = 0; - - for (int j = i; j < i + 5; j++) { - - // Collect the number of puppet data - if (getbit(pData[j / 8], j % 8) == 1) { - count_bit_x += 1; - } - - if (j != i + 4) { - // Merged bit data to In UINT8 buffer - // You need to add left -left coordinates, if it is a high part - uint8_t first_merge_offset = (iteration % 2) ? 0 : 4; - uint8_t finally_offset = first_merge_offset + ((i + 5 - 1) - j - 1); - // Nrf_log_info ("need left move %d Bit.\ n ", finally_offset); - getbit(pData[j / 8], j % 8) ? (pOut[merge_pos] |= 1 << finally_offset) : (pOut[merge_pos] &= ~(1 << finally_offset)); - } - - // If in the first line, we can go directly to the verification Y Verification of the shaft - if (iteration == 0 && j != i + 4) { - uint8_t count_bit_y = 0; - for (int m = j; m < j + 51; m += 5) { - // Nrf_log_info ("The current M coordinate is %d, Data is %d\n", m, pData[m]); - if (getbit(pData[m / 8], m % 8) == 1) { - count_bit_y += 1; - } - } - if (count_bit_y % 2) { - //NRF_LOG_INFO("bit even parity err at Y-axis from %d to %d!\n", j, j + 51); - return 0; - } - } // Otherwise, go directly to the next round of verification - } - - // After a round of verification, don't check it next time Y axis - iteration += 1; - - // If the remaining number is not 0 - // Explain that the new data processing cycle has entered - // We need to increase the bidding required for merging bytes - if (!(iteration % 2)) { - merge_pos += 1; - // NRF_LOG_INFO("\n"); - } - - if (count_bit_x % 2) { - //NRF_LOG_INFO("bit even parity err at X-axis from %d to %d!\n", i, i + 5); - return 0; - } - } - return 1; -} - -/** -* Code the EM410X card number -* @param: pData card number - ID, fixed 5 length byte -* @param: pOut Output buffer, fixed 8 -length byte -*/ -void em410x_encoder(uint8_t *pData, uint8_t *pOut) { - //#define EM410X_Encoder_NRF_LOG_INFO - - // In order to save code space, we can limit the length of the dead data in the law - // In other words, the overall loop cannot exceed more 0 - 127 Bit - // Of course, for the serious EM410, the number of this cycle is enough - int8_t i, j; - - // Some data can actually change the space through time - // But this space is too small, it is better to keep the time to change time - // So don't change it. - uint8_t pos, bit, count1; - - pOut[0] = 0xFF; // There are 9 1 of the front guide code, so we are limited to the first byte first as a 11111111 - pOut[1] = 0x80; // Nothing to say, the second Byte MSB is also one 1 Then it's enough 1 * 9 Code - - //Reset the data as empty - for (i = 2; i < 8; i++) { - pOut[i] = 0x00; - } - - // Bit is 9, because there is 0 - 8 In total 9 Ahead ( 1 * 9 ) - pos = 9; - // Reset the BIT count - count1 = 0; - - // X -aid iteration 5 Byte's card number, put together Bit to the buffer and calculate the puppet school inspection - for (i = 0; i < 5; i++) { - // Iteration processing each bit - for (j = 7; j >= 0; j--) { - // Take out a single BIT - bit = ((pData[i] >> j) & 0x01); - -#ifdef EM410X_Encoder_NRF_LOG_INFO - NRF_LOG_INFO("%d ", bit); -#endif // EM410X_Encoder_NRF_LOG_INFO - - // Put the native data into the output buffer - pOut[pos / 8] |= (bit << (7 - pos % 8)); - pos += 1; - - // Statistical occasional verification calculation - if (bit) { - count1 += 1; - } - - // Putting the inspection of the coupling school into the output buffer - if (j == 4 || j == 0) { - -#ifdef EM410X_Encoder_NRF_LOG_INFO - NRF_LOG_INFO(" <- Bit raw : Qi Dian verification -> %d\n", count1 % 2); -#endif // EM410X_Encoder_NRF_LOG_INFO - - // Needless to say, it must be placed in a bit's strange school test. - pOut[pos / 8] |= ((count1 % 2) << (7 - pos % 8)); - pos += 1; - count1 = 0; - } - } - } - -#ifdef EM410X_Encoder_NRF_LOG_INFO - NRF_LOG_INFO("\n"); -#endif // EM410X_Encoder_NRF_LOG_INFO - - // Y axis iteration 5 BYTE card numbers, generate 4 BIT's puppet school inspection - for (i = 0; i < 4; i++) { - count1 = 0; - for (j = 0; j < 5; j++) { - // High -level count - bit = ((pData[j] >> (7 - i)) & 0x01); - if (bit) { - count1 += 1; - } - // Low count - bit = ((pData[j] >> (3 - i)) & 0x01); - if (bit) { - count1 += 1; - } - } - - // The y -axis calculation is completed, and placed in the final BIT output buffer - pOut[pos / 8] |= ((count1 % 2) << (7 - pos % 8)); - pos += 1; - -#ifdef EM410X_Encoder_NRF_LOG_INFO - NRF_LOG_INFO("%d ", count1 % 2); -#endif // EM410X_Encoder_NRF_LOG_INFO - } - -#ifdef EM410X_Encoder_NRF_LOG_INFO - NRF_LOG_INFO(" <- Qi Dian verification : Tail code -> 0\n\n"); -#endif // EM410X_Encoder_NRF_LOG_INFO -} - -// Reading the card function, you need to stop calling, return 0 to read the card, 1 is to read -uint8_t em410x_acquire(void) { - if (dataindex >= RAW_BUF_SIZE * 8) { -#ifdef debug410x - { - for (int i = 0; i < RAW_BUF_SIZE * 8; i++) { - NRF_LOG_INFO("%d ", readbit(carddata.rawa, carddata.rawb, i)); - } - NRF_LOG_INFO("///raw data\r\n"); - for (int i = 0; i < RAW_BUF_SIZE * 8; i++) { - NRF_LOG_INFO("%d ", datatest[i]); - } - NRF_LOG_INFO("///time data\r\n"); - } -#endif - //Looking for goals 0 1111 1111 - carddata.startbit = 255; - for (int i = 0; i < (RAW_BUF_SIZE * 8) - 8; i++) { - if (readbit(carddata.rawa, carddata.rawb, i) == 1) { - carddata.startbit = 0; - for (int j = 1; j < 8; j++) { - carddata.startbit += (uint8_t)readbit(carddata.rawa, carddata.rawb, i + j); - } - if (carddata.startbit == 0) { - carddata.startbit = i; - break; - } else { - carddata.startbit = 255; - } - } - } - // If you find the right beginning to deal with it - if (carddata.startbit != 255 && carddata.startbit < (RAW_BUF_SIZE * 8) - 64) { - //Guarantee card data can be fully analyzed - //NRF_LOG_INFO("do mac,start: %d\r\n",startbit); - if (mcst(&carddata) == 1) { - //Card normal analysis -#ifdef debug410x - { - for (int i = 0; i < CARD_BUF_SIZE; i++) { - NRF_LOG_INFO("%02X", carddata.hexbuf[i]); - } - NRF_LOG_INFO("///card data\r\n"); - } -#endif - if (em410x_decoder(carddata.hexbuf, CARD_BUF_SIZE, cardbufbyte)) { - //Card data check passes -#ifdef debug410x - for (int i = 0; i < 5; i++) { - NRF_LOG_INFO("%02X", (int)cardbufbyte[i]); - } - NRF_LOG_INFO("///card dataBYTE\r\n"); -#endif - dataindex = 0; - return 1; - } - } - } - // Start a new cycle - dataindex = 0; - } - return 0; -} - -//GPIO interrupt recovery function is used to detect the descending edge -void GPIO_INT0_callback(void) { - static uint32_t thistimelen = 0; - thistimelen = get_lf_counter_value(); - if (thistimelen > 47) { - static uint8_t cons_temp = 0; - if (dataindex < RAW_BUF_SIZE * 8) { - if (48 <= thistimelen && thistimelen <= 80) { - cons_temp = 0; - } else if (80 <= thistimelen && thistimelen <= 112) { - cons_temp = 1; - } else if (112 <= thistimelen && thistimelen <= 144) { - cons_temp = 2; - } else { - cons_temp = 3; - } - writebit(carddata.rawa, carddata.rawb, dataindex, cons_temp); -#ifdef debug410x - datatest[dataindex] = thistimelen; -#endif - dataindex++; - } - clear_lf_counter_value(); - } - - uint16_t counter = 0; - do { - __NOP(); - } while (counter++ > 1000); -} - -//Start the timer and initialize related peripherals, start a low -frequency card reading void init_em410x_hw(void) { - //Registered card reader IO interrupt recovery - register_rio_callback(GPIO_INT0_callback); + register_rio_callback(gpio_int0_cb); + lf_125khz_radio_gpiote_init(); } -/** -* Read the card number of the EM410X card within the specified timeout -*/ -uint8_t em410x_read(uint8_t *uid, uint32_t timeout_ms) { - uint8_t ret = 0; +void uninit_em410x_hw(void) { + unregister_rio_callback(); +} - init_em410x_hw(); // Initialized decline along the sampling recovery function - start_lf_125khz_radio(); // Start 125kHz modulation +bool em410x_read(uint8_t *data, uint32_t timeout_ms) { + void **codecs = malloc(em410x_protocols_size * sizeof(void *)); + for (size_t i = 0; i < em410x_protocols_size; i++) { + codecs[i] = em410x_protocols[i]->alloc(); + em410x_protocols[i]->decoder.start(codecs[i], 0); + } - // Reading the card during timeout + cb_init(&cb, EM410X_BUFFER_SIZE, sizeof(uint16_t)); + init_em410x_hw(); + start_lf_125khz_radio(); + + bool ok = false; autotimer *p_at = bsp_obtain_timer(0); - // NO_TIMEOUT_1MS(p_at, timeout_ms) - while (NO_TIMEOUT_1MS(p_at, timeout_ms)) { - //Execute the card, exit if you read it - if (em410x_acquire()) { - stop_lf_125khz_radio(); - uid[0] = cardbufbyte[0]; - uid[1] = cardbufbyte[1]; - uid[2] = cardbufbyte[2]; - uid[3] = cardbufbyte[3]; - uid[4] = cardbufbyte[4]; - ret = 1; - break; + while (!ok && NO_TIMEOUT_1MS(p_at, timeout_ms)) { + uint16_t val = 0; + while (!ok && NO_TIMEOUT_1MS(p_at, timeout_ms) && cb_pop_front(&cb, &val)) { + for (int i = 0; i < em410x_protocols_size; i++) { + const protocol *p = em410x_protocols[i]; + if (!p->decoder.feed(codecs[i], val)) { + continue; + } + data[0] = p->tag_type >> 8; + data[1] = p->tag_type; + memcpy(data + 2, p->get_data(codecs[i]), p->data_size); + ok = true; + break; + } } } - if (ret != 1) { // If the card is not searched, it means that the timeout is over. We must manually end the card reader here. - stop_lf_125khz_radio(); - } - - dataindex = 0; // After the end, keep in mind the index of resetting data - bsp_return_timer(p_at); - p_at = NULL; + stop_lf_125khz_radio(); + uninit_em410x_hw(); + cb_free(&cb); - return ret; + for (size_t i = 0; i < em410x_protocols_size; i++) { + em410x_protocols[i]->free(codecs[i]); + } + free(codecs); + return ok; } diff --git a/firmware/application/src/rfid/reader/lf/lf_em410x_data.h b/firmware/application/src/rfid/reader/lf/lf_em410x_data.h index 864018d..161d03b 100644 --- a/firmware/application/src/rfid/reader/lf/lf_em410x_data.h +++ b/firmware/application/src/rfid/reader/lf/lf_em410x_data.h @@ -1,36 +1,22 @@ #ifndef __EM_410X_DATA_H__ #define __EM_410X_DATA_H__ +#include -#include "data_utils.h" #include "bsp_time.h" #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif -#define CARD_BUF_BYTES_SIZE 5 // Card byte buffer size +#define CARD_BUF_BYTES_SIZE 5 // Card byte buffer size -#define RAW_BUF_SIZE 24 // The maximum record buffer -#define CARD_BUF_SIZE 8 // Card size +#define RAW_BUF_SIZE 24 // The maximum record buffer +#define CARD_BUF_SIZE 8 // Card size -typedef struct { - uint8_t rawa[RAW_BUF_SIZE]; // The time difference between recording changes - uint8_t rawb[RAW_BUF_SIZE]; // The time difference between recording changes - uint8_t hexbuf[CARD_BUF_SIZE]; // Patriotic card data - uint8_t startbit; -} RAWBUF_TYPE_S; - -//Card data -extern uint8_t cardbufbyte[CARD_BUF_BYTES_SIZE]; - - -void init_em410x_hw(void); -void em410x_encoder(uint8_t *pData, uint8_t *pOut); -uint8_t em410x_decoder(uint8_t *pData, uint8_t size, uint8_t *pOut); -uint8_t em410x_read(uint8_t *uid, uint32_t timeout_ms); +#define EM410X_BUFFER_SIZE (128) +bool em410x_read(uint8_t *data, uint32_t timeout_ms); #ifdef __cplusplus } diff --git a/firmware/application/src/rfid/reader/lf/lf_hidprox_data.c b/firmware/application/src/rfid/reader/lf/lf_hidprox_data.c new file mode 100644 index 0000000..715a625 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/lf_hidprox_data.c @@ -0,0 +1,71 @@ +#include "lf_hidprox_data.h" + +#include + +#include "bsp_delay.h" +#include "bsp_time.h" +#include "circular_buffer.h" +#include "lf_125khz_radio.h" +#include "lf_reader_data.h" +#include "lf_reader_main.h" +#include "protocols/hidprox.h" +#include "time.h" + +#define NRF_LOG_MODULE_NAME lf_read +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_log_default_backends.h" +NRF_LOG_MODULE_REGISTER(); + +#define HIDPROX_BUFFER_SIZE (6144) + +static circular_buffer cb; + +// saadc irq is used to sample ANT GPIO level. +void saadc_cb(int16_t *vals, size_t size) { + for (int i = 0; i < size; i++) { + uint16_t val = vals[i]; + if (!cb_push_back(&cb, &val)) { + return; + } + } +} + +void init_hidprox_hw(void) { + register_saadc_callback(saadc_cb); + lf_125khz_radio_saadc_init(); +} + +void uninit_hidprox_hw(void) { + unregister_saadc_callback(); +} + +bool hidprox_read(uint8_t *data, uint8_t format_hint, uint32_t timeout_ms) { + void *codec = hidprox.alloc(); + hidprox.decoder.start(codec, format_hint); + + cb_init(&cb, HIDPROX_BUFFER_SIZE, sizeof(uint16_t)); + init_hidprox_hw(); + start_lf_125khz_radio(); + + bool ok = false; + autotimer *p_at = bsp_obtain_timer(0); + while (!ok && NO_TIMEOUT_1MS(p_at, timeout_ms)) { + uint16_t val = 0; + while (!ok && NO_TIMEOUT_1MS(p_at, timeout_ms) && cb_pop_front(&cb, &val)) { + if (hidprox.decoder.feed(codec, val)) { + memcpy(data, hidprox.get_data(codec), hidprox.data_size); + ok = true; + break; + } + } + } + + bsp_return_timer(p_at); + stop_lf_125khz_radio(); + uninit_hidprox_hw(); + cb_free(&cb); + + hidprox.free(codec); + return ok; +} diff --git a/firmware/application/src/rfid/reader/lf/lf_hidprox_data.h b/firmware/application/src/rfid/reader/lf/lf_hidprox_data.h new file mode 100644 index 0000000..0ba4456 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/lf_hidprox_data.h @@ -0,0 +1,19 @@ +#ifndef __LF_HIDPROX_DATA_H__ +#define __LF_HIDPROX_DATA_H__ + +#include + +#include "bsp_time.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool hidprox_read(uint8_t *data, uint8_t format_hint, uint32_t timeout_ms); +bool hidprox_debug(uint8_t *data, uint32_t timeout_ms); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/application/src/rfid/reader/lf/lf_reader_data.c b/firmware/application/src/rfid/reader/lf/lf_reader_data.c index 99449f8..a81a3c3 100644 --- a/firmware/application/src/rfid/reader/lf/lf_reader_data.c +++ b/firmware/application/src/rfid/reader/lf/lf_reader_data.c @@ -1,33 +1,40 @@ #include "lf_reader_data.h" + #include "nrf_drv_timer.h" +RIO_CALLBACK_S RIO_callback; +SAADC_CALLBACK_S SAADC_callback; -RIO_CALLBACK_S RIO_callback; // Create instance -uint8_t RIO_callback_state; // Record status - - -void register_rio_callback(RIO_CALLBACK_S P) { // Register recovery function +// Register recovery function +void register_rio_callback(RIO_CALLBACK_S P) { RIO_callback = P; - RIO_callback_state = 1; -} - -void blank_function(void) { - // This is an empty function, - // Nothing to do } void unregister_rio_callback(void) { - RIO_callback_state = 0; - RIO_callback = blank_function; + RIO_callback = NULL; +} + +// Register recovery function +void register_saadc_callback(SAADC_CALLBACK_S P) { + SAADC_callback = P; +} + +void unregister_saadc_callback(void) { + SAADC_callback = NULL; } // GPIO interrupt is the RIO pin -void GPIO_INT0_IRQHandler(void) { - if (RIO_callback_state == 1) { +void gpio_int0_irq_handler(void) { + if (RIO_callback != NULL) { RIO_callback(); } } +void saadc_irq_handler(int16_t *val, size_t size) { + if (SAADC_callback != NULL) { + SAADC_callback(val, size); + } +} extern nrfx_timer_t m_timer_lf_reader; @@ -37,6 +44,4 @@ uint32_t get_lf_counter_value(void) { } // Clear the value of the counter -void clear_lf_counter_value(void) { - nrfx_timer_clear(&m_timer_lf_reader); -} +void clear_lf_counter_value(void) { nrfx_timer_clear(&m_timer_lf_reader); } diff --git a/firmware/application/src/rfid/reader/lf/lf_reader_data.h b/firmware/application/src/rfid/reader/lf/lf_reader_data.h index f1f33b8..aeab8b3 100644 --- a/firmware/application/src/rfid/reader/lf/lf_reader_data.h +++ b/firmware/application/src/rfid/reader/lf/lf_reader_data.h @@ -1,6 +1,7 @@ #ifndef __READER_IO_H__ #define __READER_IO_H__ +#include #include // #define debug410x @@ -9,12 +10,15 @@ extern "C" { #endif -typedef void(*RIO_CALLBACK_S)(void); // Call the function format +typedef void (*RIO_CALLBACK_S)(void); // Call the function format +typedef void (*SAADC_CALLBACK_S)(int16_t *, size_t); void register_rio_callback(RIO_CALLBACK_S P); -void blank_function(void); void unregister_rio_callback(void); -void GPIO_INT0_IRQHandler(void); +void register_saadc_callback(SAADC_CALLBACK_S P); +void unregister_saadc_callback(void); +void gpio_int0_irq_handler(void); +void saadc_irq_handler(int16_t *val, size_t); // Counter uint32_t get_lf_counter_value(void); diff --git a/firmware/application/src/rfid/reader/lf/lf_reader_main.c b/firmware/application/src/rfid/reader/lf/lf_reader_main.c index cf37c3b..02e8565 100644 --- a/firmware/application/src/rfid/reader/lf/lf_reader_main.c +++ b/firmware/application/src/rfid/reader/lf/lf_reader_main.c @@ -1,8 +1,14 @@ -#include "bsp_time.h" -#include "bsp_delay.h" #include "lf_reader_main.h" -#include "lf_125khz_radio.h" +#include "bsp_delay.h" +#include "bsp_time.h" +#include "hex_utils.h" +#include "lf_125khz_radio.h" +#include "lf_em410x_data.h" +#include "lf_hidprox_data.h" +#include "protocols/em410x.h" +#include "protocols/hidprox.h" +#include "protocols/t55xx.h" #define NRF_LOG_MODULE_NAME lf_main #include "nrf_log.h" @@ -10,104 +16,98 @@ #include "nrf_log_default_backends.h" NRF_LOG_MODULE_REGISTER(); - // The default card search is available N Millisecond timeout -uint32_t g_timeout_readem_ms = 500; - +static uint32_t g_timeout_readem_ms = 500; /** -* Search EM410X tag -*/ -uint8_t PcdScanEM410X(uint8_t *uid) { - uint8_t ret = STATUS_EM410X_TAG_NO_FOUND; - if (em410x_read(uid, g_timeout_readem_ms) == 1) { - ret = STATUS_LF_TAG_OK; - } - return ret; -} - -/** -* Check whether there is a specified UID tag on the current field -*/ -uint8_t check_write_ok(uint8_t *uid, uint8_t *newuid, uint8_t on_uid_diff_return) { - // After the card is written, we need to read it once, - // If the data I read is incorrect, it means that the writing fails - if (PcdScanEM410X(newuid) != STATUS_LF_TAG_OK) { - return STATUS_EM410X_TAG_NO_FOUND; - } - // If you read the card number the same - // Explanation is successful (maybe) - if ( - uid[0] == newuid[0] && - uid[1] == newuid[1] && - uid[2] == newuid[2] && - uid[3] == newuid[3] && - uid[4] == newuid[4]) { + * Search EM410X tag + */ +uint8_t scan_em410x(uint8_t *uid) { + if (em410x_read(uid, g_timeout_readem_ms)) { return STATUS_LF_TAG_OK; } - // If you find the card, the card number is wrong, - // Then we will return the abnormal value of the inlet - return on_uid_diff_return; + return STATUS_EM410X_TAG_NO_FOUND; } /** -* Write T55XX tag -*/ -uint8_t PcdWriteT55XX(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t old_key_count) { - uint8_t datas[8] = { 255 }; - uint8_t i; - - init_t55xx_hw(); - start_lf_125khz_radio(); - - bsp_delay_ms(1); // Delays for a while after starting the field - - // keys Need at least two, one newkey, one Oldkey - // one key The length is 4 Byte - // uid newkey oldkeys * n - - // The key transmitted in iterative, - // Reset T55XX tags - // printf("The old keys count: %d\r\n", old_key_count); - for (i = 0; i < old_key_count; i++) { - T55xx_Reset_Passwd(old_keys + (i * 4), newkey); - /* - printf("oldkey is: %02x%02x%02x%02x\r\n", - (old_keys + (i * 4))[0], - (old_keys + (i * 4))[1], - (old_keys + (i * 4))[2], - (old_keys + (i * 4))[3] - );*/ + * Search HID Prox tag + */ +uint8_t scan_hidprox(uint8_t *data, uint8_t format) { + if (hidprox_read(data, format, g_timeout_readem_ms)) { + return STATUS_LF_TAG_OK; } + return STATUS_HIDPROX_TAG_NO_FOUND; +} - // In order to avoid the labels of a special control area, - // We use the new key here to reset the control area - T55xx_Reset_Passwd(newkey, newkey); +/** + * Debug HIDProx + */ +uint8_t debug_hidprox(uint8_t *data) { + hidprox_debug(data, g_timeout_readem_ms); + return STATUS_SUCCESS; +} - // The data encoded 410X is the block data to prepare for the card writing - em410x_encoder(uid, datas); +/** + * Try reset t55XX tag passwords by enumerating old passwords. + */ +static void try_reset_t55xx_passwd(uint32_t new_passwd, uint8_t *old_passwds, uint8_t old_passwd_count) { + for (uint8_t i = 0; i < old_passwd_count; i++) { + uint32_t old_passwd = bytes_to_num(old_passwds + i * 4, 4); + t55xx_reset_passwd(old_passwd, new_passwd); + } + t55xx_reset_passwd(new_passwd, new_passwd); +} - // After the key is reset, perform the card writing operation - /* - printf("newkey is: %02x%02x%02x%02x\r\n", - newkey[0], - newkey[1], - newkey[2], - newkey[3] - ); - */ - T55xx_Write_data(newkey, datas); +/** + * Write card data to t55xx + */ +static uint8_t write_t55xx(uint32_t *blks, uint8_t blk_count, uint8_t *new_passwd, uint8_t *old_passwds, uint8_t old_passwd_count) { + uint32_t passwd = bytes_to_num(new_passwd, 4); + + start_lf_125khz_radio(); + bsp_delay_ms(1); // Delays for a while after starting the field + + try_reset_t55xx_passwd(passwd, old_passwds, old_passwd_count); + t55xx_write_data(passwd, blks, blk_count); stop_lf_125khz_radio(); - // Read the verification and return the results of the card writing - // Do not read it here, you can check it by the upper machine + // writing results should be verified by upper computer return STATUS_LF_TAG_OK; } /** -* Set the time value of the card search timeout of the EM card -*/ -void SetEMScanTagTimeout(uint32_t ms) { - g_timeout_readem_ms = ms; + * Write em410x card data to t55xx + */ +uint8_t write_em410x_to_t55xx(uint8_t *uid, uint8_t *new_passwd, uint8_t *old_passwds, uint8_t old_passwd_count) { + uint32_t blks[7] = {0x00}; + uint8_t blk_count = em410x_t55xx_writer(uid, blks); + if (blk_count == 0) { + return STATUS_PAR_ERR; + } + return write_t55xx(blks, blk_count, new_passwd, old_passwds, old_passwd_count); } + +/** + * Write hidprox card data to t55xx + */ +uint8_t write_hidprox_to_t55xx(uint8_t format, uint32_t fc, uint64_t cn, uint32_t il, uint32_t oem, uint8_t *new_passwd, uint8_t *old_passwds, uint8_t old_passwd_count) { + wiegand_card_t card = { + .format = format, + .card_number = cn, + .facility_code = fc, + .issue_level = il, + .oem = oem, + }; + uint32_t blks[7] = {0x00}; + uint8_t blk_count = hidprox_t55xx_writer(&card, blks); + if (blk_count == 0) { + return STATUS_PAR_ERR; + } + return write_t55xx(blks, blk_count, new_passwd, old_passwds, old_passwd_count); +} + +/** + * Set the LF card scanning timeout value (in milliseconds). + */ +void SetScanTagTimeout(uint32_t ms) { g_timeout_readem_ms = ms; } \ No newline at end of file diff --git a/firmware/application/src/rfid/reader/lf/lf_reader_main.h b/firmware/application/src/rfid/reader/lf/lf_reader_main.h index d7fe118..6ced7de 100644 --- a/firmware/application/src/rfid/reader/lf/lf_reader_main.h +++ b/firmware/application/src/rfid/reader/lf/lf_reader_main.h @@ -1,18 +1,19 @@ -#ifndef _LFCOPIER_H_ -#define _LFCOPIER_H_ +#ifndef __LF_READER_MAIN_H__ +#define __LF_READER_MAIN_H__ +#include #include - -#include "lf_em410x_data.h" -#include "lf_t55xx_data.h" #include "app_status.h" +#include "lf_125khz_radio.h" +#include "lf_em410x_data.h" -extern uint32_t g_timeout_readem_ms; +void SetScanTagTimeout(uint32_t ms); -void SetEMScanTagTimeout(uint32_t ms); - -uint8_t PcdScanEM410X(uint8_t *uid); -uint8_t PcdWriteT55XX(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t old_key_count); +uint8_t scan_em410x(uint8_t *uid); +uint8_t write_em410x_to_t55xx(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t old_key_count); +uint8_t write_hidprox_to_t55xx(uint8_t format, uint32_t fc, uint64_t cn, uint32_t il, uint32_t oem, uint8_t *new_passwd, uint8_t *old_passwds, uint8_t old_passwd_count) ; +uint8_t scan_hidprox(uint8_t *uid, uint8_t format); +uint8_t debug_hidprox(uint8_t *data); #endif diff --git a/firmware/application/src/rfid/reader/lf/lf_t55xx_data.c b/firmware/application/src/rfid/reader/lf/lf_t55xx_data.c index a033ab2..d46c2db 100644 --- a/firmware/application/src/rfid/reader/lf/lf_t55xx_data.c +++ b/firmware/application/src/rfid/reader/lf/lf_t55xx_data.c @@ -1,16 +1,11 @@ -#ifdef debugt55xx -#include -#endif - -#include "nrf_sdh_soc.h" -#include "nrf_gpio.h" - -#include "timeslot.h" #include "bsp_delay.h" -#include "lf_t55xx_data.h" -#include "lf_reader_data.h" +#include "hex_utils.h" #include "lf_125khz_radio.h" - +#include "lf_reader_data.h" +#include "nrf_gpio.h" +#include "nrf_sdh_soc.h" +#include "protocols/t55xx.h" +#include "timeslot.h" #define NRF_LOG_MODULE_NAME lf_t55xx #include "nrf_log.h" @@ -18,243 +13,136 @@ #include "nrf_log_default_backends.h" NRF_LOG_MODULE_REGISTER(); - -/* -Small machine writing card: -01 00000000000001000010000000010000 0 000 - -01 1 00010100010010010000110110010010 000 00000000000000000000000000000 000 011 - -01 1 00010100010010010000110110010110 000 - 01010001001001000011011001011000 51243658 - -10 01010001001001000011011001001000 0 01010001001001000011011001001000 111 - -|--------------------------------------------------------------------------| -| 70bit Password write found | -|--------------------------------------------------------------------------| -|OP|PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP|L|DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD|AAA| -|10|01010001001001000011011001001000|0|01010001001001000011011001001000|111| Zone 0 7 blocks to write the current password (password) -|10|01010001001001000011011001001000|0|01010001001001000111011001001000|111| Zone 0 7 blocks to write the current password (password) -|10|01010001001001000011011001001000|0|00000000000101001000000001010000|000| Zone 0 0 blocks are written in the current password00148050 (control zone) -|10|01010001001001000011011001001000|0|11111111101001010010000000000100|001| Zone 0 1 block is written in the current passwordFFA52004 (data) -|11|01010001001001000011011001001000|0|11111111101001010010000000000100|001| zone 1 1 block is written in the current passwordFFA52004 (data) -|10|01010001001001000011011001001000|0|10100101011100011001011101101010|010| Zone 0 2 are written in the current passwordA571976A (data) -|11|01010001001001000011011001001000|0|10100101011100011001011101101010|010| zone 1 2 are written in the current passwordA571976A (data) -|11|01010001001001000011011001001000|0|01100000000000000000100000000000|011| zone 1 3 blocks are written in the current password60000800 (radio frequency parameter) -|--------------------------------------------------------------------------| -RESET Pack received -|-----------------------------------------| -| 38bit regular write found | -|OP|L|DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD|AAA| -| 10 | 0 | 00000000000101001000000000000 | 000 | 0 area 0 block writing00148050 (control zone) -| 10 | 0 | 111111111010010000000000100 | 001 | 0 area 1 pieceFFA52004 (data) -| 10 | 0 | 1010010101100011000101110101010 | 010 | 0 area 2 pieces of writingA571976A (data) -|-----------------------------------------| -RESET Pack received - -Copy Qiji Writing Card: -|-----------------------------------------| -|OP|L|DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD|AAA| -| 10 | 0 | 00011001100100000000100111 | 111 | 0 area 7 pieces19920427 (password) -| 10 | 0 | 000000000001010010000000010000 | 000 | 0 area 0 block writing00148050 (control zone) -|-----------------------------------------| -|--------------------------------------------------------------------------| -|OP|PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP|L|DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD|AAA| -|10|00011001100100100000010000100111|0|11111111101001010010000000000100|001| -|10|00011001100100100000010000100111|0|10100101011111011101110000011010|010| -|10|00011001100100100000010000100111|0|00000000000101001000000001010000|000| -|10|00011001100100100000010000100111|0|11111111101001010010000000000100|001| -|10|00011001100100100000010000100111|0|10100101011111011101110000011010|010| -|--------------------------------------------------------------------------| -|-----------------------------------------| -|OP|L|DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD|AAA| -|10|0|11111111101001010010000000000100|001| -|10|0|10100101011111011101110000011010|010| -|-----------------------------------------| -RESET Pack received -*/ - +const uint32_t start_gap = 30 * 8; // 30Tc +const uint32_t write_gap = 9 * 8; // 9Tc +const uint32_t gap_sep_zero = 24 * 8; // 24Tc +const uint32_t gap_sep_one = 54 * 8; // 54Tc static struct { uint8_t opcode; - uint8_t usepassword; - uint32_t password; - uint8_t lockBit; - uint8_t usedata; - uint32_t data; - uint8_t blockAddr; + uint8_t lock_bit; + uint32_t *data; + uint32_t *passwd; + uint8_t blk_addr; } t55xx_cmd; - -// Air function, T55XX writing card does not need to care about the data you read -void empty_callback() { } - - -//Start the timer and initialize related peripherals, start a low -frequency card reading -void init_t55xx_hw(void) { - //Registered card reader IO interrupt recovery - register_rio_callback(empty_callback); +void t55xx_send_gap(uint32_t nus) { + stop_lf_125khz_radio(); // turn off 125khz field + bsp_delay_us(nus); + start_lf_125khz_radio(); // turn on 125khz field } -void T55xx_SendGap(unsigned int tm) { - stop_lf_125khz_radio(); // Turn off PWM output - bsp_delay_us(tm); - start_lf_125khz_radio(); // Start PWM output +void t55xx_tx_bit(uint8_t data) { + if (data & 0x01) { + bsp_delay_us(gap_sep_one); + } else { + bsp_delay_us(gap_sep_zero); + } + t55xx_send_gap(write_gap); } -void TxBitRfid(uint8_t data) { - if (data & 1) - bsp_delay_us(54 * 8); - else - bsp_delay_us(24 * 8); - T55xx_SendGap(9 * 8); //write gap -} - -void TxByteRfid(uint8_t data) { - for (uint8_t n_bit = 0; n_bit < 8; n_bit++) { - TxBitRfid(data & 1); - data = data >> 1; +void t55xx_tx_uint32_t(uint32_t data) { + for (uint8_t i = 0; i < 32; i++) { + t55xx_tx_bit((data >> (31 - i)) & 1); } } -// T55XX high -precision timing control function -void T55XX_Timeslot_Callback() { - T55xx_SendGap(30 * 8); // start gap +// t55xx high-precision timing control function +void t55xx_timeslot_callback() { + t55xx_send_gap(start_gap); - //Send instructions first - TxBitRfid(t55xx_cmd.opcode >> 1); - TxBitRfid(t55xx_cmd.opcode & 1); + // send instructions first + t55xx_tx_bit(t55xx_cmd.opcode >> 1); + t55xx_tx_bit(t55xx_cmd.opcode & 1); - //The instruction does not need to be sent when it is 00 - if (t55xx_cmd.opcode != 0) { - //If you need it after the instruction, you can send the password - if (t55xx_cmd.usepassword) { - for (uint8_t i = 0; i < 32; i++) { - TxBitRfid((t55xx_cmd.password >> (31 - i)) & 1); - } - } + // the instruction does not need to be sent when it is 00 + if (t55xx_cmd.opcode == 0) { + return; + } - //Process lock position - if (t55xx_cmd.lockBit == 0 || t55xx_cmd.lockBit == 1) { - TxBitRfid(t55xx_cmd.lockBit & 1); - } + // if you need it after the instruction, you can send the password + if (t55xx_cmd.passwd != NULL) { + t55xx_tx_uint32_t(*t55xx_cmd.passwd); + } - //Only need to send data if there is a need - if (t55xx_cmd.usedata) { - for (uint8_t i = 0; i < 32; i++) { - TxBitRfid((t55xx_cmd.data >> (31 - i)) & 1); - } - } + // process lock position + if (t55xx_cmd.lock_bit == 0 || t55xx_cmd.lock_bit == 1) { + t55xx_tx_bit(t55xx_cmd.lock_bit & 1); + } - //Processing address - if (t55xx_cmd.blockAddr != 255) { - TxBitRfid(t55xx_cmd.blockAddr >> 2); - TxBitRfid(t55xx_cmd.blockAddr >> 1); - TxBitRfid(t55xx_cmd.blockAddr & 1); - } + if (t55xx_cmd.data != NULL) { + t55xx_tx_uint32_t(*t55xx_cmd.data); + } + + // processing address + if (t55xx_cmd.blk_addr != 255) { + t55xx_tx_bit(t55xx_cmd.blk_addr >> 2); + t55xx_tx_bit(t55xx_cmd.blk_addr >> 1); + t55xx_tx_bit(t55xx_cmd.blk_addr & 1); } } /** * @brief Write to 5577 instructions, this instruction can be read and write * - * @param opcode The operating code must be 1*in normal operation mode, only the reset is 00 - * @param usepassword Whether the password is used, the password is the password mode - * @param password Password, send it when USepAssWD is valid, 32 BIT, start transmission from the bidding 0 - * @param lockBit Locking position may only be 1 or 0. Passing other values means not using LOCK bit (for password awakening mode) - * @param usedata Whether the data area is used to transmit the data for 1 time - * @param data Data, 32 bits, transmitted from the lower bid 0 - * @param blockAddr Block number, 3 bit 0-7 yuan, input 255 means not using this bit (for password wake-up mode) + * @param opcode Operating code, should be 1* for normal operations, only the reset is 00. + * @param passwd Password, send when not NULL, 32bit, start transmission from the bidding 0. + * @param lock_bit Locking position may only be 1 or 0. Passing other values means not using LOCK bit (for password awakening mode) + * @param data Data, 32 bits, transmitted from the lower bit 0 + * @param blk_addr Block number, 3 bit 0-7 yuan, input 255 means not using this bit (for password wake-up mode) */ -void T55xx_Send_Cmd(uint8_t opcode, uint8_t usepassword, uint32_t password, uint8_t lockBit, uint8_t usedata, uint32_t data, uint8_t blockAddr) { - //Password reading mode, 2op(1+bck) 32pw 1(0) 3addr - //Password writing mode, 2op(1+bck) 32pw 1l 32data 3addr - //Password wake -up mode, 2op(1+0) 32pw +void t55xx_send_cmd(uint8_t opcode, uint32_t *passwd, uint8_t lock_bit, uint32_t *data, uint8_t blk_addr) { + // Password reading mode, 2op(1+bck) 32pw 1(0) 3addr + // Password writing mode, 2op(1+bck) 32pw 1l 32data 3addr + // Password wake-up mode, 2op(1+0) 32pw - //Read the mode directly, 2op(1+bck) 1(0) 3addr - //Standard writing mode, 2op(1+bck) 1l 32data 3addr + // Read the mode directly, 2op(1+bck) 1(0) 3addr + // Standard writing mode, 2op(1+bck) 1l 32data 3addr - //This will not be implemented // Standard read page mode, 2op(1+bck) - - //Reset mode, 2op(0+0) + // This will not be implemented + // Standard read page mode, 2op(1+bck) + // Reset mode, 2op(0+0) t55xx_cmd.opcode = opcode; - t55xx_cmd.usepassword = usepassword; - t55xx_cmd.password = password; - t55xx_cmd.lockBit = lockBit; - t55xx_cmd.usedata = usedata; + t55xx_cmd.passwd = passwd; + t55xx_cmd.lock_bit = lock_bit; t55xx_cmd.data = data; - t55xx_cmd.blockAddr = blockAddr; + t55xx_cmd.blk_addr = blk_addr; - - // Request timing, and wait for the order operation to complete - request_timeslot(37 * 1000, T55XX_Timeslot_Callback, true); + // request timing, and wait for the order operation to complete + request_timeslot(37 * 1000, t55xx_timeslot_callback, true); if (opcode != 0) { - bsp_delay_ms(6); // Maybe continue to write a card next time, you need to wait more for a while + bsp_delay_ms(6); // Maybe continue to write a card next time, you need to wait more for a while } else { bsp_delay_ms(1); } } /** - * @brief T55XX Write into EM410X data + * @brief T55XX Write into HIDProx data * * @param passwd The password for the final encryption (also the current password of the card) (is a pointer, 4 -byte width small end byte sequence storage) - * @param datas After the data of EM410X, you need to call the EM410X_ENCODER calculation + * @param data After the data of EM410X, you need to call the EM410X_ENCODER calculation */ -void T55xx_Write_data(uint8_t *passwd, uint8_t *datas) { - uint32_t blk1data = 0, blk2data = 0, u32passwd = 0; - //Extract the data and passwords of two blocks - for (uint8_t dataindex = 0; dataindex < 4; dataindex++) { - blk1data = blk1data << 8; - blk1data |= (uint8_t)datas[dataindex]; - u32passwd = u32passwd << 8; - u32passwd |= (uint8_t)passwd[dataindex]; +void t55xx_write_data(uint32_t passwd, uint32_t *blks, uint8_t blk_count) { + // write control bits (blk0) & data (w/wo passwd) + for (uint8_t i = 0; i < blk_count; i++) { + t55xx_send_cmd(T5577_OPCODE_PAGE0, &passwd, 0, &blks[i], i); + t55xx_send_cmd(T5577_OPCODE_PAGE0, NULL, 0, &blks[i], i); } - for (uint8_t dataindex = 4; dataindex < 8; dataindex++) { - blk2data = blk2data << 8; - blk2data |= (uint8_t)datas[dataindex]; - } - //writeToThePasswordAreaFirst - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, u32passwd, 7); // 0 area 7 blocks to write the current password (password) - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, u32passwd, 7); // 0 area 7 blocks to write the current password (password) - //Then write to the control area - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, 0X00148050, 0); // 0 area 0 blocks are written in the current password00148050 (control zone) - //Then write the data - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, blk1data, 1); // 0 area 1 block is written in the current passwordblk1data (data) - T55xx_Send_Cmd(3, 1, u32passwd, 0, 1, blk1data, 1); //zone 1 1 block is written in the current passwordblk1data (data) - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, blk2data, 2); // 0 area 2 are written in the current passwordblk2data (data) - T55xx_Send_Cmd(3, 1, u32passwd, 0, 1, blk2data, 2); //zone 1 2 are written in the current passwordblk2data (data) - //Then write in the radio frequency parameter - // 2021-12-15 FIX: Writing this data will cause the small card to be unable to write repeatedly - // T55xx_Send_Cmd(3, 1, u32passwd, 0, 1, 0X60000800, 3); //zone 1 3 blocks are written in the current password60000800 (radio frequency parameter) - //Then write again with non -password instructions - T55xx_Send_Cmd(2, 0, 0, 0, 1, 0X00148050, 0); // 0 area 0 block writing00148050 (control zone) - T55xx_Send_Cmd(2, 0, 0, 0, 1, blk1data, 1); // 0 area 1 pieceblk1data (data) - T55xx_Send_Cmd(2, 0, 0, 0, 1, blk2data, 2); // 0 area 2 pieces of writingblk2data (data) - T55xx_Send_Cmd(0, 0, 0, 0, 0, 0, 0); //Restart card + t55xx_send_cmd(T5577_OPCODE_RESET, NULL, 0, NULL, 0); } /** * @brief Reset the password function to set the card that is used to set the existing known password into a target password * - * @param oldpasswd The current password of the card (is a pointer, 4 -byte width small end byte sequential storage) - * @param newpasswd The password for the final encryption (is a pointer, 4 -byte width small end byte sequential storage) + * @param old_passwd current card password (32bits) + * @param new_passwd target card password (32bits) */ -void T55xx_Reset_Passwd(uint8_t *oldpasswd, uint8_t *newpasswd) { - uint32_t u32oldpasswd = 0, u32newpasswd = 0; - //Extract the data and passwords of two blocks - for (uint8_t dataindex = 0; dataindex < 4; dataindex++) { - u32oldpasswd = u32oldpasswd << 8; - u32oldpasswd |= (uint8_t)oldpasswd[dataindex]; - u32newpasswd = u32newpasswd << 8; - u32newpasswd |= (uint8_t)newpasswd[dataindex]; - } - - T55xx_Send_Cmd(2, 1, u32oldpasswd, 0, 1, u32newpasswd, 7); // 0 area 7 blocks to write new passwords (passwords) - T55xx_Send_Cmd(2, 1, u32oldpasswd, 0, 1, u32newpasswd, 7); // 0 area 7 blocks to write new passwords (passwords) - T55xx_Send_Cmd(0, 0, 0, 0, 0, 0, 0); //Restart card +void t55xx_reset_passwd(uint32_t old_passwd, uint32_t new_passwd) { + t55xx_send_cmd(T5577_OPCODE_PAGE0, &old_passwd, 0, &new_passwd, 7); // 0 area 7 blocks to write new passwords (passwords) + t55xx_send_cmd(T5577_OPCODE_PAGE0, &old_passwd, 0, &new_passwd, 7); // 0 area 7 blocks to write new passwords (passwords) + t55xx_send_cmd(T5577_OPCODE_RESET, NULL, 0, NULL, 0); } diff --git a/firmware/application/src/rfid/reader/lf/lf_t55xx_data.h b/firmware/application/src/rfid/reader/lf/lf_t55xx_data.h deleted file mode 100644 index ecc2afc..0000000 --- a/firmware/application/src/rfid/reader/lf/lf_t55xx_data.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __T_55XX_DATA_H__ -#define __T_55XX_DATA_H__ - - -#include "data_utils.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -void init_t55xx_hw(void); -void T55xx_Reset_Passwd(uint8_t *oldpasswd, uint8_t *newpasswd); -void T55xx_Write_data(uint8_t *passwd, uint8_t *datas); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/firmware/application/src/rfid_main.c b/firmware/application/src/rfid_main.c index 0e4d432..95d6c62 100644 --- a/firmware/application/src/rfid_main.c +++ b/firmware/application/src/rfid_main.c @@ -27,7 +27,7 @@ void reader_mode_enter(void) { nrf_gpio_pin_clear(HF_ANT_SEL); // hf ant switch to reader mode // init reader - lf_125khz_radio_init(); + lf_125khz_radio_gpiote_init(); pcd_14a_reader_init(); pcd_14a_reader_reset(); } @@ -110,10 +110,10 @@ uint8_t get_color_by_slot(uint8_t slot) { bool enabled_lf = tag_emulation_slot_is_enabled(slot, TAG_SENSE_LF); bool enabled_hf = tag_emulation_slot_is_enabled(slot, TAG_SENSE_HF); if (tag_types.tag_hf != TAG_TYPE_UNDEFINED && tag_types.tag_lf != TAG_TYPE_UNDEFINED && enabled_hf && enabled_lf) { - return 0; // Dual -frequency card simulation, return R, indicate a dual -frequency card - } else if (tag_types.tag_hf != TAG_TYPE_UNDEFINED && enabled_hf) { //High -frequency simulation, return G + return 0; // Dual -frequency card emulation, return R, indicate a dual -frequency card + } else if (tag_types.tag_hf != TAG_TYPE_UNDEFINED && enabled_hf) { //High -frequency emulation, return G return 1; - } else { // Low -frequency simulation, return B + } else { // Low -frequency emulation, return B return 2; } } diff --git a/firmware/application/src/rfid_main.h b/firmware/application/src/rfid_main.h index ea91b45..7b6132c 100644 --- a/firmware/application/src/rfid_main.h +++ b/firmware/application/src/rfid_main.h @@ -1,27 +1,22 @@ #ifndef RFID_MAIN_H #define RFID_MAIN_H -#include "nrf_gpio.h" - -#include "bsp_time.h" #include "bsp_delay.h" +#include "bsp_time.h" #include "hw_connect.h" -#include "nfc_14a.h" -#include "nfc_mf1.h" -#include "nfc_mf0_ntag.h" #include "lf_tag_em.h" +#include "nfc_14a.h" +#include "nfc_mf0_ntag.h" +#include "nfc_mf1.h" +#include "nrf_gpio.h" #include "tag_emulation.h" - #if defined(PROJECT_CHAMELEON_ULTRA) -#include "rc522.h" -#include "mf1_toolbox.h" -#include "lf_em410x_data.h" -#include "lf_125khz_radio.h" #include "lf_reader_main.h" +#include "mf1_toolbox.h" +#include "rc522.h" #endif - typedef enum { DEVICE_MODE_NONE, DEVICE_MODE_READER, diff --git a/firmware/application/src/utils/syssleep.c b/firmware/application/src/utils/syssleep.c index 2640726..eaebf8d 100644 --- a/firmware/application/src/utils/syssleep.c +++ b/firmware/application/src/utils/syssleep.c @@ -11,7 +11,7 @@ APP_TIMER_DEF(m_app_sleep_timer); //The timer for equipment sleep static volatile bool m_system_off_enter = false; extern bool g_is_ble_connected; //Link to log in BLE -extern bool g_is_tag_emulating; //The status of the logo simulation card +extern bool g_is_tag_emulating; //The status of the logo emulation card /** @brief Equipment sleep timer event @@ -48,7 +48,7 @@ void sleep_timer_start(uint32_t time_ms) { sleep_timer_stop(); // Non -USB power supply status if (nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_DISCONNECTED) { - // If Bluetooth is still connected, or is still in the state of simulation card, you don't need to start sleep + // If Bluetooth is still connected, or is still in the state of emulation card, you don't need to start sleep if (g_is_ble_connected == false && g_is_tag_emulating == false) { // Start the timer ret_code_t err_code = app_timer_start(m_app_sleep_timer, APP_TIMER_TICKS(time_ms), NULL); diff --git a/firmware/nrf52_sdk/components/libraries/block_dev/empty/nrf_block_dev_empty.c b/firmware/nrf52_sdk/components/libraries/block_dev/empty/nrf_block_dev_empty.c index 03e1012..9542bc2 100644 --- a/firmware/nrf52_sdk/components/libraries/block_dev/empty/nrf_block_dev_empty.c +++ b/firmware/nrf52_sdk/components/libraries/block_dev/empty/nrf_block_dev_empty.c @@ -81,7 +81,7 @@ static ret_code_t block_dev_empty_init(nrf_block_dev_t const * p_blk_dev, if (p_work->ev_handler) { - /*Asynchronous operation (simulation)*/ + /*Asynchronous operation (emulation)*/ const nrf_block_dev_event_t ev = { NRF_BLOCK_DEV_EVT_INIT, NRF_BLOCK_DEV_RESULT_SUCCESS, @@ -106,7 +106,7 @@ static ret_code_t block_dev_empty_uninit(nrf_block_dev_t const * p_blk_dev) if (p_work->ev_handler) { - /*Asynchronous operation (simulation)*/ + /*Asynchronous operation (emulation)*/ const nrf_block_dev_event_t ev = { NRF_BLOCK_DEV_EVT_UNINIT, NRF_BLOCK_DEV_RESULT_SUCCESS, @@ -152,7 +152,7 @@ static ret_code_t block_dev_empty_read_req(nrf_block_dev_t const * p_blk_dev, memset(p_blk->p_buff, 0, p_empty_dev->p_work->geometry.blk_size * p_blk->blk_count); if (p_work->ev_handler) { - /*Asynchronous operation (simulation)*/ + /*Asynchronous operation (emulation)*/ const nrf_block_dev_event_t ev = { NRF_BLOCK_DEV_EVT_BLK_READ_DONE, NRF_BLOCK_DEV_RESULT_SUCCESS, @@ -197,7 +197,7 @@ static ret_code_t block_dev_empty_write_req(nrf_block_dev_t const * p_blk_dev, if (p_work->ev_handler) { - /*Asynchronous operation (simulation)*/ + /*Asynchronous operation (emulation)*/ const nrf_block_dev_event_t ev = { NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE, NRF_BLOCK_DEV_RESULT_SUCCESS, diff --git a/firmware/nrf52_sdk/components/libraries/block_dev/qspi/nrf_block_dev_qspi.c b/firmware/nrf52_sdk/components/libraries/block_dev/qspi/nrf_block_dev_qspi.c index 10b13f1..40434db 100644 --- a/firmware/nrf52_sdk/components/libraries/block_dev/qspi/nrf_block_dev_qspi.c +++ b/firmware/nrf52_sdk/components/libraries/block_dev/qspi/nrf_block_dev_qspi.c @@ -408,7 +408,7 @@ static ret_code_t block_dev_qspi_init(nrf_block_dev_t const * p_blk_dev, if (p_work->ev_handler) { - /*Asynchronous operation (simulation)*/ + /*Asynchronous operation (emulation)*/ const nrf_block_dev_event_t ev = { NRF_BLOCK_DEV_EVT_INIT, NRF_BLOCK_DEV_RESULT_SUCCESS, diff --git a/firmware/nrf52_sdk/components/libraries/block_dev/ram/nrf_block_dev_ram.c b/firmware/nrf52_sdk/components/libraries/block_dev/ram/nrf_block_dev_ram.c index 900d2c3..cc822bf 100644 --- a/firmware/nrf52_sdk/components/libraries/block_dev/ram/nrf_block_dev_ram.c +++ b/firmware/nrf52_sdk/components/libraries/block_dev/ram/nrf_block_dev_ram.c @@ -77,7 +77,7 @@ static ret_code_t block_dev_ram_init(nrf_block_dev_t const * p_blk_dev, if (p_work->ev_handler) { - /*Asynchronous operation (simulation)*/ + /*Asynchronous operation (emulation)*/ const nrf_block_dev_event_t ev = { NRF_BLOCK_DEV_EVT_INIT, NRF_BLOCK_DEV_RESULT_SUCCESS, @@ -100,7 +100,7 @@ static ret_code_t block_dev_ram_uninit(nrf_block_dev_t const * p_blk_dev) NRF_LOG_INST_DEBUG(p_ram_dev->p_log, "Uninit"); if (p_work->ev_handler) { - /*Asynchronous operation (simulation)*/ + /*Asynchronous operation (emulation)*/ const nrf_block_dev_event_t ev = { NRF_BLOCK_DEV_EVT_UNINIT, NRF_BLOCK_DEV_RESULT_SUCCESS, @@ -160,7 +160,7 @@ static ret_code_t block_dev_ram_req(nrf_block_dev_t const * p_blk_dev, if (p_work->ev_handler) { - /*Asynchronous operation (simulation)*/ + /*Asynchronous operation (emulation)*/ const nrf_block_dev_event_t ev = { event, NRF_BLOCK_DEV_RESULT_SUCCESS, diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index e51935f..c1938c6 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -30,6 +30,7 @@ from chameleon_enum import Command, Status, SlotNumber, TagSenseType, TagSpecifi from chameleon_enum import MifareClassicWriteMode, MifareClassicPrngType, MifareClassicDarksideStatus, MfcKeyType from chameleon_enum import MifareUltralightWriteMode from chameleon_enum import AnimationMode, ButtonPressFunction, ButtonType, MfcValueBlockOperator +from chameleon_enum import HIDFormat # NXP IDs based on https://www.nxp.com/docs/en/application-note/AN10833.pdf type_id_SAK_dict = {0x00: "MIFARE Ultralight Classic/C/EV1/Nano | NTAG 2xx", @@ -200,15 +201,15 @@ class ReaderRequiredUnit(DeviceRequiredUnit): """ def before_exec(self, args: argparse.Namespace): - if super().before_exec(args): - ret = self.cmd.is_device_reader_mode() - if ret: - return True - else: - self.cmd.set_device_reader_mode(True) - print("Switch to { Tag Reader } mode successfully.") - return True - return False + if not super().before_exec(args): + return False + + if self.cmd.is_device_reader_mode(): + return True + + self.cmd.set_device_reader_mode(True) + print("Switch to { Tag Reader } mode successfully.") + return True class SlotIndexArgsUnit(DeviceRequiredUnit): @@ -396,12 +397,11 @@ class LFEMIdArgsUnit(DeviceRequiredUnit): return parser def before_exec(self, args: argparse.Namespace): - if super().before_exec(args): - if args.id is not None: - if not re.match(r"^[a-fA-F0-9]{10}$", args.id): - raise ArgsParserError("ID must include 10 HEX symbols") - return True - return False + if not super().before_exec(args): + return False + if args.id is None or not re.match(r"^[a-fA-F0-9]{10}$", args.id): + raise ArgsParserError("ID must include 10 HEX symbols") + return True def args_parser(self) -> ArgumentParserNoExit: raise NotImplementedError("Please implement this") @@ -409,6 +409,103 @@ class LFEMIdArgsUnit(DeviceRequiredUnit): def on_exec(self, args: argparse.Namespace): raise NotImplementedError("Please implement this") +class LFHIDIdArgsUnit(DeviceRequiredUnit): + @staticmethod + def add_card_arg(parser: ArgumentParserNoExit, required=False): + formats = [x.name for x in HIDFormat] + parser.add_argument("-f", "--format", type=str, required=required, help="HIDProx card format", metavar="", choices=formats) + parser.add_argument("--fc", type=int, required=False, help="HIDProx tag facility code", metavar="") + parser.add_argument("--cn", type=int, required=required, help="HIDProx tag card number", metavar="") + parser.add_argument("--il", type=int, required=False, help="HIDProx tag issue level", metavar="") + parser.add_argument("--oem", type=int, required=False, help="HIDProx tag OEM", metavar="") + return parser + + @staticmethod + def check_limits(format: int, fc: int | None, cn: int | None, il: int | None, oem: int | None): + limits = { + HIDFormat.H10301: [0xFF, 0xFFFF, 0, 0], + HIDFormat.IND26: [0xFFF, 0xFFF, 0, 0], + HIDFormat.IND27: [0x1FFF, 0x3FFF, 0, 0], + HIDFormat.INDASC27: [0x1FFF, 0x3FFF, 0, 0], + HIDFormat.TECOM27 : [0x7FF, 0xFFFF, 0, 0], + HIDFormat.W2804: [0xFF, 0x7FFF, 0, 0], + HIDFormat.IND29: [0x1FFF, 0xFFFF, 0, 0], + HIDFormat.ATSW30: [0xFFF, 0xFFFF, 0, 0], + HIDFormat.ADT31: [0xF, 0x7FFFFF, 0, 0], + HIDFormat.HCP32: [0, 0x3FFF, 0, 0], + HIDFormat.HPP32: [0xFFF, 0x7FFFF, 0, 0], + HIDFormat.KASTLE: [0xFF, 0xFFFF, 0x1F, 0], + HIDFormat.KANTECH: [0xFF, 0xFFFF, 0, 0], + HIDFormat.WIE32: [0xFFF, 0xFFFF, 0, 0], + HIDFormat.D10202: [0x7F, 0xFFFFFF, 0, 0], + HIDFormat.H10306: [0xFFFF, 0xFFFF, 0, 0], + HIDFormat.N10002: [0xFFFF, 0xFFFF, 0, 0], + HIDFormat.OPTUS34: [0x3FF, 0xFFFF, 0, 0], + HIDFormat.SMP34: [0x3FF, 0xFFFF, 0x7, 0], + HIDFormat.BQT34: [0xFF, 0xFFFFFF, 0, 0], + HIDFormat.C1K35S: [0xFFF, 0xFFFFF, 0, 0], + HIDFormat.C15001: [0xFF, 0xFFFF, 0, 0x3FF], + HIDFormat.S12906: [0xFF, 0xFFFFFF, 0x3, 0], + HIDFormat.SIE36: [0x3FFFF, 0xFFFF, 0, 0], + HIDFormat.H10320: [0, 99999999, 0, 0], + HIDFormat.H10302: [0, 0x7FFFFFFFF, 0, 0], + HIDFormat.H10304: [0xFFFF, 0x7FFFF, 0, 0], + HIDFormat.P10004: [0x1FFF, 0x3FFFF, 0, 0], + HIDFormat.HGEN37: [0, 0xFFFFFFFF, 0, 0], + HIDFormat.MDI37: [0xF, 0x1FFFFFFF, 0, 0], + } + limit = limits.get(HIDFormat(format)) + if limit is None: + return True + if fc is not None and fc > limit[0]: + raise ArgsParserError(f"{HIDFormat(format)}: Facility Code must between 0 to {limit[0]}") + if cn is not None and cn > limit[1]: + raise ArgsParserError(f"{HIDFormat(format)}: Card Number must between 0 to {limit[1]}") + if il is not None and il > limit[2]: + raise ArgsParserError(f"{HIDFormat(format)}: Issue Level must between 0 to {limit[2]}") + if oem is not None and oem > limit[3]: + raise ArgsParserError(f"{HIDFormat(format)}: OEM must between 0 to {limit[3]}") + + """ + HIDFormat.: [0xFFF, 0x3FFFF, 0x7, 0], + HIDFormat.: [0x3FF, 0xFFFFFF, 0, 0x7], + HIDFormat.: [0xFFFF, 0xFFFFF, 0, 0], + HIDFormat.: [0xFFF, 0xFFFF, 0, 0], + HIDFormat.: [0, 0xFFFFFFFFFF, 0, 0], + HIDFormat.: [0xFFF, 0xFFFFF, 0, 0x7F], + HIDFormat.: [0x3FFF, 0x3FFFFFFF, 0, 0], + HIDFormat.: [0x003FFFFF, 0x007FFFFF, 0, 0], + HIDFormat.: [0xFFFFF, 0x3FFFFFFFF, 0, 0], + HIDFormat.: [0xFFFFFF, 0xFFFFFFFF, 0, 0], + """ + + def before_exec(self, args: argparse.Namespace): + if super().before_exec(args): + format = HIDFormat.H10301.value + if args.format is not None: + format = HIDFormat[args.format].value + LFHIDIdArgsUnit.check_limits(format, args.fc, args.cn, args.il, args.oem) + return True + return False + + def args_parser(self) -> ArgumentParserNoExit: + raise NotImplementedError() + + def on_exec(self, args: argparse.Namespace): + raise NotImplementedError() + +class LFHIDIdReadArgsUnit(DeviceRequiredUnit): + @staticmethod + def add_card_arg(parser: ArgumentParserNoExit, required=False): + formats = [x.name for x in HIDFormat] + parser.add_argument("-f", "--format", type=str, required=False, help="HIDProx card format hint", metavar="", choices=formats) + return parser + + def args_parser(self) -> ArgumentParserNoExit: + raise NotImplementedError() + + def on_exec(self, args: argparse.Namespace): + raise NotImplementedError() class TagTypeArgsUnit(DeviceRequiredUnit): @staticmethod @@ -439,6 +536,8 @@ hf_mfu = hf.subgroup('mfu', 'MIFARE Ultralight / NTAG commands') lf = root.subgroup('lf', 'Low Frequency commands') lf_em = lf.subgroup('em', 'EM commands') lf_em_410x = lf_em.subgroup('410x', 'EM410x commands') +lf_hid = lf.subgroup('hid', 'HID commands') +lf_hid_prox = lf_hid.subgroup('prox', 'HID Prox commands') @root.command('clear') @@ -3026,8 +3125,8 @@ class LFEMRead(ReaderRequiredUnit): return parser def on_exec(self, args: argparse.Namespace): - id = self.cmd.em410x_scan() - print(f" - EM410x ID(10H): {CG}{id.hex()}{C0}") + data = self.cmd.em410x_scan() + print(f"{TagSpecificType(data[0])}: {CG}{data[1].hex()}{C0}") @lf_em_410x.command('write') @@ -3037,11 +3136,6 @@ class LFEM410xWriteT55xx(LFEMIdArgsUnit, ReaderRequiredUnit): parser.description = 'Write em410x id to t55xx' return self.add_card_arg(parser, required=True) - def before_exec(self, args: argparse.Namespace): - b1 = super(LFEMIdArgsUnit, self).before_exec(args) - b2 = super(ReaderRequiredUnit, self).before_exec(args) - return b1 and b2 - def on_exec(self, args: argparse.Namespace): id_hex = args.id id_bytes = bytes.fromhex(id_hex) @@ -3049,6 +3143,92 @@ class LFEM410xWriteT55xx(LFEMIdArgsUnit, ReaderRequiredUnit): print(f" - EM410x ID(10H): {id_hex} write done.") +@lf_hid_prox.command('read') +class LFHIDProxRead(LFHIDIdReadArgsUnit, ReaderRequiredUnit): + def args_parser(self) -> ArgumentParserNoExit: + parser = ArgumentParserNoExit() + parser.description = 'Scan hid prox tag and print card format, facility code, card number, issue level and OEM code' + return self.add_card_arg(parser, required=True) + + def on_exec(self, args: argparse.Namespace): + format = 0 + if args.format is not None: + format = HIDFormat[args.format].value + (format, fc, cn1, cn2, il, oem) = self.cmd.hidprox_scan(format) + cn = (cn1 << 32) + cn2 + print(f"HIDProx/{HIDFormat(format)}") + if fc > 0: + print(f" FC: {CG}{fc}{C0}") + if il > 0: + print(f" IL: {CG}{il}{C0}") + if oem > 0: + print(f" OEM: {CG}{oem}{C0}") + print(f" CN: {CG}{cn}{C0}") + +@lf_hid_prox.command("write") +class LFHIDProxWriteT55xx(LFHIDIdArgsUnit, ReaderRequiredUnit): + def args_parser(self) -> ArgumentParserNoExit: + parser = ArgumentParserNoExit() + parser.description = "Write hidprox card data to t55xx" + return self.add_card_arg(parser, required=True) + + def on_exec(self, args: argparse.Namespace): + if args.fc is None: + args.fc = 0 + if args.il is None: + args.il = 0 + if args.oem is None: + args.oem = 0 + format = HIDFormat[args.format] + id = struct.pack(">BIBIBH", format.value, args.fc, (args.cn >> 32), args.cn & 0xffffffff, args.il, args.oem) + self.cmd.hidprox_write_to_t55xx(id) + print(f"HIDProx/{format}") + if args.fc > 0: + print(f" FC: {args.fc}") + if args.il > 0: + print(f" IL: {args.il}") + if args.oem > 0: + print(f" OEM: {args.oem}") + print(f" CN: {args.cn}") + print(f"write done.") + +@lf_hid_prox.command('econfig') +class LFHIDProxEconfig(SlotIndexArgsAndGoUnit, LFHIDIdArgsUnit): + def args_parser(self) -> ArgumentParserNoExit: + parser = ArgumentParserNoExit() + parser.description = 'Set emulated hidprox card id' + self.add_slot_args(parser) + self.add_card_arg(parser) + return parser + + def on_exec(self, args: argparse.Namespace): + if args.cn is not None: + if args.fc is None: + args.fc = 0 + if args.il is None: + args.il = 0 + if args.oem is None: + args.oem = 0 + if args.format is None: + format = HIDFormat.H10301 + format = HIDFormat[args.format] + id = struct.pack(">BIBIBH", format.value, args.fc, (args.cn >> 32), args.cn & 0xffffffff, args.il, args.oem) + self.cmd.hidprox_set_emu_id(id) + print(' - Set hidprox tag id success.') + else: + (format, fc, cn1, cn2, il, oem) = self.cmd.hidprox_get_emu_id() + cn = (cn1 << 32) + cn2 + print(' - Get hidprox tag id success.') + print(f" - HIDProx/{HIDFormat(format)}") + if fc > 0: + print(f" FC: {CG}{fc}{C0}") + if il > 0: + print(f" IL: {CG}{il}{C0}") + if oem > 0: + print(f" OEM: {CG}{oem}{C0}") + print(f" CN: {CG}{cn}{C0}") + + @hw_slot.command('list') class HWSlotList(DeviceRequiredUnit): def args_parser(self) -> ArgumentParserNoExit: @@ -3074,6 +3254,7 @@ class HWSlotList(DeviceRequiredUnit): current = selected enabled = self.cmd.get_enabled_slots() maxnamelength = 0 + slotnames = [] all_nicks = self.cmd.get_all_slot_nicks() for slot_data in all_nicks: @@ -3082,6 +3263,7 @@ class HWSlotList(DeviceRequiredUnit): m = max(hfn['baselen'], lfn['baselen']) maxnamelength = m if m > maxnamelength else maxnamelength slotnames.append({'hf': hfn, 'lf': lfn}) + for slot in SlotNumber: fwslot = SlotNumber.to_fw(slot) hf_tag_type = TagSpecificType(slotinfo[fwslot]['hf']) @@ -3153,9 +3335,20 @@ class HWSlotList(DeviceRequiredUnit): if current != slot: self.cmd.set_active_slot(slot) current = slot - id = self.cmd.em410x_get_emu_id() - # print(' - EM 410X emulator settings:') - print(f' {"ID:":40}{CY}{id.hex().upper()}{C0}') + if lf_tag_type == TagSpecificType.EM410X: + id = self.cmd.em410x_get_emu_id() + print(f' {"ID:":40}{CY}{id.hex().upper()}{C0}') + if lf_tag_type == TagSpecificType.HIDProx: + (format, fc, cn1, cn2, il, oem) = self.cmd.hidprox_get_emu_id() + cn = (cn1 << 32) + cn2 + print(f' {"Format:":40}{CY}{HIDFormat(format)}{C0}') + if fc > 0: + print(f' {"FC:":40}{CY}{fc}{C0}') + if il > 0: + print(f' {"IL:":40}{CY}{il}{C0}') + if oem > 0: + print(f' {"OEM:":40}{CY}{oem}{C0}') + print(f' {"CN:":40}{CY}{cn}{C0}') if current != selected: self.cmd.set_active_slot(selected) @@ -3278,7 +3471,7 @@ class HWSlotDisable(SlotIndexArgsUnit, SenseTypeArgsUnit): class LFEM410xEconfig(SlotIndexArgsAndGoUnit, LFEMIdArgsUnit): def args_parser(self) -> ArgumentParserNoExit: parser = ArgumentParserNoExit() - parser.description = 'Set simulated em410x card id' + parser.description = 'Set emulated em410x card id' self.add_slot_args(parser) self.add_card_arg(parser) return parser diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index 753ecd8..de7bc93 100644 --- a/software/script/chameleon_cmd.py +++ b/software/script/chameleon_cmd.py @@ -10,6 +10,8 @@ from chameleon_enum import MfcKeyType, MfcValueBlockOperator CURRENT_VERSION_SETTINGS = 5 +new_key = b'\x20\x20\x66\x66' +old_keys = [b'\x51\x24\x36\x48', b'\x19\x92\x04\x27'] class ChameleonCMD: """ @@ -431,7 +433,8 @@ class ChameleonCMD: :return: """ resp = self.device.send_cmd_sync(Command.EM410X_SCAN) - resp.parsed = resp.data + if resp.status == Status.LF_TAG_OK: + resp.parsed = struct.unpack('!h5s', resp.data[0:7]) # card type + uid return resp @expect_response(Status.LF_TAG_OK) @@ -442,17 +445,41 @@ class ChameleonCMD: :param id_bytes: ID card number :return: """ - new_key = b'\x20\x20\x66\x66' - old_keys = [b'\x51\x24\x36\x48', b'\x19\x92\x04\x27'] if len(id_bytes) != 5: raise ValueError("The id bytes length must equal 5") data = struct.pack(f'!5s4s{4*len(old_keys)}s', id_bytes, new_key, b''.join(old_keys)) return self.device.send_cmd_sync(Command.EM410X_WRITE_TO_T55XX, data) + @expect_response(Status.LF_TAG_OK) + def hidprox_scan(self, format: int): + """ + Read the length, facility code and card number of HID Prox. + + :return: + """ + resp = self.device.send_cmd_sync(Command.HIDPROX_SCAN, struct.pack('!B', format)) + if resp.status == Status.LF_TAG_OK: + resp.parsed = struct.unpack('>BIBIBH', resp.data[:13]) + return resp + + @expect_response(Status.LF_TAG_OK) + def hidprox_write_to_t55xx(self, id_bytes: bytes): + """ + Write HID Prox card number into T55XX. + + :param id_bytes: ID card number + :return: + """ + if len(id_bytes) != 13: + raise ValueError("The id bytes length must equal 13") + data = struct.pack(f'!13s4s{4*len(old_keys)}s', id_bytes, new_key, b''.join(old_keys)) + return self.device.send_cmd_sync(Command.HIDPROX_WRITE_TO_T55XX, data) + + @expect_response(Status.SUCCESS) def get_slot_info(self): """ - Get slots info. + Get slots info. :return: """ @@ -465,7 +492,7 @@ class ChameleonCMD: @expect_response(Status.SUCCESS) def get_active_slot(self): """ - Get selected slot. + Get selected slot. :return: """ @@ -477,7 +504,7 @@ class ChameleonCMD: @expect_response(Status.SUCCESS) def set_active_slot(self, slot_index: SlotNumber): """ - Set the card slot currently active for use. + Set the card slot currently active for use. :param slot_index: Card slot index :return: @@ -489,7 +516,7 @@ class ChameleonCMD: @expect_response(Status.SUCCESS) def set_slot_tag_type(self, slot_index: SlotNumber, tag_type: TagSpecificType): """ - Set the label type of the simulated card of the current card slot + Set the label type of the emulated card of the current card slot Note: This operation will not change the data in the flash, and the change of the data in the flash will only be updated at the next save. @@ -504,7 +531,7 @@ class ChameleonCMD: @expect_response(Status.SUCCESS) def delete_slot_sense_type(self, slot_index: SlotNumber, sense_type: TagSenseType): """ - Delete a sense type for a specific slot. + Delete a sense type for a specific slot. :param slot_index: Slot index :param sense_type: Sense type to disable @@ -516,7 +543,7 @@ class ChameleonCMD: @expect_response(Status.SUCCESS) def set_slot_data_default(self, slot_index: SlotNumber, tag_type: TagSpecificType): """ - Set the data of the simulated card in the specified card slot as the default data + Set the data of the emulated card in the specified card slot as the default data Note: This API will set the data in the flash together. :param slot_index: Card slot number @@ -543,7 +570,7 @@ class ChameleonCMD: @expect_response(Status.SUCCESS) def em410x_set_emu_id(self, id: bytes): """ - Set the card number simulated by EM410x. + Set the card number emulated by EM410x. :param id_bytes: byte of the card number :return: @@ -556,12 +583,34 @@ class ChameleonCMD: @expect_response(Status.SUCCESS) def em410x_get_emu_id(self): """ - Get the simulated EM410x card id + Get the emulated EM410x card id """ resp = self.device.send_cmd_sync(Command.EM410X_GET_EMU_ID) resp.parsed = resp.data return resp + @expect_response(Status.SUCCESS) + def hidprox_set_emu_id(self, id: bytes): + """ + Set the card number emulated by HID Prox. + + :param id_bytes: byte of the card number + :return: + """ + if len(id) != 13: + raise ValueError("The id bytes length must equal 13") + return self.device.send_cmd_sync(Command.HIDPROX_SET_EMU_ID, id) + + @expect_response(Status.SUCCESS) + def hidprox_get_emu_id(self): + """ + Get the emulated HID Prox card id + """ + resp = self.device.send_cmd_sync(Command.HIDPROX_GET_EMU_ID) + if resp.status == Status.SUCCESS: + resp.parsed = struct.unpack('>BIBIBH', resp.data[:13]) + return resp + @expect_response(Status.SUCCESS) def mf1_set_detection_enable(self, enabled: bool): """ @@ -671,7 +720,7 @@ class ChameleonCMD: return resp @expect_response(Status.SUCCESS) - def mfu_read_emu_counter_data(self, index: int) -> (int, bool): + def mfu_read_emu_counter_data(self, index: int) -> tuple[int, bool]: """ Gets data for selected counter """ diff --git a/software/script/chameleon_enum.py b/software/script/chameleon_enum.py index 43c6fad..dd70e73 100644 --- a/software/script/chameleon_enum.py +++ b/software/script/chameleon_enum.py @@ -76,6 +76,8 @@ class Command(enum.IntEnum): EM410X_SCAN = 3000 EM410X_WRITE_TO_T55XX = 3001 + HIDPROX_SCAN = 3002 + HIDPROX_WRITE_TO_T55XX = 3003 MF1_WRITE_EMU_BLOCK_DATA = 4000 HF14A_SET_ANTI_COLL_DATA = 4001 @@ -116,24 +118,30 @@ class Command(enum.IntEnum): EM410X_SET_EMU_ID = 5000 EM410X_GET_EMU_ID = 5001 + HIDPROX_SET_EMU_ID = 5002 + HIDPROX_GET_EMU_ID = 5003 @enum.unique class Status(enum.IntEnum): - HF_TAG_OK = 0x00 # IC card operation is successful - HF_TAG_NO = 0x01 # IC card not found - HF_ERR_STAT = 0x02 # Abnormal IC card communication - HF_ERR_CRC = 0x03 # IC card communication verification abnormal + HF_TAG_OK = 0x00 # IC card operation is successful + HF_TAG_NO = 0x01 # IC card not found + HF_ERR_STAT = 0x02 # Abnormal IC card communication + HF_ERR_CRC = 0x03 # IC card communication verification abnormal HF_COLLISION = 0x04 # IC card conflict - HF_ERR_BCC = 0x05 # IC card BCC error - MF_ERR_AUTH = 0x06 # MF card verification failed + HF_ERR_BCC = 0x05 # IC card BCC error + MF_ERR_AUTH = 0x06 # MF card verification failed HF_ERR_PARITY = 0x07 # IC card parity error - HF_ERR_ATS = 0x08 # ATS should be present but card NAKed, or ATS too large + HF_ERR_ATS = 0x08 # ATS should be present but card NAKed, or ATS too large # Some operations with low frequency cards succeeded! LF_TAG_OK = 0x40 - # Unable to search for a valid EM410X label + # Unable to search for a valid EM410X tag EM410X_TAG_NO_FOUND = 0x41 + # Unable to search for a valid LF tag + LF_TAG_NO_FOUND = 0x42 + # Unable to search for a valid HIDProx tag + HIDPROX_TAG_NO_FOUND = 0x43 # The parameters passed by the BLE instruction are wrong, or the parameters passed # by calling some functions are wrong @@ -170,6 +178,10 @@ class Status(enum.IntEnum): return "LF tag operation succeeded" elif self == Status.EM410X_TAG_NO_FOUND: return "EM410x tag no found" + elif self == Status.LF_TAG_NO_FOUND: + return "LF tag not found" + elif self == Status.HIDPROX_TAG_NO_FOUND: + return "HIDProx tag no found" elif self == Status.PAR_ERR: return "API request fail, param error" elif self == Status.DEVICE_MODE_ERROR: @@ -241,6 +253,9 @@ class TagSpecificType(enum.IntEnum): # ASK Tag-Talk-First 100 # EM410x EM410X = 100 + EM410X_16 = 101 + EM410X_32 = 102 + EM410X_64 = 103 # FDX-B # securakey # gallagher @@ -252,7 +267,7 @@ class TagSpecificType(enum.IntEnum): # Jablotron # FSK Tag-Talk-First 200 - # HID Prox + HIDProx = 200 # ioProx # AWID # Paradox @@ -277,6 +292,7 @@ class TagSpecificType(enum.IntEnum): MIFARE_1024 = 1001 MIFARE_2048 = 1002 MIFARE_4096 = 1003 + # MFUL / NTAG series 1100 NTAG_213 = 1100 NTAG_215 = 1101 @@ -296,26 +312,43 @@ class TagSpecificType(enum.IntEnum): @staticmethod def list(exclude_meta=True): - return [t for t in TagSpecificType - if (t > TagSpecificType.OLD_TAG_TYPES_END and - t != TagSpecificType.TAG_TYPES_LF_END) - or not exclude_meta] + return [ + t + for t in TagSpecificType + if ( + t > TagSpecificType.OLD_TAG_TYPES_END + and t != TagSpecificType.TAG_TYPES_LF_END + ) + or not exclude_meta + ] @staticmethod def list_hf(): - return [t for t in TagSpecificType.list() - if (t > TagSpecificType.TAG_TYPES_LF_END)] + return [ + t for t in TagSpecificType.list() if (t > TagSpecificType.TAG_TYPES_LF_END) + ] @staticmethod def list_lf(): - return [t for t in TagSpecificType.list() - if (TagSpecificType.UNDEFINED < t < TagSpecificType.TAG_TYPES_LF_END)] + return [ + t + for t in TagSpecificType.list() + if (TagSpecificType.UNDEFINED < t < TagSpecificType.TAG_TYPES_LF_END) + ] def __str__(self): if self == TagSpecificType.UNDEFINED: return "Undefined" elif self == TagSpecificType.EM410X: return "EM410X" + elif self == TagSpecificType.EM410X_16: + return "EM410X/16" + elif self == TagSpecificType.EM410X_32: + return "EM410X/32" + elif self == TagSpecificType.EM410X_64: + return "EM410X/64" + elif self == TagSpecificType.HIDProx: + return "HIDProx" elif self == TagSpecificType.MIFARE_Mini: return "Mifare Mini" elif self == TagSpecificType.MIFARE_1024: @@ -362,9 +395,11 @@ class MifareClassicWriteMode(enum.IntEnum): @staticmethod def list(exclude_meta=True): - return [m for m in MifareClassicWriteMode - if m != MifareClassicWriteMode.SHADOW_REQ - or not exclude_meta] + return [ + m + for m in MifareClassicWriteMode + if m != MifareClassicWriteMode.SHADOW_REQ or not exclude_meta + ] def __str__(self): if self == MifareClassicWriteMode.NORMAL: @@ -395,9 +430,11 @@ class MifareUltralightWriteMode(enum.IntEnum): @staticmethod def list(exclude_meta=True): - return [m for m in MifareUltralightWriteMode - if m != MifareUltralightWriteMode.SHADOW_REQ - or not exclude_meta] + return [ + m + for m in MifareUltralightWriteMode + if m != MifareUltralightWriteMode.SHADOW_REQ or not exclude_meta + ] def __str__(self): if self == MifareUltralightWriteMode.NORMAL: @@ -475,8 +512,8 @@ class AnimationMode(enum.IntEnum): @enum.unique class ButtonType(enum.IntEnum): - A = ord('A') - B = ord('B') + A = ord("A") + B = ord("B") @enum.unique @@ -512,3 +549,74 @@ class MfcValueBlockOperator(enum.IntEnum): DECREMENT = 0xC0 INCREMENT = 0xC1 RESTORE = 0xC2 + +@enum.unique +class HIDFormat(enum.IntEnum): + H10301 = 1 + IND26 = 2 + IND27 = 3 + INDASC27 = 4 + TECOM27 = 5 + W2804 = 6 + IND29 = 7 + ATSW30 = 8 + ADT31 = 9 + HCP32 = 10 + HPP32 = 11 + KASTLE = 12 + KANTECH = 13 + WIE32 = 14 + D10202 = 15 + H10306 = 16 + N10002 = 17 + OPTUS34 = 18 + SMP34 = 19 + BQT34 = 20 + C1K35S = 21 + C15001 = 22 + S12906 = 23 + SIE36 = 24 + H10320 = 25 + H10302 = 26 + H10304 = 27 + P10004 = 28 + HGEN37 = 29 + MDI37 = 30 + + def __str__(self): + descriptions = { + HIDFormat.H10301: "HID H10301 26-bit", + HIDFormat.IND26: "Indala 26-bit", + HIDFormat.IND27: "Indala 27-bit", + HIDFormat.INDASC27: "Indala ASC 27-bit", + HIDFormat.TECOM27: "Tecom 27-bit", + HIDFormat.W2804: "2804 Wiegand 28-bit", + HIDFormat.IND29: "Indala 29-bit", + HIDFormat.ATSW30: "ATS Wiegand 30-bit", + HIDFormat.ADT31: "HID ADT 31-bit", + HIDFormat.HCP32: "HID Check Point 32-bit", + HIDFormat.HPP32: "HID Hewlett-Packard 32-bit", + HIDFormat.KASTLE: "Kastle 32-bit", + HIDFormat.KANTECH: "Indala/Kantech KFS 32-bit", + HIDFormat.WIE32: "Wiegand 32-bit", + HIDFormat.D10202: "HID D10202 33-bit", + HIDFormat.H10306: "HID H10306 34-bit", + HIDFormat.N10002: "Honeywell/Northern N10002 34-bit", + HIDFormat.OPTUS34: "Indala Optus 34-bit", + HIDFormat.SMP34: "Cardkey Smartpass 34-bit", + HIDFormat.BQT34: "BQT 34-bit", + HIDFormat.C1K35S: "HID Corporate 1000 35-bit Std", + HIDFormat.C15001: "HID KeyScan 36-bit", + HIDFormat.S12906: "HID Simplex 36-bit", + HIDFormat.SIE36: "HID 36-bit Siemens", + HIDFormat.H10320: "HID H10320 37-bit BCD", + HIDFormat.H10302: "HID H10302 37-bit huge ID", + HIDFormat.H10304: "HID H10304 37-bit", + HIDFormat.P10004: "HID P10004 37-bit PCSC", + HIDFormat.HGEN37: "HID Generic 37-bit", + HIDFormat.MDI37: "PointGuard MDI 37-bit", + } + if self in descriptions: + return descriptions[self] + return "Invalid" + diff --git a/software/src/HardnestedRecovery/cmdhfmfhard.c b/software/src/HardnestedRecovery/cmdhfmfhard.c index 1b455e3..0350e9c 100755 --- a/software/src/HardnestedRecovery/cmdhfmfhard.c +++ b/software/src/HardnestedRecovery/cmdhfmfhard.c @@ -1171,7 +1171,7 @@ static void apply_sum_a0(void) { static int simulate_acquire_nonces(uint32_t uid, char* path) { time_t time1 = time(NULL); last_sample_clock = 0; - sample_period = 1000; // for simulation + sample_period = 1000; // for emulation hardnested_stage = CHECK_1ST_BYTES; bool acquisition_completed = false; uint32_t total_num_nonces = 0;