[FL-2627] Flipper applications: SDK, build and debug system (#1387)

* Added support for running applications from SD card (FAPs - Flipper Application Packages)
* Added plugin_dist target for fbt to build FAPs
* All apps of type FlipperAppType.EXTERNAL and FlipperAppType.PLUGIN are built as FAPs by default
* Updated VSCode configuration for new fbt features - re-deploy stock configuration to use them
* Added debugging support for FAPs with fbt debug & VSCode
* Added public firmware API with automated versioning

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
SG
2022-09-15 02:11:38 +10:00
committed by Aleksandr Kutuzov
parent 0f6f9ad52e
commit b9a766d909
895 changed files with 8862 additions and 1465 deletions

View File

@@ -0,0 +1,30 @@
#include "ibutton_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const ibutton_on_enter_handlers[])(void*) = {
#include "ibutton_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 ibutton_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "ibutton_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 ibutton_on_exit_handlers[])(void* context) = {
#include "ibutton_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers ibutton_scene_handlers = {
.on_enter_handlers = ibutton_on_enter_handlers,
.on_event_handlers = ibutton_on_event_handlers,
.on_exit_handlers = ibutton_on_exit_handlers,
.scene_num = iButtonSceneNum,
};

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) iButtonScene##id,
typedef enum {
#include "ibutton_scene_config.h"
iButtonSceneNum,
} iButtonScene;
#undef ADD_SCENE
extern const SceneManagerHandlers ibutton_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "ibutton_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 "ibutton_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 "ibutton_scene_config.h"
#undef ADD_SCENE

View File

@@ -0,0 +1,61 @@
#include "../ibutton_i.h"
#include "m-string.h"
enum SubmenuIndex {
SubmenuIndexCyfral,
SubmenuIndexDallas,
SubmenuIndexMetakom,
};
void ibutton_scene_add_type_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_add_type_on_enter(void* context) {
iButton* ibutton = context;
Submenu* submenu = ibutton->submenu;
submenu_add_item(
submenu, "Cyfral", SubmenuIndexCyfral, ibutton_scene_add_type_submenu_callback, ibutton);
submenu_add_item(
submenu, "Dallas", SubmenuIndexDallas, ibutton_scene_add_type_submenu_callback, ibutton);
submenu_add_item(
submenu, "Metakom", SubmenuIndexMetakom, ibutton_scene_add_type_submenu_callback, ibutton);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddType));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
}
bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
iButtonKey* key = ibutton->key;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneAddType, event.event);
consumed = true;
if(event.event == SubmenuIndexCyfral) {
ibutton_key_set_type(key, iButtonKeyCyfral);
} else if(event.event == SubmenuIndexDallas) {
ibutton_key_set_type(key, iButtonKeyDS1990);
} else if(event.event == SubmenuIndexMetakom) {
ibutton_key_set_type(key, iButtonKeyMetakom);
} else {
furi_crash("Unknown key type");
}
string_set_str(ibutton->file_path, IBUTTON_APP_FOLDER);
ibutton_key_clear_data(key);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue);
}
return consumed;
}
void ibutton_scene_add_type_on_exit(void* context) {
iButton* ibutton = context;
submenu_reset(ibutton->submenu);
}

View File

@@ -0,0 +1,57 @@
#include "../ibutton_i.h"
#include <dolphin/dolphin.h>
void ibutton_scene_add_type_byte_input_callback(void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventByteEditResult);
}
void ibutton_scene_add_value_on_enter(void* context) {
iButton* ibutton = context;
iButtonKey* key = ibutton->key;
uint8_t* new_key_data = malloc(IBUTTON_KEY_DATA_SIZE);
scene_manager_set_scene_state(
ibutton->scene_manager, iButtonSceneAddValue, (uint32_t)new_key_data);
memcpy(new_key_data, ibutton_key_get_data_p(key), ibutton_key_get_data_size(key));
byte_input_set_result_callback(
ibutton->byte_input,
ibutton_scene_add_type_byte_input_callback,
NULL,
ibutton,
new_key_data,
ibutton_key_get_data_size(key));
byte_input_set_header_text(ibutton->byte_input, "Enter the key");
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewByteInput);
}
bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
uint8_t* new_key_data =
(uint8_t*)scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddValue);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventByteEditResult) {
ibutton_key_set_data(ibutton->key, new_key_data, IBUTTON_KEY_DATA_SIZE);
DOLPHIN_DEED(DolphinDeedIbuttonAdd);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName);
}
}
return consumed;
}
void ibutton_scene_add_value_on_exit(void* context) {
iButton* ibutton = context;
uint8_t* new_key_data =
(uint8_t*)scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddValue);
byte_input_set_result_callback(ibutton->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(ibutton->byte_input, NULL);
free(new_key_data);
}

