Merge branch 'flipperdevices:dev' into dev

This commit is contained in:
Eng1n33r
2022-04-14 17:52:45 +03:00
committed by GitHub
149 changed files with 2368 additions and 529 deletions

3
.gitignore vendored
View File

@@ -36,3 +36,6 @@ CMakeLists.txt
# bundle output # bundle output
dist dist
# kde
.directory

View File

@@ -21,13 +21,23 @@ bool archive_app_is_available(void* context, const char* path) {
ArchiveAppTypeEnum app = archive_get_app_type(path); ArchiveAppTypeEnum app = archive_get_app_type(path);
if(app == ArchiveAppTypeU2f) { if(app == ArchiveAppTypeU2f) {
FileWorker* file_worker = file_worker_alloc(true);
bool file_exists = false; bool file_exists = false;
file_worker_is_file_exist(file_worker, "/any/u2f/key.u2f", &file_exists); Storage* fs_api = furi_record_open("storage");
File* file = storage_file_alloc(fs_api);
file_exists = storage_file_open(file, "/any/u2f/key.u2f", FSAM_READ, FSOM_OPEN_EXISTING);
if(file_exists) { if(file_exists) {
file_worker_is_file_exist(file_worker, "/any/u2f/cnt.u2f", &file_exists); storage_file_close(file);
file_exists =
storage_file_open(file, "/any/u2f/cnt.u2f", FSAM_READ, FSOM_OPEN_EXISTING);
if(file_exists) {
storage_file_close(file);
}
} }
file_worker_free(file_worker);
storage_file_free(file);
furi_record_close("storage");
return file_exists; return file_exists;
} else { } else {
return false; return false;
@@ -60,10 +70,10 @@ void archive_app_delete_file(void* context, const char* path) {
bool res = false; bool res = false;
if(app == ArchiveAppTypeU2f) { if(app == ArchiveAppTypeU2f) {
FileWorker* file_worker = file_worker_alloc(true); Storage* fs_api = furi_record_open("storage");
res = file_worker_remove(file_worker, "/any/u2f/key.u2f"); res = (storage_common_remove(fs_api, "/any/u2f/key.u2f") == FSE_OK);
res |= file_worker_remove(file_worker, "/any/u2f/cnt.u2f"); res |= (storage_common_remove(fs_api, "/any/u2f/cnt.u2f") == FSE_OK);
file_worker_free(file_worker); furi_record_close("storage");
if(archive_is_favorite("/app:u2f/U2F Token")) { if(archive_is_favorite("/app:u2f/U2F Token")) {
archive_favorites_delete("/app:u2f/U2F Token"); archive_favorites_delete("/app:u2f/U2F Token");

View File

@@ -392,6 +392,17 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) {
furi_assert(browser); furi_assert(browser);
furi_assert(name); furi_assert(name);
uint8_t browser_depth = 0;
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser_depth = idx_last_array_size(model->idx_last);
return false;
});
if(browser_depth > BROWSER_DEPTH_MAX) {
return;
}
archive_dir_count_items(browser, string_get_cstr(name)); archive_dir_count_items(browser, string_get_cstr(name));
with_view_model( with_view_model(

View File

@@ -4,6 +4,7 @@
#define TAB_RIGHT InputKeyRight //default tab swith direction #define TAB_RIGHT InputKeyRight //default tab swith direction
#define FILE_LIST_BUF_LEN 100 #define FILE_LIST_BUF_LEN 100
#define BROWSER_DEPTH_MAX 8
static const char* tab_default_paths[] = { static const char* tab_default_paths[] = {
[ArchiveTabFavorites] = "/any/favorites", [ArchiveTabFavorites] = "/any/favorites",

View File

@@ -4,20 +4,63 @@
#include "archive_apps.h" #include "archive_apps.h"
#include "archive_browser.h" #include "archive_browser.h"
#define ARCHIVE_FAV_FILE_BUF_LEN 32
static bool archive_favorites_read_line(File* file, string_t str_result) {
string_reset(str_result);
uint8_t buffer[ARCHIVE_FAV_FILE_BUF_LEN];
bool result = false;
do {
uint16_t read_count = storage_file_read(file, buffer, ARCHIVE_FAV_FILE_BUF_LEN);
if(storage_file_get_error(file) != FSE_OK) {
return false;
}
for(uint16_t i = 0; i < read_count; i++) {
if(buffer[i] == '\n') {
uint32_t position = storage_file_tell(file);
if(storage_file_get_error(file) != FSE_OK) {
return false;
}
position = position - read_count + i + 1;
storage_file_seek(file, position, true);
if(storage_file_get_error(file) != FSE_OK) {
return false;
}
result = true;
break;
} else {
string_push_back(str_result, buffer[i]);
}
}
if(result || read_count == 0) {
break;
}
} while(true);
return result;
}
uint16_t archive_favorites_count(void* context) { uint16_t archive_favorites_count(void* context) {
furi_assert(context); furi_assert(context);
FileWorker* file_worker = file_worker_alloc(true); Storage* fs_api = furi_record_open("storage");
File* file = storage_file_alloc(fs_api);
string_t buffer; string_t buffer;
string_init(buffer); string_init(buffer);
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
uint16_t lines = 0; uint16_t lines = 0;
if(result) { if(result) {
while(1) { while(1) {
if(!file_worker_read_until(file_worker, buffer, '\n')) { if(!archive_favorites_read_line(file, buffer)) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
@@ -27,21 +70,26 @@ uint16_t archive_favorites_count(void* context) {
} }
} }
storage_file_close(file);
string_clear(buffer); string_clear(buffer);
file_worker_close(file_worker); storage_file_free(file);
file_worker_free(file_worker); furi_record_close("storage");
return lines; return lines;
} }
static bool archive_favourites_rescan() { static bool archive_favourites_rescan() {
string_t buffer; string_t buffer;
string_init(buffer); string_init(buffer);
FileWorker* file_worker = file_worker_alloc(true); Storage* fs_api = furi_record_open("storage");
File* file = storage_file_alloc(fs_api);
File* fav_item_file = storage_file_alloc(fs_api);
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
if(result) { if(result) {
while(1) { while(1) {
if(!file_worker_read_until(file_worker, buffer, '\n')) { if(!archive_favorites_read_line(file, buffer)) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
@@ -53,9 +101,10 @@ static bool archive_favourites_rescan() {
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
} }
} else { } else {
bool file_exists = false; bool file_exists = storage_file_open(
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists); fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
if(file_exists) { if(file_exists) {
storage_file_close(fav_item_file);
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
} }
} }
@@ -64,11 +113,13 @@ static bool archive_favourites_rescan() {
string_clear(buffer); string_clear(buffer);
file_worker_close(file_worker); storage_file_close(file);
file_worker_remove(file_worker, ARCHIVE_FAV_PATH); storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
file_worker_free(file_worker); storage_file_free(file);
storage_file_free(fav_item_file);
furi_record_close("storage");
return result; return result;
} }
@@ -77,7 +128,9 @@ bool archive_favorites_read(void* context) {
furi_assert(context); furi_assert(context);
ArchiveBrowserView* browser = context; ArchiveBrowserView* browser = context;
FileWorker* file_worker = file_worker_alloc(true); Storage* fs_api = furi_record_open("storage");
File* file = storage_file_alloc(fs_api);
File* fav_item_file = storage_file_alloc(fs_api);
string_t buffer; string_t buffer;
FileInfo file_info; FileInfo file_info;
@@ -88,11 +141,11 @@ bool archive_favorites_read(void* context) {
archive_file_array_rm_all(browser); archive_file_array_rm_all(browser);
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
if(result) { if(result) {
while(1) { while(1) {
if(!file_worker_read_until(file_worker, buffer, '\n')) { if(!archive_favorites_read_line(file, buffer)) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
@@ -107,10 +160,10 @@ bool archive_favorites_read(void* context) {
need_refresh = true; need_refresh = true;
} }
} else { } else {
bool file_exists = false; bool file_exists = storage_file_open(
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists); fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
if(file_exists) { if(file_exists) {
storage_file_close(fav_item_file);
archive_add_file_item(browser, &file_info, string_get_cstr(buffer)); archive_add_file_item(browser, &file_info, string_get_cstr(buffer));
file_count++; file_count++;
} else { } else {
@@ -121,9 +174,11 @@ bool archive_favorites_read(void* context) {
string_reset(buffer); string_reset(buffer);
} }
} }
storage_file_close(file);
string_clear(buffer); string_clear(buffer);
file_worker_close(file_worker); storage_file_free(file);
file_worker_free(file_worker); storage_file_free(fav_item_file);
furi_record_close("storage");
archive_set_item_count(browser, file_count); archive_set_item_count(browser, file_count);
@@ -143,12 +198,14 @@ bool archive_favorites_delete(const char* format, ...) {
va_end(args); va_end(args);
string_init(buffer); string_init(buffer);
FileWorker* file_worker = file_worker_alloc(true); Storage* fs_api = furi_record_open("storage");
File* file = storage_file_alloc(fs_api);
bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
if(result) { if(result) {
while(1) { while(1) {
if(!file_worker_read_until(file_worker, buffer, '\n')) { if(!archive_favorites_read_line(file, buffer)) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
@@ -164,11 +221,12 @@ bool archive_favorites_delete(const char* format, ...) {
string_clear(buffer); string_clear(buffer);
string_clear(filename); string_clear(filename);
file_worker_close(file_worker); storage_file_close(file);
file_worker_remove(file_worker, ARCHIVE_FAV_PATH); storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
file_worker_free(file_worker); storage_file_free(file);
furi_record_close("storage");
return result; return result;
} }
@@ -182,14 +240,15 @@ bool archive_is_favorite(const char* format, ...) {
va_end(args); va_end(args);
string_init(buffer); string_init(buffer);
FileWorker* file_worker = file_worker_alloc(true); Storage* fs_api = furi_record_open("storage");
File* file = storage_file_alloc(fs_api);
bool found = false; bool found = false;
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
if(result) { if(result) {
while(1) { while(1) {
if(!file_worker_read_until(file_worker, buffer, '\n')) { if(!archive_favorites_read_line(file, buffer)) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
@@ -202,10 +261,11 @@ bool archive_is_favorite(const char* format, ...) {
} }
} }
storage_file_close(file);
string_clear(buffer); string_clear(buffer);
string_clear(filename); string_clear(filename);
file_worker_close(file_worker); storage_file_free(file);
file_worker_free(file_worker); furi_record_close("storage");
return found; return found;
} }
@@ -214,7 +274,8 @@ bool archive_favorites_rename(const char* src, const char* dst) {
furi_assert(src); furi_assert(src);
furi_assert(dst); furi_assert(dst);
FileWorker* file_worker = file_worker_alloc(true); Storage* fs_api = furi_record_open("storage");
File* file = storage_file_alloc(fs_api);
string_t path; string_t path;
string_t buffer; string_t buffer;
@@ -223,11 +284,11 @@ bool archive_favorites_rename(const char* src, const char* dst) {
string_init(path); string_init(path);
string_printf(path, "%s", src); string_printf(path, "%s", src);
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); bool result = storage_file_open(file, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
if(result) { if(result) {
while(1) { while(1) {
if(!file_worker_read_until(file_worker, buffer, '\n')) { if(!archive_favorites_read_line(file, buffer)) {
break; break;
} }
if(!string_size(buffer)) { if(!string_size(buffer)) {
@@ -244,11 +305,12 @@ bool archive_favorites_rename(const char* src, const char* dst) {
string_clear(buffer); string_clear(buffer);
string_clear(path); string_clear(path);
file_worker_close(file_worker); storage_file_close(file);
file_worker_remove(file_worker, ARCHIVE_FAV_PATH); storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
file_worker_free(file_worker); storage_file_free(file);
furi_record_close("storage");
return result; return result;
} }
@@ -263,15 +325,17 @@ void archive_favorites_save(void* context) {
furi_assert(context); furi_assert(context);
ArchiveBrowserView* browser = context; ArchiveBrowserView* browser = context;
FileWorker* file_worker = file_worker_alloc(true); Storage* fs_api = furi_record_open("storage");
File* file = storage_file_alloc(fs_api);
for(size_t i = 0; i < archive_file_get_array_size(browser); i++) { for(size_t i = 0; i < archive_file_get_array_size(browser); i++) {
ArchiveFile_t* item = archive_get_file_at(browser, i); ArchiveFile_t* item = archive_get_file_at(browser, i);
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(item->name)); archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(item->name));
} }
file_worker_remove(file_worker, ARCHIVE_FAV_PATH); storage_common_remove(fs_api, ARCHIVE_FAV_PATH);
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH); storage_common_rename(fs_api, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
file_worker_free(file_worker); storage_file_free(file);
furi_record_close("storage");
} }

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "file_worker.h"
#include <storage/storage.h>
#define ARCHIVE_FAV_PATH "/any/favorites.txt" #define ARCHIVE_FAV_PATH "/any/favorites.txt"
#define ARCHIVE_FAV_TEMP_PATH "/any/favorites.tmp" #define ARCHIVE_FAV_TEMP_PATH "/any/favorites.tmp"

View File

@@ -201,18 +201,18 @@ void archive_file_append(const char* path, const char* format, ...) {
string_init_vprintf(string, format, args); string_init_vprintf(string, format, args);
va_end(args); va_end(args);
FileWorker* file_worker = file_worker_alloc(false); Storage* fs_api = furi_record_open("storage");
File* file = storage_file_alloc(fs_api);
if(!file_worker_open(file_worker, path, FSAM_WRITE, FSOM_OPEN_APPEND)) { bool res = storage_file_open(file, path, FSAM_WRITE, FSOM_OPEN_APPEND);
FURI_LOG_E(TAG, "Append open error");
if(res) {
storage_file_write(file, string_get_cstr(string), string_size(string));
} }
if(!file_worker_write(file_worker, string_get_cstr(string), string_size(string))) { storage_file_close(file);
FURI_LOG_E(TAG, "Append write error"); storage_file_free(file);
} furi_record_close("storage");
file_worker_close(file_worker);
file_worker_free(file_worker);
} }
void archive_delete_file(void* context, const char* format, ...) { void archive_delete_file(void* context, const char* format, ...) {

View File

@@ -1,6 +1,8 @@
#pragma once #pragma once
#include "file_worker.h"
#include <m-array.h> #include <m-array.h>
#include <m-string.h>
#include <storage/storage.h>
typedef enum { typedef enum {
ArchiveFileTypeIButton, ArchiveFileTypeIButton,

View File

@@ -54,6 +54,10 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset); ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset);
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
string_set_str(menu[1], "Unpin");
}
if(!archive_is_known_app(selected->type)) { if(!archive_is_known_app(selected->type)) {
string_set_str(menu[0], "---"); string_set_str(menu[0], "---");
string_set_str(menu[1], "---"); string_set_str(menu[1], "---");
@@ -67,10 +71,6 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
} }
} }
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
string_set_str(menu[1], "Unpin");
}
for(size_t i = 0; i < MENU_ITEMS; i++) { for(size_t i = 0; i < MENU_ITEMS; i++) {
canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i])); canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i]));
string_clear(menu[i]); string_clear(menu[i]);

View File

@@ -401,6 +401,8 @@ void cli_delete_command(Cli* cli, const char* name) {
int32_t cli_srv(void* p) { int32_t cli_srv(void* p) {
Cli* cli = cli_alloc(); Cli* cli = cli_alloc();
furi_hal_vcp_init();
// Init basic cli commands // Init basic cli commands
cli_commands_init(cli); cli_commands_init(cli);

View File

@@ -1,6 +1,9 @@
#include <storage/storage.h> #include <storage/storage.h>
#include <assets_icons.h> #include <assets_icons.h>
#include <gui/gui.h>
#include <gui/view_stack.h> #include <gui/view_stack.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
@@ -13,6 +16,10 @@
#include "desktop_i.h" #include "desktop_i.h"
#include "desktop_helpers.h" #include "desktop_helpers.h"
static void desktop_auto_lock_arm(Desktop*);
static void desktop_auto_lock_inhibit(Desktop*);
static void desktop_start_auto_lock_timer(Desktop*);
static void desktop_loader_callback(const void* message, void* context) { static void desktop_loader_callback(const void* message, void* context) {
furi_assert(context); furi_assert(context);
Desktop* desktop = context; Desktop* desktop = context;
@@ -37,9 +44,19 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
switch(event) { switch(event) {
case DesktopGlobalBeforeAppStarted: case DesktopGlobalBeforeAppStarted:
animation_manager_unload_and_stall_animation(desktop->animation_manager); animation_manager_unload_and_stall_animation(desktop->animation_manager);
desktop_auto_lock_inhibit(desktop);
return true; return true;
case DesktopGlobalAfterAppFinished: case DesktopGlobalAfterAppFinished:
animation_manager_load_and_continue_animation(desktop->animation_manager); animation_manager_load_and_continue_animation(desktop->animation_manager);
// TODO: Implement a message mechanism for loading settings and (optionally)
// locking and unlocking
LOAD_DESKTOP_SETTINGS(&desktop->settings);
desktop_auto_lock_arm(desktop);
return true;
case DesktopGlobalAutoLock:
if(!loader_is_locked(desktop->loader)) {
desktop_lock(desktop);
}
return true; return true;
} }
@@ -58,6 +75,63 @@ static void desktop_tick_event_callback(void* context) {
scene_manager_handle_tick_event(app->scene_manager); scene_manager_handle_tick_event(app->scene_manager);
} }
static void desktop_input_event_callback(const void* value, void* context) {
furi_assert(value);
furi_assert(context);
const InputEvent* event = value;
Desktop* desktop = context;
if(event->type == InputTypePress) {
desktop_start_auto_lock_timer(desktop);
}
}
static void desktop_auto_lock_timer_callback(void* context) {
furi_assert(context);
Desktop* desktop = context;
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAutoLock);
}
static void desktop_start_auto_lock_timer(Desktop* desktop) {
osTimerStart(
desktop->auto_lock_timer, furi_hal_ms_to_ticks(desktop->settings.auto_lock_delay_ms));
}
static void desktop_stop_auto_lock_timer(Desktop* desktop) {
osTimerStop(desktop->auto_lock_timer);
}
static void desktop_auto_lock_arm(Desktop* desktop) {
if(desktop->settings.auto_lock_delay_ms) {
desktop->input_events_subscription = furi_pubsub_subscribe(
desktop->input_events_pubsub, desktop_input_event_callback, desktop);
desktop_start_auto_lock_timer(desktop);
}
}
static void desktop_auto_lock_inhibit(Desktop* desktop) {
desktop_stop_auto_lock_timer(desktop);
if(desktop->input_events_subscription) {
furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription);
desktop->input_events_subscription = NULL;
}
}
void desktop_lock(Desktop* desktop) {
desktop_auto_lock_inhibit(desktop);
scene_manager_set_scene_state(
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
notification_message(desktop->notification, &sequence_display_off_delay_1000);
}
void desktop_unlock(Desktop* desktop) {
furi_hal_rtc_set_pin_fails(0);
desktop_helpers_unlock_system(desktop);
desktop_view_locked_unlock(desktop->locked_view);
scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain);
desktop_auto_lock_arm(desktop);
}
Desktop* desktop_alloc() { Desktop* desktop_alloc() {
Desktop* desktop = malloc(sizeof(Desktop)); Desktop* desktop = malloc(sizeof(Desktop));
@@ -146,9 +220,17 @@ Desktop* desktop_alloc() {
animation_manager_is_animation_loaded(desktop->animation_manager)) { animation_manager_is_animation_loaded(desktop->animation_manager)) {
animation_manager_unload_and_stall_animation(desktop->animation_manager); animation_manager_unload_and_stall_animation(desktop->animation_manager);
} }
desktop->notification = furi_record_open("notification");
desktop->app_start_stop_subscription = furi_pubsub_subscribe( desktop->app_start_stop_subscription = furi_pubsub_subscribe(
loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop); loader_get_pubsub(desktop->loader), desktop_loader_callback, desktop);
desktop->input_events_pubsub = furi_record_open("input_events");
desktop->input_events_subscription = NULL;
desktop->auto_lock_timer =
osTimerNew(desktop_auto_lock_timer_callback, osTimerOnce, desktop, NULL);
return desktop; return desktop;
} }
@@ -157,8 +239,17 @@ void desktop_free(Desktop* desktop) {
furi_pubsub_unsubscribe( furi_pubsub_unsubscribe(
loader_get_pubsub(desktop->loader), desktop->app_start_stop_subscription); loader_get_pubsub(desktop->loader), desktop->app_start_stop_subscription);
if(desktop->input_events_subscription) {
furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription);
desktop->input_events_subscription = NULL;
}
desktop->loader = NULL; desktop->loader = NULL;
desktop->input_events_pubsub = NULL;
furi_record_close("loader"); furi_record_close("loader");
furi_record_close("notification");
furi_record_close("input_events");
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain);
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu); view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu);
@@ -191,6 +282,8 @@ void desktop_free(Desktop* desktop) {
furi_record_close("menu"); furi_record_close("menu");
osTimerDelete(desktop->auto_lock_timer);
free(desktop); free(desktop);
} }
@@ -214,14 +307,16 @@ int32_t desktop_srv(void* p) {
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock) && !desktop->settings.pin_code.length) {
if(desktop->settings.pin_code.length > 0) { furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
scene_manager_set_scene_state( }
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
} else { if(!loader_is_locked(desktop->loader)) {
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); desktop_auto_lock_arm(desktop);
} }
} else {
desktop_lock(desktop);
} }
if(desktop_is_first_start()) { if(desktop_is_first_start()) {

View File

@@ -19,6 +19,7 @@
#include <gui/scene_manager.h> #include <gui/scene_manager.h>
#include <loader/loader.h> #include <loader/loader.h>
#include <notification/notification_app.h>
#define STATUS_BAR_Y_SHIFT 13 #define STATUS_BAR_Y_SHIFT 13
@@ -59,10 +60,18 @@ struct Desktop {
ViewPort* lock_viewport; ViewPort* lock_viewport;
AnimationManager* animation_manager; AnimationManager* animation_manager;
Loader* loader; Loader* loader;
NotificationApp* notification;
FuriPubSubSubscription* app_start_stop_subscription; FuriPubSubSubscription* app_start_stop_subscription;
FuriPubSub* input_events_pubsub;
FuriPubSubSubscription* input_events_subscription;
osTimerId_t auto_lock_timer;
}; };
Desktop* desktop_alloc(); Desktop* desktop_alloc();
void desktop_free(Desktop* desktop); void desktop_free(Desktop* desktop);
void desktop_lock(Desktop* desktop);
void desktop_unlock(Desktop* desktop);

View File

@@ -5,7 +5,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <toolbox/saved_struct.h> #include <toolbox/saved_struct.h>
#define DESKTOP_SETTINGS_VER (1) #define DESKTOP_SETTINGS_VER (2)
#define DESKTOP_SETTINGS_PATH "/int/desktop.settings" #define DESKTOP_SETTINGS_PATH "/int/desktop.settings"
#define DESKTOP_SETTINGS_MAGIC (0x17) #define DESKTOP_SETTINGS_MAGIC (0x17)
#define PIN_MAX_LENGTH 12 #define PIN_MAX_LENGTH 12
@@ -39,6 +39,7 @@ typedef struct {
typedef struct { typedef struct {
uint16_t favorite; uint16_t favorite;
PinCode pin_code; PinCode pin_code;
uint32_t auto_lock_delay_ms;
} DesktopSettings; } DesktopSettings;
static inline bool pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) { static inline bool pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) {

View File

@@ -36,12 +36,17 @@ DesktopSettingsApp* desktop_settings_app_alloc() {
app->popup = popup_alloc(); app->popup = popup_alloc();
app->submenu = submenu_alloc(); app->submenu = submenu_alloc();
app->variable_item_list = variable_item_list_alloc();
app->pin_input_view = desktop_view_pin_input_alloc(); app->pin_input_view = desktop_view_pin_input_alloc();
app->pin_setup_howto_view = desktop_settings_view_pin_setup_howto_alloc(); app->pin_setup_howto_view = desktop_settings_view_pin_setup_howto_alloc();
app->pin_setup_howto2_view = desktop_settings_view_pin_setup_howto2_alloc(); app->pin_setup_howto2_view = desktop_settings_view_pin_setup_howto2_alloc();
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu)); app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu));
view_dispatcher_add_view(
app->view_dispatcher,
DesktopSettingsAppViewVarItemList,
variable_item_list_get_view(app->variable_item_list));
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup)); app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup));
view_dispatcher_add_view( view_dispatcher_add_view(
@@ -63,10 +68,12 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
furi_assert(app); furi_assert(app);
// Variable item list // Variable item list
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMenu); view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup); view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup);
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput); view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto); view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto);
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2); view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2);
variable_item_list_free(app->variable_item_list);
submenu_free(app->submenu); submenu_free(app->submenu);
popup_free(app->popup); popup_free(app->popup);
desktop_view_pin_input_free(app->pin_input_view); desktop_view_pin_input_free(app->pin_input_view);

View File

@@ -5,6 +5,7 @@
#include <gui/view_dispatcher.h> #include <gui/view_dispatcher.h>
#include <gui/scene_manager.h> #include <gui/scene_manager.h>
#include <gui/modules/submenu.h> #include <gui/modules/submenu.h>
#include <gui/modules/variable_item_list.h>
#include "desktop_settings.h" #include "desktop_settings.h"
#include "desktop/views/desktop_view_pin_input.h" #include "desktop/views/desktop_view_pin_input.h"
@@ -13,6 +14,7 @@
typedef enum { typedef enum {
DesktopSettingsAppViewMenu, DesktopSettingsAppViewMenu,
DesktopSettingsAppViewVarItemList,
DesktopSettingsAppViewIdPopup, DesktopSettingsAppViewIdPopup,
DesktopSettingsAppViewIdPinInput, DesktopSettingsAppViewIdPinInput,
DesktopSettingsAppViewIdPinSetupHowto, DesktopSettingsAppViewIdPinSetupHowto,
@@ -25,6 +27,7 @@ typedef struct {
Gui* gui; Gui* gui;
SceneManager* scene_manager; SceneManager* scene_manager;
ViewDispatcher* view_dispatcher; ViewDispatcher* view_dispatcher;
VariableItemList* variable_item_list;
Submenu* submenu; Submenu* submenu;
Popup* popup; Popup* popup;
DesktopViewPinInput* pin_input_view; DesktopViewPinInput* pin_input_view;

View File

@@ -1,35 +1,65 @@
#include <applications.h> #include <applications.h>
#include <lib/toolbox/value_index.h>
#include "../desktop_settings_app.h" #include "../desktop_settings_app.h"
#include "desktop_settings_scene.h" #include "desktop_settings_scene.h"
#define SCENE_EVENT_SELECT_FAVORITE 0 #define SCENE_EVENT_SELECT_FAVORITE 0
#define SCENE_EVENT_SELECT_PIN_SETUP 1 #define SCENE_EVENT_SELECT_PIN_SETUP 1
#define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 2
static void desktop_settings_scene_start_submenu_callback(void* context, uint32_t index) { #define AUTO_LOCK_DELAY_COUNT 6
const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
"OFF",
"30s",
"60s",
"2min",
"5min",
"10min",
};
const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] =
{0, 30000, 60000, 120000, 300000, 600000};
static void desktop_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index); view_dispatcher_send_custom_event(app->view_dispatcher, index);
} }
static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) {
DesktopSettingsApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, auto_lock_delay_text[index]);
app->settings.auto_lock_delay_ms = auto_lock_delay_value[index];
}
void desktop_settings_scene_start_on_enter(void* context) { void desktop_settings_scene_start_on_enter(void* context) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;
Submenu* submenu = app->submenu; VariableItemList* variable_item_list = app->variable_item_list;
submenu_add_item( VariableItem* item;
submenu, uint8_t value_index;
"Favorite App",
SCENE_EVENT_SELECT_FAVORITE, variable_item_list_add(variable_item_list, "Favorite App", 1, NULL, NULL);
desktop_settings_scene_start_submenu_callback,
variable_item_list_add(variable_item_list, "PIN Setup", 1, NULL, NULL);
item = variable_item_list_add(
variable_item_list,
"Auto Lock Time",
AUTO_LOCK_DELAY_COUNT,
desktop_settings_scene_start_auto_lock_delay_changed,
app); app);
submenu_add_item( variable_item_list_set_enter_callback(
submenu, variable_item_list, desktop_settings_scene_start_var_list_enter_callback, app);
"PIN Setup", value_index = value_index_uint32(
SCENE_EVENT_SELECT_PIN_SETUP, app->settings.auto_lock_delay_ms, auto_lock_delay_value, AUTO_LOCK_DELAY_COUNT);
desktop_settings_scene_start_submenu_callback, variable_item_set_current_value_index(item, value_index);
app); variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]);
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu); view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
} }
bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent event) { bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
@@ -46,6 +76,9 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu); scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu);
consumed = true; consumed = true;
break; break;
case SCENE_EVENT_SELECT_AUTO_LOCK_DELAY:
consumed = true;
break;
} }
} }
return consumed; return consumed;
@@ -53,5 +86,6 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
void desktop_settings_scene_start_on_exit(void* context) { void desktop_settings_scene_start_on_exit(void* context) {
DesktopSettingsApp* app = context; DesktopSettingsApp* app = context;
submenu_reset(app->submenu); variable_item_list_reset(app->variable_item_list);
SAVE_DESKTOP_SETTINGS(&app->settings);
} }

