Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NFC_Eink #245

Open
wants to merge 29 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
003a618
Initial commit of Nfc Eink
RebornedBrain Sep 26, 2024
979e452
Assets added
RebornedBrain Sep 29, 2024
421d820
nfc_eink_app_i.h added
RebornedBrain Sep 29, 2024
eb6f8e3
All screen types are now aligned
RebornedBrain Sep 29, 2024
de3d95e
New goodisplay poller logic
RebornedBrain Sep 29, 2024
a7bc6d5
Merge branch 'dev' into nfc_eink
skotopes Oct 19, 2024
4e001b0
Merge branch 'dev' into nfc_eink
skotopes Oct 19, 2024
cd24df9
New api fix
RebornedBrain Oct 21, 2024
950decf
New error processing logic and api
RebornedBrain Oct 21, 2024
84f9ae5
Waceshare poller fixes and retry mechanism
RebornedBrain Oct 21, 2024
86beeca
Scenes adjustments according to new error logic in eink screens
RebornedBrain Oct 21, 2024
72d4933
Merge branch 'nfc_eink' of github.com:RebornedBrain/flipperzero-good-…
RebornedBrain Oct 21, 2024
4ac1053
Merge branch 'dev' into nfc_eink
skotopes Nov 1, 2024
00fed42
strcat replaced to strlcat
RebornedBrain Nov 14, 2024
e6b5ad1
Reworked logic of descriptors handling and filtering
RebornedBrain Nov 25, 2024
dffa04d
Now eink screen inits using name instead of screen type
RebornedBrain Nov 25, 2024
3540281
Waveshare screen config logic reworked
RebornedBrain Nov 25, 2024
b95d462
Goodisplay screen config logic reworked
RebornedBrain Nov 25, 2024
108064c
Now file load function can return 3 different states, depending on us…
RebornedBrain Nov 25, 2024
01c89f2
All scenes with init screen adjusted
RebornedBrain Nov 25, 2024
3e54943
Scene transition logic adjusted to show error if failed to load
RebornedBrain Nov 25, 2024
f15b9d5
Waveshare poller send data functions now return three statuses instea…
RebornedBrain Nov 26, 2024
5711a11
Additional poller state for reading some pages, possibly might help t…
RebornedBrain Nov 26, 2024
879a8c9
Removed read steps
RebornedBrain Nov 27, 2024
7d6f64a
Delays adjusted and some cmd fixes
RebornedBrain Nov 27, 2024
d87d7e2
Select type cmd now uses bigger timeout for big displays
RebornedBrain Nov 27, 2024
17ffe06
Some cleanups
RebornedBrain Nov 27, 2024
fc9babe
Merge branch 'dev' into nfc_eink
skotopes Jan 16, 2025
2d67d17
Fixed 3.71 inch issue when phone app sends more data then needed, now…
RebornedBrain Jan 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions nfc_eink/application.fam
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
App(
appid="nfc_eink",
name="NFC-Eink",
apptype=FlipperAppType.EXTERNAL,
targets=["f7"],
entry_point="nfc_eink",
icon="A_NFC_14",
stack_size=5 * 1024,
order=30,
sources=[
"*.c*"
],
fap_icon="icon.png",
fap_icon_assets="assets",
fap_description="Application for emulation and writing to NFC Eink tags",
fap_version="1.0",
fap_category="NFC",
)
Binary file added nfc_eink/assets/ArrowC_1_36x36.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nfc_eink/assets/DolphinDone_80x58.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nfc_eink/assets/DolphinMafia_119x62.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nfc_eink/assets/DolphinSaved_92x58.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nfc_eink/assets/NFC_dolphin_emulation_51x64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nfc_eink/assets/NFC_manual_60x50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nfc_eink/assets/Nfc_10px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nfc_eink/assets/WarningDolphin_45x42.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nfc_eink/assets/err_09.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added nfc_eink/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
279 changes: 279 additions & 0 deletions nfc_eink/nfc_eink_app.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
#include "nfc_eink_app_i.h"
#include <flipper_format/flipper_format.h>
#include <path.h>

#define TAG "NfcEinkApp"

#define NFC_EINK_SETTINGS_PATH NFC_EINK_APP_FOLDER "/.eink.settings"
#define NFC_EINK_SETTINGS_VERSION (1)
#define NFC_EINK_SETTINGS_MAGIC (0x1B)

