[FL-2514] Port iButton application to C (#1198)

* Initial C iButton app setup
* Add more scenes
* Add even more scenes
* Add even more scenes again
* More scenes...
* Add key info scene
* Add delete success scene
* Use scene state to store internal data
* Add parameter parsing
* Add emulate scene
* Add write scene
* Add write success scene
* Add Read scene
* Add read success scene
* Add exit confirm scene
* Add retry confirm scene
* Add CRC error scene
* Add not key scene
* Add read key menu scene
* Rename some scenes
* Refactor conditionals
* Remove unneeded custom events
* Remove the old iButton app
* Correct formatting
* Remove rogue comments and function prototypes
* iButton: cleanup merge artifacts and fix warnings

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Georgii Surkov 2022-05-06 19:48:39 +03:00 committed by GitHub
parent 37bd0d546a
commit 5171a6ad14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 1785 additions and 2186 deletions

View File

@ -0,0 +1,349 @@
#include "ibutton.h"
#include "ibutton_i.h"
#include "ibutton/scenes/ibutton_scene.h"
#include <toolbox/path.h>
#include <flipper_format/flipper_format.h>
static const NotificationSequence* ibutton_notification_sequences[] = {
&sequence_error,
&sequence_success,
&sequence_blink_cyan_10,
&sequence_blink_magenta_10,
&sequence_blink_yellow_10,
&sequence_set_red_255,
&sequence_reset_red,
&sequence_set_green_255,
&sequence_reset_green,
};
static void ibutton_make_app_folder(iButton* ibutton) {
if(!storage_simply_mkdir(ibutton->storage, IBUTTON_APP_FOLDER)) {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot create\napp folder");
}
}
static bool ibutton_load_key_data(iButton* ibutton, string_t key_path) {
FlipperFormat* file = flipper_format_file_alloc(ibutton->storage);
bool result = false;
string_t data;
string_init(data);
do {
if(!flipper_format_file_open_existing(file, string_get_cstr(key_path))) break;
// header
uint32_t version;
if(!flipper_format_read_header(file, data, &version)) break;
if(string_cmp_str(data, IBUTTON_APP_FILE_TYPE) != 0) break;
if(version != 1) break;
// key type
iButtonKeyType type;
if(!flipper_format_read_string(file, "Key type", data)) break;
if(!ibutton_key_get_type_by_string(string_get_cstr(data), &type)) break;
// key data
uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0};
if(!flipper_format_read_hex(file, "Data", key_data, ibutton_key_get_size_by_type(type)))
break;
ibutton_key_set_type(ibutton->key, type);
ibutton_key_set_data(ibutton->key, key_data, IBUTTON_KEY_DATA_SIZE);
result = true;
} while(false);
flipper_format_free(file);
string_clear(data);
if(!result) {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
}
return result;
}
bool ibutton_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
iButton* ibutton = context;
return scene_manager_handle_custom_event(ibutton->scene_manager, event);
}
bool ibutton_back_event_callback(void* context) {
furi_assert(context);
iButton* ibutton = context;
return scene_manager_handle_back_event(ibutton->scene_manager);
}
void ibutton_tick_event_callback(void* context) {
furi_assert(context);
iButton* ibutton = context;
scene_manager_handle_tick_event(ibutton->scene_manager);
}
iButton* ibutton_alloc() {
iButton* ibutton = malloc(sizeof(iButton));
ibutton->scene_manager = scene_manager_alloc(&ibutton_scene_handlers, ibutton);
ibutton->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(ibutton->view_dispatcher);
view_dispatcher_set_event_callback_context(ibutton->view_dispatcher, ibutton);
view_dispatcher_set_custom_event_callback(
ibutton->view_dispatcher, ibutton_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
ibutton->view_dispatcher, ibutton_back_event_callback);
view_dispatcher_set_tick_event_callback(
ibutton->view_dispatcher, ibutton_tick_event_callback, 100);
ibutton->gui = furi_record_open("gui");
view_dispatcher_attach_to_gui(
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
ibutton->storage = furi_record_open("storage");
ibutton->dialogs = furi_record_open("dialogs");
ibutton->notifications = furi_record_open("notification");
ibutton->key = ibutton_key_alloc();
ibutton->key_worker = ibutton_worker_alloc();
ibutton_worker_start_thread(ibutton->key_worker);
ibutton->submenu = submenu_alloc();
view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewSubmenu, submenu_get_view(ibutton->submenu));
ibutton->byte_input = byte_input_alloc();
view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewByteInput, byte_input_get_view(ibutton->byte_input));
ibutton->text_input = text_input_alloc();
view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewTextInput, text_input_get_view(ibutton->text_input));
ibutton->popup = popup_alloc();
view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewPopup, popup_get_view(ibutton->popup));
ibutton->widget = widget_alloc();
view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewWidget, widget_get_view(ibutton->widget));
ibutton->dialog_ex = dialog_ex_alloc();
view_dispatcher_add_view(
ibutton->view_dispatcher, iButtonViewDialogEx, dialog_ex_get_view(ibutton->dialog_ex));
return ibutton;
}
void ibutton_free(iButton* ibutton) {
furi_assert(ibutton);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewDialogEx);
dialog_ex_free(ibutton->dialog_ex);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewWidget);
widget_free(ibutton->widget);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewPopup);
popup_free(ibutton->popup);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewTextInput);
text_input_free(ibutton->text_input);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewByteInput);
byte_input_free(ibutton->byte_input);
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewSubmenu);
submenu_free(ibutton->submenu);
view_dispatcher_free(ibutton->view_dispatcher);
scene_manager_free(ibutton->scene_manager);
furi_record_close("storage");
ibutton->storage = NULL;
furi_record_close("notification");
ibutton->notifications = NULL;
furi_record_close("dialogs");
ibutton->dialogs = NULL;
furi_record_close("gui");
ibutton->gui = NULL;
ibutton_worker_stop_thread(ibutton->key_worker);
ibutton_worker_free(ibutton->key_worker);
ibutton_key_free(ibutton->key);
free(ibutton);
}
bool ibutton_file_select(iButton* ibutton) {
bool success = dialog_file_select_show(
ibutton->dialogs,
IBUTTON_APP_FOLDER,
IBUTTON_APP_EXTENSION,
ibutton->file_name,
IBUTTON_FILE_NAME_SIZE,
ibutton_key_get_name_p(ibutton->key));
if(success) {
string_t key_str;
string_init_printf(
key_str, "%s/%s%s", IBUTTON_APP_FOLDER, ibutton->file_name, IBUTTON_APP_EXTENSION);
success = ibutton_load_key_data(ibutton, key_str);
if(success) {
ibutton_key_set_name(ibutton->key, ibutton->file_name);
}
string_clear(key_str);
}
return success;
}
bool ibutton_load_key(iButton* ibutton, const char* key_name) {
string_t key_path;
string_init_set_str(key_path, key_name);
const bool success = ibutton_load_key_data(ibutton, key_path);
if(success) {
path_extract_filename_no_ext(key_name, key_path);
ibutton_key_set_name(ibutton->key, string_get_cstr(key_path));
}
string_clear(key_path);
return success;
}
bool ibutton_save_key(iButton* ibutton, const char* key_name) {
// Create ibutton directory if necessary
ibutton_make_app_folder(ibutton);
FlipperFormat* file = flipper_format_file_alloc(ibutton->storage);
iButtonKey* key = ibutton->key;
string_t key_file_name;
bool result = false;
string_init(key_file_name);
do {
// First remove key if it was saved (we rename the key)
if(!ibutton_delete_key(ibutton)) break;
// Save the key
ibutton_key_set_name(key, key_name);
// Set full file name, for new key
string_printf(
key_file_name,
"%s/%s%s",
IBUTTON_APP_FOLDER,
ibutton_key_get_name_p(key),
IBUTTON_APP_EXTENSION);
// Open file for write
if(!flipper_format_file_open_always(file, string_get_cstr(key_file_name))) break;
// Write header
if(!flipper_format_write_header_cstr(file, IBUTTON_APP_FILE_TYPE, 1)) break;
// Write key type
if(!flipper_format_write_comment_cstr(file, "Key type can be Cyfral, Dallas or Metakom"))
break;
const char* key_type = ibutton_key_get_string_by_type(ibutton_key_get_type(key));
if(!flipper_format_write_string_cstr(file, "Key type", key_type)) break;
// Write data
if(!flipper_format_write_comment_cstr(
file, "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8"))
break;
if(!flipper_format_write_hex(
file, "Data", ibutton_key_get_data_p(key), ibutton_key_get_data_size(key)))
break;
result = true;
} while(false);
flipper_format_free(file);
string_clear(key_file_name);
if(!result) {
dialog_message_show_storage_error(ibutton->dialogs, "Cannot save\nkey file");
}
return result;
}
bool ibutton_delete_key(iButton* ibutton) {
string_t file_name;
bool result = false;
string_init_printf(
file_name,
"%s/%s%s",
IBUTTON_APP_FOLDER,
ibutton_key_get_name_p(ibutton->key),
IBUTTON_APP_EXTENSION);
result = storage_simply_remove(ibutton->storage, string_get_cstr(file_name));
string_clear(file_name);
return result;
}
void ibutton_text_store_set(iButton* ibutton, const char* text, ...) {
va_list args;
va_start(args, text);
vsnprintf(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE, text, args);
va_end(args);
}
void ibutton_text_store_clear(iButton* ibutton) {
memset(ibutton->text_store, 0, IBUTTON_TEXT_STORE_SIZE);
}
void ibutton_switch_to_previous_scene_one_of(
iButton* ibutton,
const uint32_t* scene_ids,
size_t scene_ids_size) {
furi_assert(scene_ids_size);
SceneManager* scene_manager = ibutton->scene_manager;
for(size_t i = 0; i < scene_ids_size; ++i) {
const uint32_t scene_id = scene_ids[i];
if(scene_manager_has_previous_scene(scene_manager, scene_id)) {
scene_manager_search_and_switch_to_previous_scene(scene_manager, scene_id);
return;
}
}
}
void ibutton_notification_message(iButton* ibutton, uint32_t message) {
furi_assert(message < sizeof(ibutton_notification_sequences) / sizeof(NotificationSequence*));
notification_message(ibutton->notifications, ibutton_notification_sequences[message]);
}
int32_t ibutton_app(void* p) {
iButton* ibutton = ibutton_alloc();
ibutton_make_app_folder(ibutton);
if(p && ibutton_load_key(ibutton, (const char*)p)) {
// TODO: Display an error if the key from p could not be loaded
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
} else {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart);
}
view_dispatcher_run(ibutton->view_dispatcher);
ibutton_free(ibutton);
return 0;
}