View File

@@ -48,17 +48,13 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
switch(event.event) { switch(event.event) {
case DesktopLockMenuEventLock: case DesktopLockMenuEventLock:
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
scene_manager_set_scene_state( desktop_lock(desktop);
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
consumed = true; consumed = true;
break; break;
case DesktopLockMenuEventPinLock: case DesktopLockMenuEventPinLock:
if(desktop->settings.pin_code.length > 0) { if(desktop->settings.pin_code.length > 0) {
furi_hal_rtc_set_flag(FuriHalRtcFlagLock); furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
scene_manager_set_scene_state( desktop_lock(desktop);
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
} else { } else {
LoaderStatus status = LoaderStatus status =
loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG); loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG);

View File

@@ -81,13 +81,13 @@ bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) { switch(event.event) {
case DesktopLockedEventUnlocked: case DesktopLockedEventUnlocked:
furi_hal_rtc_set_pin_fails(0); desktop_unlock(desktop);
desktop_helpers_unlock_system(desktop);
scene_manager_search_and_switch_to_previous_scene(
desktop->scene_manager, DesktopSceneMain);
consumed = true; consumed = true;
break; break;
case DesktopLockedEventUpdate: case DesktopLockedEventUpdate:
if(desktop_view_locked_is_locked_hint_visible(desktop->locked_view)) {
notification_message(desktop->notification, &sequence_display_off);
}
desktop_view_locked_update(desktop->locked_view); desktop_view_locked_update(desktop->locked_view);
consumed = true; consumed = true;
break; break;

View File

@@ -129,16 +129,13 @@ bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) {
consumed = true; consumed = true;
break; break;
case DesktopPinInputEventUnlocked: case DesktopPinInputEventUnlocked:
desktop_view_locked_unlock(desktop->locked_view); desktop_unlock(desktop);
furi_hal_rtc_set_pin_fails(0);
desktop_helpers_unlock_system(desktop);
scene_manager_search_and_switch_to_previous_scene(
desktop->scene_manager, DesktopSceneMain);
consumed = true; consumed = true;
break; break;
case DesktopPinInputEventBack: case DesktopPinInputEventBack:
scene_manager_search_and_switch_to_previous_scene( scene_manager_search_and_switch_to_previous_scene(
desktop->scene_manager, DesktopSceneLocked); desktop->scene_manager, DesktopSceneLocked);
notification_message(desktop->notification, &sequence_display_off);
consumed = true; consumed = true;
break; break;
} }

View File

@@ -38,4 +38,5 @@ typedef enum {
// Global events // Global events
DesktopGlobalBeforeAppStarted, DesktopGlobalBeforeAppStarted,
DesktopGlobalAfterAppFinished, DesktopGlobalAfterAppFinished,
DesktopGlobalAutoLock,
} DesktopEvent; } DesktopEvent;

View File

@@ -114,14 +114,8 @@ bool desktop_debug_input(InputEvent* event, void* context) {
DesktopViewStatsScreens current = 0; DesktopViewStatsScreens current = 0;
with_view_model( with_view_model(
debug_view->view, (DesktopDebugViewModel * model) { debug_view->view, (DesktopDebugViewModel * model) {
#if SRV_DOLPHIN_STATE_DEBUG == 1
if(event->key == InputKeyDown) { #ifdef SRV_DOLPHIN_STATE_DEBUG
model->screen = (model->screen + 1) % DesktopViewStatsTotalCount;
} else if(event->key == InputKeyUp) {
model->screen = ((model->screen - 1) + DesktopViewStatsTotalCount) %
DesktopViewStatsTotalCount;
}
#else
if((event->key == InputKeyDown) || (event->key == InputKeyUp)) { if((event->key == InputKeyDown) || (event->key == InputKeyUp)) {
model->screen = !model->screen; model->screen = !model->screen;
} }

View File

@@ -11,6 +11,7 @@
#include "desktop_view_locked.h" #include "desktop_view_locked.h"
#define DOOR_MOVING_INTERVAL_MS (1000 / 16) #define DOOR_MOVING_INTERVAL_MS (1000 / 16)
#define LOCKED_HINT_TIMEOUT_MS (1000)
#define UNLOCKED_HINT_TIMEOUT_MS (2000) #define UNLOCKED_HINT_TIMEOUT_MS (2000)
#define DOOR_OFFSET_START -55 #define DOOR_OFFSET_START -55
@@ -32,14 +33,18 @@ struct DesktopViewLocked {
uint32_t lock_lastpress; uint32_t lock_lastpress;
}; };
typedef struct { typedef enum {
uint32_t hint_icon_expire_at; DesktopViewLockedStateUnlocked,
bool unlocked_hint; DesktopViewLockedStateLocked,
bool locked; DesktopViewLockedStateDoorsClosing,
bool pin_locked; DesktopViewLockedStateLockedHintShown,
DesktopViewLockedStateUnlockedHintShown
} DesktopViewLockedState;
typedef struct {
bool pin_locked;
int8_t door_offset; int8_t door_offset;
bool doors_closing; DesktopViewLockedState view_state;
} DesktopViewLockedModel; } DesktopViewLockedModel;
void desktop_view_locked_set_callback( void desktop_view_locked_set_callback(
@@ -78,51 +83,54 @@ static bool desktop_view_locked_doors_move(DesktopViewLockedModel* model) {
static void desktop_view_locked_update_hint_icon_timeout(DesktopViewLocked* locked_view) { static void desktop_view_locked_update_hint_icon_timeout(DesktopViewLocked* locked_view) {
DesktopViewLockedModel* model = view_get_model(locked_view->view); DesktopViewLockedModel* model = view_get_model(locked_view->view);
model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq(); const bool change_state = (model->view_state == DesktopViewLockedStateLocked) &&
view_commit_model(locked_view->view, true); !model->pin_locked;
if(change_state) {
model->view_state = DesktopViewLockedStateLockedHintShown;
}
view_commit_model(locked_view->view, change_state);
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(LOCKED_HINT_TIMEOUT_MS), portMAX_DELAY);
} }
void desktop_view_locked_update(DesktopViewLocked* locked_view) { void desktop_view_locked_update(DesktopViewLocked* locked_view) {
bool stop_timer = false;
DesktopViewLockedModel* model = view_get_model(locked_view->view); DesktopViewLockedModel* model = view_get_model(locked_view->view);
if(model->locked) { DesktopViewLockedState view_state = model->view_state;
model->doors_closing = desktop_view_locked_doors_move(model);
stop_timer = !model->doors_closing; if(view_state == DesktopViewLockedStateDoorsClosing &&
} else { !desktop_view_locked_doors_move(model)) {
model->unlocked_hint = false; model->view_state = DesktopViewLockedStateLocked;
stop_timer = true; } else if(view_state == DesktopViewLockedStateLockedHintShown) {
model->view_state = DesktopViewLockedStateLocked;
} else if(view_state == DesktopViewLockedStateUnlockedHintShown) {
model->view_state = DesktopViewLockedStateUnlocked;
} }
view_commit_model(locked_view->view, true); view_commit_model(locked_view->view, true);
if(stop_timer) { if(view_state != DesktopViewLockedStateDoorsClosing) {
xTimerStop(locked_view->timer, portMAX_DELAY); xTimerStop(locked_view->timer, portMAX_DELAY);
} }
} }
static void desktop_view_locked_draw(Canvas* canvas, void* model) { static void desktop_view_locked_draw(Canvas* canvas, void* model) {
DesktopViewLockedModel* m = model; DesktopViewLockedModel* m = model;
uint32_t now = osKernelGetTickCount(); DesktopViewLockedState view_state = m->view_state;
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
if(m->locked) { if(view_state == DesktopViewLockedStateDoorsClosing) {
if(m->doors_closing) { desktop_view_locked_doors_draw(canvas, m);
desktop_view_locked_doors_draw(canvas, m); canvas_set_font(canvas, FontPrimary);
canvas_set_font(canvas, FontPrimary); elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked"); } else if(view_state == DesktopViewLockedStateLockedHintShown) {
} else if((now < m->hint_icon_expire_at) && !m->pin_locked) { canvas_set_font(canvas, FontSecondary);
canvas_set_font(canvas, FontSecondary); elements_bold_rounded_frame(canvas, 14, 2 + STATUS_BAR_Y_SHIFT, 99, 48);
elements_bold_rounded_frame(canvas, 14, 2 + STATUS_BAR_Y_SHIFT, 99, 48); elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:");
elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:"); canvas_draw_icon(canvas, 65, 36 + STATUS_BAR_Y_SHIFT, &I_Back3_45x8);
canvas_draw_icon(canvas, 65, 36 + STATUS_BAR_Y_SHIFT, &I_Back3_45x8); canvas_draw_icon(canvas, 16, 7 + STATUS_BAR_Y_SHIFT, &I_WarningDolphin_45x42);
canvas_draw_icon(canvas, 16, 7 + STATUS_BAR_Y_SHIFT, &I_WarningDolphin_45x42); canvas_draw_dot(canvas, 17, 61);
canvas_draw_dot(canvas, 17, 61); } else if(view_state == DesktopViewLockedStateUnlockedHintShown) {
} canvas_set_font(canvas, FontPrimary);
} else { elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
if(m->unlocked_hint) {
canvas_set_font(canvas, FontPrimary);
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
}
} }
} }
@@ -134,43 +142,38 @@ View* desktop_view_locked_get_view(DesktopViewLocked* locked_view) {
static bool desktop_view_locked_input(InputEvent* event, void* context) { static bool desktop_view_locked_input(InputEvent* event, void* context) {
furi_assert(event); furi_assert(event);
furi_assert(context); furi_assert(context);
bool is_changed = false;
const uint32_t press_time = xTaskGetTickCount();
DesktopViewLocked* locked_view = context; DesktopViewLocked* locked_view = context;
bool locked = false; DesktopViewLockedModel* model = view_get_model(locked_view->view);
bool locked_with_pin = false; if(model->view_state == DesktopViewLockedStateUnlockedHintShown &&
bool doors_closing = false; event->type == InputTypePress) {
uint32_t press_time = xTaskGetTickCount(); model->view_state = DesktopViewLockedStateUnlocked;
is_changed = true;
{
DesktopViewLockedModel* model = view_get_model(locked_view->view);
bool changed = false;
locked = model->locked;
locked_with_pin = model->pin_locked;
doors_closing = model->doors_closing;
if(!locked && model->unlocked_hint && event->type == InputTypePress) {
model->unlocked_hint = false;
changed = true;
}
view_commit_model(locked_view->view, changed);
} }
const DesktopViewLockedState view_state = model->view_state;
const bool pin_locked = model->pin_locked;
view_commit_model(locked_view->view, is_changed);
if(!locked || doors_closing || (event->type != InputTypeShort)) { if(view_state == DesktopViewLockedStateUnlocked || event->type != InputTypeShort) {
return locked; return view_state != DesktopViewLockedStateUnlocked;
} } else if(view_state == DesktopViewLockedStateLocked && pin_locked) {
if(locked_with_pin) {
locked_view->callback(DesktopLockedEventShowPinInput, locked_view->context); locked_view->callback(DesktopLockedEventShowPinInput, locked_view->context);
} else { } else if(
view_state == DesktopViewLockedStateLocked ||
view_state == DesktopViewLockedStateLockedHintShown) {
if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) { if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) {
locked_view->lock_lastpress = press_time; locked_view->lock_lastpress = press_time;
locked_view->lock_count = 0; locked_view->lock_count = 0;
} }
desktop_view_locked_update_hint_icon_timeout(locked_view); desktop_view_locked_update_hint_icon_timeout(locked_view);
if(event->key == InputKeyBack) { if(event->key == InputKeyBack) {
locked_view->lock_lastpress = press_time; locked_view->lock_lastpress = press_time;
locked_view->lock_count++; locked_view->lock_count++;
if(locked_view->lock_count == UNLOCK_CNT) { if(locked_view->lock_count == UNLOCK_CNT) {
desktop_view_locked_unlock(locked_view);
locked_view->callback(DesktopLockedEventUnlocked, locked_view->context); locked_view->callback(DesktopLockedEventUnlocked, locked_view->context);
} }
} else { } else {
@@ -180,7 +183,7 @@ static bool desktop_view_locked_input(InputEvent* event, void* context) {
locked_view->lock_lastpress = press_time; locked_view->lock_lastpress = press_time;
} }
return locked; return true;
} }
DesktopViewLocked* desktop_view_locked_alloc() { DesktopViewLocked* desktop_view_locked_alloc() {
@@ -189,7 +192,6 @@ DesktopViewLocked* desktop_view_locked_alloc() {
locked_view->timer = locked_view->timer =
xTimerCreate(NULL, 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback); xTimerCreate(NULL, 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback);
locked_view->view = view_alloc();
view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopViewLockedModel)); view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopViewLockedModel));
view_set_context(locked_view->view, locked_view); view_set_context(locked_view->view, locked_view);
view_set_draw_callback(locked_view->view, desktop_view_locked_draw); view_set_draw_callback(locked_view->view, desktop_view_locked_draw);
@@ -207,7 +209,8 @@ void desktop_view_locked_free(DesktopViewLocked* locked_view) {
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) { void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) {
DesktopViewLockedModel* model = view_get_model(locked_view->view); DesktopViewLockedModel* model = view_get_model(locked_view->view);
model->doors_closing = true; furi_assert(model->view_state == DesktopViewLockedStateLocked);
model->view_state = DesktopViewLockedStateDoorsClosing;
model->door_offset = DOOR_OFFSET_START; model->door_offset = DOOR_OFFSET_START;
view_commit_model(locked_view->view, true); view_commit_model(locked_view->view, true);
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(DOOR_MOVING_INTERVAL_MS), portMAX_DELAY); xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(DOOR_MOVING_INTERVAL_MS), portMAX_DELAY);
@@ -215,19 +218,24 @@ void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) {
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked) { void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked) {
DesktopViewLockedModel* model = view_get_model(locked_view->view); DesktopViewLockedModel* model = view_get_model(locked_view->view);
model->locked = true; furi_assert(model->view_state == DesktopViewLockedStateUnlocked);
model->view_state = DesktopViewLockedStateLocked;
model->pin_locked = pin_locked; model->pin_locked = pin_locked;
view_commit_model(locked_view->view, true); view_commit_model(locked_view->view, true);
} }
void desktop_view_locked_unlock(DesktopViewLocked* locked_view) { void desktop_view_locked_unlock(DesktopViewLocked* locked_view) {
furi_assert(locked_view);
locked_view->lock_count = 0; locked_view->lock_count = 0;
DesktopViewLockedModel* model = view_get_model(locked_view->view); DesktopViewLockedModel* model = view_get_model(locked_view->view);
model->locked = false; model->view_state = DesktopViewLockedStateUnlockedHintShown;
model->pin_locked = false; model->pin_locked = false;
model->unlocked_hint = true;
view_commit_model(locked_view->view, true); view_commit_model(locked_view->view, true);
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(UNLOCKED_HINT_TIMEOUT_MS), portMAX_DELAY); xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(UNLOCKED_HINT_TIMEOUT_MS), portMAX_DELAY);
} }
bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view) {
DesktopViewLockedModel* model = view_get_model(locked_view->view);
const DesktopViewLockedState view_state = model->view_state;
view_commit_model(locked_view->view, false);
return view_state == DesktopViewLockedStateLockedHintShown;
}

View File

@@ -19,3 +19,4 @@ void desktop_view_locked_free(DesktopViewLocked* locked_view);
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked); void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked);
void desktop_view_locked_unlock(DesktopViewLocked* locked_view); void desktop_view_locked_unlock(DesktopViewLocked* locked_view);
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view); void desktop_view_locked_close_doors(DesktopViewLocked* locked_view);
bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view);

