diff --git a/CHANGELOG.md b/CHANGELOG.md index 444ca19..87ca1cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] - Fix for static nested key recovery (@jekkos) - Fix LEDs being stuck on after battery check (@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) diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index a48b27e..23ee40f 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -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 }, diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index 3aa1c82..1b47183 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -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) // // ****************************************************************** diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_14a.c b/firmware/application/src/rfid/nfctag/hf/nfc_14a.c index 043f0e4..b918b9f 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_14a.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_14a.c @@ -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."); @@ -523,6 +526,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 +611,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 +735,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; +} diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_14a.h b/firmware/application/src/rfid/nfctag/hf/nfc_14a.h index c103c02..e38b250 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_14a.h +++ b/firmware/application/src/rfid/nfctag/hf/nfc_14a.h @@ -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 diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c index 15d27c5..ade17bd 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c @@ -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; +} diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h index 3521714..eff32ab 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h @@ -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 diff --git a/firmware/application/src/usb_main.c b/firmware/application/src/usb_main.c index 3cc0d8f..d0525b3 100644 --- a/firmware/application/src/usb_main.c +++ b/firmware/application/src/usb_main.c @@ -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: diff --git a/firmware/application/src/utils/dataframe.c b/firmware/application/src/utils/dataframe.c index a2baad0..9874f5b 100644 --- a/firmware/application/src/utils/dataframe.c +++ b/firmware/application/src/utils/dataframe.c @@ -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."); diff --git a/firmware/bootloader/Makefile b/firmware/bootloader/Makefile index 52c0096..afca5ce 100644 --- a/firmware/bootloader/Makefile +++ b/firmware/bootloader/Makefile @@ -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 diff --git a/firmware/nrf52_sdk/modules/nrfx/drivers/src/nrfx_nfct.c b/firmware/nrf52_sdk/modules/nrfx/drivers/src/nrfx_nfct.c index 9c30476..2435612 100644 --- a/firmware/nrf52_sdk/modules/nrfx/drivers/src/nrfx_nfct.c +++ b/firmware/nrf52_sdk/modules/nrfx/drivers/src/nrfx_nfct.c @@ -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)