mirror of
https://github.com/RfidResearchGroup/ChameleonUltra.git
synced 2026-05-12 11:22:59 -07:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6f37c80df | ||
|
|
07e7ed2abd | ||
|
|
3b0d14759b | ||
|
|
9248223a39 | ||
|
|
1e79e8bd43 | ||
|
|
e0790f677b |
@@ -0,0 +1,5 @@
|
||||
BreakBeforeBinaryOperators: All
|
||||
ColumnLimit: 120
|
||||
BasedOnStyle: Google
|
||||
BreakBeforeBraces: Stroustrup
|
||||
IndentWidth: 4
|
||||
@@ -0,0 +1,35 @@
|
||||
name: clang-format Check
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- '**.c'
|
||||
- '**.h'
|
||||
- '**.cpp'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install clang-format
|
||||
run: sudo apt install -y clang-format
|
||||
|
||||
- name: Get files and check format
|
||||
run: |
|
||||
exit_code=0
|
||||
while IFS= read -r -d '' f; do
|
||||
if ! diff -u "$f" <(clang-format "$f"); then
|
||||
echo "Formatting issue in $f"
|
||||
exit_code=1
|
||||
fi
|
||||
done < <(find . -type f \( -name '*.c' -o -name '*.h' \) ! -path './firmware/nrf52_sdk/*' ! -path './firmware/nrf52_sdk/**' -print0)
|
||||
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
echo "Clang-format check failed."
|
||||
exit 1
|
||||
else
|
||||
echo "All files are properly formatted."
|
||||
fi
|
||||
@@ -1,10 +1,11 @@
|
||||
name: Lint (pyrefly + ruff)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- "software/**"
|
||||
- ".github/workflows/**"
|
||||
- "**.py"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
+1
-15
@@ -3,22 +3,8 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Hardware upgrade: Restarting the Ultra now only requires running each of the three RGB colors once, resolving previous firmware modification issues
|
||||
- Added commands to dump and clone Mifare tags
|
||||
- Fix bad missing tools warning (@suut)
|
||||
- Fix for FAST_READ command for nfc - mf0 tags
|
||||
- Rewrite of the dynamic and static locks logic for NTAG213, NTAG215 and NTAG216; we shouldn't take into account the block lock bits
|
||||
- Fixed an issue where we wouldn't be able to change CFG0 and CFG1 for NTAG213, NTAG215 and NTG216 once a password was added even if the cfg bit was reset.
|
||||
- Added clang formatter (@GameTec-live)
|
||||
- Fix for static nested key recovery (@jekkos)
|
||||
- Fix LEDs being stuck on after battery check (@suut)
|
||||
- Add TCP support for the CLI (@suut)
|
||||
- Fix build on Android in Termux (@suut)
|
||||
- Fix the issue where some reader cause CU to enter a strange state (@xianglin1998)
|
||||
- The transmission performance of USB has been improved (@xianglin1998)
|
||||
- Added cmd for set mf1 config 'field_off_do_reset' (@xianglin1998)
|
||||
- Fix Windows build (@suut)
|
||||
- Added `hf 14a config` to deal with badly configured cards (@azuwis)
|
||||
- New Symmetrical LED Animation Mode and Improved Minimal Mode (@WillyJL)
|
||||
|
||||
## [v2.1.0][2025-09-02]
|
||||
- Added UV, formatter and linter. Contribution guidelines. (@GameTec-live)
|
||||
|
||||
@@ -18,10 +18,6 @@ Guangdong, China: [MTools Tec](https://shop.mtoolstec.com/)
|
||||
|
||||
Lazada One, Singapore: [Aliexpress by RRG](https://proxgrind.aliexpress.com/store/1101312023)
|
||||
|
||||
# Hardware Upgrade Notice
|
||||
|
||||
**Important:** The Chameleon Ultra hardware has been upgraded! Restarting the device now only requires running each of the three RGB colors once (equivalent to a restart). This resolves previous issues where firmware modifications could cause the device to malfunction.
|
||||
|
||||
# What is it and how to use ?
|
||||
|
||||
Read the [available documentation](https://github.com/RfidResearchGroup/ChameleonUltra/wiki).
|
||||
|
||||
@@ -345,7 +345,6 @@ ifeq (${CURRENT_DEVICE_TYPE}, ${CHAMELEON_ULTRA})
|
||||
$(PROJ_DIR)/rfid/reader/lf/lf_t55xx_data.c \
|
||||
$(PROJ_DIR)/rfid/reader/lf/lf_hidprox_data.c \
|
||||
$(PROJ_DIR)/rfid/reader/lf/lf_viking_data.c \
|
||||
$(PROJ_DIR)/rfid/reader/lf/lf_reader_generic.c \
|
||||
|
||||
INC_FOLDERS +=\
|
||||
${PROJ_DIR}/rfid/reader/ \
|
||||
|
||||
@@ -141,7 +141,7 @@ static data_frame_tx_t *cmd_processor_get_device_settings(uint16_t cmd, uint16_t
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_set_animation_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if ((length != 1) || (data[0] >= SettingsAnimationModeMAX)) {
|
||||
if ((length != 1) || (data[0] > 2)) {
|
||||
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
|
||||
}
|
||||
settings_set_animation_config(data[0]);
|
||||
@@ -488,35 +488,6 @@ static data_frame_tx_t *cmd_processor_mf1_write_one_block(uint16_t cmd, uint16_t
|
||||
return data_frame_make(cmd, status, 0, NULL);
|
||||
}
|
||||
|
||||
#if defined(PROJECT_CHAMELEON_ULTRA)
|
||||
|
||||
static data_frame_tx_t *cmd_processor_hf14a_set_field_on(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
device_mode_t mode = get_device_mode();
|
||||
if (mode != DEVICE_MODE_READER) {
|
||||
return data_frame_make(cmd, STATUS_DEVICE_MODE_ERROR, 0, NULL);
|
||||
}
|
||||
|
||||
// Reset and turn on the antenna
|
||||
pcd_14a_reader_reset();
|
||||
pcd_14a_reader_antenna_on();
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_hf14a_set_field_off(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
device_mode_t mode = get_device_mode();
|
||||
if (mode != DEVICE_MODE_READER) {
|
||||
return data_frame_make(cmd, STATUS_DEVICE_MODE_ERROR, 0, NULL);
|
||||
}
|
||||
|
||||
// Turn off the antenna
|
||||
pcd_14a_reader_antenna_off();
|
||||
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static data_frame_tx_t *cmd_processor_hf14a_raw(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
// Response Buffer
|
||||
uint8_t resp[DEF_FIFO_LENGTH] = { 0x00 };
|
||||
@@ -574,21 +545,6 @@ static data_frame_tx_t *cmd_processor_hf14a_raw(uint16_t cmd, uint16_t status, u
|
||||
return data_frame_make(cmd, status, resp_length, resp);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_hf14a_get_config(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
hf14a_config_t *hc = get_hf14a_config();
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, sizeof(hf14a_config_t), (uint8_t *)hc);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_hf14a_set_config(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length != sizeof(hf14a_config_t)) {
|
||||
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
|
||||
}
|
||||
hf14a_config_t hc;
|
||||
memcpy(&hc, data, sizeof(hf14a_config_t));
|
||||
set_hf14a_config(&hc);
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf1_manipulate_value_block(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
typedef struct {
|
||||
uint8_t src_type;
|
||||
@@ -642,16 +598,12 @@ 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 card_buffer[2 + LF_EM410X_ELECTRA_TAG_ID_SIZE] = {0x00};
|
||||
uint8_t card_buffer[7] = {0x00};
|
||||
status = scan_em410x(card_buffer);
|
||||
if (status != STATUS_LF_TAG_OK) {
|
||||
return data_frame_make(cmd, status, 0, NULL);
|
||||
}
|
||||
|
||||
tag_specific_type_t tag_type = (card_buffer[0] << 8) | card_buffer[1];
|
||||
uint16_t id_size = (tag_type == TAG_TYPE_EM410X_ELECTRA) ? LF_EM410X_ELECTRA_TAG_ID_SIZE : LF_EM410X_TAG_ID_SIZE;
|
||||
|
||||
return data_frame_make(cmd, STATUS_LF_TAG_OK, 2 + id_size, card_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) {
|
||||
@@ -669,21 +621,6 @@ static data_frame_tx_t *cmd_processor_em410x_write_to_t55xx(uint16_t cmd, uint16
|
||||
return data_frame_make(cmd, status, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_em410x_electra_write_to_t55xx(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
typedef struct {
|
||||
uint8_t id[13];
|
||||
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_electra_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];
|
||||
@@ -737,32 +674,6 @@ static data_frame_tx_t *cmd_processor_viking_write_to_t55xx(uint16_t cmd, uint16
|
||||
status = write_viking_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);
|
||||
}
|
||||
|
||||
#define GENERIC_READ_LEN 800
|
||||
#define GENERIC_READ_TIMEOUT_MS 500
|
||||
static data_frame_tx_t *cmd_processor_generic_read(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
uint8_t *outdata = malloc(GENERIC_READ_LEN);
|
||||
|
||||
if (outdata == NULL) {
|
||||
return data_frame_make(cmd, STATUS_MEM_ERR, 0, NULL);
|
||||
}
|
||||
|
||||
size_t outlen = 0;
|
||||
if (!raw_read_to_buffer(outdata, GENERIC_READ_LEN, GENERIC_READ_TIMEOUT_MS, &outlen)) {
|
||||
free(outdata);
|
||||
return data_frame_make(cmd, STATUS_CMD_ERR, 0, NULL);
|
||||
};
|
||||
data_frame_tx_t *frame = data_frame_make(cmd, STATUS_LF_TAG_OK, outlen, outdata);
|
||||
|
||||
free(outdata);
|
||||
|
||||
if (frame == NULL) {
|
||||
return data_frame_make(cmd, STATUS_CREATE_RESPONSE_ERR, 0, NULL);
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -890,41 +801,24 @@ static data_frame_tx_t *cmd_processor_wipe_fds(uint16_t cmd, uint16_t status, ui
|
||||
return data_frame_make(cmd, status, 0, NULL);
|
||||
}
|
||||
|
||||
static bool get_active_em410x_type(tag_specific_type_t *tag_type_out, uint16_t *id_size_out) {
|
||||
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 || tag_types.tag_lf == TAG_TYPE_EM410X_ELECTRA) {
|
||||
*tag_type_out = tag_types.tag_lf;
|
||||
*id_size_out = (tag_types.tag_lf == TAG_TYPE_EM410X_ELECTRA) ? LF_EM410X_ELECTRA_TAG_ID_SIZE : LF_EM410X_TAG_ID_SIZE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_em410x_set_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
tag_specific_type_t tag_type;
|
||||
uint16_t id_size;
|
||||
if (!get_active_em410x_type(&tag_type, &id_size) || length != id_size) {
|
||||
if (length != LF_EM410X_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);
|
||||
memcpy(buffer->buffer, data, id_size);
|
||||
tag_emulation_load_by_buffer(tag_type, false);
|
||||
tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_EM410X);
|
||||
memcpy(buffer->buffer, data, LF_EM410X_TAG_ID_SIZE);
|
||||
tag_emulation_load_by_buffer(TAG_TYPE_EM410X, false);
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_em410x_get_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
tag_specific_type_t tag_type;
|
||||
uint16_t id_size;
|
||||
if (!get_active_em410x_type(&tag_type, &id_size)) {
|
||||
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
|
||||
}
|
||||
tag_data_buffer_t *buffer = get_buffer_by_tag_type(tag_type);
|
||||
uint8_t resp[2 + LF_EM410X_ELECTRA_TAG_ID_SIZE] = {0x00};
|
||||
resp[0] = tag_type >> 8;
|
||||
resp[1] = tag_type;
|
||||
memcpy(resp + 2, buffer->buffer, id_size);
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 2 + id_size, resp);
|
||||
tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_EM410X);
|
||||
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) {
|
||||
@@ -1073,7 +967,7 @@ static data_frame_tx_t *cmd_processor_mf1_write_emu_block_data(uint16_t cmd, uin
|
||||
uint8_t block_index = data[0];
|
||||
uint8_t block_count = (length - 1) / NFC_TAG_MF1_DATA_SIZE;
|
||||
if (block_index + block_count > NFC_TAG_MF1_BLOCK_MAX) {
|
||||
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
|
||||
status = STATUS_PAR_ERR;
|
||||
}
|
||||
tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_MIFARE_4096);
|
||||
nfc_tag_mf1_information_t *info = (nfc_tag_mf1_information_t *)buffer->buffer;
|
||||
@@ -1451,19 +1345,6 @@ static data_frame_tx_t *cmd_processor_mf1_set_write_mode(uint16_t cmd, uint16_t
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf1_get_field_off_do_reset(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
uint8_t enable = nfc_tag_mf1_is_field_off_do_reset();
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 1, &enable);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_mf1_set_field_off_do_reset(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length != 1 || data[0] >= 2) {
|
||||
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
|
||||
}
|
||||
nfc_tag_mf1_set_field_off_do_reset(data[0]);
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_get_enabled_slots(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
struct {
|
||||
uint8_t enabled_hf;
|
||||
@@ -1692,18 +1573,10 @@ static cmd_data_map_t m_data_cmd_map[] = {
|
||||
|
||||
{ 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_ELECTRA_WRITE_TO_T55XX,before_reader_run, cmd_processor_em410x_electra_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 },
|
||||
{ DATA_CMD_VIKING_SCAN, before_reader_run, cmd_processor_viking_scan, NULL },
|
||||
{ DATA_CMD_VIKING_WRITE_TO_T55XX, before_reader_run, cmd_processor_viking_write_to_t55xx, NULL },
|
||||
{ DATA_CMD_ADC_GENERIC_READ, before_reader_run, cmd_processor_generic_read, NULL },
|
||||
|
||||
{ DATA_CMD_HF14A_SET_FIELD_ON, before_reader_run, cmd_processor_hf14a_set_field_on, NULL },
|
||||
{ DATA_CMD_HF14A_SET_FIELD_OFF, before_reader_run, cmd_processor_hf14a_set_field_off, NULL },
|
||||
|
||||
{ DATA_CMD_HF14A_GET_CONFIG, NULL, cmd_processor_hf14a_get_config, NULL },
|
||||
{ DATA_CMD_HF14A_SET_CONFIG, NULL, cmd_processor_hf14a_set_config, NULL },
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1725,8 +1598,6 @@ static cmd_data_map_t m_data_cmd_map[] = {
|
||||
{ DATA_CMD_MF1_SET_BLOCK_ANTI_COLL_MODE, NULL, cmd_processor_mf1_set_block_anti_coll_mode, NULL },
|
||||
{ DATA_CMD_MF1_GET_WRITE_MODE, NULL, cmd_processor_mf1_get_write_mode, NULL },
|
||||
{ DATA_CMD_MF1_SET_WRITE_MODE, NULL, cmd_processor_mf1_set_write_mode, NULL },
|
||||
{ DATA_CMD_MF1_GET_FIELD_OFF_DO_RESET, NULL, cmd_processor_mf1_get_field_off_do_reset, NULL },
|
||||
{ DATA_CMD_MF1_SET_FIELD_OFF_DO_RESET, NULL, cmd_processor_mf1_set_field_off_do_reset, NULL },
|
||||
|
||||
{ DATA_CMD_MF0_NTAG_GET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_get_uid_mode, NULL },
|
||||
{ DATA_CMD_MF0_NTAG_SET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_set_uid_mode, NULL },
|
||||
|
||||
@@ -41,10 +41,6 @@ NRF_LOG_MODULE_REGISTER();
|
||||
#include "tag_persistence.h"
|
||||
#include "settings.h"
|
||||
|
||||
#if defined(PROJECT_CHAMELEON_ULTRA)
|
||||
#include "rc522.h"
|
||||
#endif
|
||||
|
||||
// Defining soft timers
|
||||
APP_TIMER_DEF(m_button_check_timer); // Timer for button debounce
|
||||
|
||||
@@ -60,9 +56,6 @@ static bool m_is_a_btn_release = false;
|
||||
|
||||
static bool m_system_off_processing = false;
|
||||
|
||||
// NFC field generator state
|
||||
volatile bool m_is_field_on = false;
|
||||
|
||||
// cpu reset reason
|
||||
static uint32_t m_reset_source;
|
||||
static uint32_t m_gpregret_val;
|
||||
@@ -146,41 +139,12 @@ static void gpio_te_init(void) {
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
#if defined(PROJECT_CHAMELEON_ULTRA)
|
||||
static void field_generator_rainbow_loop(void) {
|
||||
static uint8_t color_index = 0;
|
||||
static uint32_t last_update = 0;
|
||||
|
||||
if (!m_is_field_on) return;
|
||||
|
||||
uint32_t now = app_timer_cnt_get();
|
||||
|
||||
if (app_timer_cnt_diff_compute(now, last_update) < APP_TIMER_TICKS(100)) {
|
||||
return;
|
||||
}
|
||||
last_update = now;
|
||||
|
||||
// Rainbow colors
|
||||
const uint8_t colors[] = {RGB_RED, RGB_YELLOW, RGB_GREEN, RGB_CYAN, RGB_BLUE, RGB_MAGENTA};
|
||||
|
||||
set_slot_light_color(colors[color_index]);
|
||||
uint32_t *led_pins = hw_get_led_array();
|
||||
|
||||
// Light up all LEDs with current color
|
||||
for (int i = 0; i < RGB_LIST_NUM; i++) {
|
||||
nrf_gpio_pin_set(led_pins[i]);
|
||||
}
|
||||
|
||||
color_index = (color_index + 1) % 6;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**@brief Button Matrix Events
|
||||
*/
|
||||
static void button_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
||||
device_mode_t mode = get_device_mode();
|
||||
// Allow button operations in both tag and reader mode
|
||||
if (mode == DEVICE_MODE_TAG || mode == DEVICE_MODE_READER) {
|
||||
// Temporarily allow only the analog card mode to respond to button operations
|
||||
if (mode == DEVICE_MODE_TAG) {
|
||||
static nrf_drv_gpiote_pin_t pin_static; // Use static internal variables to store the GPIO where the current event occurred
|
||||
pin_static = pin; // Cache the button that currently triggers the event into an internal variable
|
||||
app_timer_start(m_button_check_timer, APP_TIMER_TICKS(50), &pin_static); // Start timer anti-shake
|
||||
@@ -198,9 +162,7 @@ static void timer_button_event_handle(void *arg) {
|
||||
NRF_LOG_INFO("BUTTON press during shutdown");
|
||||
return;
|
||||
}
|
||||
|
||||
nrf_drv_gpiote_pin_t pin = *(nrf_drv_gpiote_pin_t *)arg;
|
||||
|
||||
// Check here if the current GPIO is at the pressed level
|
||||
if (nrf_gpio_pin_read(pin) == 1) {
|
||||
if (pin == BUTTON_1) {
|
||||
@@ -301,28 +263,24 @@ static void system_off_enter(void) {
|
||||
for (uint8_t i = 0; i < RGB_LIST_NUM; i++) {
|
||||
nrf_gpio_pin_clear(p_led_array[i]);
|
||||
}
|
||||
// Power off animation
|
||||
uint8_t animation_config = settings_get_animation_config();
|
||||
uint8_t slot = tag_emulation_get_slot();
|
||||
uint8_t dir = slot > 3 ? 1 : 0;
|
||||
uint8_t color = get_color_by_slot(slot);
|
||||
if (m_reset_source & (NRF_POWER_RESETREAS_NFC_MASK | NRF_POWER_RESETREAS_LPCOMP_MASK)) {
|
||||
if (m_reset_source & NRF_POWER_RESETREAS_NFC_MASK) {
|
||||
color = 1;
|
||||
} else {
|
||||
color = 2;
|
||||
}
|
||||
}
|
||||
if (animation_config == SettingsAnimationModeFull) {
|
||||
if (m_system_off_processing) rgb_marquee_sweep_from_to(color, slot, dir ? 7 : 0);
|
||||
if (m_system_off_processing) rgb_marquee_sweep_fade(color, dir, 7, 99, 75);
|
||||
if (m_system_off_processing) rgb_marquee_sweep_fade(color, !dir, 7, 75, 50);
|
||||
if (m_system_off_processing) rgb_marquee_sweep_fade(color, dir, 7, 50, 25);
|
||||
if (m_system_off_processing) rgb_marquee_sweep_fade(color, !dir, 7, 25, 0);
|
||||
} else if (animation_config == SettingsAnimationModeMinimal) {
|
||||
if (m_system_off_processing) rgb_marquee_sweep_from_to(color, slot, !dir ? 7 : 0);
|
||||
} else if (animation_config == SettingsAnimationModeSymmetric) {
|
||||
if (m_system_off_processing) rgb_marquee_symmetric_in(color, slot);
|
||||
uint8_t slot = tag_emulation_get_slot();
|
||||
// Power off animation
|
||||
uint8_t dir = slot > 3 ? 1 : 0;
|
||||
uint8_t color = get_color_by_slot(slot);
|
||||
if (m_reset_source & (NRF_POWER_RESETREAS_NFC_MASK | NRF_POWER_RESETREAS_LPCOMP_MASK)) {
|
||||
if (m_reset_source & NRF_POWER_RESETREAS_NFC_MASK) {
|
||||
color = 1;
|
||||
} else {
|
||||
color = 2;
|
||||
}
|
||||
}
|
||||
if (m_system_off_processing) ledblink5(color, slot, dir ? 7 : 0);
|
||||
if (m_system_off_processing) ledblink4(color, dir, 7, 99, 75);
|
||||
if (m_system_off_processing) ledblink4(color, !dir, 7, 75, 50);
|
||||
if (m_system_off_processing) ledblink4(color, dir, 7, 50, 25);
|
||||
if (m_system_off_processing) ledblink4(color, !dir, 7, 25, 0);
|
||||
}
|
||||
rgb_marquee_stop();
|
||||
if (!m_system_off_processing) {
|
||||
@@ -464,13 +422,11 @@ static void check_wakeup_src(void) {
|
||||
// Button wake-up boot animation
|
||||
uint8_t animation_config = settings_get_animation_config();
|
||||
if (animation_config == SettingsAnimationModeFull) {
|
||||
rgb_marquee_sweep_to(color, !dir, 11);
|
||||
rgb_marquee_sweep_to(color, dir, 11);
|
||||
rgb_marquee_sweep_to(color, !dir, dir ? slot : 7 - slot);
|
||||
ledblink2(color, !dir, 11);
|
||||
ledblink2(color, dir, 11);
|
||||
ledblink2(color, !dir, dir ? slot : 7 - slot);
|
||||
} else if (animation_config == SettingsAnimationModeMinimal) {
|
||||
rgb_marquee_sweep_to(color, !dir, dir ? slot : 7 - slot);
|
||||
} else if (animation_config == SettingsAnimationModeSymmetric) {
|
||||
rgb_marquee_symmetric_out(color, slot);
|
||||
ledblink2(color, !dir, dir ? slot : 7 - slot);
|
||||
} else {
|
||||
set_slot_light_color(color);
|
||||
}
|
||||
@@ -503,12 +459,9 @@ static void check_wakeup_src(void) {
|
||||
uint8_t animation_config = settings_get_animation_config();
|
||||
if (animation_config == SettingsAnimationModeFull) {
|
||||
// In the case of field wake-up, only one round of RGB is swept as the power-on animation
|
||||
rgb_marquee_sweep_to(color, !dir, dir ? slot : 7 - slot);
|
||||
} else if (animation_config == SettingsAnimationModeSymmetric) {
|
||||
rgb_marquee_symmetric_out(color, slot);
|
||||
} else {
|
||||
set_slot_light_color(color);
|
||||
ledblink2(color, !dir, dir ? slot : 7 - slot);
|
||||
}
|
||||
set_slot_light_color(color);
|
||||
light_up_by_slot();
|
||||
|
||||
// We can only run tag emulation at field wakeup source.
|
||||
@@ -535,20 +488,9 @@ static void check_wakeup_src(void) {
|
||||
tag_emulation_factory_init();
|
||||
|
||||
// RGB
|
||||
uint8_t animation_config = settings_get_animation_config();
|
||||
if (animation_config == SettingsAnimationModeFull) {
|
||||
rgb_marquee_sweep_to(0, !dir, 11);
|
||||
rgb_marquee_sweep_to(1, dir, 11);
|
||||
rgb_marquee_sweep_to(2, !dir, 11);
|
||||
} else if (animation_config == SettingsAnimationModeMinimal) {
|
||||
rgb_marquee_sweep_from_to(0, 0, 2);
|
||||
rgb_marquee_sweep_from_to(1, 2, 5);
|
||||
rgb_marquee_sweep_from_to(2, 5, 7);
|
||||
} else if (animation_config == SettingsAnimationModeSymmetric) {
|
||||
rgb_marquee_symmetric_out(0, ~0);
|
||||
rgb_marquee_symmetric_in(1, ~0);
|
||||
rgb_marquee_symmetric_out(2, ~0);
|
||||
}
|
||||
ledblink2(0, !dir, 11);
|
||||
ledblink2(1, dir, 11);
|
||||
ledblink2(2, !dir, 11);
|
||||
|
||||
// Show RGB for slot.
|
||||
set_slot_light_color(color);
|
||||
@@ -579,12 +521,6 @@ static void cycle_slot(bool dec) {
|
||||
}
|
||||
// Update status only if the new card slot switch is valid
|
||||
tag_emulation_change_slot(slot_new, true); // Tell the analog card module that we need to switch card slots
|
||||
// Turn off the LEDs in case we were showing the battery status
|
||||
rgb_marquee_stop();
|
||||
uint32_t *led_pins = hw_get_led_array();
|
||||
for (int i = 0; i < RGB_LIST_NUM; i++) {
|
||||
nrf_gpio_pin_clear(led_pins[i]);
|
||||
}
|
||||
// Go back to the color corresponding to the field enablement type
|
||||
apply_slot_change(slot_now, slot_new);
|
||||
}
|
||||
@@ -668,22 +604,10 @@ static void btn_fn_copy_lf(uint8_t slot, tag_specific_type_t type) {
|
||||
data = id_buffer;
|
||||
break;
|
||||
case TAG_TYPE_EM410X:
|
||||
case TAG_TYPE_EM410X_ELECTRA: {
|
||||
status = scan_em410x(id_buffer);
|
||||
tag_specific_type_t detected_type = (id_buffer[0] << 8) | id_buffer[1];
|
||||
tag_specific_type_t new_type =
|
||||
detected_type == TAG_TYPE_EM410X_ELECTRA ? TAG_TYPE_EM410X_ELECTRA : TAG_TYPE_EM410X;
|
||||
|
||||
// If we read Electra but the slot was classic (or vice versa), switch slot type automatically.
|
||||
if (new_type != type) {
|
||||
tag_emulation_change_type(slot, new_type);
|
||||
type = new_type;
|
||||
}
|
||||
|
||||
size = (new_type == TAG_TYPE_EM410X_ELECTRA) ? LF_EM410X_ELECTRA_TAG_ID_SIZE : LF_EM410X_TAG_ID_SIZE;
|
||||
data = id_buffer + 2; // skip tag type
|
||||
size = LF_EM410X_TAG_ID_SIZE;
|
||||
data = id_buffer + 2; // skip tag type
|
||||
break;
|
||||
}
|
||||
case TAG_TYPE_VIKING:
|
||||
status = scan_viking(id_buffer);
|
||||
size = LF_VIKING_TAG_ID_SIZE;
|
||||
@@ -833,67 +757,13 @@ static void run_button_function_by_settings(settings_button_function_t sbf) {
|
||||
case SettingsButtonCloneIcUid:
|
||||
btn_fn_copy_ic_uid();
|
||||
break;
|
||||
case SettingsButtonNfcFieldGenerator:
|
||||
if (!m_is_field_on) {
|
||||
// Initialize reader hardware if not already in reader mode
|
||||
device_mode_t current_mode = get_device_mode();
|
||||
if (current_mode != DEVICE_MODE_READER) {
|
||||
// Temporarily init reader hardware just for the field
|
||||
nrf_gpio_cfg_output(READER_POWER);
|
||||
nrf_gpio_pin_set(READER_POWER); // reader power enable
|
||||
nrf_gpio_cfg_output(HF_ANT_SEL);
|
||||
nrf_gpio_pin_clear(HF_ANT_SEL); // hf ant switch to reader mode
|
||||
|
||||
pcd_14a_reader_init();
|
||||
bsp_delay_ms(10);
|
||||
}
|
||||
|
||||
pcd_14a_reader_reset();
|
||||
pcd_14a_reader_antenna_on();
|
||||
m_is_field_on = true;
|
||||
NRF_LOG_INFO("NFC field ON");
|
||||
|
||||
// Set initial rainbow state
|
||||
set_slot_light_color(RGB_RED);
|
||||
uint32_t *led_pins = hw_get_led_array();
|
||||
for (int i = 0; i < RGB_LIST_NUM; i++) {
|
||||
nrf_gpio_pin_set(led_pins[i]);
|
||||
}
|
||||
|
||||
// Stop sleep timer while field is active
|
||||
NRF_LOG_INFO("Stopping sleep timer for field generator");
|
||||
sleep_timer_stop();
|
||||
NRF_LOG_INFO("Sleep timer stopped");
|
||||
} else {
|
||||
pcd_14a_reader_antenna_off();
|
||||
m_is_field_on = false;
|
||||
NRF_LOG_INFO("NFC field OFF");
|
||||
|
||||
// If we're not in reader mode, clean up the hardware
|
||||
device_mode_t current_mode = get_device_mode();
|
||||
if (current_mode != DEVICE_MODE_READER) {
|
||||
pcd_14a_reader_uninit();
|
||||
nrf_gpio_pin_clear(READER_POWER); // reader power disable
|
||||
nrf_gpio_pin_set(HF_ANT_SEL); // hf ant switch back to tag mode
|
||||
}
|
||||
|
||||
// Restore normal LED
|
||||
light_up_by_slot();
|
||||
|
||||
// Restart sleep timer
|
||||
NRF_LOG_INFO("Field off, restarting sleep timer");
|
||||
sleep_timer_start(SLEEP_DELAY_MS_BUTTON_CLICK);
|
||||
NRF_LOG_INFO("Sleep timer restarted");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SettingsButtonShowBattery:
|
||||
show_battery();
|
||||
break;
|
||||
|
||||
default:
|
||||
NRF_LOG_ERROR("Unsupported button function");
|
||||
NRF_LOG_ERROR("Unsupported button function")
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -922,10 +792,8 @@ static void button_press_process(void) {
|
||||
}
|
||||
// Disable led marquee for usb at button pressed.
|
||||
g_usb_led_marquee_enable = false;
|
||||
// Re-delay into hibernation (unless field is on)
|
||||
if (!m_is_field_on) {
|
||||
sleep_timer_start(SLEEP_DELAY_MS_BUTTON_CLICK);
|
||||
}
|
||||
// Re-delay into hibernation
|
||||
sleep_timer_start(SLEEP_DELAY_MS_BUTTON_CLICK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,17 +812,12 @@ static void blink_usb_led_status(void) {
|
||||
}
|
||||
} else {
|
||||
// The light effect is enabled and can be displayed
|
||||
if (rgb_marquee_is_enabled()) {
|
||||
if (is_rgb_marquee_enable()) {
|
||||
is_working = true;
|
||||
if (g_usb_port_opened) {
|
||||
uint8_t animation_config = settings_get_animation_config();
|
||||
if (animation_config == SettingsAnimationModeSymmetric) {
|
||||
rgb_marquee_usb_open_symmetric(color);
|
||||
} else {
|
||||
rgb_marquee_usb_open_sweep(color, dir);
|
||||
}
|
||||
ledblink1(color, dir);
|
||||
} else {
|
||||
rgb_marquee_usb_idle();
|
||||
ledblink6();
|
||||
}
|
||||
} else {
|
||||
if (is_working) {
|
||||
@@ -1024,17 +887,8 @@ int main(void) {
|
||||
lesc_event_process();
|
||||
// Button event process
|
||||
button_press_process();
|
||||
|
||||
#if defined(PROJECT_CHAMELEON_ULTRA)
|
||||
// Field generator rainbow animation
|
||||
field_generator_rainbow_loop();
|
||||
#endif
|
||||
|
||||
// Led blink at usb status (only if field generator is off)
|
||||
if (!m_is_field_on) {
|
||||
blink_usb_led_status();
|
||||
}
|
||||
|
||||
// Led blink at usb status
|
||||
blink_usb_led_status();
|
||||
// Data pack process
|
||||
data_frame_process();
|
||||
// Log print process
|
||||
|
||||
@@ -31,9 +31,5 @@
|
||||
#define STATUS_FLASH_WRITE_FAIL (0x70) // Flash writing failed
|
||||
#define STATUS_FLASH_READ_FAIL (0x71) // Flash read failed
|
||||
#define STATUS_INVALID_SLOT_TYPE (0x72) // Invalid slot type
|
||||
#define STATUS_MEM_ERR (0x73) // Can't allocate memory or work with memory error
|
||||
#define STATUS_CREATE_RESPONSE_ERR (0x74) // Can't create response for command
|
||||
#define STATUS_CMD_ERR (0x75) // Execution of command failed
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -73,12 +73,6 @@
|
||||
#define DATA_CMD_MF1_ENC_NESTED_ACQUIRE (2014)
|
||||
#define DATA_CMD_MF1_CHECK_KEYS_ON_BLOCK (2015)
|
||||
|
||||
#define DATA_CMD_HF14A_SET_FIELD_ON (2100)
|
||||
#define DATA_CMD_HF14A_SET_FIELD_OFF (2101)
|
||||
|
||||
#define DATA_CMD_HF14A_GET_CONFIG (2200)
|
||||
#define DATA_CMD_HF14A_SET_CONFIG (2201)
|
||||
|
||||
//
|
||||
// ******************************************************************
|
||||
|
||||
@@ -90,14 +84,10 @@
|
||||
//
|
||||
#define DATA_CMD_EM410X_SCAN (3000)
|
||||
#define DATA_CMD_EM410X_WRITE_TO_T55XX (3001)
|
||||
#define DATA_CMD_EM410X_ELECTRA_WRITE_TO_T55XX (3006)
|
||||
#define DATA_CMD_HIDPROX_SCAN (3002)
|
||||
#define DATA_CMD_HIDPROX_WRITE_TO_T55XX (3003)
|
||||
#define DATA_CMD_VIKING_SCAN (3004)
|
||||
#define DATA_CMD_VIKING_WRITE_TO_T55XX (3005)
|
||||
#define DATA_CMD_ADC_GENERIC_READ (3009)
|
||||
#define DATA_CMD_GENERIC_READ (3007)
|
||||
#define DATA_CMD_CORR_GENERIC_READ (3008)
|
||||
|
||||
//
|
||||
// ******************************************************************
|
||||
@@ -146,8 +136,6 @@
|
||||
#define DATA_CMD_MF0_NTAG_GET_DETECTION_LOG (4035)
|
||||
#define DATA_CMD_MF0_NTAG_GET_DETECTION_ENABLE (4036)
|
||||
#define DATA_CMD_MF0_NTAG_GET_EMULATOR_CONFIG (4037)
|
||||
#define DATA_CMD_MF1_SET_FIELD_OFF_DO_RESET (4038)
|
||||
#define DATA_CMD_MF1_GET_FIELD_OFF_DO_RESET (4039)
|
||||
//
|
||||
// ******************************************************************
|
||||
|
||||
|
||||
@@ -61,10 +61,7 @@ static volatile bool m_is_responded = false;
|
||||
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 };
|
||||
// The N -secondary connection needs to use SAK, when the "third 'bit' in SAK is 1 is 1, the logo UID is incomplete
|
||||
static uint8_t m_uid_incomplete_sak[] = { 0x04, 0xda, 0x17 };
|
||||
// Reset nfc peripheral after field lost?
|
||||
static bool reset_if_field_lost = false; // default is 'false', Unless there is a genuine need for a reset.
|
||||
|
||||
static uint8_t m_uid_incomplete_sak[] = { 0x04, 0xda, 0x17 };
|
||||
|
||||
/**
|
||||
* @brief Calculate BCC
|
||||
@@ -352,7 +349,7 @@ void nfc_tag_14a_data_process(uint8_t *p_data) {
|
||||
m_tag_state_14a = NFC_TAG_STATE_14A_READY;
|
||||
// After receiving the WUPA or REQA instruction, we need to reply to ATQA
|
||||
nfc_tag_14a_tx_bytes(auto_coll_res->atqa, 2, false);
|
||||
// NRF_LOG_INFO("ATQA reply: %02x%02x", auto_coll_res->atqa[0], auto_coll_res->atqa[1]);
|
||||
// NRF_LOG_INFO("ATQA reply.");
|
||||
} else {
|
||||
m_tag_state_14a = NFC_TAG_STATE_14A_IDLE;
|
||||
NRF_LOG_INFO("Auto anti-collision resource no exists.");
|
||||
@@ -400,15 +397,6 @@ void nfc_tag_14a_data_process(uint8_t *p_data) {
|
||||
m_tag_state_14a = NFC_TAG_STATE_14A_IDLE;
|
||||
}
|
||||
return;
|
||||
case NFC_TAG_14A_CMD_REQA:
|
||||
case NFC_TAG_14A_CMD_WUPA:
|
||||
// Reader is re-sending REQA/WUPA while in READY state
|
||||
// This can happen if reader retries or if frame was received incorrectly
|
||||
// Respond with ATQA again and stay in READY state
|
||||
if (auto_coll_res != NULL) {
|
||||
nfc_tag_14a_tx_bytes(auto_coll_res->atqa, 2, false);
|
||||
}
|
||||
return;
|
||||
default: {
|
||||
// After receiving the wrong level instruction, directly reset the status machine
|
||||
NRF_LOG_INFO("[MFEMUL_SELECT] Incorrect cascade level received: %02x", p_data[0]);
|
||||
@@ -535,43 +523,6 @@ void nfc_tag_14a_data_process(uint8_t *p_data) {
|
||||
}
|
||||
}
|
||||
|
||||
// Copy from nrf_nfct.c and modified for nrf52840 adapted(no verify on nrf52832)
|
||||
static inline void nrf_nfct_reset(void) {
|
||||
uint32_t fdm;
|
||||
uint32_t int_enabled;
|
||||
|
||||
// Save parameter settings before the reset of the NFCT peripheral.
|
||||
fdm = nrf_nfct_frame_delay_max_get();
|
||||
int_enabled = nrf_nfct_int_enable_get();
|
||||
|
||||
// Reset the NFCT peripheral.
|
||||
*(volatile uint32_t *)0x40005FFC = 0;
|
||||
*(volatile uint32_t *)0x40005FFC;
|
||||
*(volatile uint32_t *)0x40005FFC = 1;
|
||||
|
||||
// Restore parameter settings after the reset of the NFCT peripheral.
|
||||
nrf_nfct_frame_delay_max_set(fdm);
|
||||
|
||||
// Use Window Grid frame delay mode.
|
||||
nrf_nfct_frame_delay_mode_set(NRF_NFCT_FRAME_DELAY_MODE_WINDOWGRID);
|
||||
|
||||
/* Begin: Workaround for anomaly 25 */
|
||||
/* Workaround for wrong SENSRES values require using SDD00001, but here SDD00100 is used
|
||||
because it is required to operate with Windows Phone */
|
||||
nrf_nfct_sensres_bit_frame_sdd_set(NRF_NFCT_SENSRES_BIT_FRAME_SDD_00100);
|
||||
/* End: Workaround for anomaly 25 */
|
||||
|
||||
// Restore interrupts.
|
||||
nrf_nfct_int_enable(int_enabled);
|
||||
|
||||
// Disable interrupts associated with data exchange.
|
||||
nrf_nfct_int_disable(NRF_NFCT_INT_RXFRAMESTART_MASK |
|
||||
NRF_NFCT_INT_RXFRAMEEND_MASK |
|
||||
NRF_NFCT_INT_RXERROR_MASK |
|
||||
NRF_NFCT_INT_TXFRAMESTART_MASK |
|
||||
NRF_NFCT_INT_TXFRAMEEND_MASK);
|
||||
}
|
||||
|
||||
static inline void nfc_fdt_reset(void) {
|
||||
// STOP TX
|
||||
*(volatile uint32_t *)0x40005010 = 0x01;
|
||||
@@ -620,13 +571,6 @@ void nfc_tag_14a_event_callback(nrfx_nfct_evt_t const *p_event) {
|
||||
TAG_FIELD_LED_OFF()
|
||||
m_tag_state_14a = NFC_TAG_STATE_14A_IDLE;
|
||||
|
||||
if (reset_if_field_lost) {
|
||||
// Fix a bug where certain special conditions prevent triggering TX start events and actually transmit incorrect data to the card reader.
|
||||
// After more more more testing, I found that simply going into sleep mode and restarting can restore work.
|
||||
// Therefore, I suspect that there may be some issues with the NFC peripheral that require a reset to resolve.
|
||||
nrf_nfct_reset();
|
||||
}
|
||||
|
||||
NRF_LOG_INFO("HF FIELD LOST");
|
||||
break;
|
||||
}
|
||||
@@ -744,11 +688,3 @@ bool is_valid_uid_size(uint8_t uid_length) {
|
||||
uid_length == NFC_TAG_14A_UID_DOUBLE_SIZE ||
|
||||
uid_length == NFC_TAG_14A_UID_TRIPLE_SIZE;
|
||||
}
|
||||
|
||||
void nfc_tag_14a_set_reset_enable(bool enable) {
|
||||
reset_if_field_lost = enable;
|
||||
}
|
||||
|
||||
bool nfc_tag_14a_is_reset_enable() {
|
||||
return reset_if_field_lost;
|
||||
}
|
||||
|
||||
@@ -115,8 +115,4 @@ void nfc_tag_14a_tx_nbit(uint8_t data, uint32_t bits);
|
||||
// Determine whether it is an effective UID length
|
||||
bool is_valid_uid_size(uint8_t uid_length);
|
||||
|
||||
// Reset nfc peripheral after field lost
|
||||
void nfc_tag_14a_set_reset_enable(bool enable);
|
||||
bool nfc_tag_14a_is_reset_enable();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -675,50 +675,29 @@ static void handle_fast_read_command(uint8_t block_num, uint8_t end_block_num) {
|
||||
|
||||
int block_max = get_block_max_by_tag_type(m_tag_type, true);
|
||||
|
||||
if (block_num > end_block_num || end_block_num >= block_max) {
|
||||
if (block_num >= end_block_num || end_block_num >= block_max) {
|
||||
nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBV, 4);
|
||||
return;
|
||||
}
|
||||
|
||||
NRF_LOG_INFO("HANDLING FAST READ %02x %02x", block_num, end_block_num);
|
||||
// FAST_READ is inclusive: read from block_num to end_block_num (both included)
|
||||
handle_any_read(block_num, end_block_num - block_num + 1, block_max);
|
||||
|
||||
handle_any_read(block_num, end_block_num - block_num, block_max);
|
||||
}
|
||||
|
||||
static bool check_ro_lock_on_page(int block_num) {
|
||||
if (block_num < 3) return true;
|
||||
else if (block_num == 3) {
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216:
|
||||
//page 3 can be locked or not independant of BL CC bit
|
||||
//the BL bit only freezes the lock bytes !
|
||||
return (m_tag_information->memory[2][2] & 8) != 0;
|
||||
default:
|
||||
return (m_tag_information->memory[2][2] & 9) != 0;
|
||||
}
|
||||
// bits 0 and 3
|
||||
} else if (block_num <= MF0ICU1_PAGES) {
|
||||
else if (block_num == 3) return (m_tag_information->memory[2][2] & 9) != 0; // bits 0 and 3
|
||||
else if (block_num <= MF0ICU1_PAGES) {
|
||||
bool locked = false;
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216: {
|
||||
// pages can be locked or not independant of BL bits
|
||||
//the BL bits only freezes the lock bytes !
|
||||
uint16_t lock_bits = *(uint16_t *)&m_tag_information->memory[2][2];
|
||||
return ((lock_bits >> block_num) & 0x01) == 1;
|
||||
}
|
||||
default:
|
||||
// check block locking bits
|
||||
if (block_num <= 9) locked |= (m_tag_information->memory[2][2] & 2) == 2;
|
||||
else locked |= (m_tag_information->memory[2][2] & 4) == 4;
|
||||
|
||||
locked |= (((*(uint16_t *)&m_tag_information->memory[2][2]) >> block_num) & 1) == 1;
|
||||
// check block locking bits
|
||||
if (block_num <= 9) locked |= (m_tag_information->memory[2][2] & 2) == 2;
|
||||
else locked |= (m_tag_information->memory[2][2] & 4) == 4;
|
||||
|
||||
return locked;
|
||||
}
|
||||
locked |= (((*(uint16_t *)&m_tag_information->memory[2][2]) >> block_num) & 1) == 1;
|
||||
|
||||
return locked;
|
||||
} else {
|
||||
uint8_t *p_lock_bytes = NULL;
|
||||
int user_memory_end = 0;
|
||||
@@ -797,42 +776,9 @@ static bool check_ro_lock_on_page(int block_num) {
|
||||
|
||||
bool locked_small_range = ((lock_word >> (index / dyn_lock_bit_page_cnt)) & 1) != 0;
|
||||
bool locked_large_range = ((p_lock_bytes[2] >> (index / dyn_lock_bit_page_cnt / 2)) & 1) != 0;
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216:
|
||||
// For NTAG213/215/216: byte 2 contains block-locking bits (BL) which only freeze
|
||||
// the lock configuration. We only check the actual lock bits (L0-L15) in bytes 0-1.
|
||||
return locked_small_range;
|
||||
default:
|
||||
return locked_small_range | locked_large_range;
|
||||
}
|
||||
|
||||
return locked_small_range | locked_large_range;
|
||||
} else {
|
||||
//Check the block locking bits to see if we can touch the dynamic locks bytes for NTAG tags
|
||||
if(block_num == user_memory_end)
|
||||
{
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216: {
|
||||
uint8_t block_bytes = m_tag_information->memory[user_memory_end][2];
|
||||
uint16_t block_world = 0;
|
||||
|
||||
// Each bit in block_bytes maps to 2 bits in block_world
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (block_bytes & (0x01 << i)) {
|
||||
block_world |= (0x0003 << (i * 2));
|
||||
}
|
||||
}
|
||||
|
||||
p_lock_bytes = m_tag_information->memory[user_memory_end];
|
||||
uint16_t lock_word = (((uint16_t)p_lock_bytes[1]) << 8) | (uint16_t)p_lock_bytes[0];
|
||||
return (lock_word & block_world) != 0;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// check CFGLCK bit
|
||||
int first_cfg_page = get_first_cfg_page_by_tag_type(m_tag_type);
|
||||
uint8_t access = m_tag_information->memory[first_cfg_page + CONF_ACCESS_PAGE_OFFSET][CONF_ACCESS_BYTE];
|
||||
@@ -847,26 +793,7 @@ static bool check_ro_lock_on_page(int block_num) {
|
||||
static int handle_write_command(uint8_t block_num, uint8_t *p_data) {
|
||||
int block_max = get_block_max_by_tag_type(m_tag_type, false);
|
||||
|
||||
bool out_of_bounds = false;
|
||||
switch (m_tag_type) {
|
||||
case TAG_TYPE_NTAG_213:
|
||||
case TAG_TYPE_NTAG_215:
|
||||
case TAG_TYPE_NTAG_216: {
|
||||
int first_cfg_page = get_first_cfg_page_by_tag_type(m_tag_type);
|
||||
uint8_t cfglck = m_tag_information->memory[first_cfg_page][0] & 0x40;
|
||||
// For NTAG cards we need to check CFGLCK bit for config pages
|
||||
bool is_config_page = (block_num >= first_cfg_page) && (block_num <= first_cfg_page + 1);
|
||||
bool config_locked = (cfglck != 0) && (!m_tag_information->config.mode_uid_magic);
|
||||
bool is_beyond_user_memory = (block_num >= block_max);
|
||||
out_of_bounds = (is_beyond_user_memory && !is_config_page) || (config_locked && is_config_page);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
out_of_bounds = block_num >= block_max;
|
||||
break;
|
||||
}
|
||||
// Reject out-of-bounds writes (except config pages)
|
||||
if (out_of_bounds) {
|
||||
if (block_num >= block_max) {
|
||||
NRF_LOG_ERROR("Write failed: block_num %08x >= block_max %08x", block_num, block_max);
|
||||
return NAK_INVALID_OPERATION_TBV;
|
||||
}
|
||||
|
||||
@@ -1111,8 +1111,6 @@ int nfc_tag_mf1_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer)
|
||||
.cb_reset = nfc_tag_mf1_reset_handler,
|
||||
};
|
||||
nfc_tag_14a_set_handler(&handler_for_14a);
|
||||
NRF_LOG_INFO("HF mf1 config 'field_off_do_reset' = %d", m_tag_information->config.field_off_do_reset);
|
||||
nfc_tag_14a_set_reset_enable(m_tag_information->config.field_off_do_reset);
|
||||
NRF_LOG_INFO("HF mf1 data load finish.");
|
||||
} else {
|
||||
NRF_LOG_ERROR("nfc_tag_mf1_information_t too big.");
|
||||
@@ -1159,12 +1157,6 @@ bool nfc_tag_mf1_data_factory(uint8_t slot, tag_specific_type_t tag_type) {
|
||||
p_mf1_information->config.use_mf1_coll_res = false;
|
||||
p_mf1_information->config.mode_block_write = NFC_TAG_MF1_WRITE_NORMAL;
|
||||
p_mf1_information->config.detection_enable = false;
|
||||
p_mf1_information->config.field_off_do_reset = false;
|
||||
|
||||
// zero for reserved byte
|
||||
p_mf1_information->config.reserved1 = 0x00;
|
||||
p_mf1_information->config.reserved2 = 0x00;
|
||||
p_mf1_information->config.reserved3 = 0x00;
|
||||
|
||||
// save data to flash
|
||||
tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type);
|
||||
@@ -1244,10 +1236,3 @@ nfc_tag_mf1_write_mode_t nfc_tag_mf1_get_write_mode(void) {
|
||||
return m_tag_information->config.mode_block_write;
|
||||
}
|
||||
|
||||
void nfc_tag_mf1_set_field_off_do_reset(bool enable) {
|
||||
m_tag_information->config.field_off_do_reset = enable;
|
||||
}
|
||||
|
||||
bool nfc_tag_mf1_is_field_off_do_reset(void) {
|
||||
return m_tag_information->config.field_off_do_reset;
|
||||
}
|
||||
|
||||
@@ -71,15 +71,8 @@ typedef struct {
|
||||
uint8_t detection_enable: 1;
|
||||
// Allow to write block 0 (CUID/gen2 mode)
|
||||
uint8_t mode_gen2_magic: 1;
|
||||
/**
|
||||
* Should the NFC peripheral be reset after losing the RF field?
|
||||
* This configuration can fix the issue where some card readers cause the CU to enter a strange state of no response/incorrect response.
|
||||
* Once in this state, the device must be restarted to resolve the issue.
|
||||
* Alternatively, enabling this configuration for resetting the NFC after leaving the rf field can also solve the aforementioned problem.
|
||||
*/
|
||||
uint8_t field_off_do_reset: 1;
|
||||
// reserved
|
||||
uint8_t reserved1: 3;
|
||||
// reserve
|
||||
uint8_t reserved1: 4;
|
||||
uint8_t reserved2;
|
||||
uint8_t reserved3;
|
||||
} nfc_tag_mf1_configure_t;
|
||||
@@ -164,7 +157,6 @@ void nfc_tag_mf1_set_use_mf1_coll_res(bool enable);
|
||||
bool nfc_tag_mf1_is_use_mf1_coll_res(void);
|
||||
void nfc_tag_mf1_set_write_mode(nfc_tag_mf1_write_mode_t write_mode);
|
||||
nfc_tag_mf1_write_mode_t nfc_tag_mf1_get_write_mode(void);
|
||||
void nfc_tag_mf1_set_field_off_do_reset(bool enable);
|
||||
bool nfc_tag_mf1_is_field_off_do_reset(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -155,10 +155,6 @@ static enum {
|
||||
LF_SENSE_STATE_ENABLE,
|
||||
} m_lf_sense_state = LF_SENSE_STATE_NONE;
|
||||
|
||||
static uint16_t lf_em410x_id_size(tag_specific_type_t type) {
|
||||
return type == TAG_TYPE_EM410X_ELECTRA ? LF_EM410X_ELECTRA_TAG_ID_SIZE : LF_EM410X_TAG_ID_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief switchLfFieldInductionToEnableTheState
|
||||
*/
|
||||
@@ -186,14 +182,13 @@ void lf_tag_125khz_sense_switch(bool enable) {
|
||||
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 || type == TAG_TYPE_EM410X_ELECTRA) && buffer->length >= lf_em410x_id_size(type)) {
|
||||
const protocol *p = type == TAG_TYPE_EM410X_ELECTRA ? &em410x_electra : &em410x_64;
|
||||
if (type == TAG_TYPE_EM410X && buffer->length >= LF_EM410X_TAG_ID_SIZE) {
|
||||
m_tag_type = type;
|
||||
void *codec = p->alloc();
|
||||
m_pwm_seq = p->modulator(codec, buffer->buffer);
|
||||
p->free(codec);
|
||||
NRF_LOG_INFO("load lf em410x%s data finish.", type == TAG_TYPE_EM410X_ELECTRA ? " electra" : "");
|
||||
return lf_em410x_id_size(type);
|
||||
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;
|
||||
}
|
||||
|
||||
if (type == TAG_TYPE_HID_PROX && buffer->length >= LF_HIDPROX_TAG_ID_SIZE) {
|
||||
@@ -226,13 +221,7 @@ 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) {
|
||||
// Make sure to load this tag before allowing saving
|
||||
// Just save the original card package directly
|
||||
if (m_tag_type == TAG_TYPE_EM410X) {
|
||||
return LF_EM410X_TAG_ID_SIZE;
|
||||
}
|
||||
if (m_tag_type == TAG_TYPE_EM410X_ELECTRA) {
|
||||
return LF_EM410X_ELECTRA_TAG_ID_SIZE;
|
||||
}
|
||||
return 0;
|
||||
return m_tag_type == TAG_TYPE_EM410X ? LF_EM410X_TAG_ID_SIZE : 0;
|
||||
}
|
||||
|
||||
/** @brief Id card deposit card number before callback
|
||||
@@ -263,7 +252,7 @@ bool lf_tag_data_factory(uint8_t slot, tag_specific_type_t tag_type, uint8_t *ta
|
||||
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
|
||||
bool ret = fds_write_sync(map_info.id, map_info.key, length, (uint8_t *)tag_id);
|
||||
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.");
|
||||
} else {
|
||||
@@ -278,18 +267,9 @@ bool lf_tag_data_factory(uint8_t slot, tag_specific_type_t tag_type, uint8_t *ta
|
||||
* @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) {
|
||||
static const uint8_t tag_id_base[LF_EM410X_TAG_ID_SIZE] = {0xDE, 0xAD, 0xBE, 0xEF, 0x88};
|
||||
static const uint8_t tag_id_electra[LF_EM410X_ELECTRA_TAG_ID_SIZE] = {0xDE, 0xAD, 0xBE, 0xEF, 0x88,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
switch (tag_type) {
|
||||
case TAG_TYPE_EM410X_ELECTRA:
|
||||
return lf_tag_data_factory(slot, tag_type, (uint8_t *)tag_id_electra, sizeof(tag_id_electra));
|
||||
case TAG_TYPE_EM410X:
|
||||
return lf_tag_data_factory(slot, tag_type, (uint8_t *)tag_id_base, sizeof(tag_id_base));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
// 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
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "tag_emulation.h"
|
||||
|
||||
#define LF_EM410X_TAG_ID_SIZE 5
|
||||
#define LF_EM410X_ELECTRA_TAG_ID_SIZE 13
|
||||
#define LF_HIDPROX_TAG_ID_SIZE 13
|
||||
#define LF_VIKING_TAG_ID_SIZE 4
|
||||
|
||||
|
||||
@@ -15,17 +15,11 @@
|
||||
#define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1)
|
||||
|
||||
#define EM_RAW_SIZE (64)
|
||||
#define EM_DATA_SIZE_BASE (5)
|
||||
#define EM_ELECTRA_EPILOGUE_SIZE (8)
|
||||
#define EM_DATA_SIZE_ELECTRA (EM_DATA_SIZE_BASE + EM_ELECTRA_EPILOGUE_SIZE)
|
||||
#define EM_DATA_SIZE_MAX (EM_DATA_SIZE_ELECTRA)
|
||||
#define EM_T55XX_ELECTRA_BLOCK_COUNT (5)
|
||||
#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_ENCODED_DATA_HEADER (0xFF80000000000000ULL)
|
||||
|
||||
#define EM_T55XX_BLOCK_COUNT (3)
|
||||
|
||||
#define EM_READ_TIME1_BASE (0x40)
|
||||
@@ -39,25 +33,16 @@
|
||||
#include "nrf_log_default_backends.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
static nrf_pwm_values_wave_form_t m_em410x_pwm_seq_vals_base[EM_RAW_SIZE] = {};
|
||||
static nrf_pwm_values_wave_form_t m_em410x_pwm_seq_vals_electra[EM_RAW_SIZE * 2] = {};
|
||||
static nrf_pwm_values_wave_form_t m_em410x_pwm_seq_vals[EM_RAW_SIZE] = {};
|
||||
|
||||
nrf_pwm_sequence_t const m_em410x_pwm_seq_base = {
|
||||
.values.p_wave_form = m_em410x_pwm_seq_vals_base,
|
||||
.length = NRF_PWM_VALUES_LENGTH(m_em410x_pwm_seq_vals_base),
|
||||
.repeats = 0,
|
||||
.end_delay = 0,
|
||||
};
|
||||
|
||||
nrf_pwm_sequence_t const m_em410x_pwm_seq_electra = {
|
||||
.values.p_wave_form = m_em410x_pwm_seq_vals_electra,
|
||||
.length = NRF_PWM_VALUES_LENGTH(m_em410x_pwm_seq_vals_electra),
|
||||
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_electra,
|
||||
&em410x_64,
|
||||
&em410x_32,
|
||||
&em410x_16,
|
||||
@@ -66,11 +51,9 @@ const protocol *em410x_protocols[] = {
|
||||
size_t em410x_protocols_size = ARRAY_SIZE(em410x_protocols);
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[EM_DATA_SIZE_MAX];
|
||||
uint8_t data[EM_DATA_SIZE];
|
||||
uint64_t raw;
|
||||
uint64_t epilogue;
|
||||
uint8_t raw_length;
|
||||
uint8_t total_length;
|
||||
manchester *modem;
|
||||
} em410x_codec;
|
||||
|
||||
@@ -97,17 +80,6 @@ uint64_t em410x_raw_data(uint8_t *uid) {
|
||||
return raw;
|
||||
}
|
||||
|
||||
uint64_t em410x_raw_epilogue(uint8_t *uid) {
|
||||
uint64_t raw = 0;
|
||||
|
||||
for (int i = 0; i < EM_ELECTRA_EPILOGUE_SIZE; i++) {
|
||||
raw <<= 8;
|
||||
raw |= uid[EM_DATA_SIZE_BASE + i];
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -170,11 +142,9 @@ void em410x_free(em410x_codec *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_MAX);
|
||||
memset(d->data, 0, EM_DATA_SIZE);
|
||||
d->raw = 0;
|
||||
d->raw_length = 0;
|
||||
d->total_length = 0;
|
||||
d->epilogue = 0;
|
||||
manchester_reset(d->modem);
|
||||
};
|
||||
|
||||
@@ -232,8 +202,6 @@ bool em410x_decoder_feed(em410x_codec *d, uint16_t interval) {
|
||||
if (bitlen == -1) {
|
||||
d->raw = 0;
|
||||
d->raw_length = 0;
|
||||
d->total_length = 0;
|
||||
d->epilogue = 0;
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < bitlen; i++) {
|
||||
@@ -244,79 +212,6 @@ bool em410x_decoder_feed(em410x_codec *d, uint16_t interval) {
|
||||
return false;
|
||||
};
|
||||
|
||||
void em410x_electra_decoder_start(em410x_codec *d, uint8_t format) {
|
||||
em410x_decoder_start(d, format);
|
||||
}
|
||||
|
||||
static bool em410x_electra_decode_feed(em410x_codec *d, bool bit) {
|
||||
bool carry_bit = (d->epilogue >> 63) & 0x01;
|
||||
|
||||
if (d->total_length < EM_RAW_SIZE + EM_RAW_SIZE) {
|
||||
d->total_length++;
|
||||
}
|
||||
d->raw = (d->raw << 1) | carry_bit;
|
||||
d->epilogue = (d->epilogue << 1) | (bit ? 1 : 0);
|
||||
|
||||
if (d->total_length < EM_RAW_SIZE + EM_RAW_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((d->raw & EM_ENCODED_DATA_HEADER) != EM_ENCODED_DATA_HEADER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// if we only saw the same frame twice, treat as standard EM410X
|
||||
if (d->raw == d->epilogue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < EM_ELECTRA_EPILOGUE_SIZE; i++) {
|
||||
d->data[EM_DATA_SIZE_BASE + i] = (d->epilogue >> ((EM_ELECTRA_EPILOGUE_SIZE - 1 - i) * 8)) & 0xFF;
|
||||
}
|
||||
|
||||
return pc == 0x00;
|
||||
}
|
||||
|
||||
bool em410x_electra_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) {
|
||||
em410x_decoder_start(d, 0);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < bitlen; i++) {
|
||||
if (em410x_electra_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++) {
|
||||
@@ -324,50 +219,16 @@ const nrf_pwm_sequence_t *em410x_modulator(em410x_codec *d, uint8_t *buf) {
|
||||
if (IS_SET(lo, EM_RAW_SIZE - i - 1)) {
|
||||
msb = (1 << 15);
|
||||
}
|
||||
m_em410x_pwm_seq_vals_base[i].channel_0 = msb | 32;
|
||||
m_em410x_pwm_seq_vals_base[i].counter_top = 64;
|
||||
m_em410x_pwm_seq_vals[i].channel_0 = msb | 32;
|
||||
m_em410x_pwm_seq_vals[i].counter_top = 64;
|
||||
}
|
||||
return &m_em410x_pwm_seq_base;
|
||||
};
|
||||
|
||||
const nrf_pwm_sequence_t *em410x_electra_modulator(em410x_codec *d, uint8_t *buf) {
|
||||
uint64_t data[] = {em410x_raw_data(buf), em410x_raw_epilogue(buf)};
|
||||
uint16_t output_index = 0;
|
||||
|
||||
for (int frame = 0; frame < 2; frame++) {
|
||||
for (int i = 0; i < EM_RAW_SIZE; i++) {
|
||||
uint16_t msb = 0x00;
|
||||
if (IS_SET(data[frame], EM_RAW_SIZE - i - 1)) {
|
||||
msb = (1 << 15);
|
||||
}
|
||||
m_em410x_pwm_seq_vals_electra[output_index].channel_0 = msb | 32;
|
||||
m_em410x_pwm_seq_vals_electra[output_index].counter_top = 64;
|
||||
output_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return &m_em410x_pwm_seq_electra;
|
||||
};
|
||||
|
||||
// EM-Micro, EM410x/64 (std)
|
||||
const protocol em410x_electra = {
|
||||
.tag_type = TAG_TYPE_EM410X_ELECTRA,
|
||||
.data_size = EM_DATA_SIZE_ELECTRA,
|
||||
.alloc = (codec_alloc)em410x_64_alloc,
|
||||
.free = (codec_free)em410x_free,
|
||||
.get_data = (codec_get_data)em410x_get_data,
|
||||
.modulator = (modulator)em410x_electra_modulator,
|
||||
.decoder =
|
||||
{
|
||||
.start = (decoder_start)em410x_electra_decoder_start,
|
||||
.feed = (decoder_feed)em410x_electra_decoder_feed,
|
||||
},
|
||||
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_BASE,
|
||||
.data_size = EM_DATA_SIZE,
|
||||
.alloc = (codec_alloc)em410x_64_alloc,
|
||||
.free = (codec_free)em410x_free,
|
||||
.get_data = (codec_get_data)em410x_get_data,
|
||||
@@ -382,7 +243,7 @@ const protocol em410x_64 = {
|
||||
// EM-Micro, EM410x/32
|
||||
const protocol em410x_32 = {
|
||||
.tag_type = TAG_TYPE_EM410X_32,
|
||||
.data_size = EM_DATA_SIZE_BASE,
|
||||
.data_size = EM_DATA_SIZE,
|
||||
.alloc = (codec_alloc)em410x_32_alloc,
|
||||
.free = (codec_free)em410x_free,
|
||||
.get_data = (codec_get_data)em410x_get_data,
|
||||
@@ -397,7 +258,7 @@ const protocol em410x_32 = {
|
||||
// EM-Micro, EM410x/16
|
||||
const protocol em410x_16 = {
|
||||
.tag_type = TAG_TYPE_EM410X_16,
|
||||
.data_size = EM_DATA_SIZE_BASE,
|
||||
.data_size = EM_DATA_SIZE,
|
||||
.alloc = (codec_alloc)em410x_16_alloc,
|
||||
.free = (codec_free)em410x_free,
|
||||
.get_data = (codec_get_data)em410x_get_data,
|
||||
@@ -416,17 +277,4 @@ uint8_t em410x_t55xx_writer(uint8_t *uid, uint32_t *blks) {
|
||||
blks[1] = raw >> 32;
|
||||
blks[2] = raw & 0xffffffff;
|
||||
return EM_T55XX_BLOCK_COUNT;
|
||||
}
|
||||
|
||||
uint8_t em410x_electra_t55xx_writer(uint8_t *uid, uint32_t *blks) {
|
||||
uint64_t raw_data = em410x_raw_data(uid);
|
||||
uint64_t raw_epilogue = em410x_raw_epilogue(uid);
|
||||
|
||||
blks[0] = T5577_EM410X_ELECTRA_CONFIG;
|
||||
blks[1] = raw_data >> 32;
|
||||
blks[2] = raw_data & 0xffffffff;
|
||||
blks[3] = raw_epilogue >> 32;
|
||||
blks[4] = raw_epilogue & 0xffffffff;
|
||||
|
||||
return EM_T55XX_ELECTRA_BLOCK_COUNT;
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,8 @@
|
||||
extern const protocol em410x_64;
|
||||
extern const protocol em410x_32;
|
||||
extern const protocol em410x_16;
|
||||
extern const protocol em410x_electra;
|
||||
|
||||
extern const protocol* em410x_protocols[];
|
||||
extern size_t em410x_protocols_size;
|
||||
|
||||
uint8_t em410x_t55xx_writer(uint8_t* uid, uint32_t* blks);
|
||||
uint8_t em410x_electra_t55xx_writer(uint8_t* uid, uint32_t* blks);
|
||||
uint8_t em410x_t55xx_writer(uint8_t* uid, uint32_t* blks);
|
||||
@@ -51,12 +51,6 @@ extern "C" {
|
||||
T5577_PWD | \
|
||||
(2 << T5577_MAXBLOCK_SHIFT))
|
||||
|
||||
#define T5577_EM410X_ELECTRA_CONFIG ( \
|
||||
T5577_BITRATE_RF_64 | \
|
||||
T5577_MODULATION_MANCHESTER | \
|
||||
T5577_PWD | \
|
||||
(4 << T5577_MAXBLOCK_SHIFT))
|
||||
|
||||
#define T5577_HIDPROX_CONFIG ( \
|
||||
T5577_BITRATE_RF_50 | \
|
||||
T5577_MODULATION_FSK2a | \
|
||||
@@ -74,4 +68,4 @@ void t55xx_reset_passwd(uint32_t old_passwd, uint32_t new_passwd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user