[FL-2744] SPI Mem Manager C port (#1860)

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Max Andreev
2023-02-06 17:03:29 +03:00
committed by GitHub
parent 52680fd14e
commit 9f279ac872
59 changed files with 5154 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
#include "spi_mem_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const spi_mem_on_enter_handlers[])(void*) = {
#include "spi_mem_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const spi_mem_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "spi_mem_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const spi_mem_on_exit_handlers[])(void* context) = {
#include "spi_mem_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers spi_mem_scene_handlers = {
.on_enter_handlers = spi_mem_on_enter_handlers,
.on_event_handlers = spi_mem_on_event_handlers,
.on_exit_handlers = spi_mem_on_exit_handlers,
.scene_num = SPIMemSceneNum,
};

View File

@@ -0,0 +1,29 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) SPIMemScene##id,
typedef enum {
#include "spi_mem_scene_config.h"
SPIMemSceneNum,
} SPIMemScene;
#undef ADD_SCENE
extern const SceneManagerHandlers spi_mem_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "spi_mem_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "spi_mem_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "spi_mem_scene_config.h"
#undef ADD_SCENE

View File

@@ -0,0 +1,42 @@
#include "../spi_mem_app_i.h"
#include "../lib/spi/spi_mem_chip.h"
#define SPI_MEM_VERSION_APP "0.1.0"
#define SPI_MEM_DEVELOPER "DrunkBatya"
#define SPI_MEM_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
#define SPI_MEM_NAME "\e#\e! SPI Mem Manager \e!\n"
#define SPI_MEM_BLANK_INV "\e#\e! \e!\n"
void spi_mem_scene_about_on_enter(void* context) {
SPIMemApp* app = context;
FuriString* tmp_string = furi_string_alloc();
widget_add_text_box_element(
app->widget, 0, 0, 128, 14, AlignCenter, AlignBottom, SPI_MEM_BLANK_INV, false);
widget_add_text_box_element(
app->widget, 0, 2, 128, 14, AlignCenter, AlignBottom, SPI_MEM_NAME, false);
furi_string_printf(tmp_string, "\e#%s\n", "Information");
furi_string_cat_printf(tmp_string, "Version: %s\n", SPI_MEM_VERSION_APP);
furi_string_cat_printf(tmp_string, "Developed by: %s\n", SPI_MEM_DEVELOPER);
furi_string_cat_printf(tmp_string, "Github: %s\n\n", SPI_MEM_GITHUB);
furi_string_cat_printf(tmp_string, "\e#%s\n", "Description");
furi_string_cat_printf(
tmp_string,
"SPI memory dumper\n"
"Originally written by Hedger, ghettorce and x893 at\n"
"Flipper Hackathon 2021\n\n");
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(tmp_string));
furi_string_free(tmp_string);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
}
bool spi_mem_scene_about_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void spi_mem_scene_about_on_exit(void* context) {
SPIMemApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,37 @@
#include "../spi_mem_app_i.h"
static void spi_mem_scene_chip_detect_callback(void* context, SPIMemCustomEventWorker event) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void spi_mem_scene_chip_detect_on_enter(void* context) {
SPIMemApp* app = context;
notification_message(app->notifications, &sequence_blink_start_yellow);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewDetect);
spi_mem_worker_start_thread(app->worker);
spi_mem_worker_chip_detect_start(
app->chip_info, &app->found_chips, app->worker, spi_mem_scene_chip_detect_callback, app);
}
bool spi_mem_scene_chip_detect_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == SPIMemCustomEventWorkerChipIdentified) {
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSelectVendor, 0);
scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectVendor);
} else if(event.event == SPIMemCustomEventWorkerChipUnknown) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetectFail);
}
}
return success;
}
void spi_mem_scene_chip_detect_on_exit(void* context) {
SPIMemApp* app = context;
spi_mem_worker_stop_thread(app->worker);
notification_message(app->notifications, &sequence_blink_stop);
popup_reset(app->popup);
}

View File