View File

@@ -0,0 +1,21 @@
ADD_SCENE(ibutton, start, Start)
ADD_SCENE(ibutton, emulate, Emulate)
ADD_SCENE(ibutton, write, Write)
ADD_SCENE(ibutton, write_success, WriteSuccess)
ADD_SCENE(ibutton, info, Info)
ADD_SCENE(ibutton, read, Read)
ADD_SCENE(ibutton, read_key_menu, ReadKeyMenu)
ADD_SCENE(ibutton, read_success, ReadSuccess)
ADD_SCENE(ibutton, read_crc_error, ReadCRCError)
ADD_SCENE(ibutton, read_not_key_error, ReadNotKeyError)
ADD_SCENE(ibutton, select_key, SelectKey)
ADD_SCENE(ibutton, add_type, AddType)
ADD_SCENE(ibutton, add_value, AddValue)
ADD_SCENE(ibutton, saved_key_menu, SavedKeyMenu)
ADD_SCENE(ibutton, save_name, SaveName)
ADD_SCENE(ibutton, save_success, SaveSuccess)
ADD_SCENE(ibutton, delete_confirm, DeleteConfirm)
ADD_SCENE(ibutton, delete_success, DeleteSuccess)
ADD_SCENE(ibutton, retry_confirm, RetryConfirm)
ADD_SCENE(ibutton, exit_confirm, ExitConfirm)
ADD_SCENE(ibutton, rpc, Rpc)

View File

@@ -0,0 +1,98 @@
#include "../ibutton_i.h"
#include <toolbox/path.h>
static void ibutton_scene_delete_confirm_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
iButton* ibutton = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
}
void ibutton_scene_delete_confirm_on_enter(void* context) {
iButton* ibutton = context;
Widget* widget = ibutton->widget;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
string_t key_name;
string_init(key_name);
path_extract_filename(ibutton->file_path, key_name, true);
ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", string_get_cstr(key_name));
widget_add_text_box_element(
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, ibutton->text_store, false);
widget_add_button_element(
widget, GuiButtonTypeLeft, "Cancel", ibutton_scene_delete_confirm_widget_callback, ibutton);
widget_add_button_element(
widget,
GuiButtonTypeRight,
"Delete",
ibutton_scene_delete_confirm_widget_callback,
ibutton);
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X %02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
widget_add_string_element(
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Dallas");
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
widget_add_string_element(
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
widget_add_string_element(
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Metakom");
break;
}
widget_add_string_element(
widget, 64, 33, AlignCenter, AlignBottom, FontSecondary, ibutton->text_store);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
string_clear(key_name);
}
bool ibutton_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeRight) {
if(ibutton_delete_key(ibutton)) {
scene_manager_next_scene(scene_manager, iButtonSceneDeleteSuccess);
}
//TODO: What if the key could not be deleted?
} else if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void ibutton_scene_delete_confirm_on_exit(void* context) {
iButton* ibutton = context;
ibutton_text_store_clear(ibutton);
widget_reset(ibutton->widget);
}

View File

@@ -0,0 +1,48 @@
#include "../ibutton_i.h"
static void ibutton_scene_delete_success_popup_callback(void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventBack);
}
void ibutton_scene_delete_success_on_enter(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
popup_set_callback(popup, ibutton_scene_delete_success_popup_callback);
popup_set_context(popup, ibutton);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
}
bool ibutton_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventBack) {
scene_manager_search_and_switch_to_previous_scene(
ibutton->scene_manager, iButtonSceneSelectKey);
}
}
return consumed;
}
void ibutton_scene_delete_success_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_disable_timeout(popup);
popup_set_context(popup, NULL);
popup_set_callback(popup, NULL);
}