View File

@@ -9,7 +9,9 @@
#include "scene/ibutton_scene_read_crc_error.h" #include "scene/ibutton_scene_read_crc_error.h"
#include "scene/ibutton_scene_read_not_key_error.h" #include "scene/ibutton_scene_read_not_key_error.h"
#include "scene/ibutton_scene_read_success.h" #include "scene/ibutton_scene_read_success.h"
#include "scene/ibutton_scene_readed_key_menu.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.h"
#include "scene/ibutton_scene_write_success.h" #include "scene/ibutton_scene_write_success.h"
#include "scene/ibutton_scene_saved_key_menu.h" #include "scene/ibutton_scene_saved_key_menu.h"
@@ -42,7 +44,9 @@ public:
SceneReadNotKeyError, SceneReadNotKeyError,
SceneReadCRCError, SceneReadCRCError,
SceneReadSuccess, SceneReadSuccess,
SceneReadedKeyMenu, SceneRetryConfirm,
SceneExitConfirm,
SceneReadKeyMenu,
SceneWrite, SceneWrite,
SceneWriteSuccess, SceneWriteSuccess,
SceneEmulate, SceneEmulate,
@@ -105,7 +109,9 @@ private:
{Scene::SceneReadCRCError, new iButtonSceneReadCRCError()}, {Scene::SceneReadCRCError, new iButtonSceneReadCRCError()},
{Scene::SceneReadNotKeyError, new iButtonSceneReadNotKeyError()}, {Scene::SceneReadNotKeyError, new iButtonSceneReadNotKeyError()},
{Scene::SceneReadSuccess, new iButtonSceneReadSuccess()}, {Scene::SceneReadSuccess, new iButtonSceneReadSuccess()},
{Scene::SceneReadedKeyMenu, new iButtonSceneReadedKeyMenu()}, {Scene::SceneRetryConfirm, new iButtonSceneRetryConfirm()},
{Scene::SceneExitConfirm, new iButtonSceneExitConfirm()},
{Scene::SceneReadKeyMenu, new iButtonSceneReadKeyMenu()},
{Scene::SceneWrite, new iButtonSceneWrite()}, {Scene::SceneWrite, new iButtonSceneWrite()},
{Scene::SceneWriteSuccess, new iButtonSceneWriteSuccess()}, {Scene::SceneWriteSuccess, new iButtonSceneWriteSuccess()},
{Scene::SceneEmulate, new iButtonSceneEmulate()}, {Scene::SceneEmulate, new iButtonSceneEmulate()},