@@ -0,0 +1,57 @@
#include "../spi_mem_app_i.h"
#include "../lib/spi/spi_mem_chip.h"
static void spi_mem_scene_chip_detect_fail_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
SPIMemApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void spi_mem_scene_chip_detect_fail_on_enter(void* context) {
SPIMemApp* app = context;
FuriString* str = furi_string_alloc();
widget_add_button_element(
app->widget,
GuiButtonTypeCenter,
"Retry",
spi_mem_scene_chip_detect_fail_widget_callback,
app);
widget_add_string_element(
app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "Detected");
widget_add_string_element(
app->widget, 64, 20, AlignCenter, AlignBottom, FontPrimary, "unknown SPI chip");
furi_string_printf(str, "Vendor\nid: 0x%02X", spi_mem_chip_get_vendor_id(app->chip_info));
widget_add_string_multiline_element(
app->widget, 16, 44, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str));
furi_string_printf(str, "Type\nid: 0x%02X", spi_mem_chip_get_type_id(app->chip_info));
widget_add_string_multiline_element(
app->widget, 64, 44, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str));
furi_string_printf(str, "Capacity\nid: 0x%02X", spi_mem_chip_get_capacity_id(app->chip_info));
widget_add_string_multiline_element(
app->widget, 110, 44, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str));
furi_string_free(str);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
}
bool spi_mem_scene_chip_detect_fail_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SPIMemSceneStart);
} else if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == GuiButtonTypeCenter) {
scene_manager_previous_scene(app->scene_manager);
}
}
return success;
}
void spi_mem_scene_chip_detect_fail_on_exit(void* context) {
SPIMemApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,94 @@
#include "../spi_mem_app_i.h"
static void spi_mem_scene_chip_detected_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
SPIMemApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
static void spi_mem_scene_chip_detected_print_chip_info(Widget* widget, SPIMemChip* chip_info) {
FuriString* tmp_string = furi_string_alloc();
widget_add_string_element(
widget,
40,
12,
AlignLeft,
AlignTop,
FontSecondary,
spi_mem_chip_get_vendor_name(chip_info));
widget_add_string_element(
widget, 40, 20, AlignLeft, AlignTop, FontSecondary, spi_mem_chip_get_model_name(chip_info));
furi_string_printf(tmp_string, "Size: %zu KB", spi_mem_chip_get_size(chip_info) / 1024);
widget_add_string_element(
widget, 40, 28, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp_string));
furi_string_free(tmp_string);
}
static void spi_mem_scene_chip_detect_draw_next_button(SPIMemApp* app) {
FuriString* str = furi_string_alloc();
if(app->mode == SPIMemModeRead) furi_string_printf(str, "%s", "Read");
if(app->mode == SPIMemModeWrite) furi_string_printf(str, "%s", "Write");
if(app->mode == SPIMemModeErase) furi_string_printf(str, "%s", "Erase");
if(app->mode == SPIMemModeCompare) furi_string_printf(str, "%s", "Check");
widget_add_button_element(
app->widget,
GuiButtonTypeRight,
furi_string_get_cstr(str),
spi_mem_scene_chip_detected_widget_callback,
app);
furi_string_free(str);
}
static void spi_mem_scene_chip_detected_set_previous_scene(SPIMemApp* app) {
uint32_t scene = SPIMemSceneStart;
if(app->mode == SPIMemModeCompare || app->mode == SPIMemModeWrite)
scene = SPIMemSceneSavedFileMenu;
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
}
static void spi_mem_scene_chip_detected_set_next_scene(SPIMemApp* app) {
uint32_t scene = SPIMemSceneStart;
if(app->mode == SPIMemModeRead) scene = SPIMemSceneReadFilename;
if(app->mode == SPIMemModeWrite) scene = SPIMemSceneErase;
if(app->mode == SPIMemModeErase) scene = SPIMemSceneErase;
if(app->mode == SPIMemModeCompare) scene = SPIMemSceneVerify;
scene_manager_next_scene(app->scene_manager, scene);
}
void spi_mem_scene_chip_detected_on_enter(void* context) {
SPIMemApp* app = context;
widget_add_button_element(
app->widget, GuiButtonTypeLeft, "Retry", spi_mem_scene_chip_detected_widget_callback, app);
spi_mem_scene_chip_detect_draw_next_button(app);
widget_add_icon_element(app->widget, 0, 12, &I_Dip8_32x36);
widget_add_string_element(
app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "Detected SPI chip");
spi_mem_scene_chip_detected_print_chip_info(app->widget, app->chip_info);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
}
bool spi_mem_scene_chip_detected_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
spi_mem_scene_chip_detected_set_previous_scene(app);
} else if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, SPIMemSceneChipDetect);
} else if(event.event == GuiButtonTypeRight) {
spi_mem_scene_chip_detected_set_next_scene(app);
}
}
return success;
}
void spi_mem_scene_chip_detected_on_exit(void* context) {
SPIMemApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,52 @@
#include "../spi_mem_app_i.h"
static void
spi_mem_scene_chip_error_widget_callback(GuiButtonType result, InputType type, void* context) {
SPIMemApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void spi_mem_scene_chip_error_on_enter(void* context) {
SPIMemApp* app = context;
widget_add_button_element(
app->widget, GuiButtonTypeLeft, "Back", spi_mem_scene_chip_error_widget_callback, app);
widget_add_string_element(
app->widget, 85, 15, AlignCenter, AlignBottom, FontPrimary, "SPI chip error");
widget_add_string_multiline_element(
app->widget,
85,
52,
AlignCenter,
AlignBottom,
FontSecondary,
"Error while\ncommunicating\nwith chip");
widget_add_icon_element(app->widget, 5, 6, &I_Dip8_32x36);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
}
static void spi_mem_scene_chip_error_set_previous_scene(SPIMemApp* app) {
uint32_t scene = SPIMemSceneChipDetect;
if(app->mode == SPIMemModeRead || app->mode == SPIMemModeErase) scene = SPIMemSceneStart;
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
}
bool spi_mem_scene_chip_error_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
spi_mem_scene_chip_error_set_previous_scene(app);
} else if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == GuiButtonTypeLeft) {
spi_mem_scene_chip_error_set_previous_scene(app);
}
}
return success;
}
void spi_mem_scene_chip_error_on_exit(void* context) {
SPIMemApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,21 @@
ADD_SCENE(spi_mem, start, Start)
ADD_SCENE(spi_mem, chip_detect, ChipDetect)
ADD_SCENE(spi_mem, chip_detected, ChipDetected)
ADD_SCENE(spi_mem, chip_detect_fail, ChipDetectFail)
ADD_SCENE(spi_mem, select_file, SelectFile)
ADD_SCENE(spi_mem, saved_file_menu, SavedFileMenu)
ADD_SCENE(spi_mem, read, Read)
ADD_SCENE(spi_mem, read_filename, ReadFilename)
ADD_SCENE(spi_mem, delete_confirm, DeleteConfirm)
ADD_SCENE(spi_mem, success, Success)
ADD_SCENE(spi_mem, about, About)
ADD_SCENE(spi_mem, verify, Verify)
ADD_SCENE(spi_mem, file_info, FileInfo)
ADD_SCENE(spi_mem, erase, Erase)
ADD_SCENE(spi_mem, chip_error, ChipError)
ADD_SCENE(spi_mem, verify_error, VerifyError)
ADD_SCENE(spi_mem, write, Write)
ADD_SCENE(spi_mem, storage_error, StorageError)
ADD_SCENE(spi_mem, select_vendor, SelectVendor)
ADD_SCENE(spi_mem, select_model, SelectModel)
ADD_SCENE(spi_mem, wiring, Wiring)

View File

@@ -0,0 +1,62 @@
#include "../spi_mem_app_i.h"
#include "../spi_mem_files.h"
static void spi_mem_scene_delete_confirm_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
SPIMemApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void spi_mem_scene_delete_confirm_on_enter(void* context) {
SPIMemApp* app = context;
FuriString* file_name = furi_string_alloc();
FuriString* message = furi_string_alloc();
path_extract_filename(app->file_path, file_name, true);
furi_string_printf(message, "\e#Delete %s?\e#", furi_string_get_cstr(file_name));
widget_add_text_box_element(
app->widget, 0, 0, 128, 27, AlignCenter, AlignCenter, furi_string_get_cstr(message), true);
widget_add_button_element(
app->widget,
GuiButtonTypeLeft,
"Cancel",
spi_mem_scene_delete_confirm_widget_callback,
app);
widget_add_button_element(
app->widget,
GuiButtonTypeRight,
"Delete",
spi_mem_scene_delete_confirm_widget_callback,
app);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
furi_string_free(file_name);
furi_string_free(message);
}
bool spi_mem_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == GuiButtonTypeRight) {
app->mode = SPIMemModeDelete;
if(spi_mem_file_delete(app)) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneSuccess);
} else {
scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError);
}
} else if(event.event == GuiButtonTypeLeft) {
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, SPIMemSceneSavedFileMenu);
}
}
return success;
}
void spi_mem_scene_delete_confirm_on_exit(void* context) {
SPIMemApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,65 @@
#include "../spi_mem_app_i.h"
static void
spi_mem_scene_erase_widget_callback(GuiButtonType result, InputType type, void* context) {
SPIMemApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
static void spi_mem_scene_erase_callback(void* context, SPIMemCustomEventWorker event) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void spi_mem_scene_erase_on_enter(void* context) {
SPIMemApp* app = context;
widget_add_button_element(
app->widget, GuiButtonTypeLeft, "Cancel", spi_mem_scene_erase_widget_callback, app);
widget_add_string_element(
app->widget, 64, 15, AlignCenter, AlignBottom, FontPrimary, "Erasing SPI chip");
widget_add_string_element(
app->widget, 64, 27, AlignCenter, AlignBottom, FontSecondary, "Please be patient");
notification_message(app->notifications, &sequence_blink_start_magenta);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
spi_mem_worker_start_thread(app->worker);
spi_mem_worker_erase_start(app->chip_info, app->worker, spi_mem_scene_erase_callback, app);
}
static void spi_mem_scene_erase_set_previous_scene(SPIMemApp* app) {
uint32_t scene = SPIMemSceneStart;
if(app->mode == SPIMemModeWrite) scene = SPIMemSceneSavedFileMenu;
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
}
static void spi_mem_scene_erase_set_next_scene(SPIMemApp* app) {
uint32_t scene = SPIMemSceneSuccess;
if(app->mode == SPIMemModeWrite) scene = SPIMemSceneWrite;
scene_manager_next_scene(app->scene_manager, scene);
}
bool spi_mem_scene_erase_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
spi_mem_scene_erase_set_previous_scene(app);
} else if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(app->scene_manager);
} else if(event.event == SPIMemCustomEventWorkerDone) {
spi_mem_scene_erase_set_next_scene(app);
} else if(event.event == SPIMemCustomEventWorkerChipFail) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError);
}
}
return success;
}
void spi_mem_scene_erase_on_exit(void* context) {
SPIMemApp* app = context;
spi_mem_worker_stop_thread(app->worker);
notification_message(app->notifications, &sequence_blink_stop);
widget_reset(app->widget);
}

