Skip to content

Commit

Permalink
mag_device overhaul, file loading
Browse files Browse the repository at this point in the history
File loading working
Some mag.c functions destined for deprecation
Misc small changes
Under construction placeholder scene
  • Loading branch information
zacharyweiss committed Dec 30, 2022
1 parent 0187d20 commit 8f642df
Show file tree
Hide file tree
Showing 16 changed files with 474 additions and 84 deletions.
4 changes: 2 additions & 2 deletions application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ App(
provides=[],
stack_size=2 * 1024,
order=20,
fap_icon="mag_10px.png",
fap_icon="icons/mag_10px.png",
fap_category="Tools",
fap_icon_assets="icons",
)
)
52 changes: 39 additions & 13 deletions mag.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "mag_i.h"

#define TAG "Mag"

static bool mag_debug_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
Mag* mag = context;
Expand Down Expand Up @@ -30,6 +32,8 @@ static Mag* mag_alloc() {
view_dispatcher_set_navigation_event_callback(
mag->view_dispatcher, mag_debug_back_event_callback);

mag->mag_dev = mag_device_alloc();

// Open GUI record
mag->gui = furi_record_open(RECORD_GUI);

Expand All @@ -49,6 +53,10 @@ static Mag* mag_alloc() {
mag->popup = popup_alloc();
view_dispatcher_add_view(mag->view_dispatcher, MagViewPopup, popup_get_view(mag->popup));

// Loading
mag->loading = loading_alloc();
view_dispatcher_add_view(mag->view_dispatcher, MagViewLoading, loading_get_view(mag->loading));

// Widget
mag->widget = widget_alloc();
view_dispatcher_add_view(mag->view_dispatcher, MagViewWidget, widget_get_view(mag->widget));
Expand All @@ -58,11 +66,6 @@ static Mag* mag_alloc() {
view_dispatcher_add_view(
mag->view_dispatcher, MagViewTextInput, text_input_get_view(mag->text_input));

// Byte Input
mag->byte_input = byte_input_alloc();
view_dispatcher_add_view(
mag->view_dispatcher, MagViewByteInput, byte_input_get_view(mag->byte_input));

return mag;
}

Expand All @@ -72,6 +75,10 @@ static void mag_free(Mag* mag) {
furi_string_free(mag->file_name);
furi_string_free(mag->file_path);

// Mag device
mag_device_free(mag->mag_dev);
mag->mag_dev = NULL;

// Submenu
view_dispatcher_remove_view(mag->view_dispatcher, MagViewSubmenu);
submenu_free(mag->submenu);
Expand All @@ -84,6 +91,10 @@ static void mag_free(Mag* mag) {
view_dispatcher_remove_view(mag->view_dispatcher, MagViewPopup);
popup_free(mag->popup);

// Loading
view_dispatcher_remove_view(mag->view_dispatcher, MagViewLoading);
loading_free(mag->loading);

// Widget
view_dispatcher_remove_view(mag->view_dispatcher, MagViewWidget);
widget_free(mag->widget);
Expand All @@ -92,10 +103,6 @@ static void mag_free(Mag* mag) {
view_dispatcher_remove_view(mag->view_dispatcher, MagViewTextInput);
text_input_free(mag->text_input);

// ByteInput
view_dispatcher_remove_view(mag->view_dispatcher, MagViewByteInput);
byte_input_free(mag->byte_input);

// View Dispatcher
view_dispatcher_free(mag->view_dispatcher);

Expand All @@ -118,18 +125,24 @@ static void mag_free(Mag* mag) {

// entry point for app
int32_t mag_app(void* p) {
FURI_LOG_D(TAG, "Start");
Mag* mag = mag_alloc();
char* args = p;
UNUSED(args);
FURI_LOG_D(TAG, "Mag alloc-ed");
UNUSED(p);

mag_make_app_folder(mag);
FURI_LOG_D(TAG, "mag_make_app_folder done");

view_dispatcher_attach_to_gui(mag->view_dispatcher, mag->gui, ViewDispatcherTypeFullscreen);
FURI_LOG_D(TAG, "view_dispatcher_attach... done");
scene_manager_next_scene(mag->scene_manager, MagSceneStart);
FURI_LOG_D(TAG, "scene manager next scene done");

view_dispatcher_run(mag->view_dispatcher);
FURI_LOG_D(TAG, "view dispatcher run done");

mag_free(mag);
FURI_LOG_D(TAG, "mag free done");

return 0;
}
Expand Down Expand Up @@ -157,8 +170,7 @@ bool mag_load_key_from_file_select(Mag* mag) {
furi_assert(mag);

DialogsFileBrowserOptions browser_options;
// TODO: Fix icon reference / definition! Temporarily importing asset_icons.h in mag_i.h to let it compile. Remove when fixed!
dialog_file_browser_set_basic_options(&browser_options, MAG_APP_EXTENSION, &I_125_10px);
dialog_file_browser_set_basic_options(&browser_options, MAG_APP_EXTENSION, &I_mag_10px);
browser_options.base_path = MAG_APP_FOLDER;

// Input events and views are managed by file_browser
Expand Down Expand Up @@ -241,3 +253,17 @@ void mag_text_input_callback(void* context) {
Mag* mag = context;
view_dispatcher_send_custom_event(mag->view_dispatcher, MagEventNext);
}

void mag_show_loading_popup(void* context, bool show) {
Mag* mag = context;
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);

if(show) {
// Raise timer priority so that animations can play
vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1);
view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewLoading);
} else {
// Restore default timer priority
vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY);
}
}
Binary file removed mag_10px.png
Binary file not shown.
218 changes: 216 additions & 2 deletions mag_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,219 @@
#include <toolbox/path.h>
#include <flipper_format/flipper_format.h>

//static const char* mag_file_header = "Flipper Mag device";
//static const uint32_t mag_file_version = 1;
#define TAG "MagDevice"

static const char* mag_file_header = "Flipper Mag device";
static const uint32_t mag_file_version = 0;

MagDevice* mag_device_alloc() {
MagDevice* mag_dev = malloc(sizeof(MagDevice));
mag_dev->dev_data = furi_string_alloc();
mag_dev->storage = furi_record_open(RECORD_STORAGE);
mag_dev->dialogs = furi_record_open(RECORD_DIALOGS);
mag_dev->load_path = furi_string_alloc();
return mag_dev;
}

void mag_device_data_clear(FuriString* dev_data) {
furi_string_reset(dev_data);
}

void mag_device_clear(MagDevice* mag_dev) {
furi_assert(mag_dev);

mag_device_data_clear(mag_dev->dev_data);
memset(&mag_dev->dev_data, 0, sizeof(mag_dev->dev_data));
furi_string_reset(mag_dev->load_path);
}

void mag_device_free(MagDevice* mag_dev) {
furi_assert(mag_dev);

mag_device_clear(mag_dev);
furi_record_close(RECORD_STORAGE);
furi_record_close(RECORD_DIALOGS);
furi_string_free(mag_dev->load_path);
free(mag_dev);
}

void mag_device_set_name(MagDevice* mag_dev, const char* name) {
furi_assert(mag_dev);

strlcpy(mag_dev->dev_name, name, MAG_DEV_NAME_MAX_LEN);
}

static bool mag_device_save_file(
MagDevice* mag_dev,
const char* dev_name,
const char* folder,
const char* extension,
bool use_load_path) {
furi_assert(mag_dev);

bool saved = false;
FlipperFormat* file = flipper_format_file_alloc(mag_dev->storage);
FuriString* temp_str;
temp_str = furi_string_alloc();

do {
if(use_load_path && !furi_string_empty(mag_dev->load_path)) {
// Get dir name
path_extract_dirname(furi_string_get_cstr(mag_dev->load_path), temp_str);
// Create mag directory if necessary
if(!storage_simply_mkdir((mag_dev->storage), furi_string_get_cstr(temp_str))) break;
// Make path to file to be saved
furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension);
} else {
// Create mag directory if necessary
if(!storage_simply_mkdir((mag_dev->storage), MAG_APP_FOLDER)) break;
// First remove mag device file if it was saved
furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
}
// Open file
if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;

// Write header
if(!flipper_format_write_header_cstr(file, mag_file_header, mag_file_version)) break;

// Write comment
if(!flipper_format_write_comment_cstr(file, "Mag device track data")) break;

// Write data
if(!flipper_format_write_string_cstr(file, "Data", furi_string_get_cstr(mag_dev->dev_data)))
break;

saved = true;
} while(0);

if(!saved) {
dialog_message_show_storage_error(mag_dev->dialogs, "Cannot save\nfile");
}

furi_string_free(temp_str);
flipper_format_free(file);

// TODO. Extrapolating from the picopass app
return saved;
}

bool mag_device_save(MagDevice* mag_dev, const char* dev_name) {
// wrapping function in the event we have multiple formats
return mag_device_save_file(mag_dev, dev_name, MAG_APP_FOLDER, MAG_APP_EXTENSION, true);
}

static bool mag_device_load_data(MagDevice* mag_dev, FuriString* path, bool show_dialog) {
bool parsed = false;

FlipperFormat* file = flipper_format_file_alloc(mag_dev->storage);
FuriString* temp_str;
temp_str = furi_string_alloc();
bool deprecated_version = false;
bool data_read = true;

if(mag_dev->loading_cb) {
mag_dev->loading_cb(mag_dev->loading_cb_ctx, true);
}

do {
if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break;

// Read and verify header, check file version
uint32_t version;
if(!flipper_format_read_header(file, temp_str, &version)) break;
if(furi_string_cmp_str(temp_str, mag_file_header) || (version != mag_file_version)) {
deprecated_version = true;
break;
}

// Parse data
if(!flipper_format_read_string(file, "Data", mag_dev->dev_data)) {
data_read = false;
break;
}

parsed = true;
} while(false);

if((!parsed) && (show_dialog)) {
if(deprecated_version) {
dialog_message_show_storage_error(mag_dev->dialogs, "File format\ndeprecated");
} else if(!data_read) {
dialog_message_show_storage_error(mag_dev->dialogs, "Cannot read\ndata");
} else {
dialog_message_show_storage_error(mag_dev->dialogs, "Cannot parse\nfile");
}
}

furi_string_free(temp_str);
flipper_format_free(file);

return parsed;
}

bool mag_file_select(MagDevice* mag_dev) {
furi_assert(mag_dev);

// Input events and views are managed by file_browser
FuriString* mag_app_folder;
mag_app_folder = furi_string_alloc_set(MAG_APP_FOLDER);

DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, MAG_APP_EXTENSION, &I_mag_10px);
browser_options.base_path = MAG_APP_FOLDER;

bool res = dialog_file_browser_show(
mag_dev->dialogs, mag_dev->load_path, mag_app_folder, &browser_options);

furi_string_free(mag_app_folder);
if(res) {
FuriString* filename;
filename = furi_string_alloc();
path_extract_filename(mag_dev->load_path, filename, true);
strncpy(mag_dev->dev_name, furi_string_get_cstr(filename), MAG_DEV_NAME_MAX_LEN);
res = mag_device_load_data(mag_dev, mag_dev->load_path, true);
if(res) {
mag_device_set_name(mag_dev, mag_dev->dev_name);
}
furi_string_free(filename);
}

return res;
}

bool mag_device_delete(MagDevice* mag_dev, bool use_load_path) {
furi_assert(mag_dev);

bool deleted = false;
FuriString* file_path;
file_path = furi_string_alloc();

do {
// Delete original file
if(use_load_path && !furi_string_empty(mag_dev->load_path)) {
furi_string_set(file_path, mag_dev->load_path);
} else {
furi_string_printf(
file_path, "%s/%s%s", MAG_APP_FOLDER, mag_dev->dev_name, MAG_APP_EXTENSION);
}
if(!storage_simply_remove(mag_dev->storage, furi_string_get_cstr(file_path))) break;
deleted = true;
} while(false);

if(!deleted) {
dialog_message_show_storage_error(mag_dev->dialogs, "Cannot remove\nfile");
}

furi_string_free(file_path);
return deleted;
}

void mag_device_set_loading_callback(
MagDevice* mag_dev,
MagLoadingCallback callback,
void* context) {
furi_assert(mag_dev);

mag_dev->loading_cb = callback;
mag_dev->loading_cb_ctx = context;
}
Loading

0 comments on commit 8f642df

Please sign in to comment.