View File

@ -1,10 +0,0 @@
#include "ibutton_app.h"
// app enter function
extern "C" int32_t ibutton_app(void* p) {
iButtonApp* app = new iButtonApp();
app->run(p);
delete app;
return 255;
}

View File

@ -0,0 +1,3 @@
#pragma once
typedef struct iButton iButton;

View File

@ -1,342 +0,0 @@
#include "ibutton_app.h"
#include <stdarg.h>
#include <furi_hal.h>
#include <m-string.h>
#include <toolbox/path.h>
#include <flipper_format/flipper_format.h>
const char* iButtonApp::app_folder = "/any/ibutton";
const char* iButtonApp::app_extension = ".ibtn";
const char* iButtonApp::app_filetype = "Flipper iButton key";
void iButtonApp::run(void* args) {
iButtonEvent event;
bool consumed;
bool exit = false;
make_app_folder();
if(args && load_key((const char*)args)) {
current_scene = Scene::SceneEmulate;
}
scenes[current_scene]->on_enter(this);
while(!exit) {
view.receive_event(&event);
consumed = scenes[current_scene]->on_event(this, &event);
if(!consumed) {
if(event.type == iButtonEvent::Type::EventTypeBack) {
exit = switch_to_previous_scene();
}
}
};
scenes[current_scene]->on_exit(this);
}
iButtonApp::iButtonApp()
: notification{"notification"}
, storage{"storage"}
, dialogs{"dialogs"} {
key = ibutton_key_alloc();
key_worker = ibutton_worker_alloc();
ibutton_worker_start_thread(key_worker);
}
iButtonApp::~iButtonApp() {
for(std::map<Scene, iButtonScene*>::iterator it = scenes.begin(); it != scenes.end(); ++it) {
delete it->second;
}
scenes.clear();
ibutton_worker_stop_thread(key_worker);
ibutton_worker_free(key_worker);
ibutton_key_free(key);
}
iButtonAppViewManager* iButtonApp::get_view_manager() {
return &view;
}
void iButtonApp::switch_to_next_scene(Scene next_scene) {
previous_scenes_list.push_front(current_scene);
if(next_scene != Scene::SceneExit) {
scenes[current_scene]->on_exit(this);
current_scene = next_scene;
scenes[current_scene]->on_enter(this);
}
}
void iButtonApp::search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list) {
Scene previous_scene = Scene::SceneStart;
bool scene_found = false;
while(!scene_found) {
previous_scene = get_previous_scene();
for(Scene element : scenes_list) {
if(previous_scene == element || previous_scene == Scene::SceneStart) {
scene_found = true;
break;
}
}
}
scenes[current_scene]->on_exit(this);
current_scene = previous_scene;
scenes[current_scene]->on_enter(this);
}
bool iButtonApp::switch_to_previous_scene(uint8_t count) {
Scene previous_scene = Scene::SceneStart;
for(uint8_t i = 0; i < count; i++) {
previous_scene = get_previous_scene();
if(previous_scene == Scene::SceneExit) break;
}
if(previous_scene == Scene::SceneExit) {
return true;
} else {
scenes[current_scene]->on_exit(this);
current_scene = previous_scene;
scenes[current_scene]->on_enter(this);
return false;
}
}
iButtonApp::Scene iButtonApp::get_previous_scene() {
Scene scene = previous_scenes_list.front();
previous_scenes_list.pop_front();
return scene;
}
iButtonWorker* iButtonApp::get_key_worker() {
return key_worker;
}
iButtonKey* iButtonApp::get_key() {
return key;
}
char* iButtonApp::get_file_name() {
return file_name;
}
uint8_t iButtonApp::get_file_name_size() {
return file_name_size;
}
void iButtonApp::notify_read() {
notification_message(notification, &sequence_blink_cyan_10);
}
void iButtonApp::notify_emulate() {
notification_message(notification, &sequence_blink_magenta_10);
}
void iButtonApp::notify_yellow_blink() {
notification_message(notification, &sequence_blink_yellow_10);
}
void iButtonApp::notify_error() {
notification_message(notification, &sequence_error);
}
void iButtonApp::notify_success() {
notification_message(notification, &sequence_success);
}
void iButtonApp::notify_green_on() {
notification_message_block(notification, &sequence_set_green_255);
}
void iButtonApp::notify_green_off() {
notification_message(notification, &sequence_reset_green);
}
void iButtonApp::notify_red_on() {
notification_message_block(notification, &sequence_set_red_255);
}
void iButtonApp::notify_red_off() {
notification_message(notification, &sequence_reset_red);
}
void iButtonApp::set_text_store(const char* text...) {
va_list args;
va_start(args, text);
vsnprintf(text_store, text_store_size, text, args);
va_end(args);
}
char* iButtonApp::get_text_store() {
return text_store;
}
uint8_t iButtonApp::get_text_store_size() {
return text_store_size;
}
// file managment
bool iButtonApp::save_key(const char* key_name) {
// Create ibutton directory if necessary
make_app_folder();
FlipperFormat* file = flipper_format_file_alloc(storage);
string_t key_file_name;
bool result = false;
string_init(key_file_name);
do {
// First remove key if it was saved (we rename the key)
if(!delete_key()) break;
// Save the key
ibutton_key_set_name(key, key_name);
// Set full file name, for new key
string_printf(
key_file_name, "%s/%s%s", app_folder, ibutton_key_get_name_p(key), app_extension);
// Open file for write
if(!flipper_format_file_open_always(file, string_get_cstr(key_file_name))) break;
// Write header
if(!flipper_format_write_header_cstr(file, iButtonApp::app_filetype, 1)) break;
// Write key type
if(!flipper_format_write_comment_cstr(file, "Key type can be Cyfral, Dallas or Metakom"))
break;
const char* key_type = ibutton_key_get_string_by_type(ibutton_key_get_type(key));
if(!flipper_format_write_string_cstr(file, "Key type", key_type)) break;
// Write data
if(!flipper_format_write_comment_cstr(
file, "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8"))
break;
if(!flipper_format_write_hex(
file, "Data", ibutton_key_get_data_p(key), ibutton_key_get_data_size(key)))
break;
result = true;
} while(false);
flipper_format_free(file);
string_clear(key_file_name);
if(!result) {
dialog_message_show_storage_error(dialogs, "Cannot save\nkey file");
}
return result;
}
bool iButtonApp::load_key_data(string_t key_path) {
FlipperFormat* file = flipper_format_file_alloc(storage);
bool result = false;
string_t data;
string_init(data);
do {
if(!flipper_format_file_open_existing(file, string_get_cstr(key_path))) break;
// header
uint32_t version;
if(!flipper_format_read_header(file, data, &version)) break;
if(string_cmp_str(data, iButtonApp::app_filetype) != 0) break;
if(version != 1) break;
// key type
iButtonKeyType type;
if(!flipper_format_read_string(file, "Key type", data)) break;
if(!ibutton_key_get_type_by_string(string_get_cstr(data), &type)) break;
// key data
uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0};
if(!flipper_format_read_hex(file, "Data", key_data, ibutton_key_get_size_by_type(type)))
break;
ibutton_key_set_type(key, type);
ibutton_key_set_data(key, key_data, IBUTTON_KEY_DATA_SIZE);
result = true;
} while(false);
flipper_format_free(file);
string_clear(data);
if(!result) {
dialog_message_show_storage_error(dialogs, "Cannot load\nkey file");
}
return result;
}
bool iButtonApp::load_key(const char* key_name) {
bool result = false;
string_t key_path;
string_init_set_str(key_path, key_name);
result = load_key_data(key_path);
if(result) {
path_extract_filename_no_ext(key_name, key_path);
ibutton_key_set_name(key, string_get_cstr(key_path));
}
string_clear(key_path);
return result;
}
bool iButtonApp::load_key() {
bool result = false;
// Input events and views are managed by file_select
bool res = dialog_file_select_show(
dialogs,
app_folder,
app_extension,
get_file_name(),
get_file_name_size(),
ibutton_key_get_name_p(key));
if(res) {
string_t key_str;
// Get key file path
string_init_printf(key_str, "%s/%s%s", app_folder, get_file_name(), app_extension);
result = load_key_data(key_str);
if(result) {
ibutton_key_set_name(key, get_file_name());
}
string_clear(key_str);
}
return result;
}
bool iButtonApp::delete_key() {
string_t file_name;
bool result = false;
string_init_printf(
file_name, "%s/%s%s", app_folder, ibutton_key_get_name_p(key), app_extension);
result = storage_simply_remove(storage, string_get_cstr(file_name));
string_clear(file_name);
return result;
}
void iButtonApp::make_app_folder() {
if(!storage_simply_mkdir(storage, app_folder)) {
dialog_message_show_storage_error(dialogs, "Cannot create\napp folder");
}
}