View File

@@ -0,0 +1,29 @@
#include "../spi_mem_app_i.h"
#include "../spi_mem_files.h"
void spi_mem_scene_file_info_on_enter(void* context) {
SPIMemApp* app = context;
FuriString* str = furi_string_alloc();
furi_string_printf(str, "Size: %zu KB", spi_mem_file_get_size(app) / 1024);
widget_add_string_element(
app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "File info");
widget_add_string_element(
app->widget, 64, 20, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str));
furi_string_free(str);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
}
bool spi_mem_scene_file_info_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, SPIMemSceneSavedFileMenu);
}
return success;
}
void spi_mem_scene_file_info_on_exit(void* context) {
SPIMemApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,57 @@
#include "../spi_mem_app_i.h"
#include "../spi_mem_files.h"
#include "../lib/spi/spi_mem_chip.h"
#include "../lib/spi/spi_mem_tools.h"
void spi_mem_scene_read_progress_view_result_callback(void* context) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventViewReadCancel);
}
static void spi_mem_scene_read_callback(void* context, SPIMemCustomEventWorker event) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void spi_mem_scene_read_on_enter(void* context) {
SPIMemApp* app = context;
spi_mem_view_progress_set_read_callback(
app->view_progress, spi_mem_scene_read_progress_view_result_callback, app);
notification_message(app->notifications, &sequence_blink_start_blue);
spi_mem_view_progress_set_chip_size(app->view_progress, spi_mem_chip_get_size(app->chip_info));
spi_mem_view_progress_set_block_size(
app->view_progress, spi_mem_tools_get_file_max_block_size(app->chip_info));
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewProgress);
spi_mem_worker_start_thread(app->worker);
spi_mem_worker_read_start(app->chip_info, app->worker, spi_mem_scene_read_callback, app);
}
bool spi_mem_scene_read_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
UNUSED(app);
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
} else if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == SPIMemCustomEventViewReadCancel) {
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, SPIMemSceneChipDetect);
} else if(event.event == SPIMemCustomEventWorkerBlockReaded) {
spi_mem_view_progress_inc_progress(app->view_progress);
} else if(event.event == SPIMemCustomEventWorkerDone) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneVerify);
} else if(event.event == SPIMemCustomEventWorkerChipFail) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError);
} else if(event.event == SPIMemCustomEventWorkerFileFail) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError);
}
}
return success;
}
void spi_mem_scene_read_on_exit(void* context) {
SPIMemApp* app = context;
spi_mem_worker_stop_thread(app->worker);
spi_mem_view_progress_reset(app->view_progress);
notification_message(app->notifications, &sequence_blink_stop);
}