static bool nfc_is_hal_ready(void) {
if(furi_hal_nfc_is_hal_ready() != FuriHalNfcErrorNone) {
// No connection to the chip, show an error screen
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
DialogMessage* message = dialog_message_alloc();
dialog_message_set_header(message, "Error: NFC Chip Failed", 64, 0, AlignCenter, AlignTop);
dialog_message_set_text(
message, "Send error photo via\nsupport.flipper.net", 0, 63, AlignLeft, AlignBottom);
dialog_message_set_icon(message, &I_err_09, 128 - 25, 64 - 25);
dialog_message_show(dialogs, message);
dialog_message_free(message);
furi_record_close(RECORD_DIALOGS);
return false;
} else {
return true;
}
}

static bool nfc_eink_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
NfcEinkApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}

static bool nfc_eink_app_back_event_callback(void* context) {
furi_assert(context);
NfcEinkApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}

static void nfc_eink_app_tick_event_callback(void* context) {
furi_assert(context);
NfcEinkApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}

static NfcEinkApp* nfc_eink_app_alloc() {
NfcEinkApp* instance = malloc(sizeof(NfcEinkApp));

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

// Open Dialogs record
instance->dialogs = furi_record_open(RECORD_DIALOGS);

// Open Notification record
instance->notifications = furi_record_open(RECORD_NOTIFICATION);

instance->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance);
view_dispatcher_set_custom_event_callback(
instance->view_dispatcher, nfc_eink_app_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
instance->view_dispatcher, nfc_eink_app_back_event_callback);
view_dispatcher_set_tick_event_callback(
instance->view_dispatcher, nfc_eink_app_tick_event_callback, 100);

view_dispatcher_attach_to_gui(
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);

// Submenu
instance->submenu = submenu_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, NfcEinkViewMenu, submenu_get_view(instance->submenu));

// Popup
instance->popup = popup_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, NfcEinkViewPopup, popup_get_view(instance->popup));

// Progress bar
instance->eink_progress = eink_progress_alloc();
view_dispatcher_add_view(
instance->view_dispatcher,
NfcEinkViewProgress,
eink_progress_get_view(instance->eink_progress));

// Dialog
instance->dialog_ex = dialog_ex_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, NfcEinkViewDialogEx, dialog_ex_get_view(instance->dialog_ex));

// Text Input
instance->text_input = text_input_alloc();
view_dispatcher_add_view(
instance->view_dispatcher,
NfcEinkViewTextInput,
text_input_get_view(instance->text_input));

// Custom Widget
instance->widget = widget_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, NfcEinkViewWidget, widget_get_view(instance->widget));

// Variable item list
instance->var_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
instance->view_dispatcher,
NfcEinkViewVarItemList,
variable_item_list_get_view(instance->var_item_list));

// Image scroll
instance->image_scroll = image_scroll_alloc();
view_dispatcher_add_view(
instance->view_dispatcher,
NfcEinkViewImageScroll,
image_scroll_get_view(instance->image_scroll));

instance->scene_manager = scene_manager_alloc(&nfc_eink_scene_handlers, instance);
instance->nfc = nfc_alloc();
instance->file_path = furi_string_alloc();
instance->file_name = furi_string_alloc();
return instance;
}

static void nfc_eink_app_free(NfcEinkApp* instance) {
furi_assert(instance);

nfc_free(instance->nfc);
scene_manager_free(instance->scene_manager);

// Submenu
view_dispatcher_remove_view(instance->view_dispatcher, NfcEinkViewMenu);
submenu_free(instance->submenu);

// DialogEx
view_dispatcher_remove_view(instance->view_dispatcher, NfcEinkViewDialogEx);
dialog_ex_free(instance->dialog_ex);

// Popup
view_dispatcher_remove_view(instance->view_dispatcher, NfcEinkViewPopup);
popup_free(instance->popup);

// TextInput
view_dispatcher_remove_view(instance->view_dispatcher, NfcEinkViewTextInput);
text_input_free(instance->text_input);

// Progress
view_dispatcher_remove_view(instance->view_dispatcher, NfcEinkViewProgress);
eink_progress_free(instance->eink_progress);

// Custom Widget
view_dispatcher_remove_view(instance->view_dispatcher, NfcEinkViewWidget);
widget_free(instance->widget);

// Var Item List
view_dispatcher_remove_view(instance->view_dispatcher, NfcEinkViewVarItemList);
variable_item_list_free(instance->var_item_list);

view_dispatcher_remove_view(instance->view_dispatcher, NfcEinkViewImageScroll);
image_scroll_free(instance->image_scroll);

view_dispatcher_free(instance->view_dispatcher);

furi_record_close(RECORD_DIALOGS);
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_GUI);