View File

@ -1,144 +0,0 @@
#pragma once
#include <map>
#include <list>
#include "ibutton_view_manager.h"
#include "scene/ibutton_scene_generic.h"
#include "scene/ibutton_scene_start.h"
#include "scene/ibutton_scene_read.h"
#include "scene/ibutton_scene_read_crc_error.h"
#include "scene/ibutton_scene_read_not_key_error.h"
#include "scene/ibutton_scene_read_success.h"
#include "scene/ibutton_scene_retry_confirm.h"
#include "scene/ibutton_scene_exit_confirm.h"
#include "scene/ibutton_scene_read_key_menu.h"
#include "scene/ibutton_scene_write.h"
#include "scene/ibutton_scene_write_success.h"
#include "scene/ibutton_scene_saved_key_menu.h"
#include "scene/ibutton_scene_delete_confirm.h"
#include "scene/ibutton_scene_delete_success.h"
#include "scene/ibutton_scene_emulate.h"
#include "scene/ibutton_scene_save_name.h"
#include "scene/ibutton_scene_save_success.h"
#include "scene/ibutton_scene_info.h"
#include "scene/ibutton_scene_select_key.h"
#include "scene/ibutton_scene_add_type.h"
#include "scene/ibutton_scene_add_value.h"
#include <one_wire/ibutton/ibutton_worker.h>
#include <notification/notification_messages.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include <record_controller.hpp>
class iButtonApp {
public:
void run(void* args);
iButtonApp();
~iButtonApp();
enum class Scene : uint8_t {
SceneExit,
SceneStart,
SceneRead,
SceneReadNotKeyError,
SceneReadCRCError,
SceneReadSuccess,
SceneRetryConfirm,
SceneExitConfirm,
SceneReadKeyMenu,
SceneWrite,
SceneWriteSuccess,
SceneEmulate,
SceneSavedKeyMenu,
SceneDeleteConfirm,
SceneDeleteSuccess,
SceneSaveName,
SceneSaveSuccess,
SceneInfo,
SceneSelectKey,
SceneAddType,
SceneAddValue,
};
static const char* app_folder;
static const char* app_extension;
static const char* app_filetype;
iButtonAppViewManager* get_view_manager();
void switch_to_next_scene(Scene index);
void search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list);
bool switch_to_previous_scene(uint8_t count = 1);
Scene get_previous_scene();
const GpioPin* get_ibutton_pin();
iButtonWorker* get_key_worker();
iButtonKey* get_key();
void notify_read();
void notify_yellow_blink();
void notify_emulate();
void notify_error();
void notify_success();
void notify_green_on();
void notify_green_off();
void notify_red_on();
void notify_red_off();
void set_text_store(const char* text...);
char* get_text_store();
uint8_t get_text_store_size();
char* get_file_name();
uint8_t get_file_name_size();
bool save_key(const char* key_name);
bool load_key();
bool load_key(const char* key_name);
bool delete_key();
private:
std::list<Scene> previous_scenes_list = {Scene::SceneExit};
Scene current_scene = Scene::SceneStart;
iButtonAppViewManager view;
std::map<Scene, iButtonScene*> scenes = {
{Scene::SceneStart, new iButtonSceneStart()},
{Scene::SceneRead, new iButtonSceneRead()},
{Scene::SceneReadCRCError, new iButtonSceneReadCRCError()},
{Scene::SceneReadNotKeyError, new iButtonSceneReadNotKeyError()},
{Scene::SceneReadSuccess, new iButtonSceneReadSuccess()},
{Scene::SceneRetryConfirm, new iButtonSceneRetryConfirm()},
{Scene::SceneExitConfirm, new iButtonSceneExitConfirm()},
{Scene::SceneReadKeyMenu, new iButtonSceneReadKeyMenu()},
{Scene::SceneWrite, new iButtonSceneWrite()},
{Scene::SceneWriteSuccess, new iButtonSceneWriteSuccess()},
{Scene::SceneEmulate, new iButtonSceneEmulate()},
{Scene::SceneSavedKeyMenu, new iButtonSceneSavedKeyMenu()},
{Scene::SceneDeleteConfirm, new iButtonSceneDeleteConfirm()},
{Scene::SceneDeleteSuccess, new iButtonSceneDeleteSuccess()},
{Scene::SceneSaveName, new iButtonSceneSaveName()},
{Scene::SceneSaveSuccess, new iButtonSceneSaveSuccess()},
{Scene::SceneInfo, new iButtonSceneInfo()},
{Scene::SceneSelectKey, new iButtonSceneSelectKey()},
{Scene::SceneAddType, new iButtonSceneAddType()},
{Scene::SceneAddValue, new iButtonSceneAddValue()},
};
iButtonWorker* key_worker;
iButtonKey* key;
RecordController<NotificationApp> notification;
RecordController<Storage> storage;
RecordController<DialogsApp> dialogs;
static const uint8_t file_name_size = 100;
char file_name[file_name_size];
static const uint8_t text_store_size = 128;
char text_store[text_store_size + 1];
bool load_key_data(string_t key_path);
void make_app_folder();
};

View File