View File

@@ -0,0 +1,46 @@
#include "../spi_mem_app_i.h"
#include "../spi_mem_files.h"
void spi_mem_scene_read_filename_view_result_callback(void* context) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventTextEditResult);
}
void spi_mem_scene_read_set_random_filename(SPIMemApp* app) {
if(furi_string_end_with(app->file_path, SPI_MEM_FILE_EXTENSION)) {
size_t filename_start = furi_string_search_rchar(app->file_path, '/');
furi_string_left(app->file_path, filename_start);
}
set_random_name(app->text_buffer, SPI_MEM_TEXT_BUFFER_SIZE);
}
void spi_mem_scene_read_filename_on_enter(void* context) {
SPIMemApp* app = context;
spi_mem_scene_read_set_random_filename(app);
text_input_set_header_text(app->text_input, "Name the dump");
text_input_set_result_callback(
app->text_input,
spi_mem_scene_read_filename_view_result_callback,
app,
app->text_buffer,
SPI_MEM_FILE_NAME_SIZE,
true);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewTextInput);
}
bool spi_mem_scene_read_filename_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
UNUSED(app);
bool success = false;
if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == SPIMemCustomEventTextEditResult) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneRead);
}
}
return success;
}
void spi_mem_scene_read_filename_on_exit(void* context) {
SPIMemApp* app = context;
text_input_reset(app->text_input);
}

