mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-20 04:54:45 -07:00
Merge branch 'flipperdevices:dev' into dev
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -36,3 +36,6 @@ CMakeLists.txt
|
||||
|
||||
# bundle output
|
||||
dist
|
||||
|
||||
# kde
|
||||
.directory
|
||||
|
||||
@@ -21,13 +21,23 @@ bool archive_app_is_available(void* context, const char* path) {
|
||||
ArchiveAppTypeEnum app = archive_get_app_type(path);
|
||||
|
||||
if(app == ArchiveAppTypeU2f) {
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
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) {
|
||||
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;
|
||||
} else {
|
||||
return false;
|
||||
@@ -60,10 +70,10 @@ void archive_app_delete_file(void* context, const char* path) {
|
||||
bool res = false;
|
||||
|
||||
if(app == ArchiveAppTypeU2f) {
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
res = file_worker_remove(file_worker, "/any/u2f/key.u2f");
|
||||
res |= file_worker_remove(file_worker, "/any/u2f/cnt.u2f");
|
||||
file_worker_free(file_worker);
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
res = (storage_common_remove(fs_api, "/any/u2f/key.u2f") == FSE_OK);
|
||||
res |= (storage_common_remove(fs_api, "/any/u2f/cnt.u2f") == FSE_OK);
|
||||
furi_record_close("storage");
|
||||
|
||||
if(archive_is_favorite("/app:u2f/U2F Token")) {
|
||||
archive_favorites_delete("/app:u2f/U2F Token");
|
||||
|
||||
@@ -392,6 +392,17 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) {
|
||||
furi_assert(browser);
|
||||
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));
|
||||
|
||||
with_view_model(
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#define TAB_RIGHT InputKeyRight //default tab swith direction
|
||||
#define FILE_LIST_BUF_LEN 100
|
||||
#define BROWSER_DEPTH_MAX 8
|
||||
|
||||
static const char* tab_default_paths[] = {
|
||||
[ArchiveTabFavorites] = "/any/favorites",
|
||||
|
||||
@@ -4,20 +4,63 @@
|
||||
#include "archive_apps.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) {
|
||||
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_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;
|
||||
|
||||
if(result) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@@ -27,21 +70,26 @@ uint16_t archive_favorites_count(void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
storage_file_close(file);
|
||||
|
||||
string_clear(buffer);
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
static bool archive_favourites_rescan() {
|
||||
string_t 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) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
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));
|
||||
}
|
||||
} else {
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
|
||||
bool file_exists = storage_file_open(
|
||||
fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
if(file_exists) {
|
||||
storage_file_close(fav_item_file);
|
||||
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);
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_file_close(file);
|
||||
storage_common_remove(fs_api, 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;
|
||||
}
|
||||
@@ -77,7 +128,9 @@ bool archive_favorites_read(void* context) {
|
||||
furi_assert(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;
|
||||
FileInfo file_info;
|
||||
@@ -88,11 +141,11 @@ bool archive_favorites_read(void* context) {
|
||||
|
||||
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) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@@ -107,10 +160,10 @@ bool archive_favorites_read(void* context) {
|
||||
need_refresh = true;
|
||||
}
|
||||
} else {
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
|
||||
|
||||
bool file_exists = storage_file_open(
|
||||
fav_item_file, string_get_cstr(buffer), FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
if(file_exists) {
|
||||
storage_file_close(fav_item_file);
|
||||
archive_add_file_item(browser, &file_info, string_get_cstr(buffer));
|
||||
file_count++;
|
||||
} else {
|
||||
@@ -121,9 +174,11 @@ bool archive_favorites_read(void* context) {
|
||||
string_reset(buffer);
|
||||
}
|
||||
}
|
||||
storage_file_close(file);
|
||||
string_clear(buffer);
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
storage_file_free(file);
|
||||
storage_file_free(fav_item_file);
|
||||
furi_record_close("storage");
|
||||
|
||||
archive_set_item_count(browser, file_count);
|
||||
|
||||
@@ -143,12 +198,14 @@ bool archive_favorites_delete(const char* format, ...) {
|
||||
va_end(args);
|
||||
|
||||
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) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@@ -164,11 +221,12 @@ bool archive_favorites_delete(const char* format, ...) {
|
||||
string_clear(buffer);
|
||||
string_clear(filename);
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_file_close(file);
|
||||
storage_common_remove(fs_api, 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;
|
||||
}
|
||||
@@ -182,14 +240,15 @@ bool archive_is_favorite(const char* format, ...) {
|
||||
va_end(args);
|
||||
|
||||
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 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) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@@ -202,10 +261,11 @@ bool archive_is_favorite(const char* format, ...) {
|
||||
}
|
||||
}
|
||||
|
||||
storage_file_close(file);
|
||||
string_clear(buffer);
|
||||
string_clear(filename);
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
|
||||
return found;
|
||||
}
|
||||
@@ -214,7 +274,8 @@ bool archive_favorites_rename(const char* src, const char* dst) {
|
||||
furi_assert(src);
|
||||
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 buffer;
|
||||
@@ -223,11 +284,11 @@ bool archive_favorites_rename(const char* src, const char* dst) {
|
||||
string_init(path);
|
||||
|
||||
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) {
|
||||
while(1) {
|
||||
if(!file_worker_read_until(file_worker, buffer, '\n')) {
|
||||
if(!archive_favorites_read_line(file, buffer)) {
|
||||
break;
|
||||
}
|
||||
if(!string_size(buffer)) {
|
||||
@@ -244,11 +305,12 @@ bool archive_favorites_rename(const char* src, const char* dst) {
|
||||
string_clear(buffer);
|
||||
string_clear(path);
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_file_close(file);
|
||||
storage_common_remove(fs_api, 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;
|
||||
}
|
||||
@@ -263,15 +325,17 @@ void archive_favorites_save(void* context) {
|
||||
furi_assert(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++) {
|
||||
ArchiveFile_t* item = archive_get_file_at(browser, i);
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(item->name));
|
||||
}
|
||||
|
||||
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
|
||||
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
|
||||
storage_common_remove(fs_api, 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");
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "file_worker.h"
|
||||
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define ARCHIVE_FAV_PATH "/any/favorites.txt"
|
||||
#define ARCHIVE_FAV_TEMP_PATH "/any/favorites.tmp"
|
||||
|
||||
@@ -201,18 +201,18 @@ void archive_file_append(const char* path, const char* format, ...) {
|
||||
string_init_vprintf(string, format, 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)) {
|
||||
FURI_LOG_E(TAG, "Append open error");
|
||||
bool res = storage_file_open(file, path, FSAM_WRITE, FSOM_OPEN_APPEND);
|
||||
|
||||
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))) {
|
||||
FURI_LOG_E(TAG, "Append write error");
|
||||
}
|
||||
|
||||
file_worker_close(file_worker);
|
||||
file_worker_free(file_worker);
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
furi_record_close("storage");
|
||||
}
|
||||
|
||||
void archive_delete_file(void* context, const char* format, ...) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "file_worker.h"
|
||||
|
||||
#include <m-array.h>
|
||||
#include <m-string.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
typedef enum {
|
||||
ArchiveFileTypeIButton,
|
||||
|
||||
@@ -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);
|
||||
|
||||
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
|
||||
string_set_str(menu[1], "Unpin");
|
||||
}
|
||||
|
||||
if(!archive_is_known_app(selected->type)) {
|
||||
string_set_str(menu[0], "---");
|
||||
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++) {
|
||||
canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i]));
|
||||
string_clear(menu[i]);
|
||||
|
||||
@@ -401,6 +401,8 @@ void cli_delete_command(Cli* cli, const char* name) {
|
||||
int32_t cli_srv(void* p) {
|
||||
Cli* cli = cli_alloc();
|
||||
|
||||
furi_hal_vcp_init();
|
||||
|
||||
// Init basic cli commands
|
||||
cli_commands_init(cli);
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include <storage/storage.h>
|
||||
#include <assets_icons.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_stack.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
@@ -13,6 +16,10 @@
|
||||
#include "desktop_i.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) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = context;
|
||||
@@ -37,9 +44,19 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
|
||||
switch(event) {
|
||||
case DesktopGlobalBeforeAppStarted:
|
||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||
desktop_auto_lock_inhibit(desktop);
|
||||
return true;
|
||||
case DesktopGlobalAfterAppFinished:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -58,6 +75,63 @@ static void desktop_tick_event_callback(void* context) {
|
||||
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 = malloc(sizeof(Desktop));
|
||||
|
||||
@@ -146,9 +220,17 @@ Desktop* desktop_alloc() {
|
||||
animation_manager_is_animation_loaded(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(
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -157,8 +239,17 @@ void desktop_free(Desktop* desktop) {
|
||||
|
||||
furi_pubsub_unsubscribe(
|
||||
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->input_events_pubsub = NULL;
|
||||
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, DesktopViewIdLockMenu);
|
||||
@@ -191,6 +282,8 @@ void desktop_free(Desktop* desktop) {
|
||||
|
||||
furi_record_close("menu");
|
||||
|
||||
osTimerDelete(desktop->auto_lock_timer);
|
||||
|
||||
free(desktop);
|
||||
}
|
||||
|
||||
@@ -214,14 +307,16 @@ int32_t desktop_srv(void* p) {
|
||||
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||
if(desktop->settings.pin_code.length > 0) {
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
} else {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock) && !desktop->settings.pin_code.length) {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
||||
}
|
||||
|
||||
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||
if(!loader_is_locked(desktop->loader)) {
|
||||
desktop_auto_lock_arm(desktop);
|
||||
}
|
||||
} else {
|
||||
desktop_lock(desktop);
|
||||
}
|
||||
|
||||
if(desktop_is_first_start()) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include <loader/loader.h>
|
||||
#include <notification/notification_app.h>
|
||||
|
||||
#define STATUS_BAR_Y_SHIFT 13
|
||||
|
||||
@@ -59,10 +60,18 @@ struct Desktop {
|
||||
ViewPort* lock_viewport;
|
||||
|
||||
AnimationManager* animation_manager;
|
||||
|
||||
Loader* loader;
|
||||
NotificationApp* notification;
|
||||
|
||||
FuriPubSubSubscription* app_start_stop_subscription;
|
||||
FuriPubSub* input_events_pubsub;
|
||||
FuriPubSubSubscription* input_events_subscription;
|
||||
osTimerId_t auto_lock_timer;
|
||||
};
|
||||
|
||||
Desktop* desktop_alloc();
|
||||
|
||||
void desktop_free(Desktop* desktop);
|
||||
void desktop_lock(Desktop* desktop);
|
||||
void desktop_unlock(Desktop* desktop);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <stdbool.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_MAGIC (0x17)
|
||||
#define PIN_MAX_LENGTH 12
|
||||
@@ -39,6 +39,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
uint16_t favorite;
|
||||
PinCode pin_code;
|
||||
uint32_t auto_lock_delay_ms;
|
||||
} DesktopSettings;
|
||||
|
||||
static inline bool pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) {
|
||||
|
||||
@@ -36,12 +36,17 @@ DesktopSettingsApp* desktop_settings_app_alloc() {
|
||||
|
||||
app->popup = popup_alloc();
|
||||
app->submenu = submenu_alloc();
|
||||
app->variable_item_list = variable_item_list_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_howto2_view = desktop_settings_view_pin_setup_howto2_alloc();
|
||||
|
||||
view_dispatcher_add_view(
|
||||
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(
|
||||
app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup));
|
||||
view_dispatcher_add_view(
|
||||
@@ -63,10 +68,12 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
|
||||
furi_assert(app);
|
||||
// Variable item list
|
||||
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, DesktopSettingsAppViewIdPinInput);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2);
|
||||
variable_item_list_free(app->variable_item_list);
|
||||
submenu_free(app->submenu);
|
||||
popup_free(app->popup);
|
||||
desktop_view_pin_input_free(app->pin_input_view);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
|
||||
#include "desktop_settings.h"
|
||||
#include "desktop/views/desktop_view_pin_input.h"
|
||||
@@ -13,6 +14,7 @@
|
||||
|
||||
typedef enum {
|
||||
DesktopSettingsAppViewMenu,
|
||||
DesktopSettingsAppViewVarItemList,
|
||||
DesktopSettingsAppViewIdPopup,
|
||||
DesktopSettingsAppViewIdPinInput,
|
||||
DesktopSettingsAppViewIdPinSetupHowto,
|
||||
@@ -25,6 +27,7 @@ typedef struct {
|
||||
Gui* gui;
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
VariableItemList* variable_item_list;
|
||||
Submenu* submenu;
|
||||
Popup* popup;
|
||||
DesktopViewPinInput* pin_input_view;
|
||||
|
||||
@@ -1,35 +1,65 @@
|
||||
#include <applications.h>
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
#define SCENE_EVENT_SELECT_FAVORITE 0
|
||||
#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;
|
||||
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) {
|
||||
DesktopSettingsApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
VariableItemList* variable_item_list = app->variable_item_list;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Favorite App",
|
||||
SCENE_EVENT_SELECT_FAVORITE,
|
||||
desktop_settings_scene_start_submenu_callback,
|
||||
VariableItem* item;
|
||||
uint8_t value_index;
|
||||
|
||||
variable_item_list_add(variable_item_list, "Favorite App", 1, NULL, NULL);
|
||||
|
||||
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);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"PIN Setup",
|
||||
SCENE_EVENT_SELECT_PIN_SETUP,
|
||||
desktop_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
variable_item_list_set_enter_callback(
|
||||
variable_item_list, desktop_settings_scene_start_var_list_enter_callback, app);
|
||||
value_index = value_index_uint32(
|
||||
app->settings.auto_lock_delay_ms, auto_lock_delay_value, AUTO_LOCK_DELAY_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
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) {
|
||||
@@ -46,6 +76,9 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_SELECT_AUTO_LOCK_DELAY:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
DesktopSettingsApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
variable_item_list_reset(app->variable_item_list);
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
}
|
||||
|
||||
@@ -48,17 +48,13 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
switch(event.event) {
|
||||
case DesktopLockMenuEventLock:
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
desktop_lock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockMenuEventPinLock:
|
||||
if(desktop->settings.pin_code.length > 0) {
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
desktop_lock(desktop);
|
||||
} else {
|
||||
LoaderStatus status =
|
||||
loader_start(desktop->loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG);
|
||||
|
||||
@@ -81,13 +81,13 @@ bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DesktopLockedEventUnlocked:
|
||||
furi_hal_rtc_set_pin_fails(0);
|
||||
desktop_helpers_unlock_system(desktop);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
desktop->scene_manager, DesktopSceneMain);
|
||||
desktop_unlock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
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);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
@@ -129,16 +129,13 @@ bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) {
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopPinInputEventUnlocked:
|
||||
desktop_view_locked_unlock(desktop->locked_view);
|
||||
furi_hal_rtc_set_pin_fails(0);
|
||||
desktop_helpers_unlock_system(desktop);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
desktop->scene_manager, DesktopSceneMain);
|
||||
desktop_unlock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopPinInputEventBack:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
desktop->scene_manager, DesktopSceneLocked);
|
||||
notification_message(desktop->notification, &sequence_display_off);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -38,4 +38,5 @@ typedef enum {
|
||||
// Global events
|
||||
DesktopGlobalBeforeAppStarted,
|
||||
DesktopGlobalAfterAppFinished,
|
||||
DesktopGlobalAutoLock,
|
||||
} DesktopEvent;
|
||||
|
||||
@@ -114,14 +114,8 @@ bool desktop_debug_input(InputEvent* event, void* context) {
|
||||
DesktopViewStatsScreens current = 0;
|
||||
with_view_model(
|
||||
debug_view->view, (DesktopDebugViewModel * model) {
|
||||
#if SRV_DOLPHIN_STATE_DEBUG == 1
|
||||
if(event->key == InputKeyDown) {
|
||||
model->screen = (model->screen + 1) % DesktopViewStatsTotalCount;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
model->screen = ((model->screen - 1) + DesktopViewStatsTotalCount) %
|
||||
DesktopViewStatsTotalCount;
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef SRV_DOLPHIN_STATE_DEBUG
|
||||
if((event->key == InputKeyDown) || (event->key == InputKeyUp)) {
|
||||
model->screen = !model->screen;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "desktop_view_locked.h"
|
||||
|
||||
#define DOOR_MOVING_INTERVAL_MS (1000 / 16)
|
||||
#define LOCKED_HINT_TIMEOUT_MS (1000)
|
||||
#define UNLOCKED_HINT_TIMEOUT_MS (2000)
|
||||
|
||||
#define DOOR_OFFSET_START -55
|
||||
@@ -32,14 +33,18 @@ struct DesktopViewLocked {
|
||||
uint32_t lock_lastpress;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t hint_icon_expire_at;
|
||||
bool unlocked_hint;
|
||||
bool locked;
|
||||
bool pin_locked;
|
||||
typedef enum {
|
||||
DesktopViewLockedStateUnlocked,
|
||||
DesktopViewLockedStateLocked,
|
||||
DesktopViewLockedStateDoorsClosing,
|
||||
DesktopViewLockedStateLockedHintShown,
|
||||
DesktopViewLockedStateUnlockedHintShown
|
||||
} DesktopViewLockedState;
|
||||
|
||||
typedef struct {
|
||||
bool pin_locked;
|
||||
int8_t door_offset;
|
||||
bool doors_closing;
|
||||
DesktopViewLockedState view_state;
|
||||
} DesktopViewLockedModel;
|
||||
|
||||
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) {
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq();
|
||||
view_commit_model(locked_view->view, true);
|
||||
const bool change_state = (model->view_state == DesktopViewLockedStateLocked) &&
|
||||
!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) {
|
||||
bool stop_timer = false;
|
||||
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
if(model->locked) {
|
||||
model->doors_closing = desktop_view_locked_doors_move(model);
|
||||
stop_timer = !model->doors_closing;
|
||||
} else {
|
||||
model->unlocked_hint = false;
|
||||
stop_timer = true;
|
||||
DesktopViewLockedState view_state = model->view_state;
|
||||
|
||||
if(view_state == DesktopViewLockedStateDoorsClosing &&
|
||||
!desktop_view_locked_doors_move(model)) {
|
||||
model->view_state = DesktopViewLockedStateLocked;
|
||||
} 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);
|
||||
|
||||
if(stop_timer) {
|
||||
if(view_state != DesktopViewLockedStateDoorsClosing) {
|
||||
xTimerStop(locked_view->timer, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_view_locked_draw(Canvas* canvas, void* model) {
|
||||
DesktopViewLockedModel* m = model;
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
DesktopViewLockedState view_state = m->view_state;
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(m->locked) {
|
||||
if(m->doors_closing) {
|
||||
desktop_view_locked_doors_draw(canvas, m);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
|
||||
} else if((now < m->hint_icon_expire_at) && !m->pin_locked) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
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:");
|
||||
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_dot(canvas, 17, 61);
|
||||
}
|
||||
} else {
|
||||
if(m->unlocked_hint) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
|
||||
}
|
||||
if(view_state == DesktopViewLockedStateDoorsClosing) {
|
||||
desktop_view_locked_doors_draw(canvas, m);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
|
||||
} else if(view_state == DesktopViewLockedStateLockedHintShown) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
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:");
|
||||
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_dot(canvas, 17, 61);
|
||||
} else if(view_state == DesktopViewLockedStateUnlockedHintShown) {
|
||||
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) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
bool is_changed = false;
|
||||
const uint32_t press_time = xTaskGetTickCount();
|
||||
DesktopViewLocked* locked_view = context;
|
||||
bool locked = false;
|
||||
bool locked_with_pin = false;
|
||||
bool doors_closing = false;
|
||||
uint32_t press_time = xTaskGetTickCount();
|
||||
|
||||
{
|
||||
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);
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
if(model->view_state == DesktopViewLockedStateUnlockedHintShown &&
|
||||
event->type == InputTypePress) {
|
||||
model->view_state = DesktopViewLockedStateUnlocked;
|
||||
is_changed = true;
|
||||
}
|
||||
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)) {
|
||||
return locked;
|
||||
}
|
||||
|
||||
if(locked_with_pin) {
|
||||
if(view_state == DesktopViewLockedStateUnlocked || event->type != InputTypeShort) {
|
||||
return view_state != DesktopViewLockedStateUnlocked;
|
||||
} else if(view_state == DesktopViewLockedStateLocked && pin_locked) {
|
||||
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) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
locked_view->lock_count = 0;
|
||||
}
|
||||
|
||||
desktop_view_locked_update_hint_icon_timeout(locked_view);
|
||||
|
||||
if(event->key == InputKeyBack) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
locked_view->lock_count++;
|
||||
if(locked_view->lock_count == UNLOCK_CNT) {
|
||||
desktop_view_locked_unlock(locked_view);
|
||||
locked_view->callback(DesktopLockedEventUnlocked, locked_view->context);
|
||||
}
|
||||
} else {
|
||||
@@ -180,7 +183,7 @@ static bool desktop_view_locked_input(InputEvent* event, void* context) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
}
|
||||
|
||||
return locked;
|
||||
return true;
|
||||
}
|
||||
|
||||
DesktopViewLocked* desktop_view_locked_alloc() {
|
||||
@@ -189,7 +192,6 @@ DesktopViewLocked* desktop_view_locked_alloc() {
|
||||
locked_view->timer =
|
||||
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_set_context(locked_view->view, locked_view);
|
||||
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) {
|
||||
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;
|
||||
view_commit_model(locked_view->view, true);
|
||||
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) {
|
||||
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;
|
||||
view_commit_model(locked_view->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_locked_unlock(DesktopViewLocked* locked_view) {
|
||||
furi_assert(locked_view);
|
||||
|
||||
locked_view->lock_count = 0;
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->locked = false;
|
||||
model->view_state = DesktopViewLockedStateUnlockedHintShown;
|
||||
model->pin_locked = false;
|
||||
model->unlocked_hint = true;
|
||||
view_commit_model(locked_view->view, true);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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_unlock(DesktopViewLocked* locked_view);
|
||||
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view);
|
||||
bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view);
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
#include "scene/ibutton_scene_read_crc_error.h"
|
||||
#include "scene/ibutton_scene_read_not_key_error.h"
|
||||
#include "scene/ibutton_scene_read_success.h"
|
||||
#include "scene/ibutton_scene_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_success.h"
|
||||
#include "scene/ibutton_scene_saved_key_menu.h"
|
||||
@@ -42,7 +44,9 @@ public:
|
||||
SceneReadNotKeyError,
|
||||
SceneReadCRCError,
|
||||
SceneReadSuccess,
|
||||
SceneReadedKeyMenu,
|
||||
SceneRetryConfirm,
|
||||
SceneExitConfirm,
|
||||
SceneReadKeyMenu,
|
||||
SceneWrite,
|
||||
SceneWriteSuccess,
|
||||
SceneEmulate,
|
||||
@@ -105,7 +109,9 @@ private:
|
||||
{Scene::SceneReadCRCError, new iButtonSceneReadCRCError()},
|
||||
{Scene::SceneReadNotKeyError, new iButtonSceneReadNotKeyError()},
|
||||
{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::SceneWriteSuccess, new iButtonSceneWriteSuccess()},
|
||||
{Scene::SceneEmulate, new iButtonSceneEmulate()},
|
||||
|
||||
@@ -14,7 +14,7 @@ void iButtonSceneDeleteSuccess::on_enter(iButtonApp* app) {
|
||||
Popup* popup = view_manager->get_popup();
|
||||
|
||||
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_context(popup, app);
|
||||
|
||||
51
applications/ibutton/scene/ibutton_scene_exit_confirm.cpp
Normal file
51
applications/ibutton/scene/ibutton_scene_exit_confirm.cpp
Normal 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);
|
||||
}
|
||||
9
applications/ibutton/scene/ibutton_scene_exit_confirm.h
Normal file
9
applications/ibutton/scene/ibutton_scene_exit_confirm.h
Normal 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;
|
||||
};
|
||||
@@ -34,15 +34,22 @@ bool iButtonSceneRead::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
consumed = true;
|
||||
|
||||
iButtonKey* key = app->get_key();
|
||||
bool success = false;
|
||||
if(ibutton_key_get_type(key) == iButtonKeyDS1990) {
|
||||
if(!ibutton_key_dallas_crc_is_valid(key)) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadCRCError);
|
||||
} else if(!ibutton_key_dallas_is_1990_key(key)) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadNotKeyError);
|
||||
} else {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess);
|
||||
success = true;
|
||||
}
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
if(success) {
|
||||
app->notify_success();
|
||||
app->notify_green_on();
|
||||
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadSuccess);
|
||||
}
|
||||
} else if(event->type == iButtonEvent::Type::EventTypeTick) {
|
||||
|
||||
@@ -47,7 +47,7 @@ bool iButtonSceneReadCRCError::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
|
||||
if(event->payload.dialog_result == DialogExResultRight) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadedKeyMenu);
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
|
||||
} else {
|
||||
app->switch_to_previous_scene();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include "ibutton_scene_readed_key_menu.h"
|
||||
#include "ibutton_scene_read_key_menu.h"
|
||||
#include "../ibutton_app.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexWrite,
|
||||
SubmenuIndexEmulate,
|
||||
SubmenuIndexSave,
|
||||
SubmenuIndexReadNewKey,
|
||||
} SubmenuIndex;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void iButtonSceneReadedKeyMenu::on_enter(iButtonApp* app) {
|
||||
void iButtonSceneReadKeyMenu::on_enter(iButtonApp* app) {
|
||||
iButtonAppViewManager* view_manager = app->get_view_manager();
|
||||
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, "Emulate", SubmenuIndexEmulate, submenu_callback, app);
|
||||
submenu_add_item(submenu, "Read new key", SubmenuIndexReadNewKey, submenu_callback, app);
|
||||
submenu_set_selected_item(submenu, submenu_item_selected);
|
||||
|
||||
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;
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeMenuSelected) {
|
||||
@@ -49,20 +47,17 @@ bool iButtonSceneReadedKeyMenu::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
case SubmenuIndexSave:
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneSaveName);
|
||||
break;
|
||||
case SubmenuIndexReadNewKey:
|
||||
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneRead});
|
||||
break;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == iButtonEvent::Type::EventTypeBack) {
|
||||
app->search_and_switch_to_previous_scene({iButtonApp::Scene::SceneStart});
|
||||
app->switch_to_previous_scene();
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void iButtonSceneReadedKeyMenu::on_exit(iButtonApp* app) {
|
||||
void iButtonSceneReadKeyMenu::on_exit(iButtonApp* app) {
|
||||
iButtonAppViewManager* view = app->get_view_manager();
|
||||
Submenu* submenu = view->get_submenu();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "ibutton_scene_generic.h"
|
||||
|
||||
class iButtonSceneReadedKeyMenu : public iButtonScene {
|
||||
class iButtonSceneReadKeyMenu : public iButtonScene {
|
||||
public:
|
||||
void on_enter(iButtonApp* app) final;
|
||||
bool on_event(iButtonApp* app, iButtonEvent* event) final;
|
||||
@@ -47,7 +47,7 @@ bool iButtonSceneReadNotKeyError::on_event(iButtonApp* app, iButtonEvent* event)
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeDialogResult) {
|
||||
if(event->payload.dialog_result == DialogExResultRight) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadedKeyMenu);
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
|
||||
} else {
|
||||
app->switch_to_previous_scene();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ void iButtonSceneReadSuccess::on_enter(iButtonApp* app) {
|
||||
DialogEx* dialog_ex = view_manager->get_dialog_ex();
|
||||
iButtonKey* key = app->get_key();
|
||||
const uint8_t* key_data = ibutton_key_get_data_p(key);
|
||||
DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess);
|
||||
|
||||
switch(ibutton_key_get_type(key)) {
|
||||
case iButtonKeyDS1990:
|
||||
@@ -50,9 +49,6 @@ void iButtonSceneReadSuccess::on_enter(iButtonApp* app) {
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
|
||||
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewDialogEx);
|
||||
|
||||
app->notify_success();
|
||||
app->notify_green_on();
|
||||
}
|
||||
|
||||
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->payload.dialog_result == DialogExResultRight) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadedKeyMenu);
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneReadKeyMenu);
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
||||
51
applications/ibutton/scene/ibutton_scene_retry_confirm.cpp
Normal file
51
applications/ibutton/scene/ibutton_scene_retry_confirm.cpp
Normal 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);
|
||||
}
|
||||
9
applications/ibutton/scene/ibutton_scene_retry_confirm.h
Normal file
9
applications/ibutton/scene/ibutton_scene_retry_confirm.h
Normal 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;
|
||||
};
|
||||
@@ -49,7 +49,7 @@ bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
app->switch_to_next_scene(iButtonApp::Scene::SceneSaveSuccess);
|
||||
} else {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{iButtonApp::Scene::SceneReadedKeyMenu,
|
||||
{iButtonApp::Scene::SceneReadKeyMenu,
|
||||
iButtonApp::Scene::SceneSavedKeyMenu,
|
||||
iButtonApp::Scene::SceneAddType});
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ void iButtonSceneSaveSuccess::on_enter(iButtonApp* app) {
|
||||
DOLPHIN_DEED(DolphinDeedIbuttonSave);
|
||||
|
||||
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_context(popup, app);
|
||||
@@ -31,7 +31,7 @@ bool iButtonSceneSaveSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeBack) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{iButtonApp::Scene::SceneReadedKeyMenu,
|
||||
{iButtonApp::Scene::SceneReadKeyMenu,
|
||||
iButtonApp::Scene::SceneSavedKeyMenu,
|
||||
iButtonApp::Scene::SceneAddType});
|
||||
consumed = true;
|
||||
|
||||
@@ -33,7 +33,7 @@ bool iButtonSceneWriteSuccess::on_event(iButtonApp* app, iButtonEvent* event) {
|
||||
|
||||
if(event->type == iButtonEvent::Type::EventTypeBack) {
|
||||
app->search_and_switch_to_previous_scene(
|
||||
{iButtonApp::Scene::SceneReadedKeyMenu, iButtonApp::Scene::SceneStart});
|
||||
{iButtonApp::Scene::SceneReadKeyMenu, iButtonApp::Scene::SceneStart});
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ void InfraredAppSceneEditRenameDone::on_enter(InfraredApp* app) {
|
||||
Popup* popup = view_manager->get_popup();
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
|
||||
popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
|
||||
|
||||
popup_set_callback(popup, InfraredApp::popup_callback);
|
||||
|
||||
@@ -15,7 +15,7 @@ constexpr uint32_t long_time_high = long_time + jitter_time;
|
||||
|
||||
void DecoderEMMarin::reset_state() {
|
||||
ready = false;
|
||||
readed_data = 0;
|
||||
read_data = 0;
|
||||
manchester_advance(
|
||||
manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr);
|
||||
}
|
||||
@@ -26,7 +26,7 @@ bool DecoderEMMarin::read(uint8_t* data, uint8_t data_size) {
|
||||
if(ready) {
|
||||
result = true;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -59,10 +59,10 @@ void DecoderEMMarin::process_front(bool polarity, uint32_t time) {
|
||||
manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data);
|
||||
|
||||
if(data_ok) {
|
||||
readed_data = (readed_data << 1) | data;
|
||||
read_data = (read_data << 1) | data;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
private:
|
||||
void reset_state();
|
||||
|
||||
uint64_t readed_data = 0;
|
||||
uint64_t read_data = 0;
|
||||
std::atomic<bool> ready;
|
||||
|
||||
ManchesterState manchester_saved_state;
|
||||
|
||||
@@ -78,7 +78,7 @@ void RfidReader::start() {
|
||||
start_comparator();
|
||||
|
||||
switch_timer_reset();
|
||||
last_readed_count = 0;
|
||||
last_read_count = 0;
|
||||
}
|
||||
|
||||
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 result = false;
|
||||
bool something_readed = false;
|
||||
bool something_read = false;
|
||||
|
||||
// reading
|
||||
if(decoder_em.read(data, data_size)) {
|
||||
*_type = LfrfidKeyType::KeyEM4100;
|
||||
something_readed = true;
|
||||
something_read = true;
|
||||
}
|
||||
|
||||
if(decoder_hid26.read(data, data_size)) {
|
||||
*_type = LfrfidKeyType::KeyH10301;
|
||||
something_readed = true;
|
||||
something_read = true;
|
||||
}
|
||||
|
||||
if(decoder_indala.read(data, data_size)) {
|
||||
*_type = LfrfidKeyType::KeyI40134;
|
||||
something_readed = true;
|
||||
something_read = true;
|
||||
}
|
||||
|
||||
// validation
|
||||
if(something_readed) {
|
||||
if(something_read) {
|
||||
switch_timer_reset();
|
||||
|
||||
if(last_readed_type == *_type && memcmp(last_readed_data, data, data_size) == 0) {
|
||||
last_readed_count = last_readed_count + 1;
|
||||
if(last_read_type == *_type && memcmp(last_read_data, data, data_size) == 0) {
|
||||
last_read_count = last_read_count + 1;
|
||||
|
||||
if(last_readed_count > 2) {
|
||||
if(last_read_count > 2) {
|
||||
result = true;
|
||||
}
|
||||
} else {
|
||||
last_readed_type = *_type;
|
||||
memcpy(last_readed_data, data, data_size);
|
||||
last_readed_count = 0;
|
||||
last_read_type = *_type;
|
||||
memcpy(last_read_data, data, data_size);
|
||||
last_read_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// mode switching
|
||||
if(switch_enable && switch_timer_elapsed()) {
|
||||
switch_mode();
|
||||
last_readed_count = 0;
|
||||
last_read_count = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -152,7 +152,7 @@ bool RfidReader::detect() {
|
||||
}
|
||||
|
||||
bool RfidReader::any_read() {
|
||||
return last_readed_count > 0;
|
||||
return last_read_count > 0;
|
||||
}
|
||||
|
||||
void RfidReader::start_comparator(void) {
|
||||
|
||||
@@ -49,9 +49,9 @@ private:
|
||||
void switch_timer_reset();
|
||||
void switch_mode();
|
||||
|
||||
LfrfidKeyType last_readed_type;
|
||||
uint8_t last_readed_data[LFRFID_KEY_SIZE];
|
||||
uint8_t last_readed_count;
|
||||
LfrfidKeyType last_read_type;
|
||||
uint8_t last_read_data[LFRFID_KEY_SIZE];
|
||||
uint8_t last_read_count;
|
||||
|
||||
Type type = Type::Normal;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#include "scene/lfrfid_app_scene_start.h"
|
||||
#include "scene/lfrfid_app_scene_read.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_success.h"
|
||||
#include "scene/lfrfid_app_scene_emulate.h"
|
||||
@@ -48,8 +50,10 @@ void LfRfidApp::run(void* _args) {
|
||||
} else {
|
||||
scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart());
|
||||
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::ReadedMenu, new LfRfidAppSceneReadedMenu());
|
||||
scene_controller.add_scene(SceneType::ReadKeyMenu, new LfRfidAppSceneReadKeyMenu());
|
||||
scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite());
|
||||
scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess());
|
||||
scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());
|
||||
|
||||
@@ -27,13 +27,17 @@ public:
|
||||
GENERIC_EVENT_ENUM_VALUES,
|
||||
Next,
|
||||
MenuSelected,
|
||||
Stay,
|
||||
Retry,
|
||||
};
|
||||
|
||||
enum class SceneType : uint8_t {
|
||||
GENERIC_SCENE_ENUM_VALUES,
|
||||
Read,
|
||||
ReadSuccess,
|
||||
ReadedMenu,
|
||||
RetryConfirm,
|
||||
ExitConfirm,
|
||||
ReadKeyMenu,
|
||||
Write,
|
||||
WriteSuccess,
|
||||
Emulate,
|
||||
|
||||
@@ -73,6 +73,11 @@ bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* eve
|
||||
app->delete_key(&app->worker.key);
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess);
|
||||
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;
|
||||
@@ -88,7 +93,7 @@ void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) {
|
||||
void LfRfidAppSceneDeleteConfirm::back_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Back;
|
||||
event.type = LfRfidApp::EventType::Stay;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ void LfRfidAppSceneDeleteSuccess::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
auto popup = app->view_controller.get<PopupVM>();
|
||||
|
||||
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_callback(LfRfidAppSceneDeleteSuccess::timeout_callback);
|
||||
popup->set_timeout(1500);
|
||||
|
||||
59
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp
Normal file
59
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp
Normal 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);
|
||||
}
|
||||
13
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h
Normal file
13
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h
Normal 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);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "lfrfid_app_scene_readed_menu.h"
|
||||
#include "lfrfid_app_scene_read_menu.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuWrite,
|
||||
@@ -6,7 +6,7 @@ typedef enum {
|
||||
SubmenuEmulate,
|
||||
} 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>();
|
||||
|
||||
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>();
|
||||
}
|
||||
|
||||
bool LfRfidAppSceneReadedMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool LfRfidAppSceneReadKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfRfidApp::EventType::MenuSelected) {
|
||||
@@ -38,18 +38,18 @@ bool LfRfidAppSceneReadedMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event)
|
||||
}
|
||||
consumed = true;
|
||||
} 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;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidAppSceneReadedMenu::on_exit(LfRfidApp* app) {
|
||||
void LfRfidAppSceneReadKeyMenu::on_exit(LfRfidApp* app) {
|
||||
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::Event event;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "../lfrfid_app.h"
|
||||
|
||||
class LfRfidAppSceneReadedMenu : public GenericScene<LfRfidApp> {
|
||||
class LfRfidAppSceneReadKeyMenu : public GenericScene<LfRfidApp> {
|
||||
public:
|
||||
void on_enter(LfRfidApp* app, bool need_restore) final;
|
||||
bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
|
||||
@@ -85,7 +85,13 @@ bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event
|
||||
bool consumed = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -103,7 +109,7 @@ void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) {
|
||||
void LfRfidAppSceneReadSuccess::back_callback(void* context) {
|
||||
LfRfidApp* app = static_cast<LfRfidApp*>(context);
|
||||
LfRfidApp::Event event;
|
||||
event.type = LfRfidApp::EventType::Back;
|
||||
event.type = LfRfidApp::EventType::Retry;
|
||||
app->view_controller.send_event(&event);
|
||||
}
|
||||
|
||||
|
||||
59
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp
Normal file
59
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp
Normal 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);
|
||||
}
|
||||
13
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h
Normal file
13
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h
Normal 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);
|
||||
};
|
||||
@@ -42,7 +42,7 @@ bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess);
|
||||
} else {
|
||||
app->scene_controller.search_and_switch_to_previous_scene(
|
||||
{LfRfidApp::SceneType::ReadedMenu});
|
||||
{LfRfidApp::SceneType::ReadKeyMenu});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ void LfRfidAppSceneSaveSuccess::on_enter(LfRfidApp* app, bool need_restore) {
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedRfidSave);
|
||||
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_callback(LfRfidAppSceneSaveSuccess::timeout_callback);
|
||||
popup->set_timeout(1500);
|
||||
@@ -22,11 +22,11 @@ bool LfRfidAppSceneSaveSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Back) {
|
||||
bool result = app->scene_controller.has_previous_scene(
|
||||
{LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey});
|
||||
{LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
|
||||
|
||||
if(result) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene(
|
||||
{LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey});
|
||||
{LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
|
||||
} else {
|
||||
app->scene_controller.search_and_switch_to_another_scene(
|
||||
{LfRfidApp::SceneType::SaveType}, LfRfidApp::SceneType::SelectKey);
|
||||
|
||||
@@ -18,7 +18,7 @@ bool LfRfidAppSceneWriteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* even
|
||||
|
||||
if(event->type == LfRfidApp::EventType::Back) {
|
||||
app->scene_controller.search_and_switch_to_previous_scene(
|
||||
{LfRfidApp::SceneType::ReadedMenu, LfRfidApp::SceneType::SelectKey});
|
||||
{LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <storage/storage.h>
|
||||
#include <input/input.h>
|
||||
#include "notification.h"
|
||||
#include "notification_messages.h"
|
||||
#include "notification_app.h"
|
||||
@@ -163,7 +164,6 @@ void notification_process_notification_message(
|
||||
notification_message = (*message->sequence)[notification_message_index];
|
||||
|
||||
bool led_active = false;
|
||||
uint8_t display_led_lock = 0;
|
||||
uint8_t led_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00};
|
||||
bool reset_notifications = true;
|
||||
float speaker_volume_setting = app->settings.speaker_volume;
|
||||
@@ -191,18 +191,18 @@ void notification_process_notification_message(
|
||||
reset_mask |= reset_display_mask;
|
||||
break;
|
||||
case NotificationMessageTypeLedDisplayLock:
|
||||
furi_assert(display_led_lock < UINT8_MAX);
|
||||
display_led_lock++;
|
||||
if(display_led_lock == 1) {
|
||||
furi_assert(app->display_led_lock < UINT8_MAX);
|
||||
app->display_led_lock++;
|
||||
if(app->display_led_lock == 1) {
|
||||
notification_apply_internal_led_layer(
|
||||
&app->display,
|
||||
notification_message->data.led.value * display_brightness_setting);
|
||||
}
|
||||
break;
|
||||
case NotificationMessageTypeLedDisplayUnlock:
|
||||
furi_assert(display_led_lock > 0);
|
||||
display_led_lock--;
|
||||
if(display_led_lock == 0) {
|
||||
furi_assert(app->display_led_lock > 0);
|
||||
app->display_led_lock--;
|
||||
if(app->display_led_lock == 0) {
|
||||
notification_apply_internal_led_layer(
|
||||
&app->display,
|
||||
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) {
|
||||
furi_assert(value);
|
||||
furi_assert(context);
|
||||
const InputEvent* event = value;
|
||||
NotificationApp* app = context;
|
||||
notification_message(app, &sequence_display_on);
|
||||
if(event->type == InputTypePress) {
|
||||
notification_message(app, &sequence_display_on);
|
||||
}
|
||||
}
|
||||
|
||||
// App alloc
|
||||
|
||||
@@ -49,6 +49,7 @@ struct NotificationApp {
|
||||
|
||||
NotificationLedLayer display;
|
||||
NotificationLedLayer led[NOTIFICATION_LED_COUNT];
|
||||
uint8_t display_led_lock;
|
||||
|
||||
NotificationSettings settings;
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ const NotificationMessage message_display_lock = {
|
||||
};
|
||||
|
||||
const NotificationMessage message_display_unlock = {
|
||||
.type = NotificationMessageTypeLedDisplayLock,
|
||||
.type = NotificationMessageTypeLedDisplayUnlock,
|
||||
.data.led.value = 0x00,
|
||||
};
|
||||
|
||||
@@ -208,6 +208,12 @@ const NotificationSequence sequence_display_unlock = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
const NotificationSequence sequence_display_off_delay_1000 = {
|
||||
&message_delay_1000,
|
||||
&message_display_off,
|
||||
NULL,
|
||||
};
|
||||
|
||||
// Charging
|
||||
const NotificationSequence sequence_charging = {
|
||||
&message_red_255,
|
||||
|
||||
@@ -78,6 +78,8 @@ extern const NotificationSequence sequence_display_off;
|
||||
extern const NotificationSequence sequence_display_lock;
|
||||
/** Display: backlight always on 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
|
||||
extern const NotificationSequence sequence_charging;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "notification_app.h"
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
#define MAX_NOTIFICATION_SETTINGS 4
|
||||
|
||||
@@ -63,44 +64,6 @@ const char* const vibro_text[VIBRO_COUNT] = {
|
||||
};
|
||||
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) {
|
||||
NotificationAppSettings* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
@@ -164,21 +127,21 @@ static NotificationAppSettings* alloc_settings() {
|
||||
|
||||
item = variable_item_list_add(
|
||||
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);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, backlight_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
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);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, delay_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
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);
|
||||
variable_item_set_current_value_index(item, 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(
|
||||
app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app);
|
||||
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_text(item, volume_text[value_index]);
|
||||
|
||||
item =
|
||||
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_text(item, vibro_text[value_index]);
|
||||
|
||||
|
||||
@@ -473,17 +473,17 @@ static void rpc_system_storage_md5sum_process(const PB_Main* request, void* cont
|
||||
File* file = storage_file_alloc(fs_api);
|
||||
|
||||
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;
|
||||
uint8_t* data = malloc(read_size);
|
||||
uint8_t* data = malloc(size_to_read);
|
||||
uint8_t* hash = malloc(sizeof(uint8_t) * hash_size);
|
||||
md5_context* md5_ctx = malloc(sizeof(md5_context));
|
||||
|
||||
md5_starts(md5_ctx);
|
||||
while(true) {
|
||||
uint16_t readed_size = storage_file_read(file, data, read_size);
|
||||
if(readed_size == 0) break;
|
||||
md5_update(md5_ctx, data, readed_size);
|
||||
uint16_t read_size = storage_file_read(file, data, size_to_read);
|
||||
if(read_size == 0) break;
|
||||
md5_update(md5_ctx, data, read_size);
|
||||
}
|
||||
md5_finish(md5_ctx, hash);
|
||||
free(md5_ctx);
|
||||
|
||||
@@ -33,14 +33,14 @@ struct File {
|
||||
* @param file pointer to file object
|
||||
* @param buff pointer to buffer for reading
|
||||
* @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
|
||||
* @brief Write bytes from buffer to file
|
||||
* @param file pointer to file object
|
||||
* @param buff pointer to buffer for writing
|
||||
* @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
|
||||
* @brief Move r/w pointer
|
||||
@@ -107,7 +107,7 @@ typedef struct {
|
||||
* @var FS_Dir_Api::read
|
||||
* @brief Read next object info in directory
|
||||
* @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_length name buffer length
|
||||
* @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
|
||||
* @brief Open directory to get objects from
|
||||
* @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_length name buffer length
|
||||
* @return FS_Error error info
|
||||
|
||||
@@ -76,7 +76,7 @@ bool storage_file_is_dir(File* file);
|
||||
* @param file pointer to file object.
|
||||
* @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.
|
||||
* @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);
|
||||
|
||||
@@ -144,7 +144,7 @@ bool storage_dir_close(File* file);
|
||||
|
||||
/** Reads the next object in the directory
|
||||
* @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_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)
|
||||
@@ -162,7 +162,7 @@ bool storage_dir_rewind(File* file);
|
||||
/** Retrieves information about a file/directory
|
||||
* @param app pointer to the api
|
||||
* @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
|
||||
*/
|
||||
FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo);
|
||||
|
||||
@@ -112,10 +112,10 @@ static void storage_cli_list(Cli* cli, string_t path) {
|
||||
if(storage_dir_open(file, string_get_cstr(path))) {
|
||||
FileInfo fileinfo;
|
||||
char name[MAX_NAME_LENGTH];
|
||||
bool readed = false;
|
||||
bool read_done = false;
|
||||
|
||||
while(storage_dir_read(file, &fileinfo, name, MAX_NAME_LENGTH)) {
|
||||
readed = true;
|
||||
read_done = true;
|
||||
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||
printf("\t[D] %s\r\n", name);
|
||||
} else {
|
||||
@@ -123,7 +123,7 @@ static void storage_cli_list(Cli* cli, string_t path) {
|
||||
}
|
||||
}
|
||||
|
||||
if(!readed) {
|
||||
if(!read_done) {
|
||||
printf("\tEmpty\r\n");
|
||||
}
|
||||
} else {
|
||||
@@ -141,18 +141,18 @@ static void storage_cli_read(Cli* cli, string_t path) {
|
||||
File* file = storage_file_alloc(api);
|
||||
|
||||
if(storage_file_open(file, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
const uint16_t read_size = 128;
|
||||
uint16_t readed_size = 0;
|
||||
const uint16_t size_to_read = 128;
|
||||
uint16_t read_size = 0;
|
||||
uint8_t* data = malloc(read_size);
|
||||
|
||||
printf("Size: %lu\r\n", (uint32_t)storage_file_size(file));
|
||||
|
||||
do {
|
||||
readed_size = storage_file_read(file, data, read_size);
|
||||
for(uint16_t i = 0; i < readed_size; i++) {
|
||||
read_size = storage_file_read(file, data, size_to_read);
|
||||
for(uint16_t i = 0; i < read_size; i++) {
|
||||
printf("%c", data[i]);
|
||||
}
|
||||
} while(readed_size > 0);
|
||||
} while(read_size > 0);
|
||||
printf("\r\n");
|
||||
|
||||
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)) {
|
||||
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) {
|
||||
uint8_t symbol = cli_getc(cli);
|
||||
|
||||
if(symbol == CliSymbolAsciiETX) {
|
||||
uint16_t write_size = readed_index % buffer_size;
|
||||
uint16_t write_size = read_index % buffer_size;
|
||||
|
||||
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));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buffer[readed_index % buffer_size] = symbol;
|
||||
printf("%c", buffer[readed_index % buffer_size]);
|
||||
buffer[read_index % buffer_size] = symbol;
|
||||
printf("%c", buffer[read_index % buffer_size]);
|
||||
fflush(stdout);
|
||||
readed_index++;
|
||||
read_index++;
|
||||
|
||||
if(((readed_index % buffer_size) == 0)) {
|
||||
uint16_t writed_size = storage_file_write(file, buffer, buffer_size);
|
||||
if(((read_index % buffer_size) == 0)) {
|
||||
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));
|
||||
break;
|
||||
}
|
||||
@@ -239,11 +239,11 @@ static void storage_cli_read_chunks(Cli* cli, string_t path, string_t args) {
|
||||
printf("\r\nReady?\r\n");
|
||||
cli_getc(cli);
|
||||
|
||||
uint16_t readed_size = storage_file_read(file, data, buffer_size);
|
||||
for(uint16_t i = 0; i < readed_size; i++) {
|
||||
uint16_t read_size = storage_file_read(file, data, buffer_size);
|
||||
for(uint16_t i = 0; i < read_size; i++) {
|
||||
putchar(data[i]);
|
||||
}
|
||||
file_size -= readed_size;
|
||||
file_size -= read_size;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -400,17 +400,17 @@ static void storage_cli_md5(Cli* cli, string_t path) {
|
||||
File* file = storage_file_alloc(api);
|
||||
|
||||
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;
|
||||
uint8_t* data = malloc(read_size);
|
||||
uint8_t* data = malloc(size_to_read);
|
||||
uint8_t* hash = malloc(sizeof(uint8_t) * hash_size);
|
||||
md5_context* md5_ctx = malloc(sizeof(md5_context));
|
||||
|
||||
md5_starts(md5_ctx);
|
||||
while(true) {
|
||||
uint16_t readed_size = storage_file_read(file, data, read_size);
|
||||
if(readed_size == 0) break;
|
||||
md5_update(md5_ctx, data, readed_size);
|
||||
uint16_t read_size = storage_file_read(file, data, size_to_read);
|
||||
if(read_size == 0) break;
|
||||
md5_update(md5_ctx, data, read_size);
|
||||
}
|
||||
md5_finish(md5_ctx, hash);
|
||||
free(md5_ctx);
|
||||
|
||||
@@ -340,10 +340,10 @@ static uint16_t
|
||||
storage_ext_file_read(void* ctx, File* file, void* buff, uint16_t const bytes_to_read) {
|
||||
StorageData* storage = ctx;
|
||||
SDFile* file_data = storage_get_storage_file_data(file, storage);
|
||||
uint16_t bytes_readed = 0;
|
||||
file->internal_error_id = f_read(file_data, buff, bytes_to_read, &bytes_readed);
|
||||
uint16_t bytes_read = 0;
|
||||
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);
|
||||
return bytes_readed;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
|
||||
@@ -349,7 +349,7 @@ static uint16_t
|
||||
lfs_t* lfs = lfs_get_from_storage(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)) {
|
||||
file->internal_error_id =
|
||||
@@ -361,10 +361,10 @@ static uint16_t
|
||||
file->error_id = storage_int_parse_error(file->internal_error_id);
|
||||
|
||||
if(file->error_id == FSE_OK) {
|
||||
bytes_readed = file->internal_error_id;
|
||||
bytes_read = file->internal_error_id;
|
||||
file->internal_error_id = 0;
|
||||
}
|
||||
return bytes_readed;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
|
||||
@@ -29,6 +29,7 @@ struct SubGhzFrequencyAnalyzerWorker {
|
||||
volatile bool worker_running;
|
||||
uint8_t count_repet;
|
||||
FrequencyRSSI frequency_rssi_buf;
|
||||
SubGhzSetting* setting;
|
||||
|
||||
float filVal;
|
||||
|
||||
@@ -77,10 +78,12 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
|
||||
frequency_rssi.rssi = -127.0f;
|
||||
furi_hal_subghz_idle();
|
||||
furi_hal_subghz_load_registers(subghz_preset_ook_650khz);
|
||||
for(size_t i = 0; i < subghz_frequencies_count; i++) {
|
||||
if(furi_hal_subghz_is_frequency_valid(subghz_frequencies[i])) {
|
||||
for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) {
|
||||
if(furi_hal_subghz_is_frequency_valid(
|
||||
subghz_setting_get_frequency(instance->setting, i))) {
|
||||
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();
|
||||
osDelay(3);
|
||||
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_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;
|
||||
}
|
||||
|
||||
@@ -157,7 +162,7 @@ void subghz_frequency_analyzer_worker_free(SubGhzFrequencyAnalyzerWorker* instan
|
||||
furi_assert(instance);
|
||||
|
||||
furi_thread_free(instance->thread);
|
||||
|
||||
subghz_setting_free(instance->setting);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||
} else {
|
||||
//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;
|
||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneSaved)) {
|
||||
|
||||
@@ -120,7 +120,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
||||
subghz_sleep(subghz);
|
||||
};
|
||||
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->idx_menu_chosen = 0;
|
||||
subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
|
||||
|
||||
@@ -40,6 +40,21 @@ uint8_t subghz_scene_receiver_config_uint32_value_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(
|
||||
const uint32_t value,
|
||||
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);
|
||||
|
||||
if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) {
|
||||
variable_item_set_current_value_text(item, subghz_frequencies_text[index]);
|
||||
subghz->txrx->frequency = subghz_frequencies[index];
|
||||
char text_buf[10] = {0};
|
||||
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 {
|
||||
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]);
|
||||
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(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
subghz_frequencies_text[subghz_frequencies_433_92]);
|
||||
subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
|
||||
text_buf);
|
||||
subghz->txrx->frequency = subghz_setting_get_frequency(
|
||||
subghz->setting, subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
variable_item_set_current_value_index(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
subghz_frequencies_433_92);
|
||||
subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
} else {
|
||||
variable_item_set_current_value_text(
|
||||
(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(
|
||||
(VariableItem*)scene_manager_get_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||
subghz_frequencies_433_92);
|
||||
subghz_setting_get_frequency_default_index(subghz->setting));
|
||||
}
|
||||
|
||||
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(
|
||||
subghz->variable_item_list,
|
||||
"Frequency:",
|
||||
subghz_frequencies_count,
|
||||
subghz_setting_get_frequency_count(subghz->setting),
|
||||
subghz_scene_receiver_config_set_frequency,
|
||||
subghz);
|
||||
value_index = subghz_scene_receiver_config_uint32_value_index(
|
||||
subghz->txrx->frequency, subghz_frequencies, subghz_frequencies_count);
|
||||
value_index = subghz_scene_receiver_config_next_frequency(subghz->txrx->frequency, subghz);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
|
||||
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) !=
|
||||
SubGhzCustomEventManagerSet) {
|
||||
|
||||
@@ -46,7 +46,7 @@ bool subghz_scene_set_type_submenu_gen_data_protocol(
|
||||
if(!subghz_protocol_decoder_base_serialize(
|
||||
subghz->txrx->decoder_result,
|
||||
subghz->txrx->fff_data,
|
||||
subghz_frequencies[subghz_frequencies_433_92],
|
||||
subghz_setting_get_frequency_default_index(subghz->setting),
|
||||
FuriHalSubGhzPresetOok650Async)) {
|
||||
FURI_LOG_E(TAG, "Unable to serialize");
|
||||
break;
|
||||
@@ -213,7 +213,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
0x2,
|
||||
0x0003,
|
||||
"DoorHan",
|
||||
subghz_frequencies[subghz_frequencies_433_92],
|
||||
subghz_setting_get_frequency_default_index(subghz->setting),
|
||||
FuriHalSubGhzPresetOok650Async);
|
||||
generated_protocol = true;
|
||||
} else {
|
||||
@@ -237,7 +237,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||
0x2,
|
||||
0x0003,
|
||||
"DoorHan",
|
||||
subghz_frequencies[subghz_frequencies_315_00],
|
||||
315000000,
|
||||
FuriHalSubGhzPresetOok650Async);
|
||||
generated_protocol = true;
|
||||
} else {
|
||||
|
||||
@@ -3,68 +3,6 @@
|
||||
#include "subghz_i.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) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
@@ -186,9 +124,14 @@ SubGhz* subghz_alloc() {
|
||||
SubGhzViewIdStatic,
|
||||
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
|
||||
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->txrx_state = SubGhzTxRxStateSleep;
|
||||
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
||||
@@ -281,6 +224,9 @@ void subghz_free(SubGhz* subghz) {
|
||||
furi_record_close("gui");
|
||||
subghz->gui = NULL;
|
||||
|
||||
//setting
|
||||
subghz_setting_free(subghz->setting);
|
||||
|
||||
//Worker & Protocol & History
|
||||
subghz_receiver_free(subghz->txrx->receiver);
|
||||
subghz_environment_free(subghz->txrx->environment);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/transmitter.h>
|
||||
#include <lib/subghz/subghz_file_encoder_worker.h>
|
||||
|
||||
#include "helpers/subghz_chat.h"
|
||||
|
||||
@@ -294,6 +295,110 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
|
||||
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() {
|
||||
printf("Usage:\r\n");
|
||||
printf("subghz <cmd> <args>\r\n");
|
||||
@@ -303,6 +408,7 @@ static void subghz_cli_command_print_usage() {
|
||||
printf(
|
||||
"\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("\tdecode_raw <file_name: path_RAW_file>\t - Testing\r\n");
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
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);
|
||||
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(string_cmp_str(cmd, "encrypt_keeloq") == 0) {
|
||||
subghz_cli_command_encrypt_keeloq(cli, args);
|
||||
|
||||
@@ -514,9 +514,9 @@ void subghz_hopper_update(SubGhz* subghz) {
|
||||
} else {
|
||||
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
|
||||
}
|
||||
|
||||
// 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++;
|
||||
} else {
|
||||
subghz->txrx->hopper_idx_frequency = 0;
|
||||
@@ -527,7 +527,8 @@ void subghz_hopper_update(SubGhz* subghz) {
|
||||
};
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,18 +31,11 @@
|
||||
#include <lib/subghz/transmitter.h>
|
||||
|
||||
#include "subghz_history.h"
|
||||
#include "subghz_setting.h"
|
||||
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
|
||||
#define SUBGHZ_MAX_LEN_NAME 21
|
||||
|
||||
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;
|
||||
#define SUBGHZ_MAX_LEN_NAME 40
|
||||
|
||||
/** SubGhzNotification state */
|
||||
typedef enum {
|
||||
@@ -145,6 +138,7 @@ struct SubGhz {
|
||||
SubGhzTestCarrier* subghz_test_carrier;
|
||||
SubGhzTestPacket* subghz_test_packet;
|
||||
string_t error_str;
|
||||
SubGhzSetting* setting;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
||||
361
applications/subghz/subghz_setting.c
Normal file
361
applications/subghz/subghz_setting.c
Normal 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;
|
||||
}
|
||||
17
applications/subghz/subghz_setting.h
Normal file
17
applications/subghz/subghz_setting.h
Normal 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);
|
||||
@@ -1,19 +1,6 @@
|
||||
#include "system_settings.h"
|
||||
#include <loader/loader.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;
|
||||
}
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
const char* const log_level_text[] = {
|
||||
"Default",
|
||||
@@ -80,7 +67,7 @@ SystemSettings* system_settings_alloc() {
|
||||
|
||||
item = variable_item_list_add(
|
||||
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));
|
||||
variable_item_set_current_value_index(item, 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
Reference in New Issue
Block a user