View File

@@ -0,0 +1,131 @@
#include "../ibutton_i.h"
#include <core/log.h>
#include <dolphin/dolphin.h>
#include <toolbox/path.h>
#define EMULATE_TIMEOUT_TICKS 10
static void ibutton_scene_emulate_callback(void* context, bool emulated) {
iButton* ibutton = context;
if(emulated) {
view_dispatcher_send_custom_event(
ibutton->view_dispatcher, iButtonCustomEventWorkerEmulated);
}
}
void ibutton_scene_emulate_on_enter(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
string_t key_name;
string_init(key_name);
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
uint8_t line_count = 2;
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
// check that stored key has name
if(!string_empty_p(key_name)) {
ibutton_text_store_set(ibutton, "emulating\n%s", string_get_cstr(key_name));
line_count = 2;
} else {
// if not, show key data
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"emulating\n%02X %02X %02X %02X\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
line_count = 3;
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "emulating\n%02X %02X", key_data[0], key_data[1]);
line_count = 2;
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton,
"emulating\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3]);
line_count = 2;
break;
}
}
switch(line_count) {
case 3:
popup_set_header(popup, "iButton", 82, 18, AlignCenter, AlignBottom);
popup_set_text(popup, ibutton->text_store, 82, 22, AlignCenter, AlignTop);
break;
default:
popup_set_header(popup, "iButton", 82, 24, AlignCenter, AlignBottom);
popup_set_text(popup, ibutton->text_store, 82, 28, AlignCenter, AlignTop);
break;
}
popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
ibutton_worker_emulate_set_callback(
ibutton->key_worker, ibutton_scene_emulate_callback, ibutton);
ibutton_worker_emulate_start(ibutton->key_worker, key);
string_clear(key_name);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
}
bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
uint32_t cnt = scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneEmulate);
if(cnt > 0) {
cnt--;
if(cnt == 0) {
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateBlink);
}
scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneEmulate, cnt);
}
consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventWorkerEmulated) {
if(scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneEmulate) == 0) {
ibutton_notification_message(ibutton, iButtonNotificationMessageYellowBlink);
}
scene_manager_set_scene_state(
ibutton->scene_manager, iButtonSceneEmulate, EMULATE_TIMEOUT_TICKS);
}
}
return consumed;
}
void ibutton_scene_emulate_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
ibutton_worker_stop(ibutton->key_worker);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
}

View File

@@ -0,0 +1,51 @@
#include "../ibutton_i.h"
static void ibutton_scene_exit_confirm_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
iButton* ibutton = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
}
void ibutton_scene_exit_confirm_on_enter(void* context) {
iButton* ibutton = context;
Widget* widget = ibutton->widget;
widget_add_button_element(
widget, GuiButtonTypeLeft, "Exit", ibutton_scene_exit_confirm_widget_callback, ibutton);
widget_add_button_element(
widget, GuiButtonTypeRight, "Stay", ibutton_scene_exit_confirm_widget_callback, ibutton);
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu?");
widget_add_string_element(
widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
}
bool ibutton_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true; // Ignore Back button presses
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_search_and_switch_to_previous_scene(scene_manager, iButtonSceneStart);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void ibutton_scene_exit_confirm_on_exit(void* context) {
iButton* ibutton = context;
widget_reset(ibutton->widget);
}

View File

@@ -0,0 +1,68 @@
#include "../ibutton_i.h"
#include <toolbox/path.h>
void ibutton_scene_info_on_enter(void* context) {
iButton* ibutton = context;
Widget* widget = ibutton->widget;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
string_t key_name;
string_init(key_name);
path_extract_filename(ibutton->file_path, key_name, true);
ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name));
widget_add_text_box_element(
widget, 0, 0, 128, 28, AlignCenter, AlignCenter, ibutton->text_store, false);
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X %02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
widget_add_string_element(
widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Dallas");
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton, "%02X %02X %02X %02X", key_data[0], key_data[1], key_data[2], key_data[3]);
widget_add_string_element(
widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Metakom");
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "%02X %02X", key_data[0], key_data[1]);
widget_add_string_element(
widget, 64, 51, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
break;
}
widget_add_string_element(
widget, 64, 35, AlignCenter, AlignBottom, FontPrimary, ibutton->text_store);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
string_clear(key_name);
}
bool ibutton_scene_info_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void ibutton_scene_info_on_exit(void* context) {
iButton* ibutton = context;
ibutton_text_store_clear(ibutton);
widget_reset(ibutton->widget);
}