@ -0,0 +1,12 @@
#pragma once
enum iButtonCustomEvent {
// Reserve first 100 events for button types and indexes, starting from 0
iButtonCustomEventReserved = 100,
iButtonCustomEventBack,
iButtonCustomEventTextEditResult,
iButtonCustomEventByteEditResult,
iButtonCustomEventWorkerEmulated,
iButtonCustomEventWorkerRead,
};

View File

@ -1,36 +0,0 @@
#pragma once
#include <stdint.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/widget.h>
#include <one_wire/ibutton/ibutton_worker.h>
class iButtonApp;
class iButtonEvent {
public:
// events enum
enum class Type : uint8_t {
EventTypeTick,
EventTypeBack,
EventTypeMenuSelected,
EventTypeDialogResult,
EventTypeTextEditResult,
EventTypeByteEditResult,
EventTypeWidgetButtonResult,
EventTypeWorkerEmulated,
EventTypeWorkerRead,
EventTypeWorkerWrite,
};
// payload
union {
uint32_t dummy;
uint32_t menu_index;
DialogExResult dialog_result;
GuiButtonType widget_button_result;
iButtonWorkerWriteResult worker_write_result;
} payload;
// event type
Type type;
};

View File

@ -0,0 +1,86 @@
#pragma once
#include "ibutton.h"
#include <gui/gui.h>
#include <gui/view.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <notification/notification_messages.h>
#include <one_wire/ibutton/ibutton_worker.h>
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include <gui/modules/submenu.h>
#include <gui/modules/popup.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/text_input.h>
#include <gui/modules/byte_input.h>
#include <gui/modules/widget.h>
#include "ibutton_custom_event.h"
#include "scenes/ibutton_scene.h"
#define IBUTTON_FILE_NAME_SIZE 100
#define IBUTTON_TEXT_STORE_SIZE 128
#define IBUTTON_APP_FOLDER "/any/ibutton"
#define IBUTTON_APP_EXTENSION ".ibtn"
#define IBUTTON_APP_FILE_TYPE "Flipper iButton key"
struct iButton {
SceneManager* scene_manager;
ViewDispatcher* view_dispatcher;
Gui* gui;
Storage* storage;
DialogsApp* dialogs;
NotificationApp* notifications;
iButtonWorker* key_worker;
iButtonKey* key;
char file_name[IBUTTON_FILE_NAME_SIZE];
char text_store[IBUTTON_TEXT_STORE_SIZE + 1];
Submenu* submenu;
ByteInput* byte_input;
TextInput* text_input;
Popup* popup;
Widget* widget;
DialogEx* dialog_ex;
};
typedef enum {
iButtonViewSubmenu,
iButtonViewByteInput,
iButtonViewTextInput,
iButtonViewPopup,
iButtonViewWidget,
iButtonViewDialogEx,
} iButtonView;
typedef enum {
iButtonNotificationMessageError,
iButtonNotificationMessageSuccess,
iButtonNotificationMessageRead,
iButtonNotificationMessageEmulate,
iButtonNotificationMessageYellowBlink,
iButtonNotificationMessageRedOn,
iButtonNotificationMessageRedOff,
iButtonNotificationMessageGreenOn,
iButtonNotificationMessageGreenOff,
} iButtonNotificationMessage;
bool ibutton_file_select(iButton* ibutton);
bool ibutton_load_key(iButton* ibutton, const char* key_name);
bool ibutton_save_key(iButton* ibutton, const char* key_name);
bool ibutton_delete_key(iButton* ibutton);
void ibutton_text_store_set(iButton* ibutton, const char* text, ...);
void ibutton_text_store_clear(iButton* ibutton);
void ibutton_switch_to_previous_scene_one_of(
iButton* ibutton,
const uint32_t* scene_ids,
size_t scene_ids_size);
void ibutton_notification_message(iButton* ibutton, uint32_t message);

View File

@ -1,140 +0,0 @@
#include "ibutton_view_manager.h"
#include "ibutton_event.h"
#include <callback-connector.h>
iButtonAppViewManager::iButtonAppViewManager() {
event_queue = osMessageQueueNew(10, sizeof(iButtonEvent), NULL);
view_dispatcher = view_dispatcher_alloc();
auto callback = cbc::obtain_connector(this, &iButtonAppViewManager::previous_view_callback);
dialog_ex = dialog_ex_alloc();
view_dispatcher_add_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewDialogEx),
dialog_ex_get_view(dialog_ex));
submenu = submenu_alloc();
view_dispatcher_add_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewSubmenu),
submenu_get_view(submenu));
text_input = text_input_alloc();
view_dispatcher_add_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewTextInput),
text_input_get_view(text_input));
byte_input = byte_input_alloc();
view_dispatcher_add_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewByteInput),
byte_input_get_view(byte_input));
popup = popup_alloc();
view_dispatcher_add_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewPopup),
popup_get_view(popup));
widget = widget_alloc();
view_dispatcher_add_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewWidget),
widget_get_view(widget));
gui = static_cast<Gui*>(furi_record_open("gui"));
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
//TODO think about that method, seems unsafe and over-engineered
view_set_previous_callback(dialog_ex_get_view(dialog_ex), callback);
view_set_previous_callback(submenu_get_view(submenu), callback);
view_set_previous_callback(text_input_get_view(text_input), callback);
view_set_previous_callback(byte_input_get_view(byte_input), callback);
view_set_previous_callback(popup_get_view(popup), callback);
view_set_previous_callback(widget_get_view(widget), callback);
}
iButtonAppViewManager::~iButtonAppViewManager() {
// remove views
view_dispatcher_remove_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewDialogEx));
view_dispatcher_remove_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewSubmenu));
view_dispatcher_remove_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewTextInput));
view_dispatcher_remove_view(
view_dispatcher, static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewPopup));
view_dispatcher_remove_view(
view_dispatcher,
static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewByteInput));
view_dispatcher_remove_view(
view_dispatcher, static_cast<uint32_t>(iButtonAppViewManager::Type::iButtonAppViewWidget));
// free view modules
popup_free(popup);
text_input_free(text_input);
byte_input_free(byte_input);
submenu_free(submenu);
dialog_ex_free(dialog_ex);
widget_free(widget);
// free dispatcher
view_dispatcher_free(view_dispatcher);
// free event queue
osMessageQueueDelete(event_queue);
}
void iButtonAppViewManager::switch_to(Type type) {
view_dispatcher_switch_to_view(view_dispatcher, static_cast<uint32_t>(type));
}
Submenu* iButtonAppViewManager::get_submenu() {
return submenu;
}
Popup* iButtonAppViewManager::get_popup() {
return popup;
}
DialogEx* iButtonAppViewManager::get_dialog_ex() {
return dialog_ex;
}
TextInput* iButtonAppViewManager::get_text_input() {
return text_input;
}
ByteInput* iButtonAppViewManager::get_byte_input() {
return byte_input;
}
Widget* iButtonAppViewManager::get_widget() {
return widget;
}
void iButtonAppViewManager::receive_event(iButtonEvent* event) {
if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) {
event->type = iButtonEvent::Type::EventTypeTick;
}
}
void iButtonAppViewManager::send_event(iButtonEvent* event) {
osStatus_t result = osMessageQueuePut(event_queue, event, 0, 0);
furi_check(result == osOK);
}
uint32_t iButtonAppViewManager::previous_view_callback(void*) {
if(event_queue != NULL) {
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeBack;
send_event(&event);
}
return VIEW_IGNORE;
}

View File

@ -1,51 +0,0 @@
#pragma once
#include <furi.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/submenu.h>
#include <gui/modules/text_input.h>
#include <gui/modules/byte_input.h>
#include <gui/modules/popup.h>
#include <gui/modules/widget.h>
#include "ibutton_event.h"
class iButtonAppViewManager {
public:
enum class Type : uint8_t {
iButtonAppViewTextInput,
iButtonAppViewByteInput,
iButtonAppViewSubmenu,
iButtonAppViewDialogEx,
iButtonAppViewPopup,
iButtonAppViewWidget,
};
osMessageQueueId_t event_queue;
iButtonAppViewManager();
~iButtonAppViewManager();
void switch_to(Type type);
Submenu* get_submenu();
Popup* get_popup();
DialogEx* get_dialog_ex();
TextInput* get_text_input();
ByteInput* get_byte_input();
Widget* get_widget();
void receive_event(iButtonEvent* event);
void send_event(iButtonEvent* event);
private:
ViewDispatcher* view_dispatcher;
DialogEx* dialog_ex;
Submenu* submenu;
TextInput* text_input;
ByteInput* byte_input;
Popup* popup;
Widget* widget;
Gui* gui;
uint32_t previous_view_callback(void* context);
};

