diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index 27e2e52..4ea39a0 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -86,6 +86,12 @@ data_frame_tx_t* cmd_processor_save_settings(uint16_t cmd, uint16_t status, uint return data_frame_make(cmd, status, 0, NULL); } +data_frame_tx_t* cmd_processor_reset_settings(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + settings_init_config(); + status = settings_save_config(); + return data_frame_make(cmd, status, 0, NULL); +} + data_frame_tx_t* cmd_processor_set_animation_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { if (length == 1) { settings_set_animation_config(data[0]); @@ -546,6 +552,7 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_GET_DEVICE_CHIP_ID, NULL, cmd_processor_get_device_chip_id, NULL }, { DATA_CMD_GET_DEVICE_ADDRESS, NULL, cmd_processor_get_device_address, NULL }, { DATA_CMD_SAVE_SETTINGS, NULL, cmd_processor_save_settings, NULL }, + { DATA_CMD_RESET_SETTINGS, NULL, cmd_processor_reset_settings, NULL }, { DATA_CMD_SET_ANIMATION_MODE, NULL, cmd_processor_set_animation_mode, NULL }, { DATA_CMD_GET_ANIMATION_MODE, NULL, cmd_processor_get_animation_mode, NULL }, diff --git a/firmware/application/src/app_main.c b/firmware/application/src/app_main.c index 387bd5e..99a016b 100644 --- a/firmware/application/src/app_main.c +++ b/firmware/application/src/app_main.c @@ -222,7 +222,7 @@ static void system_off_enter(void) { nrf_gpio_pin_clear(p_led_array[i]); } uint8_t animation_config = settings_get_animation_config(); - if (animation_config == SETTINGS_ANIMATION_FULL) { + if (animation_config == SettingsAnimationModeFull) { uint8_t slot = tag_emulation_get_slot(); // Power off animation uint8_t dir = slot > 3 ? 1 : 0; @@ -352,13 +352,12 @@ static void check_wakeup_src(void) { // Button wake-up boot animation uint8_t animation_config = settings_get_animation_config(); - if (animation_config == SETTINGS_ANIMATION_FULL) + if (animation_config == SettingsAnimationModeFull) { ledblink2(color, !dir, 11); ledblink2(color, dir, 11); ledblink2(color, !dir, dir ? slot : 7 - slot); - } - else if (animation_config == SETTINGS_ANIMATION_MINIMAL) { + } else if (animation_config == SettingsAnimationModeMinimal) { ledblink2(color, !dir, dir ? slot : 7 - slot); } @@ -388,7 +387,7 @@ static void check_wakeup_src(void) { TAG_FIELD_LED_ON(); uint8_t animation_config = settings_get_animation_config(); - if (animation_config == SETTINGS_ANIMATION_FULL) { + if (animation_config == SettingsAnimationModeFull) { // In the case of field wake-up, only one round of RGB is swept as the power-on animation ledblink2(color, !dir, dir ? slot : 7 - slot); } diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index 89284f2..a653574 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -21,8 +21,9 @@ #define DATA_CMD_GET_DEVICE_CHIP_ID (1011) #define DATA_CMD_GET_DEVICE_ADDRESS (1012) #define DATA_CMD_SAVE_SETTINGS (1013) -#define DATA_CMD_SET_ANIMATION_MODE (1014) -#define DATA_CMD_GET_ANIMATION_MODE (1015) +#define DATA_CMD_RESET_SETTINGS (1014) +#define DATA_CMD_SET_ANIMATION_MODE (1015) +#define DATA_CMD_GET_ANIMATION_MODE (1016) // // ****************************************************************** diff --git a/firmware/application/src/settings.c b/firmware/application/src/settings.c index eba29b5..944060c 100644 --- a/firmware/application/src/settings.c +++ b/firmware/application/src/settings.c @@ -15,29 +15,84 @@ static settings_data_t config; static uint16_t m_config_crc; +static void update_config_crc(void) +{ + calc_14a_crc_lut((uint8_t *)&config, sizeof(config), (uint8_t *)&m_config_crc); +} + +static bool config_did_change(void) +{ + uint16_t new_calc_crc; + calc_14a_crc_lut((uint8_t *)&config, sizeof(config), (uint8_t *)&new_calc_crc); + return new_calc_crc != m_config_crc; +} + +void settings_init_config(void) +{ + config.version = SETTINGS_CURRENT_VERSION; + config.animation_config = SettingsAnimationModeFull; +} + +void settings_migrate(void) +{ + switch (config.version) { + case 0: + NRF_LOG_ERROR("Unexpected configuration version detected!"); + settings_init_config(); + break; + /* + * When needed migrations can be implemented like this: + * + * case 1: + * config->new_field = some_default_value; + * case 2: + * config->another_new_field = some_default_value; + * case 3: + * config->another_new_field = some_default_value; + * break; + * + * Note that the `break` statement should only be used on the last migration step, all the previous steps must fall + * through to the next case. + */ + default: + NRF_LOG_ERROR("Unsupported configuration migration attempted! (%d -> %d)", config.version, SETTINGS_CURRENT_VERSION); + break; + } +} + void settings_load_config(void) { bool ret = fds_read_sync(FDS_SETTINGS_ID, FDS_SETTINGS_KEY, sizeof(config), (uint8_t *)&config); if (ret) { - // After the reading is complete, we first save a copy of the current CRC, which can be used as a reference for comparison of changes when saving later - calc_14a_crc_lut((uint8_t *)&config, sizeof(config), (uint8_t *)&m_config_crc); NRF_LOG_INFO("Load config done."); + // After the reading is complete, we first save a copy of the current CRC, which can be used as a reference for comparison of changes when saving later + update_config_crc(); } else { - NRF_LOG_INFO("config no exists."); + NRF_LOG_WARNING("Config does not exist, loading default values..."); + settings_init_config(); + } + if (config.version > SETTINGS_CURRENT_VERSION) { + NRF_LOG_WARNING("Config version %d is greater than current firmware supports (%d). Default config will be loaded.", config.version, SETTINGS_CURRENT_VERSION); + settings_init_config(); + } + if (config.version < SETTINGS_CURRENT_VERSION) { + NRF_LOG_INFO("Config version (%d) is not latest, performing migration to %d", config.version, SETTINGS_CURRENT_VERSION); + settings_migrate(); + } + if (config_did_change()) { + settings_save_config(); } } uint8_t settings_save_config(void) { // We are saving the configuration, we need to calculate the crc code of the current configuration to judge whether the following data is updated - uint16_t new_calc_crc; - calc_14a_crc_lut((uint8_t *)&config, sizeof(config), (uint8_t *)&new_calc_crc); - if (new_calc_crc != m_config_crc) { // Before saving, make sure that the configuration has changed + if (config_did_change()) { // Before saving, make sure that the configuration has changed NRF_LOG_INFO("Save config start."); bool ret = fds_write_sync(FDS_SETTINGS_ID, FDS_SETTINGS_KEY, sizeof(config) / 4, (uint8_t *)&config); if (ret) { NRF_LOG_INFO("Save config success."); - m_config_crc = new_calc_crc; // store new CRC so we know that we've updated the configuration + update_config_crc(); } else { @@ -45,7 +100,7 @@ uint8_t settings_save_config(void) return STATUS_FLASH_WRITE_FAIL; } } else { - NRF_LOG_INFO("Config no change."); + NRF_LOG_INFO("Config did not change."); } return STATUS_DEVICE_SUCCESS; diff --git a/firmware/application/src/settings.h b/firmware/application/src/settings.h index b0dcadd..d8cf545 100644 --- a/firmware/application/src/settings.h +++ b/firmware/application/src/settings.h @@ -5,19 +5,27 @@ #include "utils.h" -#define SETTINGS_ANIMATION_FULL 0 -#define SETTINGS_ANIMATION_MINIMAL 1 -#define SETTINGS_ANIMATION_NONE 2 +#define SETTINGS_CURRENT_VERSION 1 +typedef enum { + SettingsAnimationModeFull = 0, + SettingsAnimationModeMinimal = 1, + SettingsAnimationModeNone = 2, +} settings_animation_mode_t; typedef struct ALIGN_U32 { uint16_t version; - uint16_t animation_config : 2; + uint8_t animation_config : 2; + uint16_t reserved0 : 14; + uint32_t reserved1; + uint32_t reserved2; } settings_data_t; +void settings_init_config(void); +void settings_migrate(void); void settings_load_config(void); uint8_t settings_save_config(void); -uint8_t settings_get_animation_config(); +uint8_t settings_get_animation_config(void); void settings_set_animation_config(uint8_t value); -#endif \ No newline at end of file +#endif diff --git a/software/script/chameleon_cli_main.py b/software/script/chameleon_cli_main.py index 212fa34..c3bc0aa 100755 --- a/software/script/chameleon_cli_main.py +++ b/software/script/chameleon_cli_main.py @@ -94,6 +94,7 @@ class ChameleonCLI: 'help': 'Manage wake-up and sleep animation mode' }, 'store': new_uint(chameleon_cli_unit.HWSettingsStore, "Store current settings to flash"), + 'reset': new_uint(chameleon_cli_unit.HWSettingsReset, "Reset settings to default values"), 'help': "Chameleon settings management" }, 'help': "hardware controller", diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index aec53f8..378c922 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -1032,3 +1032,15 @@ class HWSettingsStore(DeviceRequiredUnit): print(" - Store success @.@~") else: print(" - Store failed") + +class HWSettingsReset(DeviceRequiredUnit): + def args_parser(self) -> ArgumentParserNoExit or None: + return None + + def on_exec(self, args: argparse.Namespace): + print("Initializing settings...") + resp: chameleon_com.Response = self.cmd_standard.reset_settings() + if resp.status == chameleon_status.Device.STATUS_DEVICE_SUCCESS: + print(" - Reset success @.@~") + else: + print(" - Reset failed") diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index 924ff33..ab9e94a 100644 --- a/software/script/chameleon_cmd.py +++ b/software/script/chameleon_cmd.py @@ -21,8 +21,9 @@ DATA_CMD_GET_DEVICE_CHIP_ID = 1011 DATA_CMD_GET_DEVICE_ADDRESS = 1012 DATA_CMD_SAVE_SETTINGS = 1013 -DATA_CMD_SET_ANIMATION_MODE = 1014 -DATA_CMD_GET_ANIMATION_MODE = 1015 +DATA_CMD_RESET_SETTINGS = 1014 +DATA_CMD_SET_ANIMATION_MODE = 1015 +DATA_CMD_GET_ANIMATION_MODE = 1016 DATA_CMD_SCAN_14A_TAG = 2000 DATA_CMD_MF1_SUPPORT_DETECT = 2001 @@ -441,6 +442,12 @@ class BaseChameleonCMD: """ return self.device.send_cmd_sync(DATA_CMD_SET_ANIMATION_MODE, 0x00, bytearray([value])) + def reset_settings(self): + """ + Reset settings stored in flash memory + """ + return self.device.send_cmd_sync(DATA_CMD_RESET_SETTINGS, 0x00) + def store_settings(self): """ Store settings to flash memory