From d4d87aa6a8edb051ae0a0c998ca887a095a7220e Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Fri, 21 Jan 2022 17:55:09 +0400 Subject: [PATCH] [FL-2045] SubGhz: new protocol (GSN , Beninca/Allmatic, Elmes) and validator (#958) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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: あく --- applications/gui/modules/text_input.c | 112 +++++++++++++++++- applications/gui/modules/text_input.h | 12 ++ applications/gui/modules/validators.c | 42 +++++++ applications/gui/modules/validators.h | 20 ++++ .../subghz/scenes/subghz_scene_save_name.c | 16 ++- applications/subghz/subghz_i.c | 2 +- assets/compiled/assets_icons.c | 8 ++ assets/compiled/assets_icons.h | 2 + assets/icons/Interface/Back3_45x8.png | Bin 0 -> 3630 bytes .../icons/Interface/WarningDolphin_45x42.png | Bin 0 -> 1139 bytes assets/resources/subghz/keeloq_mfcodes | 72 +++++------ assets/resources/subghz/keeloq_mfcodes_user | 2 +- lib/subghz/protocols/subghz_protocol_keeloq.c | 31 ++++- .../protocols/subghz_protocol_keeloq_common.c | 14 ++- .../protocols/subghz_protocol_keeloq_common.h | 13 +- 15 files changed, 300 insertions(+), 46 deletions(-) create mode 100644 applications/gui/modules/validators.c create mode 100644 applications/gui/modules/validators.h create mode 100644 assets/icons/Interface/Back3_45x8.png create mode 100644 assets/icons/Interface/WarningDolphin_45x42.png diff --git a/applications/gui/modules/text_input.c b/applications/gui/modules/text_input.c index 2b31f71b..e8351ce3 100755 --- a/applications/gui/modules/text_input.c +++ b/applications/gui/modules/text_input.c @@ -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; }); -} \ No newline at end of file +} diff --git a/applications/gui/modules/text_input.h b/applications/gui/modules/text_input.h index d7b32def..7b0dc5c0 100644 --- a/applications/gui/modules/text_input.h +++ b/applications/gui/modules/text_input.h @@ -6,6 +6,8 @@ #pragma once #include +#include "validators.h" +#include #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 diff --git a/applications/gui/modules/validators.c b/applications/gui/modules/validators.c new file mode 100644 index 00000000..dc752e95 --- /dev/null +++ b/applications/gui/modules/validators.c @@ -0,0 +1,42 @@ +#include +#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); +} diff --git a/applications/gui/modules/validators.h b/applications/gui/modules/validators.h new file mode 100644 index 00000000..f62064b6 --- /dev/null +++ b/applications/gui/modules/validators.h @@ -0,0 +1,20 @@ +#pragma once + +// #include +#include + +#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 \ No newline at end of file diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index f688d20d..c64d0d2c 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -1,10 +1,11 @@ #include "../subghz_i.h" #include -#include "file_worker.h" #include "../helpers/subghz_custom_event.h" #include +#include 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); diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index 2fce6f15..5a1f67fe 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -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; } diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index f5f7a6d3..71316998 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -245,6 +245,9 @@ const uint8_t *_I_ArrowUpEmpty_14x15[] = {_I_ArrowUpEmpty_14x15_0}; const uint8_t _I_ArrowUpFilled_14x15_0[] = {0x00,0xC0,0x00,0x20,0x01,0xD0,0x02,0xE8,0x05,0xF4,0x0B,0xFA,0x17,0x61,0x21,0xAF,0x3D,0x68,0x05,0xA8,0x05,0x68,0x05,0xA8,0x05,0xE8,0x05,0x08,0x04,0xF8,0x07,}; const uint8_t *_I_ArrowUpFilled_14x15[] = {_I_ArrowUpFilled_14x15_0}; +const uint8_t _I_Back3_45x8_0[] = {0x00,0x04,0x00,0x10,0x00,0x40,0x00,0x06,0x00,0x18,0x00,0x60,0x00,0x7F,0x00,0xFC,0x01,0xF0,0x07,0x86,0x20,0x18,0x82,0x60,0x08,0x04,0x71,0x10,0xC4,0x41,0x10,0x00,0x21,0x00,0x84,0x00,0x10,0x80,0x00,0x00,0x02,0x00,0x08,0x7E,0x00,0xF8,0x01,0xE0,0x07,}; +const uint8_t *_I_Back3_45x8[] = {_I_Back3_45x8_0}; + const uint8_t _I_DoorLeft_70x55_0[] = {0x01,0x00,0x19,0x01,0x00,0x2c,0x32,0x01,0x03,0x04,0x2c,0x18,0x10,0xf0,0x40,0x47,0x82,0x06,0x81,0x03,0xff,0x80,0x08,0x1a,0x20,0x82,0x15,0x28,0x21,0x87,0x82,0x08,0x6f,0xc0,0xb1,0xe6,0x10,0x10,0x8b,0x46,0x20,0x43,0x55,0x8f,0x82,0x10,0x32,0x73,0x0a,0x09,0x89,0x6c,0x1e,0x09,0x00,0x18,0x60,0xf0,0x0c,0x84,0x93,0x82,0x03,0x18,0x0c,0x02,0x1d,0x00,0x90,0x52,0x70,0x50,0x1e,0x00,0x58,0x63,0x90,0x0a,0x06,0x4a,0x09,0x03,0xb0,0x02,0x06,0x70,0x62,0x49,0xf8,0x0c,0x66,0x3f,0xf0,0x41,0x63,0x04,0x43,0x00,0x99,0x60,0x00,0x85,0xc8,0x06,0x14,0xd0,0x80,0x3f,0xc8,0x0d,0xb8,0x10,0x70,0xf8,0x34,0x13,0x03,0x39,0x04,0x1c,0x42,0x19,0xf8,0xa0,0xc2,0x01,0x07,0xef,0x02,0x8c,0x80,0x10,0x9d,0x00,0x43,0xec,0x00,0xa3,0x10,0x04,0x25,0xce,0x19,0xfc,0x88,0x82,0x12,0x0c,0x35,0x10,0x42,0x4c,0xa1,0x90,0x3f,0xc0,0x21,0x22,0x39,0x82,0xc8,0x88,0xd2,0x11,0xf0,0x01,0x88,0xd5,0x18,0xe2,0x08,0x68,0x10,0x0c,0xa8,0x00,0x83,0x81,0xcc,0xd5,0xc3,0x80,0x84,0x82,0x0e,0xcc,0xc0,0x15,0x79,0x02,0x0b,0x98,0xf8,0x11,0x88,0x82,0x0f,0x31,0x19,0x02,0x08,0x2c,0x9f,0x6a,0x1d,0x20,0x41,0x31,0x4c,0x10,0x8d,0x73,0x04,0x23,0xa4,0xc4,0x6c,0xde,0x20,0x42,0xcc,0x01,0x07,0x07,0xff,0x80,0x06,0x3e,0x08,0x38,0x70,0x20,0xa1,0xe0,0x83,0x8e,0x01,0x0c,0xf0,0x73,0x80,0x43,0x70,0x05,0x08,0x00,0x2c,0x04,0xc4,0x46,0x53,0x09,0x98,0x24,0x80,0x65,0x80,0xb0,0xd9,0x84,0x65,0x32,0x06,0x17,0x0f,0x98,0x23,0x63,0xe1,0x88,0xc4,0x08,0x5f,0xc1,0x30,0x9d,0x84,0x4e,0x66,0x94,0x11,0x98,0x75,0x26,0x00,}; const uint8_t *_I_DoorLeft_70x55[] = {_I_DoorLeft_70x55_0}; @@ -263,6 +266,9 @@ const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; const uint8_t _I_PassportLeft_6x47_0[] = {0x01,0x00,0x1c,0x00,0x9e,0x40,0xa3,0x32,0x59,0x2c,0x66,0x03,0x01,0x82,0xc2,0x62,0x32,0x50,0x16,0xc8,0x60,0x30,0x28,0x24,0x32,0x39,0x3c,0x9e,0x4d,0x25,0x80,0x1a,}; const uint8_t *_I_PassportLeft_6x47[] = {_I_PassportLeft_6x47_0}; +const uint8_t _I_WarningDolphin_45x42_0[] = {0x01,0x00,0xc6,0x00,0x00,0x1c,0x22,0x04,0x05,0x7f,0xfc,0x1e,0x20,0x05,0x1e,0x04,0x02,0x30,0x05,0x29,0x84,0x02,0xc1,0x20,0x02,0x8c,0x22,0x01,0x80,0x02,0x94,0x10,0x32,0x30,0x10,0x10,0x87,0xca,0x84,0x03,0x10,0x42,0x81,0x48,0x28,0x38,0x08,0x04,0x3e,0x01,0x84,0x83,0xe0,0x30,0x11,0x08,0x05,0xa2,0x11,0x40,0xa0,0x4b,0xc6,0xc5,0x40,0xd0,0x56,0xe0,0x10,0x60,0x29,0x54,0xf0,0x10,0x18,0xf0,0x14,0x6b,0xf6,0x0c,0x04,0x3e,0x40,0x05,0x12,0x80,0xc1,0xe4,0x01,0xd2,0xf8,0x40,0xe4,0x18,0x09,0xf4,0x03,0xf1,0x01,0x90,0x40,0x28,0x30,0x0f,0xe4,0x00,0x16,0x24,0x11,0xbf,0x01,0x44,0xee,0x53,0xf0,0x29,0xf0,0x3e,0x02,0x91,0x3b,0x8c,0xc3,0x81,0x13,0x90,0x48,0x20,0x3f,0xf9,0xfc,0x42,0x60,0x05,0x10,0x98,0x81,0x56,0x11,0x38,0x02,0x9c,0x1a,0x31,0x1e,0x02,0x8f,0x02,0x03,0x1c,0x90,0xc0,0x7c,0x02,0xf1,0xce,0x02,0x07,0x01,0x1f,0x80,0x63,0xa8,0x08,0x71,0x3c,0x8e,0x39,0x24,0x40,0x51,0xc7,0x81,0x53,0x0f,0x3c,0x02,0x9d,0x1e,0x38,0x29,0x10,0x29,0x17,0xc8,0x0a,0x32,0x3a,0x00,0x14,0x4b,0xa2,0x05,0x58,0x98,0x15,0x22,0x20,0x54,0x84,0x81,0x50,}; +const uint8_t *_I_WarningDolphin_45x42[] = {_I_WarningDolphin_45x42_0}; + const uint8_t _I_Back_15x10_0[] = {0x00,0x04,0x00,0x06,0x00,0xFF,0x0F,0x06,0x10,0x04,0x20,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x10,0xFE,0x0F,}; const uint8_t *_I_Back_15x10[] = {_I_Back_15x10_0}; @@ -748,12 +754,14 @@ const Icon I_ArrowDownEmpty_14x15 = {.width=14,.height=15,.frame_count=1,.frame_ const Icon I_ArrowDownFilled_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowDownFilled_14x15}; const Icon I_ArrowUpEmpty_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowUpEmpty_14x15}; const Icon I_ArrowUpFilled_14x15 = {.width=14,.height=15,.frame_count=1,.frame_rate=0,.frames=_I_ArrowUpFilled_14x15}; +const Icon I_Back3_45x8 = {.width=45,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Back3_45x8}; const Icon I_DoorLeft_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_70x55}; const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; const Icon I_DoorRight_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorRight_70x55}; const Icon I_LockPopup_100x49 = {.width=100,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_LockPopup_100x49}; const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; const Icon I_PassportLeft_6x47 = {.width=6,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_PassportLeft_6x47}; +const Icon I_WarningDolphin_45x42 = {.width=45,.height=42,.frame_count=1,.frame_rate=0,.frames=_I_WarningDolphin_45x42}; const Icon I_Back_15x10 = {.width=15,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Back_15x10}; const Icon I_DolphinReadingSuccess_59x63 = {.width=59,.height=63,.frame_count=1,.frame_rate=0,.frames=_I_DolphinReadingSuccess_59x63}; const Icon I_Down_25x27 = {.width=25,.height=27,.frame_count=1,.frame_rate=0,.frames=_I_Down_25x27}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index 3dac8eb1..c52821af 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -82,12 +82,14 @@ extern const Icon I_ArrowDownEmpty_14x15; extern const Icon I_ArrowDownFilled_14x15; extern const Icon I_ArrowUpEmpty_14x15; extern const Icon I_ArrowUpFilled_14x15; +extern const Icon I_Back3_45x8; extern const Icon I_DoorLeft_70x55; extern const Icon I_DoorLocked_10x56; extern const Icon I_DoorRight_70x55; extern const Icon I_LockPopup_100x49; extern const Icon I_PassportBottom_128x17; extern const Icon I_PassportLeft_6x47; +extern const Icon I_WarningDolphin_45x42; extern const Icon I_Back_15x10; extern const Icon I_DolphinReadingSuccess_59x63; extern const Icon I_Down_25x27; diff --git a/assets/icons/Interface/Back3_45x8.png b/assets/icons/Interface/Back3_45x8.png new file mode 100644 index 0000000000000000000000000000000000000000..6cb945f6297dda14d46e8bb2e77496a572c600fc GIT binary patch literal 3630 zcmaJ@c{o&U8$Y%}*>{pL;#HP0mNJvEFQY8e*hVGB7z}1<3}z%Lk&-Q2)@&s;v?-D; zDP)Txq3k3ymXIuc0hkA(-S{=jv4ZvO$7Bzku6~pf=E+LYQbZWfN!;j2~8O>9z^f9>-b3E4Rr2bch!Q#hf zLs@fk>+jdAr?RIuIvAZo5h9{0Ns|SB01O>v0Pj;sutzqw)I@MfAcwg@!jr8HK0Gf0 zV4jOX52xKX+TgfH1~>sqkLEtnrjehKRVWn~0F(p_gGHxyaU`OFW=+RtaiCcmxbN`D ziyuef!2aus^wU5*I8Q|e`9<9z<-vHz> zjlr7S^<^9pu1~bBI3sF!fZ%vcqL8r%5RqZ3-Ufj5IRUf1V(nZY8?HR9?z-U;cS=+x zk^`u3O>Iv<+N~pAnfgXHWO06YRB^N+;DIStYQL~I-#9osJxfUpImKnuu^Rwn*Sel> z=^G_ZO^%ODdQSzgzP&8i@}DPz4HXxLwyLjkas$G4oveQMiHTk=N)yNZpgRAO6F|Q+ z;5)SDrZd2ocbxxC=vpj8f5UihZa%8nKz-`_Q=`{1Oy#FYii$Kyuw$g0UJ0(4Jm21_0HcrBB{Yk+ONk3jpSM=MUUB*}40|Yef0*yraQ(X_VDLRrh9b4YLprxX zx;mPV+oYLS466u_5%G-g19$LBWyEuXu}Ix(5k;Ws81ZA^m(A27&Jt6bq z*U`^GG~n!&cw9smRM7kC2kgnKmn=LkV`NpDBykfMJ?8{HoIK`Gu!LNFE|$f+k25wx zY?k-bMd5~k3yFzV7#ob)ZRJ^|a?vVY7rw}g(1yRj$+zvxl|x0>8tIF%p?+9K8^D}j9`M& zlPVI0678?8x4amy5Qo2v8MWan*oQ7k5j~=ZH=5wSc|+SYBk#_!_LAIpymw;YH;!8q z^MX+jhf5`5x_Y$TY2r?_=a%i}W|?-Tt3=cCNv}my;i=B4 z;i*%19GwE4jCvS%b~)a461scJ`RpxAr$?x<625nmcY8|Yot~8(EbBmrpc7D?$J`5R z-8V1%zzIBzj)Mix5aDqhLNDN4T5#xGz@d#TP`GwS}=Z9PvsT${BC=2@2uhMci+ zFblln&Gb(4&Y3*j&LQ~f!SFonL-vsl#SVdvGa6hPMj8)#{Yt${!%GkKhxXU@d(Khk zB;~e#zWjGPO8pKz1u5x2O1LdRKLozooUcHLDLY`J*)Na89*k{D>rV@7(mTV-B%HgskY1Vu-4`W|B`>C3eB^xc19O)2q;4HeY!yupPM2~Z7GEhQ-3V<>osj)n z)&2PGa$(l9tijR`#CIRt5HHW(UANWDl525$fnb?@n_tC@o^BhNPKiB?~rgf`PQ1vblVf&m|?4c zm`VkLOor6jS@Hb`wC`wsIacmKJ55_v?`4j=uKU!)FC>&)eR_Dn?+G>7hv^r94#3T3 zRYp|asXR}=^xa}1U6dxak8kescw=89;__G^=TtzZPWE`FV;T)tHZfT6RBCd%qcu0g zz*WyRF-$+|x@h`Cqlrk6DGDNOKT%Awl^0vQm=$GjQCkpKaO^=v(z0kwZNqTiGV1ZuEKJ38A?#n269`CenR>Ly%Jf2JpN8+$b0L{ zn$oTdl3_K8_feJiAN5tzT^EMIbr#Pgm0}&FLNuXn=qfKdVZQrpt8eSWv`y3~2JN)y z#~56UM@M$wylJL(!9_Q*2`P>1iRCgwYdAscUeap(p zQ5QS+p0H&GvA_S*k&4%IGsu~u84`2VweH@L8b6bsH_`I~rE&{#6LRjvBcEvbp?=Hp z?d9#S+qv|xdUGe*o-hX%^A8rTgyx)cYjxf%y<1WHL8ZU9?qkTACBaB}iNl{*DYMm& z)#xt%H5O-=N!?#Bd`yt_l&h+n4F6bZ6=MG~H{s09Gdou-STlY!a=_rdy1IvaMD)S9 zy+}A^A}fO2pEZ{m@|be`fMA2k#Ph#~ZiSs0Lw(Ngcro~*eJJBx#WL>f zn~e;Aw_|QKK4zV{MpCq|HWluxElZ!K65QsiDc``Wo&(AiM@tc92&-_)<_PlM3Gxhn zwRO(Lpp5p-cII#w>+QK8e)TbOQpDk z90dhA0oj^Gua4xA;)lgzov*{4e==qQ?@kSEj;DjqQLB75RN)VQg*SI5JTayKSRM zCsNpG05CA3Q?NLHJPqWD_aTrFVAiubFo@uV0K4efYS~iE@V*3OC>8GzYUhXx^~b@y zz($5313H{dK*ZCqAUZLC6bPpyz<=|?+48m;0tWqULi0y}{~Z*@76mdRQ}Lifnotd# zmX;Ri5KI&Ah1K@d@y6oRLE2i{PzaQLAJTvxf@|x*p)k-t7ntpk>g5ebn_K?lj=e*G zeQ7ib90Cam3DFGE(IiuSAW#?#2GP=nXlrY*Ei?idBpQ~kK?+p*#bAyP#8C+p8i7m# zZ8Ks$$w4#(m>ulDvmjD_(~<)JsT8|r5IU9ufof`PXZ6d_*7pCK5{bX918Hddf8zb0 z#DR_s3Lb*S2ahuwK8hCR%^QZVv>J!uD*ArxJqkUY1lc5%hP~aKfKsG5;gq zKUl9n#sahWBNoCA2D07T|LXNG6?=fT#oxor-uxbaJc&K?RQ7PQPTCi;Ka3qH8%K+u zKYy}Cr-rxT?B%evxrrma-_ygx!^?Ol-CPjOIPc{pxWsr*JL*@+|p)oA7EpIDoAAoo_=+RA)c=F3Qf$N$` ze9k55q%DD7y=l+^ZG$aob+Aw6HDcRVJdzhs00Te;&l_3O74jlch$|r7GgAa!aDjay z@rG1;vK5ys2jF3n@vAgV<6)izn!k6Qhd>D(EhD7l zcrhJ1i9|1iwm?z2T#n2INXzM=7@p@Tnx$CQk39VDfC-hn-*jtB5oF-1j&4KUGI1}W z(rxuakw9eMRAJc3%8 zlBq3$QTyJX$a6$&1ldyi4Pe5AEE32Sg@vDzY~7qR?1u@oXh zd9(fBtV<@eK%Tm=yy&p7{=h^#@1W)WFFSe!U5pP~o71uR`FW)7xc*=d5_b}EG@XBZ z@<7MRp-;+|o}SzJvMyfx>37Y4etBizf%0H*zaIF?2ObZt?$D;{o|esJ z*PgAOIO^*8tL%z2)|}k$DP5kN5}8qo*wNa8y?R2=%wO{gCD(`sHt}TzWQuK zMDIJap(nb2=7*ns*oDcRBbC23yy`kvKYV`ovU`a=EmxNv-90;;5r6+l8hQTp^u`Hn XX6*+%8gHC`h)Tl}u@-r>vFqE{F~5F& literal 0 HcmV?d00001 diff --git a/assets/resources/subghz/keeloq_mfcodes b/assets/resources/subghz/keeloq_mfcodes index a18dd590..c969b592 100644 --- a/assets/resources/subghz/keeloq_mfcodes +++ b/assets/resources/subghz/keeloq_mfcodes @@ -1,38 +1,40 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: 7A 44 FE 5D C3 B3 65 13 73 A6 F4 2D 1E B6 7D F0 -89153B35033574AAA06D7E792CB92A486B37A2CCDF0B0152BF1A563E321518C8 -F6583A3E4148439E8A8D7ED6A095ACC0C3E22A48F1637E78DF023CAC9272934E -AA0439E6B76CD43F3FCC27CF69C5F3B6508E8103B164E4ECDDF8B2FB222D46FF -A9826C663033D25AE21CB8790406997ADCE84360B258F2B989D967009659859C -3474E7BBFA0173928F414CFD5EE19B27A558D9C171D96FE7B7840A01323A7E7446FAE3E98EA9A8C69B4A6B781BD7906A -2873939A8E0EAC16D748967E987BB0F1079C106E4235B7D35B4BF37F54B21F8E -EF6F1DC0201FCB8CEBC5642A5194A1FDCFBE1FA772A79CEAD54D2F0DA3AC4F6C -3F595EAA0E81E96C5D6DB41799D314E3E81E7F4197E19A3341C55592B1B6C4B0 -7B2D75FE11B27E99CA7610E47D712C8CFB619EC69EBC976A70CFD9574C9F4FF8 -39735CF1D009D132A33B9C546D95FA6D3E69BF3A57EF219392E57C9560E7B037 -D56FDDFB0C4E808143D3ED5F15D6FF47F6EDEBD01192FC7ACF3ACCE9FD5162FC297D0089D65ED2CBE3CE05DDA7B96446 -2750D4F0650061C3AF72C88FD080BE241F2BDD8D8C1B0EFE781120EBEFFE2C72D0EECC42CDDED50CFE4AC51C48AE68C6 -F8CE64921CB73015F2672A9EF0A8359269CAE0E515D6DBB3130CFC9E5E1A98AD -ACF6ADB9E02D67B44EB6C6F126BF64BDAB37926B8BE39E27F323E8F5A0F8FC38 -FBB1302D697F94ECED681CE047819001EDE6E013850258F61E97091DD37D24F2 -D8CD53AB5A94898EB53D4FF46546ADBAA24691181A396052A58AAC657D6817AB -43200E08C21747CABC59538888A259238E782545732A1A6EEE00A6929EC9DD97A8BA9812372374046AC66652CC561D60 -C38CBE29F22D0E83E58A52E94AA2485DA8E702FBDB89D27249473CB8A19AEF61 -9F0EB580F7474985E8460E1682451E213778B77A9CAB4734B75C5386851050BF -2364EBB8237363B21226565675B9F47819C5BBC7E917C761BA3652D0A6ED7D3273EB8F3B7FBA68DE4143FB15BBEC35FB -CCDE559A2901A8290D6B2E8EDF66612E4C90E2E7C63643C8C5F244E30874B41039E078089E2253DA73B3A6DD821A84CD -33B239455FBE7AB8CE833C3B9C063EFEAE1FC7AC876AF3294C67D5B08BF7E9EC -F0FBBCEFE99D25104022CD3621B21B5F84FFBC9A5E21B0AED2B1560B39524A5B -E15B0614D9ECA17784E994652755559B7A3DA4B53CE6E63108BCFCD8024761DD -9E244C80E72937274DD6B2787F1A75F278A2DF7CB3B89F7C2BF7CC8DBBF2A3F0 -689DCA188A40DFDD3575A9BD9D7AF2427D0CE707F591029463AEC6B8679969AC -25D9B04D10AF541925901F55D8D7FA9C87523995F53183FB04F00C6023D5930A -D11F70508485C019AFC5FDBE5FD7223710033483C803FC7C2C69BAAD6ACB7CA7 -C081A0ACEA8210AB117028EDFF15641EE287CB1CFF8332A9D208B7324523129E -4C5B7C959C00A30F39A431B20EA1FEBDFB1C71C01CCC45DD883CD511360479BE -ECC0A8237E19D3883A06C5A700647860B3D9E570976D3606A11A4005424FD935 -8F5D7B39696F6F5C2100FFDF71D1C8ECAD98BD1D4CEE7BA8C793815747CE6FD5 -52ED6DE1583093E8D8AB8D16C912F7E89F78A24CE36ED53D3E06D3F81BF62ED1 -416015A128EA3A008573DE760C6AE05BD958BFCB46351F614B617CEE55C5E294 +IV: 2A 44 FE 5A A3 63 F5 11 83 A6 FE DA 1E B7 3D F1 +BF22677F79DF533C83FFE485B5F9CFABA24352FDEBED14B6FFA16EE9F00D6AC4 +B9343EDBB8B8C6EEFDA7AE9934445E27B04950DBB4F31ECCD1735CCB8C1600DE +54CC71AF6794D47FFC49823DA6C4CCAD94EC5540515FD6F537A078BFD736105C +4A3A12125D4F1186369B3B0ECB86B28A6EE4A0AF49DD4C42743A5C2C9BD1F5FC +190D7746CDC7782157E95532070BCFE8637CF9A7BE03F9382A435ACAAA7A5F5E6BEB8E34A320BDB6E492D793E470CAB4 +59ABF9B68B31BF9CCF2CCCC0A6B3182FA2772691A400B2BFB5E2490DA2BCD2A4 +304DF68472EC9C78341218C10242DC3D62887A5281B52061BC0C9D117CDE1185 +D146050F90D30FA166615706FBC8D5B3573BDCB081E2445930CE1B71F5BDB7AE +9386C94D044CCCBEE7972319191933328A06B20138C432B86C76EB909BB06019 +CFC23206853E9D01C3986FD849908686A2442287277C06574928A362F988CE1B +534B351BE03A98B56ED622D37B9BBCD871CA76EB6EF250B1615105FA496E991C8F195293F83EE38AE5831D95F45238E3 +AFF90EC99CF4278D79DA9B1163FF07C83203AD34F9C4228423B4B58FF3F6978C605CC282FB1E37C0946D86C51809222C +44C9EF18971905D2207F62D3365CB4A31D449FA215F950CEB67368D13181959C +0CF10950D8A3EDEEEEA9AA4E41354373584FBFE6BB2E8A52C3149757C133445C +4FBE939E87B8438AFC86773DADA39FE3856A3518A5159C9BF6B2EFA752F5B3F5 +CBFD648024823A33481B8A7381CD28930765265A1CA9BBDE1879F0827273A860 +8D3C70EF2E4ED2EF23752046538BF30F6DA8266F2B10A4BAD8549B3D20298F08EF9E6C21F78DDA9CA6EBB1E3CDF82C78 +D31EBB7C994C397776777D4904661C6F8DF5CDA9F828CA19378CAA397555F8C0 +FDA58BA7B0CD5C9090FE891029A3773EA16DB77EB5FA06A4C443C01B537B2615 +5CEE7A27D0D1B1AB5BAAC93D78121BC6D5FCD589C093A22C71E81C390045C85FDE98C202340FDD2046FF906A035E31E9 +C3121624E5B91EDCF651B8A89C2EEF4379876D0E0D918596F3E5CED9F3C92AB689D609AA1FB5362F57738A0AF62E3C92 +25F715B4CEA880E4879C6C03DC61875A43FB314AB4F21AE1CF7C933172B4A29D +574166A278E2FA4AB8A09078152929E631E4E182E20CCF803250A0A2D4BB62F3 +B0D1C7AA1752135BA7627D8F65EC9651B810EC29BA01C8D9BC5B3EB20B1A0939 +E3E9D30E4F7003E63917DF3B5FC4E03863E37AFD6C5987CCFEC8129C692474EF +67A35F2E3C400953EC1CD1874A35A4734D3E9F116F7E334276BF898E48C21AFE +BC8D612FA363AB364BB9D2701273C4FA587B2F8D8CD039DEFB72BAD00360149F +9A88BBDA111C9185EE5BBA610574D46A4D53EC79B63D5FB57BAB5A6609F2160F +9512A1F77A4C46BD7F79D792B1578AC1FA41F15F6D7C72BC952BD89262C85327 +182685E3E0A23055025F7218AB16F7AE3A7F9DD71761AAE3B5E4AB85E2EFBF929D640258AEBC9F0BB167985A1E4B132D +1DD9156B6BF97424DC639708ACEE21DD1D64FC5BC0DD5252DDDDE7832C2B7B6F +109BB4D660897DB00676093B585535D267426310CDE81F05793ACB46B9F6176E +D7A2D468DF76A8E5C495D5280524B2996254B94458485B11CCAB36CD1EE3918F +9F445C93FF382433015BEAE6D78F70AE2C02E0C961E1B9576D66E64978D984D0 +195CB755E6AC710B5AF10761AC2B13F8CA57355443B593BC59AAF3A819070568028BBAE75C0DA4BA6B90D63E679098B7 +C6ECD39EC47DFFD1ABC55F47AC8E2C26A8DB5EB8184153746F7D9AD5F0015E85 diff --git a/assets/resources/subghz/keeloq_mfcodes_user b/assets/resources/subghz/keeloq_mfcodes_user index 910157d6..f013afa2 100644 --- a/assets/resources/subghz/keeloq_mfcodes_user +++ b/assets/resources/subghz/keeloq_mfcodes_user @@ -1,7 +1,7 @@ # for adding manufacture keys # AABBCCDDEEFFAABB:X:NAME\r\n # AABBCCDDEEFFAABB - man 64 bit -# X - encryption method 1 - Simple Learning, 2 - Normal_Learning, 3 - Secure_Learning +# X - encryption method 1 - Simple Learning, 2 - Normal_Learning, 3 - Secure_Learning, 4 - Magic_xor_type1 Learning # 0 - iterates over both previous and man in direct and reverse byte sequence # NAME - name (string without spaces) max 64 characters long Filetype: Flipper SubGhz Keystore File diff --git a/lib/subghz/protocols/subghz_protocol_keeloq.c b/lib/subghz/protocols/subghz_protocol_keeloq.c index 1db8da4d..bdecb4ee 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq.c @@ -115,6 +115,15 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( return 1; } break; + case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1: + man_learning = subghz_protocol_keeloq_common_magic_xor_type1_learning( + fix, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } + break; case KEELOQ_LEARNING_UNKNOWN: // Simple Learning decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); @@ -144,6 +153,8 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( instance->manufacture_name = string_get_cstr(manufacture_code->name); return 1; } + + // Check for mirrored man man_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev); decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { @@ -161,13 +172,30 @@ uint8_t subghz_protocol_keeloq_check_remote_controller_selector( } // Check for mirrored man - man_learning = subghz_protocol_keeloq_common_secure_learning(fix, seed, man_rev); decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { instance->manufacture_name = string_get_cstr(manufacture_code->name); return 1; } + + // Magic xor type1 learning + man_learning = subghz_protocol_keeloq_common_magic_xor_type1_learning( + fix, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } + + // Check for mirrored man + man_learning = + subghz_protocol_keeloq_common_magic_xor_type1_learning(fix, man_rev); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_learning); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + instance->manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } break; } } @@ -198,6 +226,7 @@ void subghz_protocol_keeloq_check_remote_controller(SubGhzProtocolKeeloq* instan } else { subghz_protocol_keeloq_check_remote_controller_selector(instance, key_fix, key_hop); } + instance->common.serial = key_fix & 0x0FFFFFFF; instance->common.btn = key_fix >> 28; } diff --git a/lib/subghz/protocols/subghz_protocol_keeloq_common.c b/lib/subghz/protocols/subghz_protocol_keeloq_common.c index 0726a604..9f9d105b 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq_common.c +++ b/lib/subghz/protocols/subghz_protocol_keeloq_common.c @@ -53,7 +53,7 @@ inline uint64_t subghz_protocol_keeloq_common_normal_learning(uint32_t data, con /** Secure Learning * @param data - serial number (28bit) - * @param seed - serial number (32bit) + * @param seed - seed number (32bit) * @param key - manufacture (64bit) * @return manufacture for this serial number (64bit) */ @@ -69,4 +69,16 @@ inline uint64_t subghz_protocol_keeloq_common_secure_learning( k2 = subghz_protocol_keeloq_common_decrypt(seed, key); return ((uint64_t)k1 << 32) | k2; +} + +/** Magic_xor_type1 Learning + * @param data - serial number (28bit) + * @param xor - magic xor (64bit) + * @return manufacture for this serial number (64bit) + */ + +inline uint64_t + subghz_protocol_keeloq_common_magic_xor_type1_learning(uint32_t data, uint64_t xor) { + data &= 0x0FFFFFFF; + return (((uint64_t)data << 32) | data) ^ xor; } \ No newline at end of file diff --git a/lib/subghz/protocols/subghz_protocol_keeloq_common.h b/lib/subghz/protocols/subghz_protocol_keeloq_common.h index 906aad1f..110ce9f9 100644 --- a/lib/subghz/protocols/subghz_protocol_keeloq_common.h +++ b/lib/subghz/protocols/subghz_protocol_keeloq_common.h @@ -24,6 +24,7 @@ #define KEELOQ_LEARNING_SIMPLE 1u #define KEELOQ_LEARNING_NORMAL 2u #define KEELOQ_LEARNING_SECURE 3u +#define KEELOQ_LEARNING_MAGIC_XOR_TYPE_1 4u /** Simple Learning Encrypt * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter @@ -48,10 +49,18 @@ uint64_t subghz_protocol_keeloq_common_normal_learning(uint32_t data, const uint /** Secure Learning * @param data - serial number (28bit) - * @param seed - serial number (32bit) + * @param seed - seed number (32bit) * @param key - manufacture (64bit) * @return manufacture for this serial number (64bit) */ uint64_t - subghz_protocol_keeloq_common_secure_learning(uint32_t data, uint32_t seed, const uint64_t key); \ No newline at end of file + subghz_protocol_keeloq_common_secure_learning(uint32_t data, uint32_t seed, const uint64_t key); + +/** Magic_xor_type1 Learning + * @param data - serial number (28bit) + * @param xor - magic xor (64bit) + * @return manufacture for this serial number (64bit) + */ + +uint64_t subghz_protocol_keeloq_common_magic_xor_type1_learning(uint32_t data, uint64_t xor);