View File

@@ -14,7 +14,7 @@ void iButtonSceneDeleteSuccess::on_enter(iButtonApp* app) {
Popup* popup = view_manager->get_popup(); Popup* popup = view_manager->get_popup();
popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
popup_set_text(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
popup_set_callback(popup, popup_callback); popup_set_callback(popup, popup_callback);
popup_set_context(popup, app); popup_set_context(popup, app);

View File

@@ -0,0 +1,51 @@
#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

@@ -0,0 +1,9 @@
#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

@@ -34,15 +34,22 @@ bool iButtonSceneRead::on_event(iButtonApp* app, iButtonEvent* event) {
consumed = true; consumed = true;
iButtonKey* key = app->get_key(); iButtonKey* key = app->get_key();
bool success = false;
if(ibutton_key_get_type(key) == iButtonKeyDS1990) { if(ibutton_key_get_type(key) == iButtonKeyDS1990) {
if(!ibutton_key_dallas_crc_is_valid(key)) { if(!ibutton_key_dallas_crc_is_valid(key)) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadCRCError); app->switch_to_next_scene(iButtonApp::Scene::SceneReadCRCError);
} else if(!ibutton_key_dallas_is_1990_key(key)) { } else if(!ibutton_key_dallas_is_1990_key(key)) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadNotKeyError); app->switch_to_next_scene(iButtonApp::Scene::SceneReadNotKeyError);
} else { } else {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess); success = true;
} }
} else { } else {
success = true;
}
if(success) {
app->notify_success();
app->notify_green_on();
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess); app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess);
} }
} else if(event->type == iButtonEvent::Type::EventTypeTick) { } else if(event->type == iButtonEvent::Type::EventTypeTick) {

View File

@@ -47,7 +47,7 @@ bool iButtonSceneReadCRCError::on_event(iButtonApp* app, iButtonEvent* event) {
if(event->type == iButtonEvent::Type::EventTypeDialogResult) { if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
if(event->payload.dialog_result == DialogExResultRight) { if(event->payload.dialog_result == DialogExResultRight) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadedKeyMenu); app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
} else { } else {
app->switch_to_previous_scene(); app->switch_to_previous_scene();
} }

View File

@@ -1,11 +1,10 @@
#include "ibutton_scene_readed_key_menu.h" #include "ibutton_scene_read_key_menu.h"
#include "../ibutton_app.h" #include "../ibutton_app.h"
typedef enum { typedef enum {
SubmenuIndexWrite, SubmenuIndexWrite,
SubmenuIndexEmulate, SubmenuIndexEmulate,
SubmenuIndexSave, SubmenuIndexSave,
SubmenuIndexReadNewKey,
} SubmenuIndex; } SubmenuIndex;
static void submenu_callback(void* context, uint32_t index) { static void submenu_callback(void* context, uint32_t index) {
@@ -19,7 +18,7 @@ static void submenu_callback(void* context, uint32_t index) {
app->get_view_manager()->send_event(&event); app->get_view_manager()->send_event(&event);
} }
void iButtonSceneReadedKeyMenu::on_enter(iButtonApp* app) { void iButtonSceneReadKeyMenu::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager(); iButtonAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu(); Submenu* submenu = view_manager->get_submenu();
@@ -28,13 +27,12 @@ void iButtonSceneReadedKeyMenu::on_enter(iButtonApp* app) {
} }
submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app); submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app);
submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app); submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app);
submenu_add_item(submenu, "Read new key", SubmenuIndexReadNewKey, submenu_callback, app);
submenu_set_selected_item(submenu, submenu_item_selected); submenu_set_selected_item(submenu, submenu_item_selected);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu);
} }
bool iButtonSceneReadedKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) { bool iButtonSceneReadKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) {
bool consumed = false; bool consumed = false;
if(event->type == iButtonEvent::Type::EventTypeMenuSelected) { if(event->type == iButtonEvent::Type::EventTypeMenuSelected) {
@@ -49,20 +47,17 @@ bool iButtonSceneReadedKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) {
case SubmenuIndexSave: case SubmenuIndexSave:
app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName); app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName);
break; break;
case SubmenuIndexReadNewKey:
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneRead});
break;
} }
consumed = true; consumed = true;
} else if(event->type == iButtonEvent::Type::EventTypeBack) { } else if(event->type == iButtonEvent::Type::EventTypeBack) {
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneStart}); app->switch_to_previous_scene();
consumed = true; consumed = true;
} }
return consumed; return consumed;
} }
void iButtonSceneReadedKeyMenu::on_exit(iButtonApp* app) { void iButtonSceneReadKeyMenu::on_exit(iButtonApp* app) {
iButtonAppViewManager* view = app->get_view_manager(); iButtonAppViewManager* view = app->get_view_manager();
Submenu* submenu = view->get_submenu(); Submenu* submenu = view->get_submenu();

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "ibutton_scene_generic.h" #include "ibutton_scene_generic.h"
class iButtonSceneReadedKeyMenu : public iButtonScene { class iButtonSceneReadKeyMenu : public iButtonScene {
public: public:
void on_enter(iButtonApp* app) final; void on_enter(iButtonApp* app) final;
bool on_event(iButtonApp* app, iButtonEvent* event) final; bool on_event(iButtonApp* app, iButtonEvent* event) final;

View File

@@ -47,7 +47,7 @@ bool iButtonSceneReadNotKeyError::on_event(iButtonApp* app, iButtonEvent* event)
if(event->type == iButtonEvent::Type::EventTypeDialogResult) { if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
if(event->payload.dialog_result == DialogExResultRight) { if(event->payload.dialog_result == DialogExResultRight) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadedKeyMenu); app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
} else { } else {
app->switch_to_previous_scene(); app->switch_to_previous_scene();
} }

View File

@@ -18,7 +18,6 @@ void iButtonSceneReadSuccess::on_enter(iButtonApp* app) {
DialogEx* dialog_ex = view_manager->get_dialog_ex(); DialogEx* dialog_ex = view_manager->get_dialog_ex();
iButtonKey* key = app->get_key(); iButtonKey* key = app->get_key();
const uint8_t* key_data = ibutton_key_get_data_p(key); const uint8_t* key_data = ibutton_key_get_data_p(key);
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
switch(ibutton_key_get_type(key)) { switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990: case iButtonKeyDS1990:
@@ -50,9 +49,6 @@ void iButtonSceneReadSuccess::on_enter(iButtonApp* app) {
dialog_ex_set_context(dialog_ex, app); dialog_ex_set_context(dialog_ex, app);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx);
app->notify_success();
app->notify_green_on();
} }
bool iButtonSceneReadSuccess::on_event(iButtonApp* app, iButtonEvent* event) { bool iButtonSceneReadSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
@@ -60,11 +56,13 @@ bool iButtonSceneReadSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
if(event->type == iButtonEvent::Type::EventTypeDialogResult) { if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
if(event->payload.dialog_result == DialogExResultRight) { if(event->payload.dialog_result == DialogExResultRight) {
app->switch_to_next_scene(iButtonApp::Scene::SceneReadedKeyMenu); app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
} else { } else {
app->switch_to_previous_scene(); 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; consumed = true;
} }

View File

@@ -0,0 +1,51 @@
#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

@@ -0,0 +1,9 @@
#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

@@ -49,7 +49,7 @@ bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) {
app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess); app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess);
} else { } else {
app->search_and_switch_to_previous_scene( app->search_and_switch_to_previous_scene(
{iButtonApp::Scene::SceneReadedKeyMenu, {iButtonApp::Scene::SceneReadKeyMenu,
iButtonApp::Scene::SceneSavedKeyMenu, iButtonApp::Scene::SceneSavedKeyMenu,
iButtonApp::Scene::SceneAddType}); iButtonApp::Scene::SceneAddType});
} }

View File

@@ -16,7 +16,7 @@ void iButtonSceneSaveSuccess::on_enter(iButtonApp* app) {
DOLPHIN_DEED(DolphinDeedIbuttonSave); DOLPHIN_DEED(DolphinDeedIbuttonSave);
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_text(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
popup_set_callback(popup, popup_callback); popup_set_callback(popup, popup_callback);
popup_set_context(popup, app); popup_set_context(popup, app);
@@ -31,7 +31,7 @@ bool iButtonSceneSaveSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
if(event->type == iButtonEvent::Type::EventTypeBack) { if(event->type == iButtonEvent::Type::EventTypeBack) {
app->search_and_switch_to_previous_scene( app->search_and_switch_to_previous_scene(
{iButtonApp::Scene::SceneReadedKeyMenu, {iButtonApp::Scene::SceneReadKeyMenu,
iButtonApp::Scene::SceneSavedKeyMenu, iButtonApp::Scene::SceneSavedKeyMenu,
iButtonApp::Scene::SceneAddType}); iButtonApp::Scene::SceneAddType});
consumed = true; consumed = true;

View File

@@ -33,7 +33,7 @@ bool iButtonSceneWriteSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
if(event->type == iButtonEvent::Type::EventTypeBack) { if(event->type == iButtonEvent::Type::EventTypeBack) {
app->search_and_switch_to_previous_scene( app->search_and_switch_to_previous_scene(
{iButtonApp::Scene::SceneReadedKeyMenu, iButtonApp::Scene::SceneStart}); {iButtonApp::Scene::SceneReadKeyMenu, iButtonApp::Scene::SceneStart});
consumed = true; consumed = true;
} }

View File

@@ -5,7 +5,6 @@ void InfraredAppSceneEditRenameDone::on_enter(InfraredApp* app) {
Popup* popup = view_manager->get_popup(); Popup* popup = view_manager->get_popup();
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
popup_set_callback(popup, InfraredApp::popup_callback); popup_set_callback(popup, InfraredApp::popup_callback);

View File

@@ -15,7 +15,7 @@ constexpr uint32_t long_time_high = long_time + jitter_time;
void DecoderEMMarin::reset_state() { void DecoderEMMarin::reset_state() {
ready = false; ready = false;
readed_data = 0; read_data = 0;
manchester_advance( manchester_advance(
manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr); manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr);
} }
@@ -26,7 +26,7 @@ bool DecoderEMMarin::read(uint8_t* data, uint8_t data_size) {
if(ready) { if(ready) {
result = true; result = true;
em_marin.decode( em_marin.decode(
reinterpret_cast<const uint8_t*>(&readed_data), sizeof(uint64_t), data, data_size); reinterpret_cast<const uint8_t*>(&read_data), sizeof(uint64_t), data, data_size);
ready = false; ready = false;
} }
@@ -59,10 +59,10 @@ void DecoderEMMarin::process_front(bool polarity, uint32_t time) {
manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data); manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data);
if(data_ok) { if(data_ok) {
readed_data = (readed_data << 1) | data; read_data = (read_data << 1) | data;
ready = em_marin.can_be_decoded( ready = em_marin.can_be_decoded(
reinterpret_cast<const uint8_t*>(&readed_data), sizeof(uint64_t)); reinterpret_cast<const uint8_t*>(&read_data), sizeof(uint64_t));
} }
} }
} }

View File

@@ -13,7 +13,7 @@ public:
private: private:
void reset_state(); void reset_state();
uint64_t readed_data = 0; uint64_t read_data = 0;
std::atomic<bool> ready; std::atomic<bool> ready;
ManchesterState manchester_saved_state; ManchesterState manchester_saved_state;

View File

@@ -78,7 +78,7 @@ void RfidReader::start() {
start_comparator(); start_comparator();
switch_timer_reset(); switch_timer_reset();
last_readed_count = 0; last_read_count = 0;
} }
void RfidReader::start_forced(RfidReader::Type _type) { void RfidReader::start_forced(RfidReader::Type _type) {
@@ -97,45 +97,45 @@ void RfidReader::stop() {
bool RfidReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bool switch_enable) { bool RfidReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size, bool switch_enable) {
bool result = false; bool result = false;
bool something_readed = false; bool something_read = false;
// reading // reading
if(decoder_em.read(data, data_size)) { if(decoder_em.read(data, data_size)) {
*_type = LfrfidKeyType::KeyEM4100; *_type = LfrfidKeyType::KeyEM4100;
something_readed = true; something_read = true;
} }
if(decoder_hid26.read(data, data_size)) { if(decoder_hid26.read(data, data_size)) {
*_type = LfrfidKeyType::KeyH10301; *_type = LfrfidKeyType::KeyH10301;
something_readed = true; something_read = true;
} }
if(decoder_indala.read(data, data_size)) { if(decoder_indala.read(data, data_size)) {
*_type = LfrfidKeyType::KeyI40134; *_type = LfrfidKeyType::KeyI40134;
something_readed = true; something_read = true;
} }
// validation // validation
if(something_readed) { if(something_read) {
switch_timer_reset(); switch_timer_reset();
if(last_readed_type == *_type && memcmp(last_readed_data, data, data_size) == 0) { if(last_read_type == *_type && memcmp(last_read_data, data, data_size) == 0) {
last_readed_count = last_readed_count + 1; last_read_count = last_read_count + 1;
if(last_readed_count > 2) { if(last_read_count > 2) {
result = true; result = true;
} }
} else { } else {
last_readed_type = *_type; last_read_type = *_type;
memcpy(last_readed_data, data, data_size); memcpy(last_read_data, data, data_size);
last_readed_count = 0; last_read_count = 0;
} }
} }
// mode switching // mode switching
if(switch_enable && switch_timer_elapsed()) { if(switch_enable && switch_timer_elapsed()) {
switch_mode(); switch_mode();
last_readed_count = 0; last_read_count = 0;
} }
return result; return result;
@@ -152,7 +152,7 @@ bool RfidReader::detect() {
} }
bool RfidReader::any_read() { bool RfidReader::any_read() {
return last_readed_count > 0; return last_read_count > 0;
} }
void RfidReader::start_comparator(void) { void RfidReader::start_comparator(void) {

View File

@@ -49,9 +49,9 @@ private:
void switch_timer_reset(); void switch_timer_reset();
void switch_mode(); void switch_mode();
LfrfidKeyType last_readed_type; LfrfidKeyType last_read_type;
uint8_t last_readed_data[LFRFID_KEY_SIZE]; uint8_t last_read_data[LFRFID_KEY_SIZE];
uint8_t last_readed_count; uint8_t last_read_count;
Type type = Type::Normal; Type type = Type::Normal;
}; };

View File

@@ -2,7 +2,9 @@
#include "scene/lfrfid_app_scene_start.h" #include "scene/lfrfid_app_scene_start.h"
#include "scene/lfrfid_app_scene_read.h" #include "scene/lfrfid_app_scene_read.h"
#include "scene/lfrfid_app_scene_read_success.h" #include "scene/lfrfid_app_scene_read_success.h"
#include "scene/lfrfid_app_scene_readed_menu.h" #include "scene/lfrfid_app_scene_retry_confirm.h"
#include "scene/lfrfid_app_scene_exit_confirm.h"
#include "scene/lfrfid_app_scene_read_menu.h"
#include "scene/lfrfid_app_scene_write.h" #include "scene/lfrfid_app_scene_write.h"
#include "scene/lfrfid_app_scene_write_success.h" #include "scene/lfrfid_app_scene_write_success.h"
#include "scene/lfrfid_app_scene_emulate.h" #include "scene/lfrfid_app_scene_emulate.h"
@@ -48,8 +50,10 @@ void LfRfidApp::run(void* _args) {
} else { } else {
scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart()); scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart());
scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead()); scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead());
scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm());
scene_controller.add_scene(SceneType::ExitConfirm, new LfRfidAppSceneExitConfirm());
scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess()); scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess());
scene_controller.add_scene(SceneType::ReadedMenu, new LfRfidAppSceneReadedMenu()); scene_controller.add_scene(SceneType::ReadKeyMenu, new LfRfidAppSceneReadKeyMenu());
scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite()); scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite());
scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess()); scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess());
scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate()); scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());