View File

@@ -0,0 +1,76 @@
#include "../spi_mem_app_i.h"
typedef enum {
SPIMemSceneSavedFileMenuSubmenuIndexWrite,
SPIMemSceneSavedFileMenuSubmenuIndexCompare,
SPIMemSceneSavedFileMenuSubmenuIndexInfo,
SPIMemSceneSavedFileMenuSubmenuIndexDelete,
} SPIMemSceneSavedFileMenuSubmenuIndex;
static void spi_mem_scene_saved_file_menu_submenu_callback(void* context, uint32_t index) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void spi_mem_scene_saved_file_menu_on_enter(void* context) {
SPIMemApp* app = context;
submenu_add_item(
app->submenu,
"Write",
SPIMemSceneSavedFileMenuSubmenuIndexWrite,
spi_mem_scene_saved_file_menu_submenu_callback,
app);
submenu_add_item(
app->submenu,
"Compare",
SPIMemSceneSavedFileMenuSubmenuIndexCompare,
spi_mem_scene_saved_file_menu_submenu_callback,
app);
submenu_add_item(
app->submenu,
"Info",
SPIMemSceneSavedFileMenuSubmenuIndexInfo,
spi_mem_scene_saved_file_menu_submenu_callback,
app);
submenu_add_item(
app->submenu,
"Delete",
SPIMemSceneSavedFileMenuSubmenuIndexDelete,
spi_mem_scene_saved_file_menu_submenu_callback,
app);
submenu_set_selected_item(
app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneSavedFileMenu));
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu);
}
bool spi_mem_scene_saved_file_menu_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSavedFileMenu, event.event);
if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexWrite) {
app->mode = SPIMemModeWrite;
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect);
success = true;
}
if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexCompare) {
app->mode = SPIMemModeCompare;
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect);
success = true;
}
if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexDelete) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneDeleteConfirm);
success = true;
}
if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexInfo) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneFileInfo);
success = true;
}
}
return success;
}
void spi_mem_scene_saved_file_menu_on_exit(void* context) {
SPIMemApp* app = context;
submenu_reset(app->submenu);
}

View File

@@ -0,0 +1,22 @@
#include "../spi_mem_app_i.h"
#include "../spi_mem_files.h"
void spi_mem_scene_select_file_on_enter(void* context) {
SPIMemApp* app = context;
if(spi_mem_file_select(app)) {
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSavedFileMenu, 0);
scene_manager_next_scene(app->scene_manager, SPIMemSceneSavedFileMenu);
} else {
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SPIMemSceneStart);
}
}
bool spi_mem_scene_select_file_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void spi_mem_scene_select_file_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,45 @@
#include "../spi_mem_app_i.h"
static void spi_mem_scene_select_model_submenu_callback(void* context, uint32_t index) {
SPIMemApp* app = context;
spi_mem_chip_copy_chip_info(app->chip_info, *found_chips_get(app->found_chips, index));
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void spi_mem_scene_select_model_on_enter(void* context) {
SPIMemApp* app = context;
size_t models_on_vendor = 0;
for(size_t index = 0; index < found_chips_size(app->found_chips); index++) {
if(spi_mem_chip_get_vendor_enum(*found_chips_get(app->found_chips, index)) !=
app->chip_vendor_enum)
continue;
submenu_add_item(
app->submenu,
spi_mem_chip_get_model_name(*found_chips_get(app->found_chips, index)),
index,
spi_mem_scene_select_model_submenu_callback,
app);
models_on_vendor++;
}
if(models_on_vendor == 1) spi_mem_scene_select_model_submenu_callback(context, 0);
submenu_set_header(app->submenu, "Choose chip model");
submenu_set_selected_item(
app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneSelectVendor));
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu);
}
bool spi_mem_scene_select_model_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSelectVendor, event.event);
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetected);
success = true;
}
return success;
}
void spi_mem_scene_select_model_on_exit(void* context) {
SPIMemApp* app = context;
submenu_reset(app->submenu);
}

