[FL-2045] SubGhz: new protocol (GSN , Beninca/Allmatic, Elmes) and validator (#958)

* SubGhz: add new method of obtaining a manufactory code subghz_protocol_keeloq_common_magic_xor_type1_learning
* TextInput: checking for a lock on a file with the same name
* TextInput:  fix checking for a lock on a file with the same name
* Assets: rename and recompile
* TextInput: added picture and timer to turn off blob
* TextInput: Fix graphics
* TextInput:  fix validator
* Validators: Add validator is file
* TextInput: fix callback validator_is_file_alloc
* SubGhz: add propocol GNS (dimamic), Beninca/Alcatic,  Elmes
* SubGhz: fix function description
* Gui: correct timer routine on deallocation
* Format sources

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Skorpionm
2022-01-21 17:55:09 +04:00
committed by GitHub
parent 32c92a80ea
commit d4d87aa6a8
15 changed files with 300 additions and 46 deletions

View File

@@ -4,6 +4,7 @@
struct TextInput {
View* view;
osTimerId_t timer;
};
typedef struct {
@@ -23,6 +24,11 @@ typedef struct {
uint8_t selected_row;
uint8_t selected_column;
TextInputValidatorCallback validator_callback;
void* validator_callback_context;
string_t validator_text;
bool valadator_message_visible;
} TextInputModel;
static const uint8_t keyboard_origin_x = 1;
@@ -236,6 +242,17 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) {
}
}
}
if(model->valadator_message_visible) {
canvas_set_font(canvas, FontSecondary);
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 8, 10, 110, 48);
canvas_set_color(canvas, ColorBlack);
canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42);
canvas_draw_rframe(canvas, 8, 8, 112, 50, 3);
canvas_draw_rframe(canvas, 9, 9, 110, 48, 2);
elements_multiline_text(canvas, 62, 20, string_get_cstr(model->validator_text));
canvas_set_font(canvas, FontKeyboard);
}
}
static void text_input_handle_up(TextInput* text_input) {
@@ -295,7 +312,13 @@ static void text_input_handle_ok(TextInput* text_input) {
uint8_t text_length = strlen(model->text_buffer);
if(selected == ENTER_KEY) {
if(model->callback != 0 && text_length > 0) {
if(model->validator_callback && (!model->validator_callback(
model->text_buffer,
model->validator_text,
model->validator_callback_context))) {
model->valadator_message_visible = true;
osTimerStart(text_input->timer, osKernelGetTickFreq() * 4);
} else if(model->callback != 0 && text_length > 0) {
model->callback(model->callback_context);
}
} else if(selected == BACKSPACE_KEY) {
@@ -321,6 +344,16 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) {
bool consumed = false;
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
with_view_model(
text_input->view, (TextInputModel * model) {
if(model->valadator_message_visible) {
if(event->key == InputKeyBack) {
consumed = true;
}
}
model->valadator_message_visible = false;
return false;
});
switch(event->key) {
case InputKeyUp:
text_input_handle_up(text_input);
@@ -351,7 +384,11 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) {
event->key == InputKeyBack) {
with_view_model(
text_input->view, (TextInputModel * model) {
text_input_backspace_cb(model);
if(model->valadator_message_visible) {
model->valadator_message_visible = false;
} else {
text_input_backspace_cb(model);
}
return true;
});
@@ -361,6 +398,17 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) {
return consumed;
}
void text_input_timer_callback(void* context) {
furi_assert(context);
TextInput* text_input = context;
with_view_model(
text_input->view, (TextInputModel * model) {
model->valadator_message_visible = false;
return true;
});
}
TextInput* text_input_alloc() {
TextInput* text_input = furi_alloc(sizeof(TextInput));
text_input->view = view_alloc();
@@ -369,6 +417,14 @@ TextInput* text_input_alloc() {
view_set_draw_callback(text_input->view, text_input_view_draw_callback);
view_set_input_callback(text_input->view, text_input_view_input_callback);
text_input->timer = osTimerNew(text_input_timer_callback, osTimerOnce, text_input, NULL);
with_view_model(
text_input->view, (TextInputModel * model) {
string_init(model->validator_text);
return false;
});
text_input_clean(text_input);
return text_input;
@@ -376,7 +432,21 @@ TextInput* text_input_alloc() {
void text_input_free(TextInput* text_input) {
furi_assert(text_input);
with_view_model(
text_input->view, (TextInputModel * model) {
string_clear(model->validator_text);
return false;
});
// Send stop command
osTimerStop(text_input->timer);
// Wait till timer stop
while(osTimerIsRunning(text_input->timer)) osDelay(1);
// Release allocated memory
osTimerDelete(text_input->timer);
view_free(text_input->view);
free(text_input);
}
@@ -393,6 +463,10 @@ void text_input_clean(TextInput* text_input) {
model->text_buffer_size = 0;
model->callback = NULL;
model->callback_context = NULL;
model->validator_callback = NULL;
model->validator_callback_context = NULL;
string_reset(model->validator_text);
model->valadator_message_visible = false;
return true;
});
}
@@ -425,10 +499,42 @@ void text_input_set_result_callback(
});
}
void text_input_set_validator(
TextInput* text_input,
TextInputValidatorCallback callback,
void* callback_context) {
with_view_model(
text_input->view, (TextInputModel * model) {
model->validator_callback = callback;
model->validator_callback_context = callback_context;
return true;
});
}
TextInputValidatorCallback text_input_get_validator_callback(TextInput* text_input) {
TextInputValidatorCallback validator_callback = NULL;
with_view_model(
text_input->view, (TextInputModel * model) {
validator_callback = model->validator_callback;
return false;
});
return validator_callback;
}
void* text_input_get_validator_callback_context(TextInput* text_input) {
void* validator_callback_context = NULL;
with_view_model(
text_input->view, (TextInputModel * model) {
validator_callback_context = model->validator_callback_context;
return false;
});
return validator_callback_context;
}
void text_input_set_header_text(TextInput* text_input, const char* text) {
with_view_model(
text_input->view, (TextInputModel * model) {
model->header = text;
return true;
});
}
}

View File

@@ -6,6 +6,8 @@
#pragma once
#include <gui/view.h>
#include "validators.h"
#include <m-string.h>
#ifdef __cplusplus
extern "C" {
@@ -14,6 +16,7 @@ extern "C" {
/** Text input anonymous structure */
typedef struct TextInput TextInput;
typedef void (*TextInputCallback)(void* context);
typedef bool (*TextInputValidatorCallback)(const char* text, string_t error, void* context);
/** Allocate and initialize text input
*
@@ -63,6 +66,15 @@ void text_input_set_result_callback(
size_t text_buffer_size,
bool clear_default_text);
void text_input_set_validator(
TextInput* text_input,
TextInputValidatorCallback callback,
void* callback_context);
TextInputValidatorCallback text_input_get_validator_callback(TextInput* text_input);
void* text_input_get_validator_callback_context(TextInput* text_input);
/** Set text input header text
*
* @param text_input TextInput instance

View File

@@ -0,0 +1,42 @@
#include <furi.h>
#include "validators.h"
#include "applications/storage/storage.h"
struct ValidatorIsFile {
const char* app_path_folder;
const char* app_extension;
};
bool validator_is_file_callback(const char* text, string_t error, void* context) {
furi_assert(context);
ValidatorIsFile* instance = context;
bool ret = true;
string_t path;
string_init_printf(path, "%s/%s%s", instance->app_path_folder, text, instance->app_extension);
Storage* storage = furi_record_open("storage");
if(storage_common_stat(storage, string_get_cstr(path), NULL) == FSE_OK) {
ret = false;
string_printf(error, "This name\nexists!\nChoose\nanother one.");
} else {
ret = true;
}
string_clear(path);
furi_record_close("storage");
return ret;
}
ValidatorIsFile*
validator_is_file_alloc_init(const char* app_path_folder, const char* app_extension) {
ValidatorIsFile* instance = furi_alloc(sizeof(ValidatorIsFile));
instance->app_path_folder = app_path_folder;
instance->app_extension = app_extension;
return instance;
}
void validator_is_file_free(ValidatorIsFile* instance) {
furi_assert(instance);
free(instance);
}

View File

@@ -0,0 +1,20 @@
#pragma once
// #include <gui/view.h>
#include <m-string.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ValidatorIsFile ValidatorIsFile;
ValidatorIsFile*
validator_is_file_alloc_init(const char* app_path_folder, const char* app_extension);
void validator_is_file_free(ValidatorIsFile* instance);
bool validator_is_file_callback(const char* text, string_t error, void* context);
#ifdef __cplusplus
}
#endif

View File

@@ -1,10 +1,11 @@
#include "../subghz_i.h"
#include <lib/toolbox/random_name.h>
#include "file_worker.h"
#include "../helpers/subghz_custom_event.h"
#include <lib/subghz/protocols/subghz_protocol_raw.h>
#include <gui/modules/validators.h>
void subghz_scene_save_name_text_input_callback(void* context) {
furi_assert(context);
SubGhz* subghz = context;
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveName);
}
@@ -37,6 +38,11 @@ void subghz_scene_save_name_on_enter(void* context) {
subghz->file_name,
22, //Max len name
dev_name_empty);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(SUBGHZ_APP_PATH_FOLDER, SUBGHZ_APP_EXTENSION);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTextInput);
}
@@ -50,7 +56,9 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
if(event.event == SubghzCustomEventSceneSaveName) {
if(strcmp(subghz->file_name, "")) {
if(strcmp(subghz->file_name_tmp, "")) {
subghz_rename_file(subghz);
if(!subghz_rename_file(subghz)) {
return false;
}
} else {
subghz_save_protocol_to_file(subghz, subghz->file_name);
}
@@ -79,6 +87,10 @@ void subghz_scene_save_name_on_exit(void* context) {
SubGhz* subghz = context;
// Clear view
void* validator_context = text_input_get_validator_callback_context(subghz->text_input);
text_input_set_validator(subghz->text_input, NULL, NULL);
validator_is_file_free(validator_context);
text_input_clean(subghz->text_input);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);

View File

@@ -421,7 +421,7 @@ bool subghz_rename_file(SubGhz* subghz) {
FS_Error fs_result =
storage_common_rename(storage, string_get_cstr(old_path), string_get_cstr(new_path));
if(fs_result != FSE_OK && fs_result != FSE_EXIST) {
if(fs_result != FSE_OK) {
dialog_message_show_storage_error(subghz->dialogs, "Cannot rename\n file/directory");
ret = false;
}