View File

@@ -27,13 +27,17 @@ public:
GENERIC_EVENT_ENUM_VALUES, GENERIC_EVENT_ENUM_VALUES,
Next, Next,
MenuSelected, MenuSelected,
Stay,
Retry,
}; };
enum class SceneType : uint8_t { enum class SceneType : uint8_t {
GENERIC_SCENE_ENUM_VALUES, GENERIC_SCENE_ENUM_VALUES,
Read, Read,
ReadSuccess, ReadSuccess,
ReadedMenu, RetryConfirm,
ExitConfirm,
ReadKeyMenu,
Write, Write,
WriteSuccess, WriteSuccess,
Emulate, Emulate,

View File

@@ -73,6 +73,11 @@ bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* eve
app->delete_key(&app->worker.key); app->delete_key(&app->worker.key);
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess); app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess);
consumed = true; consumed = true;
} else if(event->type == LfRfidApp::EventType::Stay) {
app->scene_controller.switch_to_previous_scene();
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
consumed = true;
} }
return consumed; return consumed;
@@ -88,7 +93,7 @@ void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) {
void LfRfidAppSceneDeleteConfirm::back_callback(void* context) { void LfRfidAppSceneDeleteConfirm::back_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context); LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event; LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Back; event.type = LfRfidApp::EventType::Stay;
app->view_controller.send_event(&event); app->view_controller.send_event(&event);
} }

View File

@@ -4,7 +4,7 @@ void LfRfidAppSceneDeleteSuccess::on_enter(LfRfidApp* app, bool need_restore) {
auto popup = app->view_controller.get<PopupVM>(); auto popup = app->view_controller.get<PopupVM>();
popup->set_icon(0, 2, &I_DolphinMafia_115x62); popup->set_icon(0, 2, &I_DolphinMafia_115x62);
popup->set_text("Deleted", 83, 19, AlignLeft, AlignBottom); popup->set_header("Deleted", 83, 19, AlignLeft, AlignBottom);
popup->set_context(app); popup->set_context(app);
popup->set_callback(LfRfidAppSceneDeleteSuccess::timeout_callback); popup->set_callback(LfRfidAppSceneDeleteSuccess::timeout_callback);
popup->set_timeout(1500); popup->set_timeout(1500);

View File

@@ -0,0 +1,59 @@
#include "lfrfid_app_scene_exit_confirm.h"
#include "../view/elements/button_element.h"
#include "../view/elements/icon_element.h"
#include "../view/elements/string_element.h"
void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool need_restore) {
auto container = app->view_controller.get<ContainerVM>();
auto button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Left, "Exit");
button->set_callback(app, LfRfidAppSceneExitConfirm::exit_callback);
button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Right, "Stay");
button->set_callback(app, LfRfidAppSceneExitConfirm::stay_callback);
auto line_1 = container->add<StringElement>();
auto line_2 = container->add<StringElement>();
line_1->set_text("Exit to RFID menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
line_2->set_text(
"All unsaved data will be lost", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
app->view_controller.switch_to<ContainerVM>();
}
bool LfRfidAppSceneExitConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Start});
consumed = true;
} else if(event->type == LfRfidApp::EventType::Stay) {
app->scene_controller.switch_to_previous_scene();
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
consumed = true;
}
return consumed;
}
void LfRfidAppSceneExitConfirm::on_exit(LfRfidApp* app) {
app->view_controller.get<ContainerVM>()->clean();
}
void LfRfidAppSceneExitConfirm::exit_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}
void LfRfidAppSceneExitConfirm::stay_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Stay;
app->view_controller.send_event(&event);
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneExitConfirm : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void exit_callback(void* context);
static void stay_callback(void* context);
};

View File

@@ -1,4 +1,4 @@
#include "lfrfid_app_scene_readed_menu.h" #include "lfrfid_app_scene_read_menu.h"
typedef enum { typedef enum {
SubmenuWrite, SubmenuWrite,
@@ -6,7 +6,7 @@ typedef enum {
SubmenuEmulate, SubmenuEmulate,
} SubmenuIndex; } SubmenuIndex;
void LfRfidAppSceneReadedMenu::on_enter(LfRfidApp* app, bool need_restore) { void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) {
auto submenu = app->view_controller.get<SubmenuVM>(); auto submenu = app->view_controller.get<SubmenuVM>();
submenu->add_item("Write", SubmenuWrite, submenu_callback, app); submenu->add_item("Write", SubmenuWrite, submenu_callback, app);
@@ -20,7 +20,7 @@ void LfRfidAppSceneReadedMenu::on_enter(LfRfidApp* app, bool need_restore) {
app->view_controller.switch_to<SubmenuVM>(); app->view_controller.switch_to<SubmenuVM>();
} }
bool LfRfidAppSceneReadedMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) { bool LfRfidAppSceneReadKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false; bool consumed = false;
if(event->type == LfRfidApp::EventType::MenuSelected) { if(event->type == LfRfidApp::EventType::MenuSelected) {
@@ -38,18 +38,18 @@ bool LfRfidAppSceneReadedMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event)
} }
consumed = true; consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) { } else if(event->type == LfRfidApp::EventType::Back) {
app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Start}); app->scene_controller.switch_to_previous_scene();
consumed = true; consumed = true;
} }
return consumed; return consumed;
} }
void LfRfidAppSceneReadedMenu::on_exit(LfRfidApp* app) { void LfRfidAppSceneReadKeyMenu::on_exit(LfRfidApp* app) {
app->view_controller.get<SubmenuVM>()->clean(); app->view_controller.get<SubmenuVM>()->clean();
} }
void LfRfidAppSceneReadedMenu::submenu_callback(void* context, uint32_t index) { void LfRfidAppSceneReadKeyMenu::submenu_callback(void* context, uint32_t index) {
LfRfidApp* app = static_cast<LfRfidApp*>(context); LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event; LfRfidApp::Event event;

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../lfrfid_app.h" #include "../lfrfid_app.h"
class LfRfidAppSceneReadedMenu : public GenericScene<LfRfidApp> { class LfRfidAppSceneReadKeyMenu : public GenericScene<LfRfidApp> {
public: public:
void on_enter(LfRfidApp* app, bool need_restore) final; void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final; bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;

View File

@@ -85,7 +85,13 @@ bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event
bool consumed = false; bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) { if(event->type == LfRfidApp::EventType::Next) {
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadedMenu); app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadKeyMenu);
consumed = true;
} else if(event->type == LfRfidApp::EventType::Retry) {
app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::RetryConfirm});
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::ExitConfirm});
consumed = true; consumed = true;
} }
@@ -103,7 +109,7 @@ void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) {
void LfRfidAppSceneReadSuccess::back_callback(void* context) { void LfRfidAppSceneReadSuccess::back_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context); LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event; LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Back; event.type = LfRfidApp::EventType::Retry;
app->view_controller.send_event(&event); app->view_controller.send_event(&event);
} }

View File

@@ -0,0 +1,59 @@
#include "lfrfid_app_scene_retry_confirm.h"
#include "../view/elements/button_element.h"
#include "../view/elements/icon_element.h"
#include "../view/elements/string_element.h"
void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool need_restore) {
auto container = app->view_controller.get<ContainerVM>();
auto button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Left, "Exit");
button->set_callback(app, LfRfidAppSceneRetryConfirm::exit_callback);
button = container->add<ButtonElement>();
button->set_type(ButtonElement::Type::Right, "Stay");
button->set_callback(app, LfRfidAppSceneRetryConfirm::stay_callback);
auto line_1 = container->add<StringElement>();
auto line_2 = container->add<StringElement>();
line_1->set_text("Return to reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
line_2->set_text(
"All unsaved data will be lost", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
app->view_controller.switch_to<ContainerVM>();
}
bool LfRfidAppSceneRetryConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
bool consumed = false;
if(event->type == LfRfidApp::EventType::Next) {
app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Read});
consumed = true;
} else if(event->type == LfRfidApp::EventType::Stay) {
app->scene_controller.switch_to_previous_scene();
consumed = true;
} else if(event->type == LfRfidApp::EventType::Back) {
consumed = true;
}
return consumed;
}
void LfRfidAppSceneRetryConfirm::on_exit(LfRfidApp* app) {
app->view_controller.get<ContainerVM>()->clean();
}
void LfRfidAppSceneRetryConfirm::exit_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Next;
app->view_controller.send_event(&event);
}
void LfRfidAppSceneRetryConfirm::stay_callback(void* context) {
LfRfidApp* app = static_cast<LfRfidApp*>(context);
LfRfidApp::Event event;
event.type = LfRfidApp::EventType::Stay;
app->view_controller.send_event(&event);
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "../lfrfid_app.h"
class LfRfidAppSceneRetryConfirm : public GenericScene<LfRfidApp> {
public:
void on_enter(LfRfidApp* app, bool need_restore) final;
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
void on_exit(LfRfidApp* app) final;
private:
static void exit_callback(void* context);
static void stay_callback(void* context);
};

View File

@@ -42,7 +42,7 @@ bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess); app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess);
} else { } else {
app->scene_controller.search_and_switch_to_previous_scene( app->scene_controller.search_and_switch_to_previous_scene(
{LfRfidApp::SceneType::ReadedMenu}); {LfRfidApp::SceneType::ReadKeyMenu});
} }
} }

View File