View File

@@ -0,0 +1,70 @@
#include "../spi_mem_app_i.h"
#include <m-array.h>
#include <m-algo.h>
ARRAY_DEF(vendors, uint32_t)
ALGO_DEF(vendors, ARRAY_OPLIST(vendors))
static void spi_mem_scene_select_vendor_submenu_callback(void* context, uint32_t index) {
SPIMemApp* app = context;
app->chip_vendor_enum = index;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
static void spi_mem_scene_select_vendor_sort_vendors(SPIMemApp* app, vendors_t vendors_arr) {
for(size_t index = 0; index < found_chips_size(app->found_chips); index++) {
vendors_push_back(
vendors_arr, spi_mem_chip_get_vendor_enum(*found_chips_get(app->found_chips, index)));
}
vendors_uniq(vendors_arr);
}
void spi_mem_scene_select_vendor_on_enter(void* context) {
SPIMemApp* app = context;
vendors_t vendors_arr;
vendors_init(vendors_arr);
spi_mem_scene_select_vendor_sort_vendors(app, vendors_arr);
size_t vendors_arr_size = vendors_size(vendors_arr);
if(vendors_arr_size == 1)
spi_mem_scene_select_vendor_submenu_callback(context, *vendors_get(vendors_arr, 0));
for(size_t index = 0; index < vendors_arr_size; index++) {
uint32_t vendor_enum = *vendors_get(vendors_arr, index);
submenu_add_item(
app->submenu,
spi_mem_chip_get_vendor_name_by_enum(vendor_enum),
vendor_enum,
spi_mem_scene_select_vendor_submenu_callback,
app);
}
vendors_clear(vendors_arr);
submenu_set_header(app->submenu, "Choose chip vendor");
submenu_set_selected_item(
app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneSelectVendor));
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu);
}
static void spi_mem_scene_select_vendor_set_previous_scene(SPIMemApp* app) {
uint32_t scene = SPIMemSceneStart;
if(app->mode == SPIMemModeCompare || app->mode == SPIMemModeWrite)
scene = SPIMemSceneSavedFileMenu;
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
}
bool spi_mem_scene_select_vendor_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
spi_mem_scene_select_vendor_set_previous_scene(app);
} else if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSelectVendor, event.event);
scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectModel);
success = true;
}
return success;
}
void spi_mem_scene_select_vendor_on_exit(void* context) {
SPIMemApp* app = context;
submenu_reset(app->submenu);
}

View File

@@ -0,0 +1,84 @@
#include "../spi_mem_app_i.h"
typedef enum {
SPIMemSceneStartSubmenuIndexRead,
SPIMemSceneStartSubmenuIndexSaved,
SPIMemSceneStartSubmenuIndexErase,
SPIMemSceneStartSubmenuIndexWiring,
SPIMemSceneStartSubmenuIndexAbout
} SPIMemSceneStartSubmenuIndex;
static void spi_mem_scene_start_submenu_callback(void* context, uint32_t index) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void spi_mem_scene_start_on_enter(void* context) {
SPIMemApp* app = context;
submenu_add_item(
app->submenu,
"Read",
SPIMemSceneStartSubmenuIndexRead,
spi_mem_scene_start_submenu_callback,
app);
submenu_add_item(
app->submenu,
"Saved",
SPIMemSceneStartSubmenuIndexSaved,
spi_mem_scene_start_submenu_callback,
app);
submenu_add_item(
app->submenu,
"Erase",
SPIMemSceneStartSubmenuIndexErase,
spi_mem_scene_start_submenu_callback,
app);
submenu_add_item(
app->submenu,
"Wiring",
SPIMemSceneStartSubmenuIndexWiring,
spi_mem_scene_start_submenu_callback,
app);
submenu_add_item(
app->submenu,
"About",
SPIMemSceneStartSubmenuIndexAbout,
spi_mem_scene_start_submenu_callback,
app);
submenu_set_selected_item(
app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneStart));
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu);
}
bool spi_mem_scene_start_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneStart, event.event);
if(event.event == SPIMemSceneStartSubmenuIndexRead) {
app->mode = SPIMemModeRead;
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect);
success = true;
} else if(event.event == SPIMemSceneStartSubmenuIndexSaved) {
furi_string_set(app->file_path, SPI_MEM_FILE_FOLDER);
scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectFile);
success = true;
} else if(event.event == SPIMemSceneStartSubmenuIndexErase) {
app->mode = SPIMemModeErase;
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect);
success = true;
} else if(event.event == SPIMemSceneStartSubmenuIndexWiring) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneWiring);
success = true;
} else if(event.event == SPIMemSceneStartSubmenuIndexAbout) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneAbout);
success = true;
}
}
return success;
}
void spi_mem_scene_start_on_exit(void* context) {
SPIMemApp* app = context;
submenu_reset(app->submenu);
}

