diff --git a/firmware/application/Makefile b/firmware/application/Makefile index 4208e15..9e9ac54 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -31,6 +31,7 @@ SRC_FILES += \ $(PROJ_DIR)/rfid/nfctag/hf/nfc_ntag.c \ $(PROJ_DIR)/rfid/nfctag/lf/lf_tag_em.c \ $(PROJ_DIR)/utils/dataframe.c \ + $(PROJ_DIR)/utils/delayed_reset.c \ $(PROJ_DIR)/utils/fds_util.c \ $(PROJ_DIR)/utils/syssleep.c \ $(PROJ_DIR)/utils/timeslot.c \ diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index dbe49d3..2bbbdbd 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -13,6 +13,7 @@ #include "tag_persistence.h" #include "nrf_pwr_mgmt.h" #include "settings.h" +#include "delayed_reset.h" #define NRF_LOG_MODULE_NAME app_cmd @@ -357,6 +358,13 @@ data_frame_tx_t* cmd_processor_get_slot_info(uint16_t cmd, uint16_t status, uint return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, 16, slot_info); } +data_frame_tx_t* cmd_processor_wipe_fds(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + bool success = fds_wipe(); + status = success ? STATUS_DEVICE_SUCCESS : STATUS_FLASH_WRITE_FAIL; + delayed_reset(50); + return data_frame_make(cmd, status, 0, NULL); +} + data_frame_tx_t* cmd_processor_set_em410x_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { if (length == LF_EM410X_TAG_ID_SIZE) { tag_data_buffer_t* buffer = get_buffer_by_tag_type(TAG_TYPE_EM410X); @@ -605,6 +613,7 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_SLOT_DATA_CONFIG_SAVE, NULL, cmd_processor_slot_data_config_save, NULL }, { DATA_CMD_GET_ACTIVE_SLOT, NULL, cmd_processor_get_activated_slot, NULL }, { DATA_CMD_GET_SLOT_INFO, NULL, cmd_processor_get_slot_info, NULL }, + { DATA_CMD_WIPE_FDS, NULL, cmd_processor_wipe_fds, NULL }, { DATA_CMD_SET_EM410X_EMU_ID, NULL, cmd_processor_set_em410x_emu_id, NULL }, diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index 32803cf..2050fa8 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -27,6 +27,7 @@ #define DATA_CMD_GET_GIT_VERSION (1017) #define DATA_CMD_GET_ACTIVE_SLOT (1018) #define DATA_CMD_GET_SLOT_INFO (1019) +#define DATA_CMD_WIPE_FDS (1020) // // ****************************************************************** diff --git a/firmware/application/src/utils/delayed_reset.c b/firmware/application/src/utils/delayed_reset.c new file mode 100644 index 0000000..1dc4c89 --- /dev/null +++ b/firmware/application/src/utils/delayed_reset.c @@ -0,0 +1,26 @@ +#include "app_timer.h" +#include "delayed_reset.h" + +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_log_default_backends.h" + +APP_TIMER_DEF(m_reset_timer); + +static void delayed_reset_event_handler(void* ctx) { + while (NRF_LOG_PROCESS()); + ret_code_t ret = sd_nvic_SystemReset(); + APP_ERROR_CHECK(ret); + while (1) { + __NOP(); + } +} + +void delayed_reset(uint32_t delay) { + NRF_LOG_INFO("Resetting in %d ms...", delay); + ret_code_t ret; + ret = app_timer_create(&m_reset_timer, APP_TIMER_MODE_SINGLE_SHOT, delayed_reset_event_handler); + APP_ERROR_CHECK(ret); + ret = app_timer_start(m_reset_timer, APP_TIMER_TICKS(delay), NULL); + APP_ERROR_CHECK(ret); +} diff --git a/firmware/application/src/utils/delayed_reset.h b/firmware/application/src/utils/delayed_reset.h new file mode 100644 index 0000000..6be37ad --- /dev/null +++ b/firmware/application/src/utils/delayed_reset.h @@ -0,0 +1,3 @@ +#pragma once + +void delayed_reset(uint32_t delay); \ No newline at end of file diff --git a/firmware/application/src/utils/fds_util.c b/firmware/application/src/utils/fds_util.c index 43850b8..7006854 100644 --- a/firmware/application/src/utils/fds_util.c +++ b/firmware/application/src/utils/fds_util.c @@ -10,10 +10,11 @@ NRF_LOG_MODULE_REGISTER(); // current write record info static struct { - uint16_t id; // file id - uint16_t key; // file key - bool success; // task is success - bool waiting; // task waiting done. + uint32_t record_id; // record id, used for sync delete + uint16_t id; // file id + uint16_t key; // file key + bool success; // task is success + bool waiting; // task waiting done. } fds_operation_info; @@ -120,12 +121,7 @@ bool fds_write_sync(uint16_t id, uint16_t key, uint16_t data_length_words, void* } else if (err_code == FDS_ERR_NO_SPACE_IN_FLASH) { // 确保还有空间可以操作,否则需要GC // 当前报错是属于空间不足的报错,可能我们需要进行GC NRF_LOG_INFO("FDS no space, gc auto start."); - err_code = fds_gc(); // 发起GC操作 - APP_ERROR_CHECK(err_code); // 检查GC是否正常执行 - // 等待GC完成 - while(!fds_operation_info.success) { - __NOP(); - }; + fds_gc_sync(); // gc完成后,可以重新进行相应的操作了 NRF_LOG_INFO("FDS auto gc success, write record continue."); @@ -162,6 +158,7 @@ int fds_delete_sync(uint16_t id, uint16_t key) { ret_code_t err_code; while(fds_find_record(id, key, &record_desc)) { fds_operation_info.success = false; + fds_record_id_from_desc(&record_desc, &fds_operation_info.record_id); err_code = fds_record_delete(&record_desc); APP_ERROR_CHECK(err_code); delete_count++; @@ -199,9 +196,13 @@ static void fds_evt_handler(fds_evt_t const * p_evt) { } break; case FDS_EVT_DEL_RECORD: { if (p_evt->result == NRF_SUCCESS) { - NRF_LOG_INFO("Record remove: FileID: 0x%04x, RecordKey: 0x%04x", p_evt->del.file_id, p_evt->del.record_key); - if (p_evt->write.file_id == fds_operation_info.id && p_evt->write.record_key == fds_operation_info.key) { - // 上面的逻辑已经确保是我们当前删除记录的任务完成了! + NRF_LOG_INFO( + "Record remove: FileID: 0x%04x, RecordKey: 0x%04x, RecordID: %08x", + p_evt->del.file_id, p_evt->del.record_key, p_evt->del.record_id + ); + if (p_evt->del.record_id == fds_operation_info.record_id) { + // Only check record id because fileID and recordKey aren't available + // if deleting via fds_record_iterate. record id is guaranteed to be unique. fds_operation_info.success = true; } } else { @@ -234,3 +235,45 @@ void fds_util_init() { err_code = fds_init(); APP_ERROR_CHECK(err_code); } + +void fds_gc_sync(void) { + fds_operation_info.success = false; + ret_code_t err_code = fds_gc(); + APP_ERROR_CHECK(err_code); + while(!fds_operation_info.success) { + __NOP(); + }; +} + +static bool fds_next_record_delete_sync() { + fds_find_token_t tok = {0}; + fds_record_desc_t desc = {0}; + if (fds_record_iterate(&desc, &tok) != NRF_SUCCESS) { + NRF_LOG_INFO("No more records to delete"); + return false; + } + + fds_record_id_from_desc(&desc, &fds_operation_info.record_id); + NRF_LOG_INFO("Deleting record with id=%08x", fds_operation_info.record_id); + + fds_operation_info.success = false; + ret_code_t rc = fds_record_delete(&desc); + if (rc != NRF_SUCCESS) { + NRF_LOG_WARNING("Record id=%08x deletion failed with rc=%d!", fds_operation_info.record_id, rc); + return false; + } + + while(!fds_operation_info.success) { + __NOP(); + } + + NRF_LOG_INFO("Record id=%08x deleted successfully", fds_operation_info.record_id); + return true; +} + +bool fds_wipe(void) { + NRF_LOG_INFO("Full fds wipe requested"); + while (fds_next_record_delete_sync()) {} + fds_gc_sync(); + return true; +} diff --git a/firmware/application/src/utils/fds_util.h b/firmware/application/src/utils/fds_util.h index 706ca42..df1b832 100644 --- a/firmware/application/src/utils/fds_util.h +++ b/firmware/application/src/utils/fds_util.h @@ -9,5 +9,7 @@ bool fds_write_sync(uint16_t id, uint16_t key, uint16_t data_length_words, void* int fds_delete_sync(uint16_t id, uint16_t key); bool fds_is_exists(uint16_t id, uint16_t key); void fds_util_init(void); +void fds_gc_sync(void); +bool fds_wipe(void); #endif diff --git a/software/script/chameleon_cli_main.py b/software/script/chameleon_cli_main.py index 7bc9e85..bb17915 100755 --- a/software/script/chameleon_cli_main.py +++ b/software/script/chameleon_cli_main.py @@ -98,6 +98,7 @@ class ChameleonCLI: 'reset': new_uint(chameleon_cli_unit.HWSettingsReset, "Reset settings to default values"), 'help': "Chameleon settings management" }, + 'factory_reset': new_uint(chameleon_cli_unit.HWFactoryReset, "Wipe all data and return to factory settings"), 'help': "hardware controller", }, 'hf': { diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index a6964aa..9dae002 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -1067,3 +1067,27 @@ class HWSettingsReset(DeviceRequiredUnit): print(" - Reset success @.@~") else: print(" - Reset failed") + +class HWFactoryReset(DeviceRequiredUnit): + def args_parser(self) -> ArgumentParserNoExit: + parser = ArgumentParserNoExit() + parser.description = "Permanently wipes Chameleon to factory settings. " \ + "This will delete all your slot data and custom settings. " \ + "There's no going back." + parser.add_argument( + "--i-know-what-im-doing", + default=False, + action="store_true", + help="Just to be sure :)" + ) + return parser + def on_exec(self, args: argparse.Namespace): + if not args.i_know_what_im_doing: + print("This time your data's safe. Read the command documentation next time.") + return + resp = self.cmd_positive.factory_reset() + if resp.status == chameleon_status.Device.STATUS_DEVICE_SUCCESS: + print(" - Reset successful! Please reconnect.") + print(" - A Serial Error below is normal, please ignore it") + else: + print(" - Reset failed!") diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index 88ab7de..d6eb8fe 100644 --- a/software/script/chameleon_cmd.py +++ b/software/script/chameleon_cmd.py @@ -30,6 +30,8 @@ DATA_CMD_GET_GIT_VERSION = 1017 DATA_CMD_GET_ACTIVE_SLOT = 1018 DATA_CMD_GET_SLOT_INFO = 1019 +DATA_CMD_WIPE_FDS = 1020 + DATA_CMD_SCAN_14A_TAG = 2000 DATA_CMD_MF1_SUPPORT_DETECT = 2001 DATA_CMD_MF1_NT_LEVEL_DETECT = 2002 @@ -495,6 +497,12 @@ class BaseChameleonCMD: Store settings to flash memory """ return self.device.send_cmd_sync(DATA_CMD_SAVE_SETTINGS, 0x00) + + def factory_reset(self): + """ + Reset to factory settings + """ + return self.device.send_cmd_sync(DATA_CMD_WIPE_FDS, 0x00) class NegativeResponseError(Exception):