View File

@ -1,66 +0,0 @@
#include "ibutton_scene_add_type.h"
#include "../ibutton_app.h"
#include <callback-connector.h>
typedef enum {
SubmenuIndexCyfral,
SubmenuIndexDallas,
SubmenuIndexMetakom,
} SubmenuIndex;
static void submenu_callback(void* context, uint32_t index) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeMenuSelected;
event.payload.menu_index = index;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneAddType::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu();
submenu_add_item(submenu, "Cyfral", SubmenuIndexCyfral, submenu_callback, app);
submenu_add_item(submenu, "Dallas", SubmenuIndexDallas, submenu_callback, app);
submenu_add_item(submenu, "Metakom", SubmenuIndexMetakom, submenu_callback, app);
submenu_set_selected_item(submenu, submenu_item_selected);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu);
}
bool iButtonSceneAddType::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeMenuSelected) {
submenu_item_selected = event->payload.menu_index;
iButtonKey* key = app->get_key();
switch(event->payload.menu_index) {
case SubmenuIndexCyfral:
ibutton_key_set_type(key, iButtonKeyCyfral);
break;
case SubmenuIndexDallas:
ibutton_key_set_type(key, iButtonKeyDS1990);
break;
case SubmenuIndexMetakom:
ibutton_key_set_type(key, iButtonKeyMetakom);
break;
}
ibutton_key_set_name(key, "");
ibutton_key_clear_data(key);
app->switch_to_next_scene(iButtonApp::Scene::SceneAddValue);
consumed = true;
}
return consumed;
}
void iButtonSceneAddType::on_exit(iButtonApp* app) {
iButtonAppViewManager* view = app->get_view_manager();
Submenu* submenu = view->get_submenu();
submenu_reset(submenu);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneAddType : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
private:
uint32_t submenu_item_selected = 0;
};

View File

@ -1,53 +0,0 @@
#include "ibutton_scene_add_value.h"
#include "../ibutton_app.h"
#include <dolphin/dolphin.h>
static void byte_input_callback(void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeByteEditResult;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneAddValue::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
ByteInput* byte_input = view_manager->get_byte_input();
iButtonKey* key = app->get_key();
memcpy(this->new_key_data, ibutton_key_get_data_p(key), ibutton_key_get_data_size(key));
byte_input_set_result_callback(
byte_input,
byte_input_callback,
NULL,
app,
this->new_key_data,
ibutton_key_get_data_size(key));
byte_input_set_header_text(byte_input, "Enter the key");
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewByteInput);
}
bool iButtonSceneAddValue::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeByteEditResult) {
ibutton_key_set_data(app->get_key(), this->new_key_data, IBUTTON_KEY_DATA_SIZE);
DOLPHIN_DEED(DolphinDeedIbuttonAdd);
app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName);
consumed = true;
}
return consumed;
}
void iButtonSceneAddValue::on_exit(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
ByteInput* byte_input = view_manager->get_byte_input();
byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(byte_input, {0});
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
#include <one_wire/ibutton/ibutton_key.h>
class iButtonSceneAddValue : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
private:
uint8_t new_key_data[IBUTTON_KEY_DATA_SIZE] = {};
};

View File

@ -1,86 +0,0 @@
#include "ibutton_scene_delete_confirm.h"
#include "../ibutton_app.h"
static void widget_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
if(type == InputTypeShort) {
event.type = iButtonEvent::Type::EventTypeWidgetButtonResult;
event.payload.widget_button_result = result;
app->get_view_manager()->send_event(&event);
}
}
void iButtonSceneDeleteConfirm::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Widget* widget = view_manager->get_widget();
iButtonKey* key = app->get_key();
const uint8_t* key_data = ibutton_key_get_data_p(key);
app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key));
widget_add_text_box_element(
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store(), false);
widget_add_button_element(widget, GuiButtonTypeLeft, "Cancel", widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app);
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
app->set_text_store(
"%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:
app->set_text_store("%02X %02X", key_data[0], key_data[1]);
widget_add_string_element(
widget, 64, 45, AlignCenter, AlignBottom, FontSecondary, "Cyfral");
break;
case iButtonKeyMetakom:
app->set_text_store(
"%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, app->get_text_store());
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget);
}
bool iButtonSceneDeleteConfirm::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeWidgetButtonResult) {
if(event->payload.widget_button_result == GuiButtonTypeRight) {
if(app->delete_key()) {
app->switch_to_next_scene(iButtonApp::Scene::SceneDeleteSuccess);
}
} else {
app->switch_to_previous_scene();
}
consumed = true;
}
return consumed;
}
void iButtonSceneDeleteConfirm::on_exit(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Widget* widget = view_manager->get_widget();
app->set_text_store("");
widget_reset(widget);
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneDeleteConfirm : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,47 +0,0 @@
#include "ibutton_scene_delete_success.h"
#include "../ibutton_app.h"
static void popup_callback(void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeBack;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneDeleteSuccess::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Popup* popup = view_manager->get_popup();
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
popup_set_callback(popup, popup_callback);
popup_set_context(popup, app);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup);
}
bool iButtonSceneDeleteSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeBack) {
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneSelectKey});
consumed = true;
}
return consumed;
}
void iButtonSceneDeleteSuccess::on_exit(iButtonApp* app) {
Popup* popup = app->get_view_manager()->get_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

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneDeleteSuccess : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneEmulate : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,51 +0,0 @@
#include "ibutton_scene_exit_confirm.h"
#include "../ibutton_app.h"
static void widget_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
if(type == InputTypeShort) {
event.type = iButtonEvent::Type::EventTypeWidgetButtonResult;
event.payload.widget_button_result = result;
app->get_view_manager()->send_event(&event);
}
}
void iButtonSceneExitConfirm::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Widget* widget = view_manager->get_widget();
widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "Stay", widget_callback, app);
widget_add_string_element(
widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu");
widget_add_string_element(
widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost");
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget);
}
bool iButtonSceneExitConfirm::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeWidgetButtonResult) {
if(event->payload.widget_button_result == GuiButtonTypeLeft) {
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneStart});
} else if(event->payload.widget_button_result == GuiButtonTypeRight) {
app->switch_to_previous_scene();
}
consumed = true;
} else if(event->type == iButtonEvent::Type::EventTypeBack) {
consumed = true;
}
return consumed;
}
void iButtonSceneExitConfirm::on_exit(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Widget* widget = view_manager->get_widget();
widget_reset(widget);
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneExitConfirm : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,14 +0,0 @@
#pragma once
#include "../ibutton_event.h"
class iButtonApp;
class iButtonScene {
public:
virtual void on_enter(iButtonApp* app) = 0;
virtual bool on_event(iButtonApp* app, iButtonEvent* event) = 0;
virtual void on_exit(iButtonApp* app) = 0;
virtual ~iButtonScene(){};
private:
};

View File

@ -1,58 +0,0 @@
#include "ibutton_scene_info.h"
#include "../ibutton_app.h"
void iButtonSceneInfo::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Widget* widget = view_manager->get_widget();
iButtonKey* key = app->get_key();
const uint8_t* key_data = ibutton_key_get_data_p(key);
app->set_text_store("%s", ibutton_key_get_name_p(key));
widget_add_text_box_element(
widget, 0, 0, 128, 28, AlignCenter, AlignCenter, app->get_text_store(), false);
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
app->set_text_store(
"%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:
app->set_text_store(
"%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:
app->set_text_store("%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, app->get_text_store());
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget);
}
bool iButtonSceneInfo::on_event(iButtonApp*, iButtonEvent*) {
return false;
}
void iButtonSceneInfo::on_exit(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Widget* widget = view_manager->get_widget();
app->set_text_store("");
widget_reset(widget);
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneInfo : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,72 +0,0 @@
#include "ibutton_scene_read.h"
#include "../ibutton_app.h"
#include <dolphin/dolphin.h>
static void read_callback(void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event = {
.payload = {.dummy = 0},
.type = iButtonEvent::Type::EventTypeWorkerRead,
};
app->get_view_manager()->send_event(&event);
}
void iButtonSceneRead::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Popup* popup = view_manager->get_popup();
iButtonKey* key = app->get_key();
iButtonWorker* worker = app->get_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_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup);
ibutton_key_set_name(key, "");
ibutton_worker_read_set_callback(worker, read_callback, app);
ibutton_worker_read_start(worker, key);
}
bool iButtonSceneRead::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeWorkerRead) {
consumed = true;
iButtonKey* key = app->get_key();
bool success = false;
if(ibutton_key_get_type(key) == iButtonKeyDS1990) {
if(!ibutton_key_dallas_crc_is_valid(key)) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadCRCError);
} else if(!ibutton_key_dallas_is_1990_key(key)) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadNotKeyError);
} else {
success = true;
}
} else {
success = true;
}
if(success) {
app->notify_success();
app->notify_green_on();
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess);
}
} else if(event->type == iButtonEvent::Type::EventTypeTick) {
consumed = true;
app->notify_read();
}
return consumed;
}
void iButtonSceneRead::on_exit(iButtonApp* app) {
Popup* popup = app->get_view_manager()->get_popup();
ibutton_worker_stop(app->get_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);
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneRead : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,74 +0,0 @@
#include "ibutton_scene_read_crc_error.h"
#include "../ibutton_app.h"
#include <one_wire/maxim_crc.h>
static void dialog_ex_callback(DialogExResult result, void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeDialogResult;
event.payload.dialog_result = result;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneReadCRCError::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
DialogEx* dialog_ex = view_manager->get_dialog_ex();
const uint8_t* key_data = ibutton_key_get_data_p(app->get_key());
app->set_text_store(
"%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, app->get_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, dialog_ex_callback);
dialog_ex_set_context(dialog_ex, app);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx);
app->notify_error();
app->notify_red_on();
}
bool iButtonSceneReadCRCError::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
if(event->payload.dialog_result == DialogExResultRight) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
} else {
app->switch_to_previous_scene();
}
consumed = true;
}
return consumed;
}
void iButtonSceneReadCRCError::on_exit(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
DialogEx* dialog_ex = view_manager->get_dialog_ex();
app->set_text_store("");
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
app->notify_red_off();
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneReadCRCError : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,65 +0,0 @@
#include "ibutton_scene_read_key_menu.h"
#include "../ibutton_app.h"
typedef enum {
SubmenuIndexSave,
SubmenuIndexEmulate,
SubmenuIndexWrite,
} SubmenuIndex;
static void submenu_callback(void* context, uint32_t index) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeMenuSelected;
event.payload.menu_index = index;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneReadKeyMenu::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu();
submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app);
submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app);
if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) {
submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app);
}
submenu_set_selected_item(submenu, submenu_item_selected);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu);
}
bool iButtonSceneReadKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeMenuSelected) {
submenu_item_selected = event->payload.menu_index;
switch(event->payload.menu_index) {
case SubmenuIndexWrite:
app->switch_to_next_scene(iButtonApp::Scene::SceneWrite);
break;
case SubmenuIndexEmulate:
app->switch_to_next_scene(iButtonApp::Scene::SceneEmulate);
break;
case SubmenuIndexSave:
app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName);
break;
}
consumed = true;
} else if(event->type == iButtonEvent::Type::EventTypeBack) {
app->switch_to_previous_scene();
consumed = true;
}
return consumed;
}
void iButtonSceneReadKeyMenu::on_exit(iButtonApp* app) {
iButtonAppViewManager* view = app->get_view_manager();
Submenu* submenu = view->get_submenu();
submenu_reset(submenu);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneReadKeyMenu : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
private:
uint32_t submenu_item_selected = 0;
};

