Merge branch 'main' into fix-hidprox-cli-args

This commit is contained in:
Rick Console
2026-02-02 15:58:42 -05:00
committed by GitHub
21 changed files with 1299 additions and 143 deletions
+10
View File
@@ -3,7 +3,17 @@ 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]
- 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.
- 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)
## [v2.1.0][2025-09-02]
- Added UV, formatter and linter. Contribution guidelines. (@GameTec-live)
+16 -1
View File
@@ -996,7 +996,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) {
status = STATUS_PAR_ERR;
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
}
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;
@@ -1374,6 +1374,19 @@ 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;
@@ -1630,6 +1643,8 @@ 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 },
+6
View File
@@ -559,6 +559,12 @@ 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);
}
+2
View File
@@ -139,6 +139,8 @@
#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,7 +61,10 @@ 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 };
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.
/**
* @brief Calculate BCC
@@ -349,7 +352,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.");
// NRF_LOG_INFO("ATQA reply: %02x%02x", auto_coll_res->atqa[0], auto_coll_res->atqa[1]);
} else {
m_tag_state_14a = NFC_TAG_STATE_14A_IDLE;
NRF_LOG_INFO("Auto anti-collision resource no exists.");
@@ -397,6 +400,15 @@ 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]);
@@ -523,6 +535,43 @@ 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;
@@ -571,6 +620,13 @@ 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;
}
@@ -688,3 +744,11 @@ 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,4 +115,8 @@ 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,29 +675,49 @@ 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);
handle_any_read(block_num, end_block_num - block_num, block_max);
// 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);
}
static bool check_ro_lock_on_page(int block_num) {
if (block_num < 3) return true;
else if (block_num == 3) return (m_tag_information->memory[2][2] & 9) != 0; // bits 0 and 3
else if (block_num <= MF0ICU1_PAGES) {
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) {
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;
// 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;
locked |= (((*(uint16_t *)&m_tag_information->memory[2][2]) >> block_num) & 1) == 1;
return locked;
return locked;
}
} else {
uint8_t *p_lock_bytes = NULL;
int user_memory_end = 0;
@@ -776,9 +796,43 @@ 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;
return locked_small_range | locked_large_range;
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;
}
} 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];
@@ -793,7 +847,25 @@ 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);
if (block_num >= block_max) {
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) {
NRF_LOG_ERROR("Write failed: block_num %08x >= block_max %08x", block_num, block_max);
return NAK_INVALID_OPERATION_TBV;
}
@@ -1111,6 +1111,8 @@ 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.");
@@ -1157,6 +1159,12 @@ 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);
@@ -1236,3 +1244,10 @@ 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,8 +71,15 @@ typedef struct {
uint8_t detection_enable: 1;
// Allow to write block 0 (CUID/gen2 mode)
uint8_t mode_gen2_magic: 1;
// reserve
uint8_t reserved1: 4;
/**
* 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;
uint8_t reserved2;
uint8_t reserved3;
} nfc_tag_mf1_configure_t;
@@ -157,6 +164,7 @@ 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
@@ -18,6 +18,7 @@
#define PREAMBLE_34BIT (0x009)
#define PREAMBLE_35BIT (0x005)
#define PREAMBLE_36BIT (0x003)
#define PREAMBLE_ACTP (0x095)
/**@brief Set a bit in the uint64 word.
*
@@ -548,6 +549,37 @@ static wiegand_card_t *unpack_c15001(uint64_t hi, uint64_t lo) {
return d;
}
static uint64_t pack_actprox(wiegand_card_t *card) {
if (card->oem == 0) {
card->oem = 900;
}
uint64_t bits = PREAMBLE_ACTP;
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_actprox(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;
@@ -819,6 +851,7 @@ static const card_format_table_t formats[] = {
{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
{ACTPHID, pack_actprox, unpack_actprox, 36, {1, 0xFF, 0xFFFF, 0x3FF, 0}}, // HID ACTProx 36-bit
};
uint64_t pack(wiegand_card_t *card) {
@@ -72,6 +72,7 @@ typedef enum {
C1K48S,
AVIG56,
IR56,
ACTPHID,
} card_format_t;
// Structure for defined Wiegand card formats available for packing/unpacking
+12 -15
View File
@@ -40,19 +40,19 @@ APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm,
volatile bool g_usb_connected = false;
volatile bool g_usb_port_opened = false;
volatile bool g_usb_led_marquee_enable = true;
static uint8_t cdc_data_buffer[NRF_DRV_USBD_EPSIZE];
/** @brief User event handler @ref app_usbd_cdc_acm_user_ev_handler_t */
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const *p_inst, app_usbd_cdc_acm_user_event_t event) {
static uint8_t cdc_data_buffer[1];
// app_usbd_cdc_acm_t const *p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst);
switch (event) {
case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN: {
/*
*theProbabilityOfTheEntireUsbReceivingDataIsTheAppUsbdCdcAcmRead *AppUsbdCdcAcmReadFunctionIsNotASeriousReception,ItIsGivenAPointer,AndThenWaitForTheUsbBuffer *SoYouNeedToInitializeTheHeadPointerFirstWhenTheAppUsbdCdcAcmUserEvtPortOpenIsInitialized *IfTheAppUsbdCdcAcmUserEvtRxDoneUsesASubscribed0ToAccessTheBuffer,ItWillCauseTheFirstByteToLoseTheFirstSendEssence
*/
ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, cdc_data_buffer, 1);
// Setup first transfer
ret_code_t ret = app_usbd_cdc_acm_read_any(&m_app_cdc_acm, cdc_data_buffer, sizeof(cdc_data_buffer));
UNUSED_VARIABLE(ret);
NRF_LOG_INFO("CDC ACM port opened");
g_usb_port_opened = true;
break;
@@ -68,16 +68,13 @@ static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const *p_inst, app_usb
break;
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE: {
ret_code_t ret;
//Take out the first byte first
data_frame_receive(cdc_data_buffer, 1);
do {
ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, cdc_data_buffer, 1);
if (ret == NRF_SUCCESS) {
// The byte after success
data_frame_receive(cdc_data_buffer, 1);
}
} while (ret == NRF_SUCCESS);
// Get amount of data transfered to process data
size_t size = app_usbd_cdc_acm_rx_size(&m_app_cdc_acm);
data_frame_receive(cdc_data_buffer, size);
// Setup next transfer
ret_code_t ret = app_usbd_cdc_acm_read_any(&m_app_cdc_acm, cdc_data_buffer, sizeof(cdc_data_buffer));
UNUSED_VARIABLE(ret);
break;
}
default:
+15 -9
View File
@@ -28,6 +28,11 @@ static uint8_t compute_lrc(uint8_t *buf, uint16_t bufsize) {
return 0x100 - lrc;
}
//
// !!!!!!!!!!!!!!!!! NRF_LOG_HEXDUMP_INFO() printing long data can cause freezing and needs to be fixed. !!!!!!!!!!!!!!!!!
// FIXME.
//
/**
* @brief: create a packet, put the created data packet into the buffer, and wait for the post to set up a non busy state
* @param cmd: instructionResponse
@@ -44,10 +49,11 @@ data_frame_tx_t *data_frame_make(uint16_t cmd, uint16_t status, uint16_t data_le
NRF_LOG_ERROR("data_frame_make error, too much data.");
return NULL;
}
NRF_LOG_INFO("TX Data frame: cmd = 0x%04x (%i), status = 0x%04x, length = %d%s", cmd, cmd, status, data_length, data_length > 0 ? ", data =" : "");
if (data_length > 0) {
NRF_LOG_HEXDUMP_INFO(data, data_length);
}
// NRF_LOG_INFO("TX Data frame: cmd = 0x%04x (%i), status = 0x%04x, length = %d%s", cmd, cmd, status, data_length, data_length > 0 ? ", data =" : "");
// if (data_length > 0) {
// NRF_LOG_HEXDUMP_INFO(data, data_length);
// }
netdata_frame_postamble_t *tx_post = (netdata_frame_postamble_t *)((uint8_t *)&m_netdata_frame_tx_buf + sizeof(netdata_frame_preamble_t) + data_length);
// sof
@@ -92,7 +98,7 @@ void data_frame_receive(uint8_t *data, uint16_t length) {
return;
}
// buffer overflow
if (m_data_rx_position + length >= sizeof(m_netdata_frame_rx_buf)) {
if (m_data_rx_position + length > sizeof(m_netdata_frame_rx_buf)) {
NRF_LOG_ERROR("Data frame wait overflow.");
data_frame_reset();
return;
@@ -142,10 +148,10 @@ void data_frame_receive(uint8_t *data, uint16_t length) {
// and we are receive completed
m_data_buffer = m_data_len > 0 ? (uint8_t *)&m_netdata_frame_rx_buf.data : NULL;
m_data_completed = true;
NRF_LOG_INFO("RX Data frame: cmd = 0x%04x (%i), status = 0x%04x, length = %d%s", m_data_cmd, m_data_cmd, m_data_status, m_data_len, m_data_len > 0 ? ", data =" : "");
if (m_data_len > 0) {
NRF_LOG_HEXDUMP_INFO(m_data_buffer, m_data_len);
}
// NRF_LOG_INFO("RX Data frame: cmd = 0x%04x (%i), status = 0x%04x, length = %d%s", m_data_cmd, m_data_cmd, m_data_status, m_data_len, m_data_len > 0 ? ", data =" : "");
// if (m_data_len > 0) {
// NRF_LOG_HEXDUMP_INFO(m_data_buffer, m_data_len);
// }
} else {
// data frame lrc error
NRF_LOG_ERROR("Data frame finally lrc error.");
+2 -1
View File
@@ -259,7 +259,8 @@ include $(TEMPLATE_PATH)/Makefile.common
# tolerate warnings in newer gcc versions
# need to be called after $(TEMPLATE_PATH)/Makefile.common
CC_VERSION = $(shell $(CC) -dumpversion 2>/dev/null|sed 's/\..*//')
# The return value of the Windows+msys2 build platform has carriage returns and line breaks, which need to be removed.
CC_VERSION = $(shell $(CC) -dumpversion 2>/dev/null | tr -d '\r' | cut -d. -f1)
CC_VERSION := $(or $(strip $(CC_VERSION)),0)
ifeq ($(shell expr $(CC_VERSION) \>= 12), 1)
# avoid a couple of false warnings in nRF SDK
@@ -818,29 +818,9 @@ void nrfx_nfct_irq_handler(void)
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
/* Clear TXFRAMESTART EVENT so it can be checked in hal_nfc_send */
nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMESTART);
NRFX_LOG_DEBUG("Rx fend");
}
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMEEND))
{
nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMEEND);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_TX_FRAMEEND
};
/* Disable TX END event to ignore frame transmission other than READ response */
nrf_nfct_int_disable(NRFX_NFCT_TX_INT_MASK);
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
NRFX_LOG_DEBUG("Tx fend");
}
if (NRFX_NFCT_EVT_ACTIVE(SELECTED))
{
nrf_nfct_event_clear(NRF_NFCT_EVENT_SELECTED);
@@ -913,6 +893,23 @@ void nrfx_nfct_irq_handler(void)
m_nfct_cb.config.cb(&nfct_evt);
}
}
if (NRFX_NFCT_EVT_ACTIVE(TXFRAMEEND))
{
nrf_nfct_event_clear(NRF_NFCT_EVENT_TXFRAMEEND);
nrfx_nfct_evt_t nfct_evt =
{
.evt_id = NRFX_NFCT_EVT_TX_FRAMEEND
};
/* Disable TX END event to ignore frame transmission other than READ response */
nrf_nfct_int_disable(NRFX_NFCT_TX_INT_MASK);
NRFX_NFCT_CB_HANDLE(m_nfct_cb.config.cb, nfct_evt);
NRFX_LOG_DEBUG("Tx fend");
}
}
#endif // NRFX_CHECK(NRFX_NFCT_ENABLED)
File diff suppressed because it is too large Load Diff
+12
View File
@@ -1304,6 +1304,18 @@ class ChameleonCMD:
def set_ble_pairing_enable(self, enabled: bool):
data = struct.pack('!B', enabled)
return self.device.send_cmd_sync(Command.SET_BLE_PAIRING_ENABLE, data)
@expect_response(Status.SUCCESS)
def mf1_get_field_off_do_reset(self):
resp = self.device.send_cmd_sync(Command.MF1_GET_FIELD_OFF_DO_RESET)
if resp.status == Status.SUCCESS:
resp.parsed = struct.unpack('!B', resp.data)[0] == 1
return resp
@expect_response(Status.SUCCESS)
def mf1_set_field_off_do_reset(self, enabled: bool):
data = struct.pack('!B', enabled)
return self.device.send_cmd_sync(Command.MF1_SET_FIELD_OFF_DO_RESET, data)
def test_fn():
+85 -31
View File
@@ -1,18 +1,29 @@
import sys
import queue
import struct
import threading
import time
import serial
import platform
from typing import Union
from enum import Enum, auto
import serial
import socket
from chameleon_utils import CR, CG, CC, CY, color_string
from chameleon_enum import Command, Status
ANDROID = 'android' in platform.release()
# each thread is waiting for its data for 100 ms before looping again
THREAD_BLOCKING_TIMEOUT = 0.1
# TODO: client settings
DEBUG = False
class TransportType(Enum):
NONE = auto()
SERIAL = auto()
SOCKET = auto()
class NotOpenException(Exception):
"""
@@ -57,7 +68,8 @@ class ChameleonCom:
"""
Create a chameleon device instance
"""
self.serial_instance: Union[serial.Serial, None] = None
self.transport: Union[serial.Serial, socket.socket, None] = None
self.transport_type = TransportType.NONE
self.send_data_queue = queue.Queue()
self.wait_response_map = {}
self.event_closing = threading.Event()
@@ -68,7 +80,7 @@ class ChameleonCom:
:return:
"""
return self.serial_instance is not None and self.serial_instance.is_open
return self.transport is not None and (self.transport_type is TransportType.SOCKET or self.transport.is_open)
def open(self, port) -> "ChameleonCom":
"""
@@ -82,19 +94,35 @@ class ChameleonCom:
error = None
try:
# open serial port
self.serial_instance = serial.Serial(port=port, baudrate=115200)
if port.startswith('tcp:'):
host, _, port = port[4:].partition(':')
if not host or not port:
sys.exit(color_string(CR, 'Usage: tcp:127.0.0.1:4321'))
self.transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Connecting to', host, int(port))
self.transport.connect((host, int(port)))
self.transport_type = TransportType.SOCKET
else:
if ANDROID:
sys.exit(color_string(CR, 'COM port is not supported on Android, make a USB-serial to TCP communication bridge'))
self.transport = serial.Serial(port=port, baudrate=115200)
self.transport_type = TransportType.SERIAL
except Exception as e:
error = e
finally:
if error is not None:
raise OpenFailException(error)
assert self.serial_instance is not None
try:
self.serial_instance.dtr = True # must make dtr enable
except Exception:
# not all serial support dtr, e.g. virtual serial over BLE
pass
self.serial_instance.timeout = THREAD_BLOCKING_TIMEOUT
assert self.transport is not None
assert self.transport_type is not TransportType.NONE
if self.transport_type is TransportType.SERIAL:
try:
self.transport.dtr = True # must make dtr enable
except Exception:
# not all serial support dtr, e.g. virtual serial over BLE
pass
self.transport.timeout = THREAD_BLOCKING_TIMEOUT
else: # SOCKET
self.transport.settimeout(THREAD_BLOCKING_TIMEOUT)
# clear variable
self.send_data_queue.queue.clear()
self.wait_response_map.clear()
@@ -136,12 +164,14 @@ class ChameleonCom:
"""
self.event_closing.set()
try:
assert self.serial_instance is not None
self.serial_instance.close()
assert self.transport is not None
if self.transport_type is TransportType.SOCKET:
self.transport.shutdown()
self.transport.close()
except Exception:
pass
finally:
self.serial_instance = None
self.transport = None
self.wait_response_map.clear()
self.send_data_queue.queue.clear()
@@ -159,16 +189,29 @@ class ChameleonCom:
while self.isOpen():
# receive
try:
assert self.serial_instance is not None
data_bytes = self.serial_instance.read()
except Exception as e:
if not self.event_closing.is_set():
print(f"Serial Error {e}, thread for receiver exit.")
self.close()
break
if len(data_bytes) > 0:
assert self.transport_type is not TransportType.NONE
if self.transport_type is TransportType.SERIAL:
try:
assert self.transport is not None
data_bytes = bytearray(self.transport.read())
except Exception as e:
if not self.event_closing.is_set():
print(f"Serial Error {e}, thread for receiver exit.")
self.close()
break
else: # SOCKET
try:
data_bytes = bytearray(self.transport.recv(1024))
except socket.timeout:
continue
except OSError:
print(color_string(CR, 'socket closed'))
self.transport = None
break
while len(data_bytes) > 0:
data_byte = data_bytes[0]
data_bytes = data_bytes[1:]
data_buffer.append(data_byte)
if data_position < struct.calcsize('!BB'): # start of frame + lrc1
if data_position == 0:
@@ -267,14 +310,25 @@ class ChameleonCom:
self.wait_response_map[task_cmd]['start_time'] = start_time
self.wait_response_map[task_cmd]['end_time'] = start_time + task_timeout
self.wait_response_map[task_cmd]['is_timeout'] = False
try:
assert self.serial_instance is not None
# send to device
self.serial_instance.write(task['frame'])
except Exception as e:
print(f"Serial Error {e}, thread for transfer exit.")
self.close()
break
assert self.transport_type is not TransportType.NONE
if self.transport_type == TransportType.SERIAL:
try:
assert self.transport is not None
# send to device
self.transport.write(task['frame'])
except Exception as e:
print(f"Serial Error {e}, thread for transfer exit.")
self.close()
break
else: # SOCKET
try:
assert self.transport is not None
self.transport.sendall(task['frame'])
except OSError as e:
self.transport = None
print(f'Socket error {e}, thread for transfer exit.')
self.close()
break
# update queue status
self.send_data_queue.task_done()
# disconnect if DFU command has been sent
+5
View File
@@ -124,6 +124,9 @@ class Command(enum.IntEnum):
# FIXME: not implemented
MF0_NTAG_GET_EMULATOR_CONFIG = 4037
MF1_SET_FIELD_OFF_DO_RESET = 4038
MF1_GET_FIELD_OFF_DO_RESET = 4039
EM410X_SET_EMU_ID = 5000
EM410X_GET_EMU_ID = 5001
HIDPROX_SET_EMU_ID = 5002
@@ -581,6 +584,7 @@ class HIDFormat(enum.IntEnum):
C1K35S = 21
C15001 = 22
S12906 = 23
ACTPHID = 42
SIE36 = 24
H10320 = 25
H10302 = 26
@@ -614,6 +618,7 @@ class HIDFormat(enum.IntEnum):
HIDFormat.C1K35S: "HID Corporate 1000 35-bit Std",
HIDFormat.C15001: "HID KeyScan 36-bit",
HIDFormat.S12906: "HID Simplex 36-bit",
HIDFormat.ACTPHID: "HID ACTProx 36-bit",
HIDFormat.SIE36: "HID 36-bit Siemens",
HIDFormat.H10320: "HID H10320 37-bit BCD",
HIDFormat.H10302: "HID H10302 37-bit huge ID",
+25 -11
View File
@@ -77,7 +77,7 @@ endif()
# --- Platform specific settings ---
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
MESSAGE(STATUS "Run on linux.")
if (CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
@@ -126,7 +126,7 @@ endif()
add_executable(nested ${COMMON_FILES} ${NESTED_UTIL} nested.c)
target_include_directories(nested PRIVATE ${SRC_DIR})
target_link_libraries(nested PRIVATE ${LIBTHREAD}) # Link common thread lib
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(nested PRIVATE _GNU_SOURCE)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -138,7 +138,7 @@ endif()
add_executable(staticnested ${COMMON_FILES} ${NESTED_UTIL} staticnested.c)
target_include_directories(staticnested PRIVATE ${SRC_DIR})
target_link_libraries(staticnested PRIVATE ${LIBTHREAD}) # Link common thread lib
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(staticnested PRIVATE _GNU_SOURCE)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -150,7 +150,7 @@ endif()
add_executable(darkside ${COMMON_FILES} ${MFKEY_UTIL} darkside.c)
target_include_directories(darkside PRIVATE ${SRC_DIR})
# darkside doesn't seem to need pthreads based on original file
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(darkside PRIVATE _GNU_SOURCE)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -161,7 +161,7 @@ endif()
add_executable(mfkey32 ${COMMON_FILES} mfkey32.c)
target_include_directories(mfkey32 PRIVATE ${SRC_DIR})
# mfkey32 doesn't seem to need pthreads based on original file
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(mfkey32 PRIVATE _GNU_SOURCE)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -172,7 +172,7 @@ endif()
add_executable(mfkey32v2 ${COMMON_FILES} mfkey32v2.c)
target_include_directories(mfkey32v2 PRIVATE ${SRC_DIR})
# mfkey32v2 doesn't seem to need pthreads based on original file
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(mfkey32v2 PRIVATE _GNU_SOURCE)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -183,7 +183,7 @@ endif()
add_executable(mfkey64 ${COMMON_FILES} mfkey64.c)
target_include_directories(mfkey64 PRIVATE ${SRC_DIR})
# mfkey64 doesn't seem to need pthreads based on original file
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(mfkey64 PRIVATE _GNU_SOURCE)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -192,7 +192,7 @@ endif()
add_executable(staticnested_1nt ${COMMON_FILES} staticnested_1nt.c)
target_include_directories(staticnested_1nt PRIVATE ${SRC_DIR})
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(staticnested_1nt PRIVATE _GNU_SOURCE)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -201,7 +201,7 @@ endif()
add_executable(staticnested_2x1nt_rf08s ${COMMON_FILES} staticnested_2x1nt_rf08s.c)
target_include_directories(staticnested_2x1nt_rf08s PRIVATE ${SRC_DIR})
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(staticnested_2x1nt_rf08s PRIVATE _GNU_SOURCE)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
@@ -210,13 +210,27 @@ endif()
add_executable(staticnested_2x1nt_rf08s_1key ${COMMON_FILES} staticnested_2x1nt_rf08s_1key.c)
target_include_directories(staticnested_2x1nt_rf08s_1key PRIVATE ${SRC_DIR})
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(staticnested_2x1nt_rf08s_1key PRIVATE _GNU_SOURCE)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
target_compile_definitions(staticnested_2x1nt_rf08s_1key PRIVATE HAVE_STRUCT_TIMESPEC)
endif()
# --- mfulc_des_brute Executable ---
add_executable(mfulc_des_brute mfulc_des_brute.c)
target_include_directories(mfulc_des_brute PRIVATE ${SRC_DIR})
target_link_libraries(mfulc_des_brute PRIVATE ${LIBTHREAD} OpenSSL::Crypto)
target_compile_options(mfulc_des_brute PRIVATE -Wno-deprecated-declarations)
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(mfulc_des_brute PRIVATE _GNU_SOURCE)
find_package(OpenSSL REQUIRED)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
target_compile_definitions(mfulc_des_brute PRIVATE HAVE_STRUCT_TIMESPEC)
find_package(OpenSSL REQUIRED)
endif()
# --- hardnested Executable ---
add_executable(hardnested ${COMMON_FILES} ${HARDNESTED_SOURCES})
@@ -230,7 +244,7 @@ target_include_directories(hardnested PRIVATE
)
target_compile_options(hardnested PRIVATE -Wall)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_compile_definitions(hardnested PRIVATE _GNU_SOURCE)
endif()

Some files were not shown because too many files have changed in this diff Show More