View File

@@ -0,0 +1,56 @@
#include "../spi_mem_app_i.h"
static void spi_mem_scene_storage_error_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
SPIMemApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void spi_mem_scene_storage_error_on_enter(void* context) {
SPIMemApp* app = context;
widget_add_button_element(
app->widget, GuiButtonTypeLeft, "Back", spi_mem_scene_storage_error_widget_callback, app);
widget_add_string_element(
app->widget, 85, 15, AlignCenter, AlignBottom, FontPrimary, "Storage error");
widget_add_string_multiline_element(
app->widget,
85,
52,
AlignCenter,
AlignBottom,
FontSecondary,
"Error while\nworking with\nfilesystem");
widget_add_icon_element(app->widget, 5, 6, &I_SDQuestion_35x43);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
}
static void spi_mem_scene_storage_error_set_previous_scene(SPIMemApp* app) {
uint32_t scene = SPIMemSceneChipDetect;
if(app->mode == SPIMemModeRead) scene = SPIMemSceneStart;
if(app->mode == SPIMemModeErase) scene = SPIMemSceneStart;
if(app->mode == SPIMemModeDelete) scene = SPIMemSceneStart;
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
}
bool spi_mem_scene_storage_error_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
spi_mem_scene_storage_error_set_previous_scene(app);
} else if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == GuiButtonTypeLeft) {
spi_mem_scene_storage_error_set_previous_scene(app);
}
}
return success;
}
void spi_mem_scene_storage_error_on_exit(void* context) {
SPIMemApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,40 @@
#include "../spi_mem_app_i.h"
static void spi_mem_scene_success_popup_callback(void* context) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventPopupBack);
}
void spi_mem_scene_success_on_enter(void* context) {
SPIMemApp* app = context;
popup_set_icon(app->popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(app->popup, "Success!", 5, 7, AlignLeft, AlignTop);
popup_set_callback(app->popup, spi_mem_scene_success_popup_callback);
popup_set_context(app->popup, app);
popup_set_timeout(app->popup, 1500);
popup_enable_timeout(app->popup);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewPopup);
}
static void spi_mem_scene_success_set_previous_scene(SPIMemApp* app) {
uint32_t scene = SPIMemSceneSelectFile;
if(app->mode == SPIMemModeErase) scene = SPIMemSceneStart;
scene_manager_search_and_switch_to_another_scene(app->scene_manager, scene);
}
bool spi_mem_scene_success_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == SPIMemCustomEventPopupBack) {
spi_mem_scene_success_set_previous_scene(app);
}
}
return success;
}
void spi_mem_scene_success_on_exit(void* context) {
SPIMemApp* app = context;
popup_reset(app->popup);
}

View File

@@ -0,0 +1,59 @@
#include "../spi_mem_app_i.h"
#include "../spi_mem_files.h"
#include "../lib/spi/spi_mem_chip.h"
#include "../lib/spi/spi_mem_tools.h"
void spi_mem_scene_verify_view_result_callback(void* context) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventViewVerifySkip);
}
static void spi_mem_scene_verify_callback(void* context, SPIMemCustomEventWorker event) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void spi_mem_scene_verify_on_enter(void* context) {
SPIMemApp* app = context;
spi_mem_view_progress_set_verify_callback(
app->view_progress, spi_mem_scene_verify_view_result_callback, app);
notification_message(app->notifications, &sequence_blink_start_cyan);
spi_mem_view_progress_set_chip_size(app->view_progress, spi_mem_chip_get_size(app->chip_info));
spi_mem_view_progress_set_file_size(app->view_progress, spi_mem_file_get_size(app));
spi_mem_view_progress_set_block_size(
app->view_progress, spi_mem_tools_get_file_max_block_size(app->chip_info));
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewProgress);
spi_mem_worker_start_thread(app->worker);
spi_mem_worker_verify_start(app->chip_info, app->worker, spi_mem_scene_verify_callback, app);
}
bool spi_mem_scene_verify_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
UNUSED(app);
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
} else if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == SPIMemCustomEventViewVerifySkip) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneSuccess);
} else if(event.event == SPIMemCustomEventWorkerBlockReaded) {
spi_mem_view_progress_inc_progress(app->view_progress);
} else if(event.event == SPIMemCustomEventWorkerChipFail) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError);
} else if(event.event == SPIMemCustomEventWorkerFileFail) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError);
} else if(event.event == SPIMemCustomEventWorkerDone) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneSuccess);
} else if(event.event == SPIMemCustomEventWorkerVerifyFail) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneVerifyError);
}
}
return success;
}
void spi_mem_scene_verify_on_exit(void* context) {
SPIMemApp* app = context;
spi_mem_worker_stop_thread(app->worker);
spi_mem_view_progress_reset(app->view_progress);
notification_message(app->notifications, &sequence_blink_stop);
}