View File

@ -1,74 +0,0 @@
#include "ibutton_scene_read_not_key_error.h"
#include "../ibutton_app.h"
#include <one_wire/maxim_crc.h>
static void dialog_ex_callback(DialogExResult result, void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeDialogResult;
event.payload.dialog_result = result;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneReadNotKeyError::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
DialogEx* dialog_ex = view_manager->get_dialog_ex();
const uint8_t* key_data = ibutton_key_get_data_p(app->get_key());
app->set_text_store(
"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, "ERROR:", 64, 10, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, app->get_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, dialog_ex_callback);
dialog_ex_set_context(dialog_ex, app);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx);
app->notify_error();
app->notify_red_on();
}
bool iButtonSceneReadNotKeyError::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
if(event->payload.dialog_result == DialogExResultRight) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
} else {
app->switch_to_previous_scene();
}
consumed = true;
}
return consumed;
}
void iButtonSceneReadNotKeyError::on_exit(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
DialogEx* dialog_ex = view_manager->get_dialog_ex();
app->set_text_store("");
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
app->notify_red_off();
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneReadNotKeyError : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,86 +0,0 @@
#include "ibutton_scene_read_success.h"
#include "../ibutton_app.h"
#include <dolphin/dolphin.h>
static void dialog_ex_callback(DialogExResult result, void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeDialogResult;
event.payload.dialog_result = result;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneReadSuccess::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
DialogEx* dialog_ex = view_manager->get_dialog_ex();
iButtonKey* key = app->get_key();
const uint8_t* key_data = ibutton_key_get_data_p(key);
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
app->set_text_store(
"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:
app->set_text_store("Cyfral\n%02X %02X", key_data[0], key_data[1]);
break;
case iButtonKeyMetakom:
app->set_text_store(
"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, app->get_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, dialog_ex_callback);
dialog_ex_set_context(dialog_ex, app);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx);
}
bool iButtonSceneReadSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
if(event->payload.dialog_result == DialogExResultRight) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
} else {
app->switch_to_next_scene(iButtonApp::Scene::SceneRetryConfirm);
}
consumed = true;
} else if(event->type == iButtonEvent::Type::EventTypeBack) {
app->switch_to_next_scene(iButtonApp::Scene::SceneExitConfirm);
consumed = true;
}
return consumed;
}
void iButtonSceneReadSuccess::on_exit(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
DialogEx* dialog_ex = view_manager->get_dialog_ex();
app->set_text_store("");
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_right_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
app->notify_green_off();
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneReadSuccess : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,51 +0,0 @@
#include "ibutton_scene_retry_confirm.h"
#include "../ibutton_app.h"
static void widget_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
if(type == InputTypeShort) {
event.type = iButtonEvent::Type::EventTypeWidgetButtonResult;
event.payload.widget_button_result = result;
app->get_view_manager()->send_event(&event);
}
}
void iButtonSceneRetryConfirm::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Widget* widget = view_manager->get_widget();
widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "Stay", widget_callback, app);
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_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewWidget);
}
bool iButtonSceneRetryConfirm::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeWidgetButtonResult) {
if(event->payload.widget_button_result == GuiButtonTypeLeft) {
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneRead});
} else if(event->payload.widget_button_result == GuiButtonTypeRight) {
app->switch_to_previous_scene();
}
consumed = true;
} else if(event->type == iButtonEvent::Type::EventTypeBack) {
consumed = true;
}
return consumed;
}
void iButtonSceneRetryConfirm::on_exit(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Widget* widget = view_manager->get_widget();
widget_reset(widget);
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneRetryConfirm : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,70 +0,0 @@
#include "ibutton_scene_save_name.h"
#include "../ibutton_app.h"
#include <lib/toolbox/random_name.h>
static void text_input_callback(void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeTextEditResult;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneSaveName::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
TextInput* text_input = view_manager->get_text_input();
const char* key_name = ibutton_key_get_name_p(app->get_key());
bool key_name_empty = !strcmp(key_name, "");
if(key_name_empty) {
set_random_name(app->get_text_store(), app->get_text_store_size());
} else {
app->set_text_store("%s", key_name);
}
text_input_set_header_text(text_input, "Name the key");
text_input_set_result_callback(
text_input,
text_input_callback,
app,
app->get_text_store(),
IBUTTON_KEY_NAME_SIZE,
key_name_empty);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(app->app_folder, app->app_extension, key_name);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewTextInput);
}
bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeTextEditResult) {
if(app->save_key(app->get_text_store())) {
app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess);
} else {
app->search_and_switch_to_previous_scene(
{iButtonApp::Scene::SceneReadKeyMenu,
iButtonApp::Scene::SceneSavedKeyMenu,
iButtonApp::Scene::SceneAddType});
}
consumed = true;
}
return consumed;
}
void iButtonSceneSaveName::on_exit(iButtonApp* app) {
TextInput* text_input = app->get_view_manager()->get_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

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneSaveName : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,52 +0,0 @@
#include "ibutton_scene_save_success.h"
#include "../ibutton_app.h"
#include <dolphin/dolphin.h>
static void popup_callback(void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeBack;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneSaveSuccess::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Popup* popup = view_manager->get_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, popup_callback);
popup_set_context(popup, app);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup);
}
bool iButtonSceneSaveSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeBack) {
app->search_and_switch_to_previous_scene(
{iButtonApp::Scene::SceneReadKeyMenu,
iButtonApp::Scene::SceneSavedKeyMenu,
iButtonApp::Scene::SceneAddType});
consumed = true;
}
return consumed;
}
void iButtonSceneSaveSuccess::on_exit(iButtonApp* app) {
Popup* popup = app->get_view_manager()->get_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

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneSaveSuccess : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,73 +0,0 @@
#include "ibutton_scene_saved_key_menu.h"
#include "../ibutton_app.h"
#include <callback-connector.h>
typedef enum {
SubmenuIndexEmulate,
SubmenuIndexWrite,
SubmenuIndexEdit,
SubmenuIndexDelete,
SubmenuIndexInfo,
} SubmenuIndex;
static void submenu_callback(void* context, uint32_t index) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeMenuSelected;
event.payload.menu_index = index;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneSavedKeyMenu::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu();
submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app);
if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) {
submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app);
}
submenu_add_item(submenu, "Edit", SubmenuIndexEdit, submenu_callback, app);
submenu_add_item(submenu, "Delete", SubmenuIndexDelete, submenu_callback, app);
submenu_add_item(submenu, "Info", SubmenuIndexInfo, submenu_callback, app);
submenu_set_selected_item(submenu, submenu_item_selected);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu);
}
bool iButtonSceneSavedKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeMenuSelected) {
submenu_item_selected = event->payload.menu_index;
switch(event->payload.menu_index) {
case SubmenuIndexWrite:
app->switch_to_next_scene(iButtonApp::Scene::SceneWrite);
break;
case SubmenuIndexEmulate:
app->switch_to_next_scene(iButtonApp::Scene::SceneEmulate);
break;
case SubmenuIndexEdit:
app->switch_to_next_scene(iButtonApp::Scene::SceneAddValue);
break;
case SubmenuIndexDelete:
app->switch_to_next_scene(iButtonApp::Scene::SceneDeleteConfirm);
break;
case SubmenuIndexInfo:
app->switch_to_next_scene(iButtonApp::Scene::SceneInfo);
break;
}
consumed = true;
}
return consumed;
}
void iButtonSceneSavedKeyMenu::on_exit(iButtonApp* app) {
iButtonAppViewManager* view = app->get_view_manager();
Submenu* submenu = view->get_submenu();
submenu_reset(submenu);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneSavedKeyMenu : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
private:
uint32_t submenu_item_selected = 0;
};

