diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index 99c7d01..8dba70e 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -357,6 +357,19 @@ 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(); + if (!success) { + return data_frame_make(cmd, STATUS_FLASH_WRITE_FAIL, 0, NULL); + } + while (NRF_LOG_PROCESS()); + ret_code_t ret = sd_nvic_SystemReset(); + APP_ERROR_CHECK(ret); + while (1) { + __NOP(); + } +} + 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); @@ -607,6 +620,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/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 5241e90..5519eb8 100755 --- a/software/script/chameleon_cli_main.py +++ b/software/script/chameleon_cli_main.py @@ -99,6 +99,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 15f056d..7bd0fa7 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -1066,3 +1066,29 @@ 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 + try: + resp = self.cmd_positive.factory_reset() + if resp.status != chameleon_status.Device.STATUS_DEVICE_SUCCESS: + print(" - Reset failed!") + return + except KeyError: + print(" - A Serial Error above is normal, please ignore it") + print(" - Reset successful! Please reconnect.") diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index 391f605..284be24 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):