View File

@@ -0,0 +1,75 @@
#include "../ibutton_i.h"
#include <dolphin/dolphin.h>
static void ibutton_scene_read_callback(void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventWorkerRead);
}
void ibutton_scene_read_on_enter(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
iButtonKey* key = ibutton->key;
iButtonWorker* worker = ibutton->key_worker;
DOLPHIN_DEED(DolphinDeedIbuttonRead);
popup_set_header(popup, "iButton", 95, 26, AlignCenter, AlignBottom);
popup_set_text(popup, "Waiting\nfor key ...", 95, 30, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 5, &I_DolphinWait_61x59);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
string_set_str(ibutton->file_path, IBUTTON_APP_FOLDER);
ibutton_worker_read_set_callback(worker, ibutton_scene_read_callback, ibutton);
ibutton_worker_read_start(worker, key);
ibutton_notification_message(ibutton, iButtonNotificationMessageReadStart);
}
bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
consumed = true;
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventWorkerRead) {
bool success = false;
iButtonKey* key = ibutton->key;
if(ibutton_key_get_type(key) == iButtonKeyDS1990) {
if(!ibutton_key_dallas_crc_is_valid(key)) {
scene_manager_next_scene(scene_manager, iButtonSceneReadCRCError);
} else if(!ibutton_key_dallas_is_1990_key(key)) {
scene_manager_next_scene(scene_manager, iButtonSceneReadNotKeyError);
} else {
success = true;
}
} else {
success = true;
}
if(success) {
ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess);
ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn);
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess);
}
}
}
return consumed;
}
void ibutton_scene_read_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
ibutton_worker_stop(ibutton->key_worker);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
}

View File

@@ -0,0 +1,70 @@
#include "../ibutton_i.h"
#include <one_wire/maxim_crc.h>
static void ibutton_scene_read_crc_error_dialog_ex_callback(DialogExResult result, void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_read_crc_error_on_enter(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
ibutton_text_store_set(
ibutton,
"%02X %02X %02X %02X %02X %02X %02X %02X\nExpected CRC: %X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7],
maxim_crc8(key_data, 7, MAXIM_CRC8_INIT));
dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, ibutton->text_store, 64, 19, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_crc_error_dialog_ex_callback);
dialog_ex_set_context(dialog_ex, ibutton);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx);
ibutton_notification_message(ibutton, iButtonNotificationMessageError);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn);
}
bool ibutton_scene_read_crc_error_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == DialogExResultRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
} else if(event.event == DialogExResultLeft) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void ibutton_scene_read_crc_error_on_exit(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
ibutton_text_store_clear(ibutton);
dialog_ex_reset(dialog_ex);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
}

View File