View File

@ -1,18 +0,0 @@
#include "ibutton_scene_select_key.h"
#include "../ibutton_app.h"
void iButtonSceneSelectKey::on_enter(iButtonApp* app) {
// Process file_select return
if(app->load_key()) {
app->switch_to_next_scene(iButtonApp::Scene::SceneSavedKeyMenu);
} else {
app->switch_to_previous_scene();
}
}
bool iButtonSceneSelectKey::on_event(iButtonApp*, iButtonEvent*) {
return false;
}
void iButtonSceneSelectKey::on_exit(iButtonApp*) {
}

View File

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneSelectKey : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

View File

@ -1,60 +0,0 @@
#include "ibutton_scene_start.h"
#include "../ibutton_app.h"
typedef enum {
SubmenuIndexRead,
SubmenuIndexSaved,
SubmenuIndexAdd,
} SubmenuIndex;
static void submenu_callback(void* context, uint32_t index) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeMenuSelected;
event.payload.menu_index = index;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneStart::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu();
submenu_add_item(submenu, "Read", SubmenuIndexRead, submenu_callback, app);
submenu_add_item(submenu, "Saved", SubmenuIndexSaved, submenu_callback, app);
submenu_add_item(submenu, "Add Manually", SubmenuIndexAdd, submenu_callback, app);
submenu_set_selected_item(submenu, submenu_item_selected);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu);
}
bool iButtonSceneStart::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeMenuSelected) {
submenu_item_selected = event->payload.menu_index;
switch(event->payload.menu_index) {
case SubmenuIndexRead:
app->switch_to_next_scene(iButtonApp::Scene::SceneRead);
break;
case SubmenuIndexSaved:
app->switch_to_next_scene(iButtonApp::Scene::SceneSelectKey);
break;
case SubmenuIndexAdd:
app->switch_to_next_scene(iButtonApp::Scene::SceneAddType);
break;
}
consumed = true;
}
return consumed;
}
void iButtonSceneStart::on_exit(iButtonApp* app) {
iButtonAppViewManager* view = app->get_view_manager();
Submenu* submenu = view->get_submenu();
submenu_reset(submenu);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneStart : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
private:
uint32_t submenu_item_selected = 0;
};

View File

@ -1,111 +0,0 @@
#include "ibutton_scene_write.h"
#include "../ibutton_app.h"
static void ibutton_worker_write_cb(void* context, iButtonWorkerWriteResult result) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeWorkerWrite;
event.payload.worker_write_result = result;
app->get_view_manager()->send_event(&event);
}
void iButtonSceneWrite::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Popup* popup = view_manager->get_popup();
iButtonKey* key = app->get_key();
iButtonWorker* worker = app->get_key_worker();
const uint8_t* key_data = ibutton_key_get_data_p(key);
const char* key_name = ibutton_key_get_name_p(key);
uint8_t line_count = 2;
// check that stored key has name
if(strcmp(key_name, "") != 0) {
app->set_text_store("writing\n%s", key_name);
line_count = 2;
} else {
// if not, show key data
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
app->set_text_store(
"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:
app->set_text_store("writing\n%02X %02X", key_data[0], key_data[1]);
line_count = 2;
break;
case iButtonKeyMetakom:
app->set_text_store(
"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, app->get_text_store(), 82, 22, AlignCenter, AlignTop);
break;
default:
popup_set_header(popup, "iButton", 82, 24, AlignCenter, AlignBottom);
popup_set_text(popup, app->get_text_store(), 82, 28, AlignCenter, AlignTop);
break;
}
popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup);
blink_yellow = false;
ibutton_worker_write_set_callback(worker, ibutton_worker_write_cb, app);
ibutton_worker_write_start(worker, key);
}
bool iButtonSceneWrite::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeWorkerWrite) {
consumed = true;
switch(event->payload.worker_write_result) {
case iButtonWorkerWriteOK:
case iButtonWorkerWriteSameKey:
app->switch_to_next_scene(iButtonApp::Scene::SceneWriteSuccess);
break;
case iButtonWorkerWriteNoDetect:
blink_yellow = false;
break;
case iButtonWorkerWriteCannotWrite:
blink_yellow = true;
break;
}
} else if(event->type == iButtonEvent::Type::EventTypeTick) {
if(blink_yellow) {
app->notify_yellow_blink();
} else {
app->notify_emulate();
}
}
return consumed;
}
void iButtonSceneWrite::on_exit(iButtonApp* app) {
Popup* popup = app->get_view_manager()->get_popup();
ibutton_worker_stop(app->get_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);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneWrite : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
private:
bool blink_yellow;
};

View File