@@ -8,7 +8,7 @@ void LfRfidAppSceneSaveSuccess::on_enter(LfRfidApp* app, bool need_restore) {
DOLPHIN_DEED(DolphinDeedRfidSave); DOLPHIN_DEED(DolphinDeedRfidSave);
popup->set_icon(32, 5, &I_DolphinNice_96x59); popup->set_icon(32, 5, &I_DolphinNice_96x59);
popup->set_text("Saved!", 13, 22, AlignLeft, AlignBottom); popup->set_header("Saved!", 5, 7, AlignLeft, AlignTop);
popup->set_context(app); popup->set_context(app);
popup->set_callback(LfRfidAppSceneSaveSuccess::timeout_callback); popup->set_callback(LfRfidAppSceneSaveSuccess::timeout_callback);
popup->set_timeout(1500); popup->set_timeout(1500);
@@ -22,11 +22,11 @@ bool LfRfidAppSceneSaveSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event
if(event->type == LfRfidApp::EventType::Back) { if(event->type == LfRfidApp::EventType::Back) {
bool result = app->scene_controller.has_previous_scene( bool result = app->scene_controller.has_previous_scene(
{LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey}); {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
if(result) { if(result) {
app->scene_controller.search_and_switch_to_previous_scene( app->scene_controller.search_and_switch_to_previous_scene(
{LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey}); {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
} else { } else {
app->scene_controller.search_and_switch_to_another_scene( app->scene_controller.search_and_switch_to_another_scene(
{LfRfidApp::SceneType::SaveType}, LfRfidApp::SceneType::SelectKey); {LfRfidApp::SceneType::SaveType}, LfRfidApp::SceneType::SelectKey);

View File

@@ -18,7 +18,7 @@ bool LfRfidAppSceneWriteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* even
if(event->type == LfRfidApp::EventType::Back) { if(event->type == LfRfidApp::EventType::Back) {
app->scene_controller.search_and_switch_to_previous_scene( app->scene_controller.search_and_switch_to_previous_scene(
{LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey}); {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
consumed = true; consumed = true;
} }

View File

@@ -1,6 +1,7 @@
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include <storage/storage.h> #include <storage/storage.h>
#include <input/input.h>
#include "notification.h" #include "notification.h"
#include "notification_messages.h" #include "notification_messages.h"
#include "notification_app.h" #include "notification_app.h"
@@ -163,7 +164,6 @@ void notification_process_notification_message(
notification_message = (*message->sequence)[notification_message_index]; notification_message = (*message->sequence)[notification_message_index];
bool led_active = false; bool led_active = false;
uint8_t display_led_lock = 0;
uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00}; uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00};
bool reset_notifications = true; bool reset_notifications = true;
float speaker_volume_setting = app->settings.speaker_volume; float speaker_volume_setting = app->settings.speaker_volume;
@@ -191,18 +191,18 @@ void notification_process_notification_message(
reset_mask |= reset_display_mask; reset_mask |= reset_display_mask;
break; break;
case NotificationMessageTypeLedDisplayLock: case NotificationMessageTypeLedDisplayLock:
furi_assert(display_led_lock < UINT8_MAX); furi_assert(app->display_led_lock < UINT8_MAX);
display_led_lock++; app->display_led_lock++;
if(display_led_lock == 1) { if(app->display_led_lock == 1) {
notification_apply_internal_led_layer( notification_apply_internal_led_layer(
&app->display, &app->display,
notification_message->data.led.value * display_brightness_setting); notification_message->data.led.value * display_brightness_setting);
} }
break; break;
case NotificationMessageTypeLedDisplayUnlock: case NotificationMessageTypeLedDisplayUnlock:
furi_assert(display_led_lock > 0); furi_assert(app->display_led_lock > 0);
display_led_lock--; app->display_led_lock--;
if(display_led_lock == 0) { if(app->display_led_lock == 0) {
notification_apply_internal_led_layer( notification_apply_internal_led_layer(
&app->display, &app->display,
notification_message->data.led.value * display_brightness_setting); notification_message->data.led.value * display_brightness_setting);
@@ -416,8 +416,13 @@ static bool notification_save_settings(NotificationApp* app) {
}; };
static void input_event_callback(const void* value, void* context) { static void input_event_callback(const void* value, void* context) {
furi_assert(value);
furi_assert(context);
const InputEvent* event = value;
NotificationApp* app = context; NotificationApp* app = context;
notification_message(app, &sequence_display_on); if(event->type == InputTypePress) {
notification_message(app, &sequence_display_on);
}
} }
// App alloc // App alloc

View File

@@ -49,6 +49,7 @@ struct NotificationApp {
NotificationLedLayer display; NotificationLedLayer display;
NotificationLedLayer led[NOTIFICATION_LED_COUNT]; NotificationLedLayer led[NOTIFICATION_LED_COUNT];
uint8_t display_led_lock;
NotificationSettings settings; NotificationSettings settings;
}; };

View File

@@ -21,7 +21,7 @@ const NotificationMessage message_display_lock = {
}; };
const NotificationMessage message_display_unlock = { const NotificationMessage message_display_unlock = {
.type = NotificationMessageTypeLedDisplayLock, .type = NotificationMessageTypeLedDisplayUnlock,
.data.led.value = 0x00, .data.led.value = 0x00,
}; };
@@ -208,6 +208,12 @@ const NotificationSequence sequence_display_unlock = {
NULL, NULL,
}; };
const NotificationSequence sequence_display_off_delay_1000 = {
&message_delay_1000,
&message_display_off,
NULL,
};
// Charging // Charging
const NotificationSequence sequence_charging = { const NotificationSequence sequence_charging = {
&message_red_255, &message_red_255,

View File

@@ -78,6 +78,8 @@ extern const NotificationSequence sequence_display_off;
extern const NotificationSequence sequence_display_lock; extern const NotificationSequence sequence_display_lock;
/** Display: backlight always on unlock */ /** Display: backlight always on unlock */
extern const NotificationSequence sequence_display_unlock; extern const NotificationSequence sequence_display_unlock;
/** Display: backlight force off after a delay of 1000ms */
extern const NotificationSequence sequence_display_off_delay_1000;
// Charging // Charging
extern const NotificationSequence sequence_charging; extern const NotificationSequence sequence_charging;

View File

@@ -2,6 +2,7 @@
#include "notification_app.h" #include "notification_app.h"
#include <gui/modules/variable_item_list.h> #include <gui/modules/variable_item_list.h>
#include <gui/view_dispatcher.h> #include <gui/view_dispatcher.h>
#include <lib/toolbox/value_index.h>
#define MAX_NOTIFICATION_SETTINGS 4 #define MAX_NOTIFICATION_SETTINGS 4
@@ -63,44 +64,6 @@ const char* const vibro_text[VIBRO_COUNT] = {
}; };
const bool vibro_value[VIBRO_COUNT] = {false, true}; const bool vibro_value[VIBRO_COUNT] = {false, true};
uint8_t float_value_index(const float value, const float values[], uint8_t values_count) {
const float epsilon = 0.01f;
float last_value = values[0];
uint8_t index = 0;
for(uint8_t i = 0; i < values_count; i++) {
if((value >= last_value - epsilon) && (value <= values[i] + epsilon)) {
index = i;
break;
}
last_value = values[i];
}
return index;
}
uint8_t uint32_value_index(const uint32_t value, const uint32_t values[], uint8_t values_count) {
int64_t last_value = INT64_MIN;
uint8_t index = 0;
for(uint8_t i = 0; i < values_count; i++) {
if((value >= last_value) && (value <= values[i])) {
index = i;
break;
}
last_value = values[i];
}
return index;
}
uint8_t bool_value_index(const bool value, const bool values[], uint8_t values_count) {
uint8_t index = 0;
for(uint8_t i = 0; i < values_count; i++) {
if(value == values[i]) {
index = i;
break;
}
}
return index;
}
static void backlight_changed(VariableItem* item) { static void backlight_changed(VariableItem* item) {
NotificationAppSettings* app = variable_item_get_context(item); NotificationAppSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item); uint8_t index = variable_item_get_current_value_index(item);
@@ -164,21 +127,21 @@ static NotificationAppSettings* alloc_settings() {
item = variable_item_list_add( item = variable_item_list_add(
app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app); app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app);
value_index = float_value_index( value_index = value_index_float(
app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT); app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT);
variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, backlight_text[value_index]); variable_item_set_current_value_text(item, backlight_text[value_index]);
item = variable_item_list_add( item = variable_item_list_add(
app->variable_item_list, "Backlight Time", DELAY_COUNT, screen_changed, app); app->variable_item_list, "Backlight Time", DELAY_COUNT, screen_changed, app);
value_index = uint32_value_index( value_index = value_index_uint32(
app->notification->settings.display_off_delay_ms, delay_value, DELAY_COUNT); app->notification->settings.display_off_delay_ms, delay_value, DELAY_COUNT);
variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, delay_text[value_index]); variable_item_set_current_value_text(item, delay_text[value_index]);
item = variable_item_list_add( item = variable_item_list_add(
app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app); app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app);
value_index = float_value_index( value_index = value_index_float(
app->notification->settings.led_brightness, backlight_value, BACKLIGHT_COUNT); app->notification->settings.led_brightness, backlight_value, BACKLIGHT_COUNT);
variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, backlight_text[value_index]); variable_item_set_current_value_text(item, backlight_text[value_index]);
@@ -186,13 +149,13 @@ static NotificationAppSettings* alloc_settings() {
item = variable_item_list_add( item = variable_item_list_add(
app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app); app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app);
value_index = value_index =
float_value_index(app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT); value_index_float(app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT);
variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, volume_text[value_index]); variable_item_set_current_value_text(item, volume_text[value_index]);
item = item =
variable_item_list_add(app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app); variable_item_list_add(app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app);
value_index = bool_value_index(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT); value_index = value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT);
variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, vibro_text[value_index]); variable_item_set_current_value_text(item, vibro_text[value_index]);

View File

@@ -473,17 +473,17 @@ static void rpc_system_storage_md5sum_process(const PB_Main* request, void* cont
File* file = storage_file_alloc(fs_api); File* file = storage_file_alloc(fs_api);
if(storage_file_open(file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) { if(storage_file_open(file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) {
const uint16_t read_size = 512; const uint16_t size_to_read = 512;
const uint8_t hash_size = 16; const uint8_t hash_size = 16;
uint8_t* data = malloc(read_size); uint8_t* data = malloc(size_to_read);
uint8_t* hash = malloc(sizeof(uint8_t) * hash_size); uint8_t* hash = malloc(sizeof(uint8_t) * hash_size);
md5_context* md5_ctx = malloc(sizeof(md5_context)); md5_context* md5_ctx = malloc(sizeof(md5_context));
md5_starts(md5_ctx); md5_starts(md5_ctx);
while(true) { while(true) {
uint16_t readed_size = storage_file_read(file, data, read_size); uint16_t read_size = storage_file_read(file, data, size_to_read);
if(readed_size == 0) break; if(read_size == 0) break;
md5_update(md5_ctx, data, readed_size); md5_update(md5_ctx, data, read_size);
} }
md5_finish(md5_ctx, hash); md5_finish(md5_ctx, hash);
free(md5_ctx); free(md5_ctx);

View File

@@ -33,14 +33,14 @@ struct File {
* @param file pointer to file object * @param file pointer to file object
* @param buff pointer to buffer for reading * @param buff pointer to buffer for reading
* @param bytes_to_read how many bytes to read, must be smaller or equal to buffer size * @param bytes_to_read how many bytes to read, must be smaller or equal to buffer size
* @return how many bytes actually has been readed * @return how many bytes actually has been read
* *
* @var FS_File_Api::write * @var FS_File_Api::write
* @brief Write bytes from buffer to file * @brief Write bytes from buffer to file
* @param file pointer to file object * @param file pointer to file object
* @param buff pointer to buffer for writing * @param buff pointer to buffer for writing
* @param bytes_to_read how many bytes to write, must be smaller or equal to buffer size * @param bytes_to_read how many bytes to write, must be smaller or equal to buffer size
* @return how many bytes actually has been writed * @return how many bytes actually has been written
* *
* @var FS_File_Api::seek * @var FS_File_Api::seek
* @brief Move r/w pointer * @brief Move r/w pointer
@@ -107,7 +107,7 @@ typedef struct {
* @var FS_Dir_Api::read * @var FS_Dir_Api::read
* @brief Read next object info in directory * @brief Read next object info in directory
* @param file pointer to file object * @param file pointer to file object
* @param fileinfo pointer to readed FileInfo, can be NULL * @param fileinfo pointer to read FileInfo, can be NULL
* @param name pointer to name buffer, can be NULL * @param name pointer to name buffer, can be NULL
* @param name_length name buffer length * @param name_length name buffer length
* @return success flag (if next object not exist also returns false and set error_id to FSE_NOT_EXIST) * @return success flag (if next object not exist also returns false and set error_id to FSE_NOT_EXIST)
@@ -133,7 +133,7 @@ typedef struct {
* @var FS_Common_Api::stat * @var FS_Common_Api::stat
* @brief Open directory to get objects from * @brief Open directory to get objects from
* @param path path to file/directory * @param path path to file/directory
* @param fileinfo pointer to readed FileInfo, can be NULL * @param fileinfo pointer to read FileInfo, can be NULL
* @param name pointer to name buffer, can be NULL * @param name pointer to name buffer, can be NULL
* @param name_length name buffer length * @param name_length name buffer length
* @return FS_Error error info * @return FS_Error error info

View File

@@ -76,7 +76,7 @@ bool storage_file_is_dir(File* file);
* @param file pointer to file object. * @param file pointer to file object.
* @param buff pointer to a buffer, for reading * @param buff pointer to a buffer, for reading
* @param bytes_to_read how many bytes to read. Must be less than or equal to the size of the buffer. * @param bytes_to_read how many bytes to read. Must be less than or equal to the size of the buffer.
* @return uint16_t how many bytes were actually readed * @return uint16_t how many bytes were actually read
*/ */
uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read); uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read);
@@ -144,7 +144,7 @@ bool storage_dir_close(File* file);
/** Reads the next object in the directory /** Reads the next object in the directory
* @param file pointer to file object. * @param file pointer to file object.
* @param fileinfo pointer to the readed FileInfo, may be NULL * @param fileinfo pointer to the read FileInfo, may be NULL
* @param name pointer to name buffer, may be NULL * @param name pointer to name buffer, may be NULL
* @param name_length name buffer length * @param name_length name buffer length
* @return success flag (if the next object does not exist, it also returns false and sets the file error id to FSE_NOT_EXIST) * @return success flag (if the next object does not exist, it also returns false and sets the file error id to FSE_NOT_EXIST)
@@ -162,7 +162,7 @@ bool storage_dir_rewind(File* file);
/** Retrieves information about a file/directory /** Retrieves information about a file/directory
* @param app pointer to the api * @param app pointer to the api
* @param path path to file/directory * @param path path to file/directory
* @param fileinfo pointer to the readed FileInfo, may be NULL * @param fileinfo pointer to the read FileInfo, may be NULL
* @return FS_Error operation result * @return FS_Error operation result
*/ */
FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo); FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo);

View File

@@ -112,10 +112,10 @@ static void storage_cli_list(Cli* cli, string_t path) {
if(storage_dir_open(file, string_get_cstr(path))) { if(storage_dir_open(file, string_get_cstr(path))) {
FileInfo fileinfo; FileInfo fileinfo;
char name[MAX_NAME_LENGTH]; char name[MAX_NAME_LENGTH];
bool readed = false; bool read_done = false;
while(storage_dir_read(file, &fileinfo, name, MAX_NAME_LENGTH)) { while(storage_dir_read(file, &fileinfo, name, MAX_NAME_LENGTH)) {
readed = true; read_done = true;
if(fileinfo.flags & FSF_DIRECTORY) { if(fileinfo.flags & FSF_DIRECTORY) {
printf("\t[D] %s\r\n", name); printf("\t[D] %s\r\n", name);
} else { } else {
@@ -123,7 +123,7 @@ static void storage_cli_list(Cli* cli, string_t path) {
} }
} }
if(!readed) { if(!read_done) {
printf("\tEmpty\r\n"); printf("\tEmpty\r\n");
} }
} else { } else {
@@ -141,18 +141,18 @@ static void storage_cli_read(Cli* cli, string_t path) {
File* file = storage_file_alloc(api); File* file = storage_file_alloc(api);
if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
const uint16_t read_size = 128; const uint16_t size_to_read = 128;
uint16_t readed_size = 0; uint16_t read_size = 0;
uint8_t* data = malloc(read_size); uint8_t* data = malloc(read_size);
printf("Size: %lu\r\n", (uint32_t)storage_file_size(file)); printf("Size: %lu\r\n", (uint32_t)storage_file_size(file));
do { do {
readed_size = storage_file_read(file, data, read_size); read_size = storage_file_read(file, data, size_to_read);
for(uint16_t i = 0; i < readed_size; i++) { for(uint16_t i = 0; i < read_size; i++) {
printf("%c", data[i]); printf("%c", data[i]);
} }
} while(readed_size > 0); } while(read_size > 0);
printf("\r\n"); printf("\r\n");
free(data); free(data);
@@ -176,33 +176,33 @@ static void storage_cli_write(Cli* cli, string_t path) {
if(storage_file_open(file, string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) { if(storage_file_open(file, string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) {
printf("Just write your text data. New line by Ctrl+Enter, exit by Ctrl+C.\r\n"); printf("Just write your text data. New line by Ctrl+Enter, exit by Ctrl+C.\r\n");
uint32_t readed_index = 0; uint32_t read_index = 0;
while(true) { while(true) {
uint8_t symbol = cli_getc(cli); uint8_t symbol = cli_getc(cli);
if(symbol == CliSymbolAsciiETX) { if(symbol == CliSymbolAsciiETX) {
uint16_t write_size = readed_index % buffer_size; uint16_t write_size = read_index % buffer_size;
if(write_size > 0) { if(write_size > 0) {
uint16_t writed_size = storage_file_write(file, buffer, write_size); uint16_t written_size = storage_file_write(file, buffer, write_size);
if(writed_size != write_size) { if(written_size != write_size) {
storage_cli_print_error(storage_file_get_error(file)); storage_cli_print_error(storage_file_get_error(file));
} }
break; break;
} }
} }
buffer[readed_index % buffer_size] = symbol; buffer[read_index % buffer_size] = symbol;
printf("%c", buffer[readed_index % buffer_size]); printf("%c", buffer[read_index % buffer_size]);
fflush(stdout); fflush(stdout);
readed_index++; read_index++;
if(((readed_index % buffer_size) == 0)) { if(((read_index % buffer_size) == 0)) {
uint16_t writed_size = storage_file_write(file, buffer, buffer_size); uint16_t written_size = storage_file_write(file, buffer, buffer_size);
if(writed_size != buffer_size) { if(written_size != buffer_size) {
storage_cli_print_error(storage_file_get_error(file)); storage_cli_print_error(storage_file_get_error(file));
break; break;
} }
@@ -239,11 +239,11 @@ static void storage_cli_read_chunks(Cli* cli, string_t path, string_t args) {
printf("\r\nReady?\r\n"); printf("\r\nReady?\r\n");
cli_getc(cli); cli_getc(cli);
uint16_t readed_size = storage_file_read(file, data, buffer_size); uint16_t read_size = storage_file_read(file, data, buffer_size);
for(uint16_t i = 0; i < readed_size; i++) { for(uint16_t i = 0; i < read_size; i++) {
putchar(data[i]); putchar(data[i]);
} }
file_size -= readed_size; file_size -= read_size;
} }
printf("\r\n"); printf("\r\n");
@@ -277,9 +277,9 @@ static void storage_cli_write_chunk(Cli* cli, string_t path, string_t args) {
buffer[i] = cli_getc(cli); buffer[i] = cli_getc(cli);
} }
uint16_t writed_size = storage_file_write(file, buffer, buffer_size); uint16_t written_size = storage_file_write(file, buffer, buffer_size);
if(writed_size != buffer_size) { if(written_size != buffer_size) {
storage_cli_print_error(storage_file_get_error(file)); storage_cli_print_error(storage_file_get_error(file));
} }
@@ -400,17 +400,17 @@ static void storage_cli_md5(Cli* cli, string_t path) {
File* file = storage_file_alloc(api); File* file = storage_file_alloc(api);
if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
const uint16_t read_size = 512; const uint16_t size_to_read = 512;
const uint8_t hash_size = 16; const uint8_t hash_size = 16;
uint8_t* data = malloc(read_size); uint8_t* data = malloc(size_to_read);
uint8_t* hash = malloc(sizeof(uint8_t) * hash_size); uint8_t* hash = malloc(sizeof(uint8_t) * hash_size);
md5_context* md5_ctx = malloc(sizeof(md5_context)); md5_context* md5_ctx = malloc(sizeof(md5_context));
md5_starts(md5_ctx); md5_starts(md5_ctx);
while(true) { while(true) {
uint16_t readed_size = storage_file_read(file, data, read_size); uint16_t read_size = storage_file_read(file, data, size_to_read);
if(readed_size == 0) break; if(read_size == 0) break;
md5_update(md5_ctx, data, readed_size); md5_update(md5_ctx, data, read_size);
} }
md5_finish(md5_ctx, hash); md5_finish(md5_ctx, hash);
free(md5_ctx); free(md5_ctx);

View File

@@ -340,10 +340,10 @@ static uint16_t
storage_ext_file_read(void* ctx, File* file, void* buff, uint16_t const bytes_to_read) { storage_ext_file_read(void* ctx, File* file, void* buff, uint16_t const bytes_to_read) {
StorageData* storage = ctx; StorageData* storage = ctx;
SDFile* file_data = storage_get_storage_file_data(file, storage); SDFile* file_data = storage_get_storage_file_data(file, storage);
uint16_t bytes_readed = 0; uint16_t bytes_read = 0;
file->internal_error_id = f_read(file_data, buff, bytes_to_read, &bytes_readed); file->internal_error_id = f_read(file_data, buff, bytes_to_read, &bytes_read);
file->error_id = storage_ext_parse_error(file->internal_error_id); file->error_id = storage_ext_parse_error(file->internal_error_id);
return bytes_readed; return bytes_read;
} }
static uint16_t static uint16_t

View File

@@ -349,7 +349,7 @@ static uint16_t
lfs_t* lfs = lfs_get_from_storage(storage); lfs_t* lfs = lfs_get_from_storage(storage);
LFSHandle* handle = storage_get_storage_file_data(file, storage); LFSHandle* handle = storage_get_storage_file_data(file, storage);
uint16_t bytes_readed = 0; uint16_t bytes_read = 0;
if(lfs_handle_is_open(handle)) { if(lfs_handle_is_open(handle)) {
file->internal_error_id = file->internal_error_id =
@@ -361,10 +361,10 @@ static uint16_t
file->error_id = storage_int_parse_error(file->internal_error_id); file->error_id = storage_int_parse_error(file->internal_error_id);
if(file->error_id == FSE_OK) { if(file->error_id == FSE_OK) {
bytes_readed = file->internal_error_id; bytes_read = file->internal_error_id;
file->internal_error_id = 0; file->internal_error_id = 0;
} }
return bytes_readed; return bytes_read;
} }
static uint16_t static uint16_t

View File

@@ -29,6 +29,7 @@ struct SubGhzFrequencyAnalyzerWorker {
volatile bool worker_running; volatile bool worker_running;
uint8_t count_repet; uint8_t count_repet;
FrequencyRSSI frequency_rssi_buf; FrequencyRSSI frequency_rssi_buf;
SubGhzSetting* setting;
float filVal; float filVal;
@@ -77,10 +78,12 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
frequency_rssi.rssi = -127.0f; frequency_rssi.rssi = -127.0f;
furi_hal_subghz_idle(); furi_hal_subghz_idle();
furi_hal_subghz_load_registers(subghz_preset_ook_650khz); furi_hal_subghz_load_registers(subghz_preset_ook_650khz);
for(size_t i = 0; i < subghz_frequencies_count; i++) { for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) {
if(furi_hal_subghz_is_frequency_valid(subghz_frequencies[i])) { if(furi_hal_subghz_is_frequency_valid(
subghz_setting_get_frequency(instance->setting, i))) {
furi_hal_subghz_idle(); furi_hal_subghz_idle();
frequency = furi_hal_subghz_set_frequency(subghz_frequencies[i]); frequency = furi_hal_subghz_set_frequency(
subghz_setting_get_frequency(instance->setting, i));
furi_hal_subghz_rx(); furi_hal_subghz_rx();
osDelay(3); osDelay(3);
rssi = furi_hal_subghz_get_rssi(); rssi = furi_hal_subghz_get_rssi();
@@ -150,6 +153,8 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc() {
furi_thread_set_context(instance->thread, instance); furi_thread_set_context(instance->thread, instance);
furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread); furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread);
instance->setting = subghz_setting_alloc();
subghz_setting_load(instance->setting, "/ext/subghz/assets/setting_frequency_analyzer_user");
return instance; return instance;
} }
@@ -157,7 +162,7 @@ void subghz_frequency_analyzer_worker_free(SubGhzFrequencyAnalyzerWorker* instan
furi_assert(instance); furi_assert(instance);
furi_thread_free(instance->thread); furi_thread_free(instance->thread);
subghz_setting_free(instance->setting);
free(instance); free(instance);
} }

View File

@@ -127,7 +127,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
} else { } else {
//Restore default setting //Restore default setting
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; subghz->txrx->frequency = subghz_setting_get_frequency(
subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting));
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
if(!scene_manager_search_and_switch_to_previous_scene( if(!scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneSaved)) { subghz->scene_manager, SubGhzSceneSaved)) {

View File

@@ -120,7 +120,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
subghz_sleep(subghz); subghz_sleep(subghz);
}; };
subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->hopper_state = SubGhzHopperStateOFF;
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; subghz->txrx->frequency = subghz_setting_get_frequency(
subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting));
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
subghz->txrx->idx_menu_chosen = 0; subghz->txrx->idx_menu_chosen = 0;
subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);

View File

@@ -40,6 +40,21 @@ uint8_t subghz_scene_receiver_config_uint32_value_index(
return index; return index;
} }
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
furi_assert(context);
SubGhz* subghz = context;
int64_t last_value = INT64_MIN;
uint8_t index = 0;
for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->setting); i++) {
if((value >= last_value) && (value <= subghz_setting_get_frequency(subghz->setting, i))) {
index = i;
break;
}
last_value = subghz_setting_get_frequency(subghz->setting, i);
}
return index;
}
uint8_t subghz_scene_receiver_config_hopper_value_index( uint8_t subghz_scene_receiver_config_hopper_value_index(
const uint32_t value, const uint32_t value,
const uint32_t values[], const uint32_t values[],
@@ -64,10 +79,17 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
uint8_t index = variable_item_get_current_value_index(item); uint8_t index = variable_item_get_current_value_index(item);
if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) { if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) {
variable_item_set_current_value_text(item, subghz_frequencies_text[index]); char text_buf[10] = {0};
subghz->txrx->frequency = subghz_frequencies[index]; sprintf(
text_buf,
"%lu.%02lu",
subghz_setting_get_frequency(subghz->setting, index) / 1000000,
(subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000);
variable_item_set_current_value_text(item, text_buf);
subghz->txrx->frequency = subghz_setting_get_frequency(subghz->setting, index);
} else { } else {
variable_item_set_current_value_index(item, subghz_frequencies_433_92); variable_item_set_current_value_index(
item, subghz_setting_get_frequency_default_index(subghz->setting));
} }
} }
@@ -85,15 +107,27 @@ static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item)
variable_item_set_current_value_text(item, hopping_text[index]); variable_item_set_current_value_text(item, hopping_text[index]);
if(hopping_value[index] == SubGhzHopperStateOFF) { if(hopping_value[index] == SubGhzHopperStateOFF) {
char text_buf[10] = {0};
sprintf(
text_buf,
"%lu.%02lu",
subghz_setting_get_frequency(
subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting)) /
1000000,
(subghz_setting_get_frequency(
subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting)) %
1000000) /
10000);
variable_item_set_current_value_text( variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state( (VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig), subghz->scene_manager, SubGhzSceneReceiverConfig),
subghz_frequencies_text[subghz_frequencies_433_92]); text_buf);
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; subghz->txrx->frequency = subghz_setting_get_frequency(
subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting));
variable_item_set_current_value_index( variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state( (VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig), subghz->scene_manager, SubGhzSceneReceiverConfig),
subghz_frequencies_433_92); subghz_setting_get_frequency_default_index(subghz->setting));
} else { } else {
variable_item_set_current_value_text( variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state( (VariableItem*)scene_manager_get_scene_state(
@@ -102,7 +136,7 @@ static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item)
variable_item_set_current_value_index( variable_item_set_current_value_index(
(VariableItem*)scene_manager_get_scene_state( (VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig), subghz->scene_manager, SubGhzSceneReceiverConfig),
subghz_frequencies_433_92); subghz_setting_get_frequency_default_index(subghz->setting));
} }
subghz->txrx->hopper_state = hopping_value[index]; subghz->txrx->hopper_state = hopping_value[index];
@@ -116,15 +150,20 @@ void subghz_scene_receiver_config_on_enter(void* context) {
item = variable_item_list_add( item = variable_item_list_add(
subghz->variable_item_list, subghz->variable_item_list,
"Frequency:", "Frequency:",
subghz_frequencies_count, subghz_setting_get_frequency_count(subghz->setting),
subghz_scene_receiver_config_set_frequency, subghz_scene_receiver_config_set_frequency,
subghz); subghz);
value_index = subghz_scene_receiver_config_uint32_value_index( value_index = subghz_scene_receiver_config_next_frequency(subghz->txrx->frequency, subghz);
subghz->txrx->frequency, subghz_frequencies, subghz_frequencies_count);
scene_manager_set_scene_state( scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item); subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]); char text_buf[10] = {0};
sprintf(
text_buf,
"%lu.%02lu",
subghz_setting_get_frequency(subghz->setting, value_index) / 1000000,
(subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000);
variable_item_set_current_value_text(item, text_buf);
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
SubGhzCustomEventManagerSet) { SubGhzCustomEventManagerSet) {

View File

@@ -46,7 +46,7 @@ bool subghz_scene_set_type_submenu_gen_data_protocol(
if(!subghz_protocol_decoder_base_serialize( if(!subghz_protocol_decoder_base_serialize(
subghz->txrx->decoder_result, subghz->txrx->decoder_result,
subghz->txrx->fff_data, subghz->txrx->fff_data,
subghz_frequencies[subghz_frequencies_433_92], subghz_setting_get_frequency_default_index(subghz->setting),
FuriHalSubGhzPresetOok650Async)) { FuriHalSubGhzPresetOok650Async)) {
FURI_LOG_E(TAG, "Unable to serialize"); FURI_LOG_E(TAG, "Unable to serialize");
break; break;
@@ -213,7 +213,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
0x2, 0x2,
0x0003, 0x0003,
"DoorHan", "DoorHan",
subghz_frequencies[subghz_frequencies_433_92], subghz_setting_get_frequency_default_index(subghz->setting),
FuriHalSubGhzPresetOok650Async); FuriHalSubGhzPresetOok650Async);
generated_protocol = true; generated_protocol = true;
} else { } else {
@@ -237,7 +237,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
0x2, 0x2,
0x0003, 0x0003,
"DoorHan", "DoorHan",
subghz_frequencies[subghz_frequencies_315_00], 315000000,
FuriHalSubGhzPresetOok650Async); FuriHalSubGhzPresetOok650Async);
generated_protocol = true; generated_protocol = true;
} else { } else {

View File

@@ -3,68 +3,6 @@
#include "subghz_i.h" #include "subghz_i.h"
#include <lib/toolbox/path.h> #include <lib/toolbox/path.h>
const char* const subghz_frequencies_text[] = {
"300.00",
"303.88",
"304.25",
"315.00",
"318.00",
"390.00",
"418.00",
"433.08",
"433.42",
"433.92",
"434.42",
"434.78",
"438.90",
"868.35",
"915.00",
"925.00",
};
const uint32_t subghz_frequencies[] = {
/* 300 - 348 */
300000000,
303875000,
304250000,
315000000,
318000000,
/* 387 - 464 */
390000000,
418000000,
433075000, /* LPD433 first */
433420000,
433920000, /* LPD433 mid */
434420000,
434775000, /* LPD433 last channels */
438900000,
/* 779 - 928 */
868350000,
915000000,
925000000,
};
const uint32_t subghz_hopper_frequencies[] = {
315000000,
318000000,
390000000,
433920000,
868350000,
};
const uint32_t subghz_frequencies_count = sizeof(subghz_frequencies) / sizeof(uint32_t);
const uint32_t subghz_hopper_frequencies_count =
sizeof(subghz_hopper_frequencies) / sizeof(uint32_t);
const uint32_t subghz_frequencies_433_92 = 9;
const uint32_t subghz_frequencies_315_00 = 3;
bool subghz_custom_event_callback(void* context, uint32_t event) { bool subghz_custom_event_callback(void* context, uint32_t event) {
furi_assert(context); furi_assert(context);
SubGhz* subghz = context; SubGhz* subghz = context;
@@ -186,9 +124,14 @@ SubGhz* subghz_alloc() {
SubGhzViewIdStatic, SubGhzViewIdStatic,
subghz_test_static_get_view(subghz->subghz_test_static)); subghz_test_static_get_view(subghz->subghz_test_static));
//init setting
subghz->setting = subghz_setting_alloc();
subghz_setting_load(subghz->setting, "/ext/subghz/assets/setting_user");
//init Worker & Protocol & History //init Worker & Protocol & History
subghz->txrx = malloc(sizeof(SubGhzTxRx)); subghz->txrx = malloc(sizeof(SubGhzTxRx));
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92]; subghz->txrx->frequency = subghz_setting_get_frequency(
subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting));
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
subghz->txrx->txrx_state = SubGhzTxRxStateSleep; subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->hopper_state = SubGhzHopperStateOFF;
@@ -281,6 +224,9 @@ void subghz_free(SubGhz* subghz) {
furi_record_close("gui"); furi_record_close("gui");
subghz->gui = NULL; subghz->gui = NULL;
//setting
subghz_setting_free(subghz->setting);
//Worker & Protocol & History //Worker & Protocol & History
subghz_receiver_free(subghz->txrx->receiver); subghz_receiver_free(subghz->txrx->receiver);
subghz_environment_free(subghz->txrx->environment); subghz_environment_free(subghz->txrx->environment);

View File

@@ -9,6 +9,7 @@
#include <lib/subghz/receiver.h> #include <lib/subghz/receiver.h>
#include <lib/subghz/transmitter.h> #include <lib/subghz/transmitter.h>
#include <lib/subghz/subghz_file_encoder_worker.h>
#include "helpers/subghz_chat.h" #include "helpers/subghz_chat.h"
@@ -294,6 +295,110 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
free(instance); free(instance);
} }
void subghz_cli_command_decode_raw(Cli* cli, string_t args, void* context) {
string_t file_name;
string_init(file_name);
string_set(file_name, "/any/subghz/test.sub");
Storage* storage = furi_record_open("storage");
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
string_t temp_str;
string_init(temp_str);
uint32_t temp_data32;
bool check_file = false;
do {
if(string_size(args)) {
if(!args_read_string_and_trim(args, file_name)) {
cli_print_usage(
"subghz decode_raw", "<file_name: path_RAW_file>", string_get_cstr(args));
break;
}
}
if(!flipper_format_file_open_existing(fff_data_file, string_get_cstr(file_name))) {
printf(
"subghz decode_raw \033[0;31mError open file\033[0m %s\r\n",
string_get_cstr(file_name));
break;
}
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
printf("subghz decode_raw \033[0;31mMissing or incorrect header\033[0m\r\n");
break;
}
if(!strcmp(string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE) &&
temp_data32 == SUBGHZ_KEY_FILE_VERSION) {
} else {
printf("subghz decode_raw \033[0;31mType or version mismatch\033[0m\r\n");
break;
}
check_file = true;
} while(false);
string_clear(temp_str);
flipper_format_free(fff_data_file);
furi_record_close("storage");
if(check_file) {
// Allocate context
SubGhzCliCommandRx* instance = malloc(sizeof(SubGhzCliCommandRx));
SubGhzEnvironment* environment = subghz_environment_alloc();
if(subghz_environment_load_keystore(environment, "/ext/subghz/assets/keeloq_mfcodes")) {
printf("SubGhz test: Load_keystore \033[0;32mOK\033[0m\r\n");
} else {
printf("SubGhz test: Load_keystore \033[0;31mERROR\033[0m\r\n");
}
subghz_environment_set_came_atomo_rainbow_table_file_name(
environment, "/ext/subghz/assets/came_atomo");
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
environment, "/ext/subghz/assets/nice_flor_s");
SubGhzReceiver* receiver = subghz_receiver_alloc_init(environment);
subghz_receiver_set_filter(receiver, SubGhzProtocolFlag_Decodable);
subghz_receiver_set_rx_callback(receiver, subghz_cli_command_rx_callback, instance);
SubGhzFileEncoderWorker* file_worker_encoder = subghz_file_encoder_worker_alloc();
if(subghz_file_encoder_worker_start(file_worker_encoder, string_get_cstr(file_name))) {
//the worker needs a file in order to open and read part of the file
osDelay(100);
}
printf(
"Listening at \033[0;33m%s\033[0m.\r\n\r\nPress CTRL+C to stop\r\n\r\n",
string_get_cstr(file_name));
LevelDuration level_duration;
while(!cli_cmd_interrupt_received(cli)) {
furi_hal_delay_us(500); //you need to have time to read from the file from the SD card
level_duration = subghz_file_encoder_worker_get_level_duration(file_worker_encoder);
if(!level_duration_is_reset(level_duration)) {
bool level = level_duration_get_level(level_duration);
uint32_t duration = level_duration_get_duration(level_duration);
subghz_receiver_decode(receiver, level, duration);
} else {
break;
}
}
printf("\r\nPackets recieved \033[0;32m%u\033[0m\r\n", instance->packet_count);
// Cleanup
subghz_receiver_free(receiver);
subghz_environment_free(environment);
if(subghz_file_encoder_worker_is_running(file_worker_encoder)) {
subghz_file_encoder_worker_stop(file_worker_encoder);
}
subghz_file_encoder_worker_free(file_worker_encoder);
free(instance);
}
string_clear(file_name);
}
static void subghz_cli_command_print_usage() { static void subghz_cli_command_print_usage() {
printf("Usage:\r\n"); printf("Usage:\r\n");
printf("subghz <cmd> <args>\r\n"); printf("subghz <cmd> <args>\r\n");
@@ -303,6 +408,7 @@ static void subghz_cli_command_print_usage() {
printf( printf(
"\ttx <3 byte Key: in hex> <frequency: in Hz> <repeat: count>\t - Transmitting key\r\n"); "\ttx <3 byte Key: in hex> <frequency: in Hz> <repeat: count>\t - Transmitting key\r\n");
printf("\trx <frequency:in Hz>\t - Reception key\r\n"); printf("\trx <frequency:in Hz>\t - Reception key\r\n");
printf("\tdecode_raw <file_name: path_RAW_file>\t - Testing\r\n");
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
printf("\r\n"); printf("\r\n");
@@ -595,6 +701,12 @@ static void subghz_cli_command(Cli* cli, string_t args, void* context) {
subghz_cli_command_rx(cli, args, context); subghz_cli_command_rx(cli, args, context);
break; break;
} }
if(string_cmp_str(cmd, "decode_raw") == 0) {
subghz_cli_command_decode_raw(cli, args, context);
break;
}
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
if(string_cmp_str(cmd, "encrypt_keeloq") == 0) { if(string_cmp_str(cmd, "encrypt_keeloq") == 0) {
subghz_cli_command_encrypt_keeloq(cli, args); subghz_cli_command_encrypt_keeloq(cli, args);

View File

@@ -514,9 +514,9 @@ void subghz_hopper_update(SubGhz* subghz) {
} else { } else {
subghz->txrx->hopper_state = SubGhzHopperStateRunnig; subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
} }
// Select next frequency // Select next frequency
if(subghz->txrx->hopper_idx_frequency < subghz_hopper_frequencies_count - 1) { if(subghz->txrx->hopper_idx_frequency <
subghz_setting_get_hopper_frequency_count(subghz->setting) - 1) {
subghz->txrx->hopper_idx_frequency++; subghz->txrx->hopper_idx_frequency++;
} else { } else {
subghz->txrx->hopper_idx_frequency = 0; subghz->txrx->hopper_idx_frequency = 0;
@@ -527,7 +527,8 @@ void subghz_hopper_update(SubGhz* subghz) {
}; };
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) { if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
subghz_receiver_reset(subghz->txrx->receiver); subghz_receiver_reset(subghz->txrx->receiver);
subghz->txrx->frequency = subghz_hopper_frequencies[subghz->txrx->hopper_idx_frequency]; subghz->txrx->frequency = subghz_setting_get_hopper_frequency(
subghz->setting, subghz->txrx->hopper_idx_frequency);
subghz_rx(subghz, subghz->txrx->frequency); subghz_rx(subghz, subghz->txrx->frequency);
} }
} }

View File

@@ -31,18 +31,11 @@
#include <lib/subghz/transmitter.h> #include <lib/subghz/transmitter.h>
#include "subghz_history.h" #include "subghz_history.h"
#include "subghz_setting.h"
#include <gui/modules/variable_item_list.h> #include <gui/modules/variable_item_list.h>
#define SUBGHZ_MAX_LEN_NAME 21 #define SUBGHZ_MAX_LEN_NAME 40
extern const char* const subghz_frequencies_text[];
extern const uint32_t subghz_frequencies[];
extern const uint32_t subghz_hopper_frequencies[];
extern const uint32_t subghz_frequencies_count;
extern const uint32_t subghz_hopper_frequencies_count;
extern const uint32_t subghz_frequencies_433_92;
extern const uint32_t subghz_frequencies_315_00;
/** SubGhzNotification state */ /** SubGhzNotification state */
typedef enum { typedef enum {
@@ -145,6 +138,7 @@ struct SubGhz {
SubGhzTestCarrier* subghz_test_carrier; SubGhzTestCarrier* subghz_test_carrier;
SubGhzTestPacket* subghz_test_packet; SubGhzTestPacket* subghz_test_packet;
string_t error_str; string_t error_str;
SubGhzSetting* setting;
}; };
typedef enum { typedef enum {

View File

@@ -0,0 +1,361 @@
#include "subghz_setting.h"
#include "subghz_i.h"
#include <furi.h>
#include <m-list.h>
#include <lib/flipper_format/flipper_format.h>
#define TAG "SubGhzSetting"
#define SUBGHZ_SETTING_FILE_VERSION 1
#define SUBGHZ_SETTING_FILE_TYPE "Flipper SubGhz Setting File"
typedef enum {
SubGhzSettingStateNoLoad = 0,
SubGhzSettingStateLoadFrequencyDefault,
SubGhzSettingStateOkLoad,
} SubGhzSettingState;
static const uint32_t subghz_frequencies[] = {
/* 300 - 348 */
300000000,
303875000,
304250000,
315000000,
318000000,
/* 387 - 464 */
390000000,
418000000,
433075000, /* LPD433 first */
433420000,
433920000, /* LPD433 mid */
434420000,
434775000, /* LPD433 last channels */
438900000,
/* 779 - 928 */
868350000,
915000000,
925000000,
0,
};
static const uint32_t subghz_hopper_frequencies[] = {
315000000,
318000000,
390000000,
433920000,
868350000,
0,
};
static const uint32_t subghz_frequency_default_index = 9;
static const uint32_t subghz_frequencies_region_eu_ru[] = {
/* 300 - 348 */
300000000,
303875000,
304250000,
315000000,
318000000,
/* 387 - 464 */
390000000,
418000000,
433075000, /* LPD433 first */
433420000,
433920000, /* LPD433 mid */
434420000,
434775000, /* LPD433 last channels */
438900000,
/* 779 - 928 */
868350000,
915000000,
925000000,
0,
};
static const uint32_t subghz_hopper_frequencies_region_eu_ru[] = {
315000000,
318000000,
390000000,
433920000,
868350000,
0,
};
static const uint32_t subghz_frequency_default_index_region_eu_ru = 9;
static const uint32_t subghz_frequencies_region_us_ca_au[] = {
/* 300 - 348 */
300000000,
303875000,
304250000,
315000000,
318000000,
/* 387 - 464 */
390000000,
418000000,
433075000, /* LPD433 first */
433420000,
433920000, /* LPD433 mid */
434420000,
434775000, /* LPD433 last channels */
438900000,
/* 779 - 928 */
868350000,
915000000,
925000000,
0,
};
static const uint32_t subghz_hopper_frequencies_region_us_ca_au[] = {
315000000,
318000000,
390000000,
433920000,
868350000,
0,
};
static const uint32_t subghz_frequency_default_index_region_us_ca_au = 9;
static const uint32_t subghz_frequencies_region_jp[] = {
/* 300 - 348 */
300000000,
303875000,
304250000,
315000000,
318000000,
/* 387 - 464 */
390000000,
418000000,
433075000, /* LPD433 first */
433420000,
433920000, /* LPD433 mid */
434420000,
434775000, /* LPD433 last channels */
438900000,
/* 779 - 928 */
868350000,
915000000,
925000000,
0,
};
static const uint32_t subghz_hopper_frequencies_region_jp[] = {
315000000,
318000000,
390000000,
433920000,
868350000,
0,
};
static const uint32_t subghz_frequency_default_index_region_jp = 9;
LIST_DEF(frequencies_list, uint32_t)
LIST_DEF(hopper_frequencies_list, uint32_t)
struct SubGhzSetting {
frequencies_list_t frequencies;
hopper_frequencies_list_t hopper_frequencies;
size_t frequencies_count;
size_t hopper_frequencies_count;
uint32_t frequency_default_index;
};
SubGhzSetting* subghz_setting_alloc(void) {
SubGhzSetting* instance = malloc(sizeof(SubGhzSetting));
frequencies_list_init(instance->frequencies);
hopper_frequencies_list_init(instance->hopper_frequencies);
return instance;
}
void subghz_setting_free(SubGhzSetting* instance) {
furi_assert(instance);
frequencies_list_clear(instance->frequencies);
hopper_frequencies_list_clear(instance->hopper_frequencies);
free(instance);
}
void subghz_setting_load_default(
SubGhzSetting* instance,
const uint32_t frequencies[],
const uint32_t hopper_frequencies[],
const uint32_t frequency_default_index) {
furi_assert(instance);
size_t i = 0;
frequencies_list_clear(instance->frequencies);
hopper_frequencies_list_clear(instance->hopper_frequencies);
i = 0;
while(frequencies[i]) {
frequencies_list_push_back(instance->frequencies, frequencies[i]);
i++;
}
instance->frequencies_count = i;
i = 0;
while(hopper_frequencies[i]) {
hopper_frequencies_list_push_back(instance->hopper_frequencies, hopper_frequencies[i]);
i++;
}
instance->hopper_frequencies_count = i;
instance->frequency_default_index = frequency_default_index;
}
void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
furi_assert(instance);
frequencies_list_clear(instance->frequencies);
hopper_frequencies_list_clear(instance->hopper_frequencies);
Storage* storage = furi_record_open("storage");
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
string_t temp_str;
string_init(temp_str);
uint32_t temp_data32;
SubGhzSettingState loading = SubGhzSettingStateNoLoad;
uint16_t i = 0;
if(file_path) {
do {
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
FURI_LOG_E(TAG, "Error open file %s", file_path);
break;
}
if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
FURI_LOG_E(TAG, "Missing or incorrect header");
break;
}
if((!strcmp(string_get_cstr(temp_str), SUBGHZ_SETTING_FILE_TYPE)) &&
temp_data32 == SUBGHZ_SETTING_FILE_VERSION) {
} else {
FURI_LOG_E(TAG, "Type or version mismatch");
break;
}
if(!flipper_format_rewind(fff_data_file)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
i = 0;
while(flipper_format_read_uint32(
fff_data_file, "Frequency", (uint32_t*)&temp_data32, 1)) {
if(furi_hal_subghz_is_frequency_valid(temp_data32)) {
FURI_LOG_I(TAG, "Frequency loaded %lu", temp_data32);
frequencies_list_push_back(instance->frequencies, temp_data32);
i++;
} else {
FURI_LOG_E(TAG, "Frequency not supported %lu", temp_data32);
}
}
instance->frequencies_count = i;
if(!flipper_format_rewind(fff_data_file)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
i = 0;
while(flipper_format_read_uint32(
fff_data_file, "Hopper_frequency", (uint32_t*)&temp_data32, 1)) {
if(furi_hal_subghz_is_frequency_valid(temp_data32)) {
FURI_LOG_I(TAG, "Hopper frequency loaded %lu", temp_data32);
hopper_frequencies_list_push_back(instance->hopper_frequencies, temp_data32);
i++;
} else {
FURI_LOG_E(TAG, "Hopper frequency not supported %lu", temp_data32);
}
}
instance->hopper_frequencies_count = i;
if(!flipper_format_rewind(fff_data_file)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_uint32(
fff_data_file, "Frequency_default", (uint32_t*)&temp_data32, 1)) {
FURI_LOG_E(TAG, "Frequency default missing");
break;
}
for(i = 0; i < instance->frequencies_count; i++) {
if(subghz_setting_get_frequency(instance, i) == temp_data32) {
instance->frequency_default_index = i;
FURI_LOG_I(TAG, "Frequency default index %lu", i);
loading = SubGhzSettingStateLoadFrequencyDefault;
break;
}
}
if(loading == SubGhzSettingStateLoadFrequencyDefault) {
loading = SubGhzSettingStateOkLoad;
} else {
FURI_LOG_E(TAG, "Frequency default index missing");
}
} while(false);
}
flipper_format_free(fff_data_file);
furi_record_close("storage");
if(loading != SubGhzSettingStateOkLoad) {
switch(furi_hal_version_get_hw_region()) {
case FuriHalVersionRegionEuRu:
subghz_setting_load_default(
instance,
subghz_frequencies_region_eu_ru,
subghz_hopper_frequencies_region_eu_ru,
subghz_frequency_default_index_region_eu_ru);
break;
case FuriHalVersionRegionUsCaAu:
subghz_setting_load_default(
instance,
subghz_frequencies_region_us_ca_au,
subghz_hopper_frequencies_region_us_ca_au,
subghz_frequency_default_index_region_us_ca_au);
break;
case FuriHalVersionRegionJp:
subghz_setting_load_default(
instance,
subghz_frequencies_region_jp,
subghz_hopper_frequencies_region_jp,
subghz_frequency_default_index_region_jp);
break;
default:
subghz_setting_load_default(
instance,
subghz_frequencies,
subghz_hopper_frequencies,
subghz_frequency_default_index);
break;
}
}
}
size_t subghz_setting_get_frequency_count(SubGhzSetting* instance) {
furi_assert(instance);
return instance->frequencies_count;
}
size_t subghz_setting_get_hopper_frequency_count(SubGhzSetting* instance) {
furi_assert(instance);
return instance->hopper_frequencies_count;
}
uint32_t subghz_setting_get_frequency(SubGhzSetting* instance, size_t idx) {
furi_assert(instance);
return *frequencies_list_get(instance->frequencies, idx);
}
uint32_t subghz_setting_get_hopper_frequency(SubGhzSetting* instance, size_t idx) {
furi_assert(instance);
return *hopper_frequencies_list_get(instance->hopper_frequencies, idx);
}
uint32_t subghz_setting_get_frequency_default_index(SubGhzSetting* instance) {
furi_assert(instance);
return instance->frequency_default_index;
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include <math.h>
#include <furi.h>
#include <furi_hal.h>
typedef struct SubGhzSetting SubGhzSetting;
SubGhzSetting* subghz_setting_alloc(void);
void subghz_setting_free(SubGhzSetting* instance);
void subghz_setting_load(SubGhzSetting* instance, const char* file_path);
size_t subghz_setting_get_frequency_count(SubGhzSetting* instance);
size_t subghz_setting_get_hopper_frequency_count(SubGhzSetting* instance);
uint32_t subghz_setting_get_frequency(SubGhzSetting* instance, size_t idx);
uint32_t subghz_setting_get_hopper_frequency(SubGhzSetting* instance, size_t idx);
uint32_t subghz_setting_get_frequency_default_index(SubGhzSetting* instance);

View File

@@ -1,19 +1,6 @@
#include "system_settings.h" #include "system_settings.h"
#include <loader/loader.h> #include <loader/loader.h>
#include <lib/toolbox/value_index.h>
static uint8_t
uint32_value_index(const uint32_t value, const uint32_t values[], uint8_t values_count) {
int64_t last_value = INT64_MIN;
uint8_t index = 0;
for(uint8_t i = 0; i < values_count; i++) {
if((value >= last_value) && (value <= values[i])) {
index = i;
break;
}
last_value = values[i];
}
return index;
}
const char* const log_level_text[] = { const char* const log_level_text[] = {
"Default", "Default",
@@ -80,7 +67,7 @@ SystemSettings* system_settings_alloc() {
item = variable_item_list_add( item = variable_item_list_add(
app->var_item_list, "Log Level", COUNT_OF(log_level_text), log_level_changed, app); app->var_item_list, "Log Level", COUNT_OF(log_level_text), log_level_changed, app);
value_index = uint32_value_index( value_index = value_index_uint32(
furi_hal_rtc_get_log_level(), log_level_value, COUNT_OF(log_level_text)); furi_hal_rtc_get_log_level(), log_level_value, COUNT_OF(log_level_text));
variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, log_level_text[value_index]); variable_item_set_current_value_text(item, log_level_text[value_index]);

Some files were not shown because too many files have changed in this diff Show More