@@ -0,0 +1,63 @@
#include "../ibutton_i.h"
typedef enum {
SubmenuIndexSave,
SubmenuIndexEmulate,
SubmenuIndexWrite,
} SubmenuIndex;
void ibutton_scene_read_key_menu_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_read_key_menu_on_enter(void* context) {
iButton* ibutton = context;
Submenu* submenu = ibutton->submenu;
submenu_add_item(
submenu, "Save", SubmenuIndexSave, ibutton_scene_read_key_menu_submenu_callback, ibutton);
submenu_add_item(
submenu,
"Emulate",
SubmenuIndexEmulate,
ibutton_scene_read_key_menu_submenu_callback,
ibutton);
if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) {
submenu_add_item(
submenu,
"Write",
SubmenuIndexWrite,
ibutton_scene_read_key_menu_submenu_callback,
ibutton);
}
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneReadKeyMenu));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
}
bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(
ibutton->scene_manager, iButtonSceneReadKeyMenu, event.event);
consumed = true;
if(event.event == SubmenuIndexSave) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName);
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite);
}
}
return consumed;
}
void ibutton_scene_read_key_menu_on_exit(void* context) {
iButton* ibutton = context;
submenu_reset(ibutton->submenu);
}

View File

@@ -0,0 +1,71 @@
#include "../ibutton_i.h"
#include <one_wire/maxim_crc.h>
static void
ibutton_scene_read_not_key_error_dialog_ex_callback(DialogExResult result, void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_read_not_key_error_on_enter(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
ibutton_text_store_set(
ibutton,
"THIS IS NOT A KEY\n%02X %02X %02X %02X %02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7],
maxim_crc8(key_data, 7, MAXIM_CRC8_INIT));
dialog_ex_set_header(dialog_ex, "CRC ERROR", 64, 10, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, ibutton->text_store, 64, 19, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_not_key_error_dialog_ex_callback);
dialog_ex_set_context(dialog_ex, ibutton);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx);
ibutton_notification_message(ibutton, iButtonNotificationMessageError);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOn);
}
bool ibutton_scene_read_not_key_error_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == DialogExResultRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
} else if(event.event == DialogExResultLeft) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void ibutton_scene_read_not_key_error_on_exit(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
ibutton_text_store_clear(ibutton);
dialog_ex_reset(dialog_ex);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
}

View File

@@ -0,0 +1,82 @@
#include "../ibutton_i.h"
#include <dolphin/dolphin.h>
static void ibutton_scene_read_success_dialog_ex_callback(DialogExResult result, void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_read_success_on_enter(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
iButtonKey* key = ibutton->key;
const uint8_t* key_data = ibutton_key_get_data_p(key);
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"Dallas\n%02X %02X %02X %02X\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "Cyfral\n%02X %02X", key_data[0], key_data[1]);
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton,
"Metakom\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3]);
break;
}
dialog_ex_set_text(dialog_ex, ibutton->text_store, 95, 30, AlignCenter, AlignCenter);
dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More");
dialog_ex_set_icon(dialog_ex, 0, 1, &I_DolphinReadingSuccess_59x63);
dialog_ex_set_result_callback(dialog_ex, ibutton_scene_read_success_dialog_ex_callback);
dialog_ex_set_context(dialog_ex, ibutton);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewDialogEx);
}
bool ibutton_scene_read_success_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true;
scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == DialogExResultRight) {
scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);
} else if(event.event == DialogExResultLeft) {
scene_manager_next_scene(scene_manager, iButtonSceneRetryConfirm);
}
}
return consumed;
}
void ibutton_scene_read_success_on_exit(void* context) {
iButton* ibutton = context;
DialogEx* dialog_ex = ibutton->dialog_ex;
ibutton_text_store_clear(ibutton);
dialog_ex_reset(dialog_ex);
ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOff);
}

View File

@@ -0,0 +1,51 @@
#include "../ibutton_i.h"
static void ibutton_scene_retry_confirm_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
iButton* ibutton = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
}
void ibutton_scene_retry_confirm_on_enter(void* context) {
iButton* ibutton = context;
Widget* widget = ibutton->widget;
widget_add_button_element(
widget, GuiButtonTypeLeft, "Exit", ibutton_scene_retry_confirm_widget_callback, ibutton);
widget_add_button_element(
widget, GuiButtonTypeRight, "Stay", ibutton_scene_retry_confirm_widget_callback, ibutton);
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?");
widget_add_string_element(
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
}
bool ibutton_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeBack) {
consumed = true; // Ignore Back button presses
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeLeft) {
scene_manager_search_and_switch_to_previous_scene(scene_manager, iButtonSceneRead);
} else if(event.event == GuiButtonTypeRight) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void ibutton_scene_retry_confirm_on_exit(void* context) {
iButton* ibutton = context;
widget_reset(ibutton->widget);
}