@ -1,52 +0,0 @@
#include "ibutton_scene_write_success.h"
#include "../ibutton_app.h"
static void popup_callback(void* context) {
furi_assert(context);
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event;
event.type = iButtonEvent::Type::EventTypeBack;
app->get_view_manager()->send_event(&event);
app->notify_green_off();
}
void iButtonSceneWriteSuccess::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Popup* popup = view_manager->get_popup();
popup_set_icon(popup, 0, 12, &I_iButtonDolphinVerySuccess_108x52);
popup_set_text(popup, "Successfully written!", 40, 12, AlignLeft, AlignBottom);
popup_set_callback(popup, popup_callback);
popup_set_context(popup, app);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup);
app->notify_success();
app->notify_green_on();
}
bool iButtonSceneWriteSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeBack) {
app->search_and_switch_to_previous_scene(
{iButtonApp::Scene::SceneReadKeyMenu, iButtonApp::Scene::SceneStart});
consumed = true;
}
return consumed;
}
void iButtonSceneWriteSuccess::on_exit(iButtonApp* app) {
Popup* popup = app->get_view_manager()->get_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

@ -1,9 +0,0 @@
#pragma once
#include "ibutton_scene_generic.h"
class iButtonSceneWriteSuccess : public iButtonScene {
public:
void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final;
void on_exit(iButtonApp* app) final;
};

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,58 @@
#include "../ibutton_i.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, SubmenuIndexCyfral);
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) {
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");
}
ibutton_key_set_name(key, "");
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,20 @@
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)

View File

@ -0,0 +1,91 @@
#include "../ibutton_i.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);
ibutton_text_store_set(ibutton, "\e#Delete %s?\e#", ibutton_key_get_name_p(key));
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);
}
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

@ -1,37 +1,35 @@
#include "ibutton_scene_emulate.h"
#include "../ibutton_app.h"
#include "../ibutton_i.h"
#include <dolphin/dolphin.h>
static void emulate_callback(void* context, bool emulated) {
furi_assert(context);
static void ibutton_scene_emulate_callback(void* context, bool emulated) {
iButton* ibutton = context;
if(emulated) {
iButtonApp* app = static_cast<iButtonApp*>(context);
iButtonEvent event = {
.payload = {.worker_write_result = iButtonWorkerWriteOK},
.type = iButtonEvent::Type::EventTypeWorkerEmulated,
};
app->get_view_manager()->send_event(&event);
view_dispatcher_send_custom_event(
ibutton->view_dispatcher, iButtonCustomEventWorkerEmulated);
}
}
void iButtonSceneEmulate::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Popup* popup = view_manager->get_popup();
iButtonKey* key = app->get_key();
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);
const char* key_name = ibutton_key_get_name_p(key);
uint8_t line_count = 2;
DOLPHIN_DEED(DolphinDeedIbuttonEmulate);
// check that stored key has name
if(strcmp(key_name, "") != 0) {
app->set_text_store("emulating\n%s", key_name);
ibutton_text_store_set(ibutton, "emulating\n%s", key_name);
line_count = 2;
} else {
// if not, show key data
switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990:
app->set_text_store(
ibutton_text_store_set(
ibutton,
"emulating\n%02X %02X %02X %02X\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
@ -44,11 +42,12 @@ void iButtonSceneEmulate::on_enter(iButtonApp* app) {
line_count = 3;
break;
case iButtonKeyCyfral:
app->set_text_store("emulating\n%02X %02X", key_data[0], key_data[1]);
ibutton_text_store_set(ibutton, "emulating\n%02X %02X", key_data[0], key_data[1]);
line_count = 2;
break;
case iButtonKeyMetakom:
app->set_text_store(
ibutton_text_store_set(
ibutton,
"emulating\n%02X %02X %02X %02X",
key_data[0],
key_data[1],
@ -62,40 +61,45 @@ void iButtonSceneEmulate::on_enter(iButtonApp* app) {
switch(line_count) {
case 3:
popup_set_header(popup, "iButton", 82, 18, AlignCenter, AlignBottom);
popup_set_text(popup, app->get_text_store(), 82, 22, AlignCenter, AlignTop);
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, app->get_text_store(), 82, 28, AlignCenter, AlignTop);
popup_set_text(popup, ibutton->text_store, 82, 28, AlignCenter, AlignTop);
break;
}
popup_set_icon(popup, 2, 10, &I_iButtonKey_49x44);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewPopup);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
ibutton_worker_emulate_set_callback(app->get_key_worker(), emulate_callback, app);
ibutton_worker_emulate_start(app->get_key_worker(), key);
ibutton_worker_emulate_set_callback(
ibutton->key_worker, ibutton_scene_emulate_callback, ibutton);
ibutton_worker_emulate_start(ibutton->key_worker, key);
}
bool iButtonSceneEmulate::on_event(iButtonApp* app, iButtonEvent* event) {
bool ibutton_scene_emulate_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeWorkerEmulated) {
app->notify_yellow_blink();
if(event.type == SceneManagerEventTypeTick) {
consumed = true;
} else if(event->type == iButtonEvent::Type::EventTypeTick) {
app->notify_emulate();
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulate);
} else if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventWorkerEmulated) {
ibutton_notification_message(ibutton, iButtonNotificationMessageYellowBlink);
}
}
return consumed;
}
void iButtonSceneEmulate::on_exit(iButtonApp* app) {
Popup* popup = app->get_view_manager()->get_popup();
ibutton_worker_stop(app->get_key_worker());
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);

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, 29, 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,61 @@
#include "../ibutton_i.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);
ibutton_text_store_set(ibutton, "%s", ibutton_key_get_name_p(key));
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);
}
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,72 @@
#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);
ibutton_key_set_name(key, "");
ibutton_worker_read_set_callback(worker, ibutton_scene_read_callback, ibutton);
ibutton_worker_read_start(worker, key);
}
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;
ibutton_notification_message(ibutton, iButtonNotificationMessageRead);
} 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);
}

View File

@ -0,0 +1,71 @@
#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 == 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_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
}

View File

@ -0,0 +1,61 @@
#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, SubmenuIndexSave);
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) {
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,72 @@
#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 == 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_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
ibutton_notification_message(ibutton, iButtonNotificationMessageRedOff);
}

View File

@ -0,0 +1,87 @@
#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_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_right_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
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,68 @@
#include "../ibutton_i.h"
#include <lib/toolbox/random_name.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;
const char* key_name = ibutton_key_get_name_p(ibutton->key);
const bool key_name_is_empty = !strcmp(key_name, "");
if(key_name_is_empty) {
set_random_name(ibutton->text_store, IBUTTON_TEXT_STORE_SIZE);
} else {
ibutton_text_store_set(ibutton, "%s", 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);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(IBUTTON_APP_FOLDER, IBUTTON_APP_EXTENSION, key_name);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewTextInput);
}
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};
ibutton_switch_to_previous_scene_one_of(
ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t));
}
}
}
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};
ibutton_switch_to_previous_scene_one_of(
ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t));
}
}
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,75 @@
#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, SubmenuIndexEmulate);
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) {
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,51 @@
#include "../ibutton_i.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, SubmenuIndexRead);
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) {
consumed = true;
if(event.event == SubmenuIndexRead) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);
} else if(event.event == SubmenuIndexSaved) {
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,121 @@
#include "../ibutton_i.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);
const char* key_name = ibutton_key_get_name_p(key);
uint8_t line_count = 2;
// check that stored key has name
if(strcmp(key_name, "") != 0) {
ibutton_text_store_set(ibutton, "writing\n%s", 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);
scene_manager_set_scene_state(
ibutton->scene_manager, iButtonSceneWrite, iButtonSceneWriteStateDefault);
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);
}
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) {
scene_manager_set_scene_state(
scene_manager, iButtonSceneWrite, iButtonSceneWriteStateDefault);
} else if(event.event == iButtonWorkerWriteCannotWrite) {
scene_manager_set_scene_state(
scene_manager, iButtonSceneWrite, iButtonSceneWriteStateBlinkYellow);
}
} else if(event.type == SceneManagerEventTypeTick) {
consumed = true;
if(scene_manager_get_scene_state(scene_manager, iButtonSceneWrite) ==
iButtonSceneWriteStateBlinkYellow) {
ibutton_notification_message(ibutton, iButtonNotificationMessageYellowBlink);
} else {
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulate);
}
}
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);
}

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};
ibutton_switch_to_previous_scene_one_of(
ibutton, possible_scenes, sizeof(possible_scenes) / sizeof(uint32_t));
}
}
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);
}