[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
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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;
}

View file

@ -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};

View file

@ -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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
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);