View File

@@ -0,0 +1,81 @@
#include "../ibutton_i.h"
#include <toolbox/path.h>
#include <rpc/rpc_app.h>
void ibutton_scene_rpc_on_enter(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_header(popup, "iButton", 82, 28, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop);
popup_set_icon(popup, 2, 14, &I_iButtonKey_49x44);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
notification_message(ibutton->notifications, &sequence_display_backlight_on);
}
bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
iButton* ibutton = context;
Popup* popup = ibutton->popup;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventRpcLoad) {
const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx);
bool result = false;
if(arg && (string_empty_p(ibutton->file_path))) {
string_set_str(ibutton->file_path, arg);
if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
string_t key_name;
string_init(key_name);
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
if(!string_empty_p(key_name)) {
ibutton_text_store_set(
ibutton, "emulating\n%s", string_get_cstr(key_name));
} else {
ibutton_text_store_set(ibutton, "emulating");
}
popup_set_text(popup, ibutton->text_store, 82, 32, AlignCenter, AlignTop);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
string_clear(key_name);
result = true;
} else {
string_reset(ibutton->file_path);
}
}
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result);
} else if(event.event == iButtonCustomEventRpcExit) {
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true);
scene_manager_stop(ibutton->scene_manager);
view_dispatcher_stop(ibutton->view_dispatcher);
} else if(event.event == iButtonCustomEventRpcSessionClose) {
scene_manager_stop(ibutton->scene_manager);
view_dispatcher_stop(ibutton->view_dispatcher);
}
}
return consumed;
}
void ibutton_scene_rpc_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
}

View File

@@ -0,0 +1,82 @@
#include "../ibutton_i.h"
#include "m-string.h"
#include <lib/toolbox/random_name.h>
#include <toolbox/path.h>
static void ibutton_scene_save_name_text_input_callback(void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventTextEditResult);
}
void ibutton_scene_save_name_on_enter(void* context) {
iButton* ibutton = context;
TextInput* text_input = ibutton->text_input;
string_t key_name;
string_init(key_name);
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
const bool key_name_is_empty = string_empty_p(key_name);
if(key_name_is_empty) {
set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE);
} else {
ibutton_text_store_set(ibutton, "%s", string_get_cstr(key_name));
}
text_input_set_header_text(text_input, "Name the key");
text_input_set_result_callback(
text_input,
ibutton_scene_save_name_text_input_callback,
ibutton,
ibutton->text_store,
IBUTTON_KEY_NAME_SIZE,
key_name_is_empty);
string_t folder_path;
string_init(folder_path);
path_extract_dirname(string_get_cstr(ibutton->file_path), folder_path);
ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
string_get_cstr(folder_path), IBUTTON_APP_EXTENSION, string_get_cstr(key_name));
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput);
string_clear(key_name);
string_clear(folder_path);
}
bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventTextEditResult) {
if(ibutton_save_key(ibutton, ibutton->text_store)) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess);
} else {
const uint32_t possible_scenes[] = {
iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType};
scene_manager_search_and_switch_to_previous_scene_one_of(
ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes));
}
}
}
return consumed;
}
void ibutton_scene_save_name_on_exit(void* context) {
iButton* ibutton = context;
TextInput* text_input = ibutton->text_input;
void* validator_context = text_input_get_validator_callback_context(text_input);
text_input_set_validator(text_input, NULL, NULL);
validator_is_file_free((ValidatorIsFile*)validator_context);
text_input_reset(text_input);
}

View File