furi_string_free(instance->file_path);
furi_string_free(instance->file_name);

instance->dialogs = NULL;
instance->gui = NULL;
instance->notifications = NULL;
free(instance);
}

static void nfc_eink_make_app_folders(const NfcEinkApp* instance) {
furi_assert(instance);

Storage* storage = furi_record_open(RECORD_STORAGE);
if(!storage_simply_mkdir(storage, NFC_EINK_APP_FOLDER)) {
dialog_message_show_storage_error(instance->dialogs, "Cannot create\napp folder");
}
furi_record_close(RECORD_STORAGE);
}

static void nfc_eink_load_settings(NfcEinkApp* instance) {
NfcEinkSettings settings = {0};

if(!saved_struct_load(
NFC_EINK_SETTINGS_PATH,
&settings,
sizeof(NfcEinkSettings),
NFC_EINK_SETTINGS_MAGIC,
NFC_EINK_SETTINGS_VERSION)) {
FURI_LOG_D(TAG, "Failed to load settings, using defaults");
nfc_eink_save_settings(instance);
}

instance->settings.invert_image = settings.invert_image;
instance->settings.write_mode = settings.write_mode;
}

void nfc_eink_save_settings(NfcEinkApp* instance) {
NfcEinkSettings settings = {
.invert_image = instance->settings.invert_image,
.write_mode = instance->settings.write_mode,
};

if(!saved_struct_save(
NFC_EINK_SETTINGS_PATH,
&settings,
sizeof(NfcEinkSettings),
NFC_EINK_SETTINGS_MAGIC,
NFC_EINK_SETTINGS_VERSION)) {
FURI_LOG_E(TAG, "Failed to save settings");
}
}

NfcEinkLoadResult nfc_eink_load_from_file_select(NfcEinkApp* instance) {
furi_assert(instance);

DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, NFC_EINK_APP_EXTENSION, &I_Nfc_10px);
browser_options.base_path = NFC_EINK_APP_FOLDER;
browser_options.hide_dot_files = true;

FuriString* tmp = furi_string_alloc();
furi_string_reset(instance->file_path);

NfcEinkLoadResult result = NfcEinkLoadResultFailed;
do {
// Input events and views are managed by file_browser
furi_string_printf(tmp, NFC_EINK_APP_FOLDER);

if(!dialog_file_browser_show(
instance->dialogs, instance->file_path, tmp, &browser_options)) {
result = NfcEinkLoadResultCanceled;
break;
}

if(nfc_eink_screen_load_info(
furi_string_get_cstr(instance->file_path), &instance->info_temp))
result = NfcEinkLoadResultSuccess;
path_extract_filename(instance->file_path, instance->file_name, false);
} while(false);

furi_string_free(tmp);

return result;
}

void nfc_eink_blink_emulate_start(NfcEinkApp* app) {
notification_message(app->notifications, &sequence_blink_start_magenta);
}

void nfc_eink_blink_write_start(NfcEinkApp* app) {
notification_message(app->notifications, &sequence_blink_start_cyan);
}

void nfc_eink_blink_stop(NfcEinkApp* app) {
notification_message(app->notifications, &sequence_blink_stop);
}

int32_t nfc_eink(/* void* p */) {
if(!nfc_is_hal_ready()) return 0;

NfcEinkApp* app = nfc_eink_app_alloc();

nfc_eink_make_app_folders(app);
nfc_eink_load_settings(app);
scene_manager_next_scene(app->scene_manager, NfcEinkAppSceneStart);

view_dispatcher_run(app->view_dispatcher);

nfc_eink_app_free(app);
return 0;
}
3 changes: 3 additions & 0 deletions nfc_eink/nfc_eink_app.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

typedef struct NfcEinkApp NfcEinkApp;
Loading