View File

@@ -0,0 +1,43 @@
#include "../spi_mem_app_i.h"
static void spi_mem_scene_verify_error_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
SPIMemApp* app = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(app->view_dispatcher, result);
}
}
void spi_mem_scene_verify_error_on_enter(void* context) {
SPIMemApp* app = context;
widget_add_button_element(
app->widget, GuiButtonTypeLeft, "Back", spi_mem_scene_verify_error_widget_callback, app);
widget_add_string_element(
app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "Verification error");
widget_add_string_element(
app->widget, 64, 21, AlignCenter, AlignBottom, FontSecondary, "Data mismatch");
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
}
bool spi_mem_scene_verify_error_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, SPIMemSceneChipDetect);
} else if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, SPIMemSceneChipDetect);
}
}
return success;
}
void spi_mem_scene_verify_error_on_exit(void* context) {
SPIMemApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,18 @@
#include "../spi_mem_app_i.h"
#include "../lib/spi/spi_mem_chip.h"
void spi_mem_scene_wiring_on_enter(void* context) {
SPIMemApp* app = context;
widget_add_icon_element(app->widget, 0, 0, &I_Wiring_SPI_128x64);
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
}
bool spi_mem_scene_wiring_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void spi_mem_scene_wiring_on_exit(void* context) {
SPIMemApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,58 @@
#include "../spi_mem_app_i.h"
#include "../spi_mem_files.h"
#include "../lib/spi/spi_mem_chip.h"
#include "../lib/spi/spi_mem_tools.h"
void spi_mem_scene_write_progress_view_result_callback(void* context) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventViewReadCancel);
}
static void spi_mem_scene_write_callback(void* context, SPIMemCustomEventWorker event) {
SPIMemApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void spi_mem_scene_write_on_enter(void* context) {
SPIMemApp* app = context;
spi_mem_view_progress_set_write_callback(
app->view_progress, spi_mem_scene_write_progress_view_result_callback, app);
notification_message(app->notifications, &sequence_blink_start_cyan);
spi_mem_view_progress_set_chip_size(app->view_progress, spi_mem_chip_get_size(app->chip_info));
spi_mem_view_progress_set_file_size(app->view_progress, spi_mem_file_get_size(app));
spi_mem_view_progress_set_block_size(
app->view_progress, spi_mem_tools_get_file_max_block_size(app->chip_info));
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewProgress);
spi_mem_worker_start_thread(app->worker);
spi_mem_worker_write_start(app->chip_info, app->worker, spi_mem_scene_write_callback, app);
}
bool spi_mem_scene_write_on_event(void* context, SceneManagerEvent event) {
SPIMemApp* app = context;
UNUSED(app);
bool success = false;
if(event.type == SceneManagerEventTypeBack) {
success = true;
} else if(event.type == SceneManagerEventTypeCustom) {
success = true;
if(event.event == SPIMemCustomEventViewReadCancel) {
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, SPIMemSceneChipDetect);
} else if(event.event == SPIMemCustomEventWorkerBlockReaded) {
spi_mem_view_progress_inc_progress(app->view_progress);
} else if(event.event == SPIMemCustomEventWorkerDone) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneVerify);
} else if(event.event == SPIMemCustomEventWorkerChipFail) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError);
} else if(event.event == SPIMemCustomEventWorkerFileFail) {
scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError);
}
}
return success;
}
void spi_mem_scene_write_on_exit(void* context) {
SPIMemApp* app = context;
spi_mem_worker_stop_thread(app->worker);
spi_mem_view_progress_reset(app->view_progress);
notification_message(app->notifications, &sequence_blink_stop);
}