@@ -0,0 +1,52 @@
#include "../ibutton_i.h"
#include <dolphin/dolphin.h>
static void ibutton_scene_save_success_popup_callback(void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventBack);
}
void ibutton_scene_save_success_on_enter(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
DOLPHIN_DEED(DolphinDeedIbuttonSave);
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
popup_set_callback(popup, ibutton_scene_save_success_popup_callback);
popup_set_context(popup, ibutton);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
}
bool ibutton_scene_save_success_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventBack) {
const uint32_t possible_scenes[] = {
iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType};
scene_manager_search_and_switch_to_previous_scene_one_of(
ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes));
}
}
return consumed;
}
void ibutton_scene_save_success_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_disable_timeout(popup);
popup_set_context(popup, NULL);
popup_set_callback(popup, NULL);
}

View File

@@ -0,0 +1,78 @@
#include "../ibutton_i.h"
enum SubmenuIndex {
SubmenuIndexEmulate,
SubmenuIndexWrite,
SubmenuIndexEdit,
SubmenuIndexDelete,
SubmenuIndexInfo,
};
void ibutton_scene_saved_key_menu_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_saved_key_menu_on_enter(void* context) {
iButton* ibutton = context;
Submenu* submenu = ibutton->submenu;
submenu_add_item(
submenu,
"Emulate",
SubmenuIndexEmulate,
ibutton_scene_saved_key_menu_submenu_callback,
ibutton);
if(ibutton_key_get_type(ibutton->key) == iButtonKeyDS1990) {
submenu_add_item(
submenu,
"Write",
SubmenuIndexWrite,
ibutton_scene_saved_key_menu_submenu_callback,
ibutton);
}
submenu_add_item(
submenu, "Edit", SubmenuIndexEdit, ibutton_scene_saved_key_menu_submenu_callback, ibutton);
submenu_add_item(
submenu,
"Delete",
SubmenuIndexDelete,
ibutton_scene_saved_key_menu_submenu_callback,
ibutton);
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, ibutton_scene_saved_key_menu_submenu_callback, ibutton);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneSavedKeyMenu));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
}
bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(
ibutton->scene_manager, iButtonSceneSavedKeyMenu, event.event);
consumed = true;
if(event.event == SubmenuIndexEmulate) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexEdit) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddValue);
} else if(event.event == SubmenuIndexDelete) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneDeleteConfirm);
} else if(event.event == SubmenuIndexInfo) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneInfo);
}
}
return consumed;
}
void ibutton_scene_saved_key_menu_on_exit(void* context) {
iButton* ibutton = context;
submenu_reset(ibutton->submenu);
}

View File

@@ -0,0 +1,22 @@
#include "../ibutton_i.h"
void ibutton_scene_select_key_on_enter(void* context) {
iButton* ibutton = context;
if(!ibutton_file_select(ibutton)) {
scene_manager_search_and_switch_to_previous_scene(
ibutton->scene_manager, iButtonSceneStart);
} else {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSavedKeyMenu);
}
}
bool ibutton_scene_select_key_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void ibutton_scene_select_key_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,55 @@
#include "../ibutton_i.h"
#include "ibutton/scenes/ibutton_scene.h"
enum SubmenuIndex {
SubmenuIndexRead,
SubmenuIndexSaved,
SubmenuIndexAdd,
};
void ibutton_scene_start_submenu_callback(void* context, uint32_t index) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
}
void ibutton_scene_start_on_enter(void* context) {
iButton* ibutton = context;
Submenu* submenu = ibutton->submenu;
submenu_add_item(
submenu, "Read", SubmenuIndexRead, ibutton_scene_start_submenu_callback, ibutton);
submenu_add_item(
submenu, "Saved", SubmenuIndexSaved, ibutton_scene_start_submenu_callback, ibutton);
submenu_add_item(
submenu, "Add Manually", SubmenuIndexAdd, ibutton_scene_start_submenu_callback, ibutton);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneStart));
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
}
bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneStart, event.event);
consumed = true;
if(event.event == SubmenuIndexRead) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);
} else if(event.event == SubmenuIndexSaved) {
string_set_str(ibutton->file_path, IBUTTON_APP_FOLDER);
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey);
} else if(event.event == SubmenuIndexAdd) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneAddType);
}
}
return consumed;
}
void ibutton_scene_start_on_exit(void* context) {
iButton* ibutton = context;
submenu_reset(ibutton->submenu);
}

