[FL-3377] Update error code descriptions (#2875)

* updater: added update error code descriptions
* updater: separate ram/flash messages
* updater: extra pre-update checks
* updater: fixed string comparison
* updater: Additional logging

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
hedger 2023-07-14 16:45:16 +03:00 committed by GitHub
parent af64ae0e40
commit f2324e4d1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 238 additions and 36 deletions

View file

@ -19,7 +19,7 @@ static const char* update_task_stage_descr[] = {
[UpdateTaskStageRadioErase] = "Uninstalling radio FW",
[UpdateTaskStageRadioWrite] = "Writing radio FW",
[UpdateTaskStageRadioInstall] = "Installing radio FW",
[UpdateTaskStageRadioBusy] = "Radio is updating",
[UpdateTaskStageRadioBusy] = "Core 2 busy",
[UpdateTaskStageOBValidation] = "Validating opt. bytes",
[UpdateTaskStageLfsBackup] = "Backing up LFS",
[UpdateTaskStageLfsRestore] = "Restoring LFS",
@ -30,6 +30,191 @@ static const char* update_task_stage_descr[] = {
[UpdateTaskStageOBError] = "OB, report",
};
static const struct {
UpdateTaskStage stage;
uint8_t percent_min, percent_max;
const char* descr;
} update_task_error_detail[] = {
{
.stage = UpdateTaskStageReadManifest,
.percent_min = 0,
.percent_max = 13,
.descr = "Wrong Updater HW",
},
{
.stage = UpdateTaskStageReadManifest,
.percent_min = 14,
.percent_max = 20,
.descr = "Manifest pointer error",
},
{
.stage = UpdateTaskStageReadManifest,
.percent_min = 21,
.percent_max = 30,
.descr = "Manifest load error",
},
{
.stage = UpdateTaskStageReadManifest,
.percent_min = 31,
.percent_max = 40,
.descr = "Wrong package version",
},
{
.stage = UpdateTaskStageReadManifest,
.percent_min = 41,
.percent_max = 50,
.descr = "HW Target mismatch",
},
{
.stage = UpdateTaskStageReadManifest,
.percent_min = 51,
.percent_max = 60,
.descr = "No DFU file",
},
{
.stage = UpdateTaskStageReadManifest,
.percent_min = 61,
.percent_max = 80,
.descr = "No Radio file",
},
#ifndef FURI_RAM_EXEC
{
.stage = UpdateTaskStageLfsBackup,
.percent_min = 0,
.percent_max = 100,
.descr = "FS R/W error",
},
#else
{
.stage = UpdateTaskStageRadioImageValidate,
.percent_min = 0,
.percent_max = 98,
.descr = "FS Read error",
},
{
.stage = UpdateTaskStageRadioImageValidate,
.percent_min = 99,
.percent_max = 100,
.descr = "CRC mismatch",
},
{
.stage = UpdateTaskStageRadioErase,
.percent_min = 0,
.percent_max = 30,
.descr = "Stack remove: cmd error",
},
{
.stage = UpdateTaskStageRadioErase,
.percent_min = 31,
.percent_max = 100,
.descr = "Stack remove: wait failed",
},
{
.stage = UpdateTaskStageRadioWrite,
.percent_min = 0,
.percent_max = 100,
.descr = "Stack write: error",
},
{
.stage = UpdateTaskStageRadioInstall,
.percent_min = 0,
.percent_max = 10,
.descr = "Stack install: cmd error",
},
{
.stage = UpdateTaskStageRadioInstall,
.percent_min = 11,
.percent_max = 100,
.descr = "Stack install: wait failed",
},
{
.stage = UpdateTaskStageRadioBusy,
.percent_min = 0,
.percent_max = 10,
.descr = "Failed to start C2",
},
{
.stage = UpdateTaskStageRadioBusy,
.percent_min = 11,
.percent_max = 20,
.descr = "C2 FUS swich failed",
},
{
.stage = UpdateTaskStageRadioBusy,
.percent_min = 21,
.percent_max = 30,
.descr = "FUS operation failed",
},
{
.stage = UpdateTaskStageRadioBusy,
.percent_min = 31,
.percent_max = 100,
.descr = "C2 Stach switch failed",
},
{
.stage = UpdateTaskStageOBValidation,
.percent_min = 0,
.percent_max = 100,
.descr = "Uncorr. value mismatch",
},
{
.stage = UpdateTaskStageValidateDFUImage,
.percent_min = 0,
.percent_max = 1,
.descr = "Failed to open DFU file",
},
{
.stage = UpdateTaskStageValidateDFUImage,
.percent_min = 1,
.percent_max = 97,
.descr = "DFU file read error",
},
{
.stage = UpdateTaskStageValidateDFUImage,
.percent_min = 98,
.percent_max = 100,
.descr = "DFU file CRC mismatch",
},
{
.stage = UpdateTaskStageFlashWrite,
.percent_min = 0,
.percent_max = 100,
.descr = "Flash write error",
},
{
.stage = UpdateTaskStageFlashValidate,
.percent_min = 0,
.percent_max = 100,
.descr = "Flash compare error",
},
#endif
#ifndef FURI_RAM_EXEC
{
.stage = UpdateTaskStageLfsRestore,
.percent_min = 0,
.percent_max = 100,
.descr = "LFS I/O error",
},
{
.stage = UpdateTaskStageResourcesUpdate,
.percent_min = 0,
.percent_max = 100,
.descr = "SD card I/O error",
},
#endif
};
static const char* update_task_get_error_message(UpdateTaskStage stage, uint8_t percent) {
for(size_t i = 0; i < COUNT_OF(update_task_error_detail); i++) {
if(update_task_error_detail[i].stage == stage &&
percent >= update_task_error_detail[i].percent_min &&
percent <= update_task_error_detail[i].percent_max) {
return update_task_error_detail[i].descr;
}
}
return "Unknown error";
}
typedef struct {
UpdateTaskStageGroup group;
uint8_t weight;
@ -111,8 +296,9 @@ void update_task_set_progress(UpdateTask* update_task, UpdateTaskStage stage, ui
if(stage >= UpdateTaskStageError) {
furi_string_printf(
update_task->state.status,
"%s #[%d-%d]",
update_task_stage_descr[stage],
"%s\n#[%d-%d]",
update_task_get_error_message(
update_task->state.stage, update_task->state.stage_progress),
update_task->state.stage,
update_task->state.stage_progress);
} else {

View file

@ -24,3 +24,8 @@ bool update_task_open_file(UpdateTask* update_task, FuriString* filename);
int32_t update_task_worker_flash_writer(void* context);
int32_t update_task_worker_backup_restore(void* context);
#define CHECK_RESULT(x) \
if(!(x)) { \
break; \
}

View file

@ -15,11 +15,6 @@
#define TAG "UpdWorkerBackup"
#define CHECK_RESULT(x) \
if(!(x)) { \
break; \
}
static bool update_task_pre_update(UpdateTask* update_task) {
bool success = false;
FuriString* backup_file_path;

View file

@ -13,11 +13,6 @@
#define TAG "UpdWorkerRAM"
#define CHECK_RESULT(x) \
if(!(x)) { \
break; \
}
#define STM_DFU_VENDOR_ID 0x0483
#define STM_DFU_PRODUCT_ID 0xDF11
/* Written into DFU file by build pipeline */
@ -137,7 +132,7 @@ static bool update_task_write_stack_data(UpdateTask* update_task) {
}
static void update_task_wait_for_restart(UpdateTask* update_task) {
update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 10);
update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 70);
furi_delay_ms(C2_MODE_SWITCH_TIMEOUT);
furi_crash("C2 timeout");
}
@ -153,12 +148,12 @@ static bool update_task_write_stack(UpdateTask* update_task) {
manifest->radio_crc);
CHECK_RESULT(update_task_write_stack_data(update_task));
update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 0);
update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 10);
CHECK_RESULT(
ble_glue_fus_stack_install(manifest->radio_address, 0) != BleGlueCommandResultError);
update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 80);
update_task_set_progress(update_task, UpdateTaskStageProgress, 80);
CHECK_RESULT(ble_glue_fus_wait_operation() == BleGlueCommandResultOK);
update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 100);
update_task_set_progress(update_task, UpdateTaskStageProgress, 100);
/* ...system will restart here. */
update_task_wait_for_restart(update_task);
} while(false);
@ -170,9 +165,9 @@ static bool update_task_remove_stack(UpdateTask* update_task) {
FURI_LOG_W(TAG, "Removing stack");
update_task_set_progress(update_task, UpdateTaskStageRadioErase, 30);
CHECK_RESULT(ble_glue_fus_stack_delete() != BleGlueCommandResultError);
update_task_set_progress(update_task, UpdateTaskStageRadioErase, 80);
update_task_set_progress(update_task, UpdateTaskStageProgress, 80);
CHECK_RESULT(ble_glue_fus_wait_operation() == BleGlueCommandResultOK);
update_task_set_progress(update_task, UpdateTaskStageRadioErase, 100);
update_task_set_progress(update_task, UpdateTaskStageProgress, 100);
/* ...system will restart here. */
update_task_wait_for_restart(update_task);
} while(false);
@ -180,6 +175,7 @@ static bool update_task_remove_stack(UpdateTask* update_task) {
}
static bool update_task_manage_radiostack(UpdateTask* update_task) {
update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 10);
bool success = false;
do {
CHECK_RESULT(ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT));
@ -208,15 +204,17 @@ static bool update_task_manage_radiostack(UpdateTask* update_task) {
/* Version or type mismatch. Let's boot to FUS and start updating. */
FURI_LOG_W(TAG, "Restarting to FUS");
furi_hal_rtc_set_flag(FuriHalRtcFlagC2Update);
update_task_set_progress(update_task, UpdateTaskStageProgress, 20);
CHECK_RESULT(furi_hal_bt_ensure_c2_mode(BleGlueC2ModeFUS));
/* ...system will restart here. */
update_task_wait_for_restart(update_task);
}
} else if(c2_state->mode == BleGlueC2ModeFUS) {
/* OK, we're in FUS mode. */
update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 10);
FURI_LOG_W(TAG, "Waiting for FUS to settle");
ble_glue_fus_wait_operation();
update_task_set_progress(update_task, UpdateTaskStageProgress, 30);
CHECK_RESULT(ble_glue_fus_wait_operation() == BleGlueCommandResultOK);
if(stack_version_match) {
/* We can't check StackType with FUS, but partial version matches */
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagC2Update)) {
@ -230,7 +228,7 @@ static bool update_task_manage_radiostack(UpdateTask* update_task) {
/* We might just had the stack installed.
* Let's start it up to check its version */
FURI_LOG_W(TAG, "Starting stack to check full version");
update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 40);
update_task_set_progress(update_task, UpdateTaskStageProgress, 50);
CHECK_RESULT(furi_hal_bt_ensure_c2_mode(BleGlueC2ModeStack));
/* ...system will restart here. */
update_task_wait_for_restart(update_task);

View file

@ -81,16 +81,17 @@ static void updater_main_draw_callback(Canvas* canvas, void* _model) {
canvas_set_font(canvas, FontPrimary);
if(model->failed) {
canvas_draw_str_aligned(canvas, 42, 16, AlignLeft, AlignTop, "Update Failed!");
canvas_draw_icon(canvas, 2, 22, &I_Warning_30x23);
canvas_draw_str_aligned(canvas, 40, 9, AlignLeft, AlignTop, "Update Failed!");
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas, 42, 32, AlignLeft, AlignTop, furi_string_get_cstr(model->status));
canvas_draw_icon(canvas, 7, 16, &I_Warning_30x23);
elements_multiline_text_aligned(
canvas, 75, 26, AlignCenter, AlignTop, furi_string_get_cstr(model->status));
canvas_draw_str_aligned(
canvas, 18, 51, AlignLeft, AlignTop, "to retry, hold to abort");
canvas_draw_icon(canvas, 7, 50, &I_Ok_btn_9x9);
canvas_draw_icon(canvas, 75, 51, &I_Pin_back_arrow_10x8);
canvas, 18, 55, AlignLeft, AlignTop, "to retry, hold to abort");
canvas_draw_icon(canvas, 7, 54, &I_Ok_btn_9x9);
canvas_draw_icon(canvas, 75, 55, &I_Pin_back_arrow_10x8);
} else {
canvas_draw_str_aligned(canvas, 55, 14, AlignLeft, AlignTop, "UPDATING");
canvas_set_font(canvas, FontSecondary);

View file

@ -87,9 +87,12 @@ Even if something goes wrong, updater allows you to retry failed operations and
| Uninstalling radio FW | **4** | **0** | SHCI Delete command error |
| | | **80** | Error awaiting command status |
| Writing radio FW | **5** | **0-100** | Block read/write error |
| Installing radio FW | **6** | **0** | SHCI Install command error |
| Installing radio FW | **6** | **10** | SHCI Install command error |
| | | **80** | Error awaiting command status |
| Radio is updating | **7** | **10** | Error waiting for operation completion |
| Core2 is busy | **7** | **10** | Couldn't start C2 |
| | | **20** | Failed to switch C2 to FUS mode |
| | | **30** | Error in FUS operation |
| | | **50** | Failed to switch C2 to stack mode |
| Validating opt. bytes | **8** | **yy** | Option byte code |
| Checking DFU file | **9** | **0** | Error opening DFU file |
| | | **1-98** | Error reading DFU file |

View file

@ -20,7 +20,8 @@ static const char* update_prepare_result_descr[] = {
[UpdatePrepareResultManifestInvalid] = "Invalid manifest data",
[UpdatePrepareResultStageMissing] = "Missing Stage2 loader",
[UpdatePrepareResultStageIntegrityError] = "Corrupted Stage2 loader",
[UpdatePrepareResultManifestPointerError] = "Failed to create update pointer file",
[UpdatePrepareResultManifestPointerCreateError] = "Failed to create update pointer file",
[UpdatePrepareResultManifestPointerCheckError] = "Update pointer file error (corrupted FS?)",
[UpdatePrepareResultTargetMismatch] = "Hardware target mismatch",
[UpdatePrepareResultOutdatedManifestVersion] = "Update package is too old",
[UpdatePrepareResultIntFull] = "Need more free space in internal storage",
@ -142,8 +143,8 @@ UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) {
File* file = storage_file_alloc(storage);
uint64_t free_int_space;
FuriString* stage_path;
stage_path = furi_string_alloc();
FuriString* stage_path = furi_string_alloc();
FuriString* manifest_path_check = furi_string_alloc();
do {
if((storage_common_fs_info(storage, STORAGE_INT_PATH_PREFIX, NULL, &free_int_space) !=
FSE_OK) ||
@ -188,7 +189,18 @@ UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) {
}
if(!update_operation_persist_manifest_path(storage, manifest_file_path)) {
result = UpdatePrepareResultManifestPointerError;
result = UpdatePrepareResultManifestPointerCreateError;
break;
}
if(!update_operation_get_current_package_manifest_path(storage, manifest_path_check) ||
(furi_string_cmpi_str(manifest_path_check, manifest_file_path) != 0)) {
FURI_LOG_E(
"update",
"Manifest pointer check failed: '%s' != '%s'",
furi_string_get_cstr(manifest_path_check),
manifest_file_path);
result = UpdatePrepareResultManifestPointerCheckError;
break;
}
@ -197,6 +209,7 @@ UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) {
} while(false);
furi_string_free(stage_path);
furi_string_free(manifest_path_check);
storage_file_free(file);
update_manifest_free(manifest);

View file

@ -28,7 +28,8 @@ typedef enum {
UpdatePrepareResultManifestInvalid,
UpdatePrepareResultStageMissing,
UpdatePrepareResultStageIntegrityError,
UpdatePrepareResultManifestPointerError,
UpdatePrepareResultManifestPointerCreateError,
UpdatePrepareResultManifestPointerCheckError,
UpdatePrepareResultTargetMismatch,
UpdatePrepareResultOutdatedManifestVersion,
UpdatePrepareResultIntFull,