View File

@@ -0,0 +1,124 @@
#include "../ibutton_i.h"
#include "m-string.h"
#include "toolbox/path.h"
typedef enum {
iButtonSceneWriteStateDefault,
iButtonSceneWriteStateBlinkYellow,
} iButtonSceneWriteState;
static void ibutton_scene_write_callback(void* context, iButtonWorkerWriteResult result) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, result);
}
void ibutton_scene_write_on_enter(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
iButtonKey* key = ibutton->key;
iButtonWorker* worker = ibutton->key_worker;
const uint8_t* key_data = ibutton_key_get_data_p(key);
string_t key_name;
string_init(key_name);
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
path_extract_filename(ibutton->file_path, key_name, true);
}
uint8_t line_count = 2;
// check that stored key has name
if(!string_empty_p(key_name)) {
ibutton_text_store_set(ibutton, "writing\n%s", string_get_cstr(key_name));
line_count = 2;
} else {
// if not, show key data
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
ibutton_text_store_set(
ibutton,
"writing\n%02X %02X %02X %02X\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3],
key_data[4],
key_data[5],
key_data[6],
key_data[7]);
line_count = 3;
break;
case iButtonKeyCyfral:
ibutton_text_store_set(ibutton, "writing\n%02X %02X", key_data[0], key_data[1]);
line_count = 2;
break;
case iButtonKeyMetakom:
ibutton_text_store_set(
ibutton,
"writing\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
key_data[2],
key_data[3]);
line_count = 2;
break;
}
}
switch(line_count) {
case 3:
popup_set_header(popup, "iButton", 82, 18, AlignCenter, AlignBottom);
popup_set_text(popup, ibutton->text_store, 82, 22, AlignCenter, AlignTop);
break;
default:
popup_set_header(popup, "iButton", 82, 24, AlignCenter, AlignBottom);
popup_set_text(popup, ibutton->text_store, 82, 28, AlignCenter, AlignTop);
break;
}
popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
ibutton_worker_write_set_callback(worker, ibutton_scene_write_callback, ibutton);
ibutton_worker_write_start(worker, key);
string_clear(key_name);
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
}
bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
SceneManager* scene_manager = ibutton->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if((event.event == iButtonWorkerWriteOK) || (event.event == iButtonWorkerWriteSameKey)) {
scene_manager_next_scene(scene_manager, iButtonSceneWriteSuccess);
} else if(event.event == iButtonWorkerWriteNoDetect) {
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateBlink);
} else if(event.event == iButtonWorkerWriteCannotWrite) {
ibutton_notification_message(ibutton, iButtonNotificationMessageYellowBlink);
}
} else if(event.type == SceneManagerEventTypeTick) {
consumed = true;
}
return consumed;
}
void ibutton_scene_write_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
ibutton_worker_stop(ibutton->key_worker);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
}

View File

@@ -0,0 +1,52 @@
#include "../ibutton_i.h"
static void ibutton_scene_write_success_popup_callback(void* context) {
iButton* ibutton = context;
view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventBack);
ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOff);
}
void ibutton_scene_write_success_on_enter(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_icon(popup, 0, 12, &I_iButtonDolphinVerySuccess_108x52);
popup_set_text(popup, "Successfully written!", 40, 12, AlignLeft, AlignBottom);
popup_set_callback(popup, ibutton_scene_write_success_popup_callback);
popup_set_context(popup, ibutton);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess);
ibutton_notification_message(ibutton, iButtonNotificationMessageGreenOn);
}
bool ibutton_scene_write_success_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventBack) {
const uint32_t possible_scenes[] = {iButtonSceneReadKeyMenu, iButtonSceneStart};
scene_manager_search_and_switch_to_previous_scene_one_of(
ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes));
}
}
return consumed;
}
void ibutton_scene_write_success_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_disable_timeout(popup);
popup_set_context(popup, NULL);
popup_set_callback(popup, NULL);
}