Merge pull request #465 from gid9798/SubGhz_lib

SubGhz some improvements
This commit is contained in:
MX 2023-05-14 04:35:33 +03:00 committed by GitHub
commit bdc720ac7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 759 additions and 935 deletions

View File

@ -76,8 +76,8 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
subghz->state_notifications = SubGhzNotificationStateIDLE;
subghz_txrx_stop(subghz->txrx);
if(subghz_custom_btn_get() != 0) {
subghz_custom_btn_set(0);
if(subghz_custom_btn_get() != SUBGHZ_CUSTOM_BTN_OK) {
subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK);
uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult();
furi_hal_subghz_set_rolling_counter_mult(0);
// Calling restore!

View File

@ -124,7 +124,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
},
false);
return false;
}
} // Finish "Back" key processing
with_view_model(
subghz_transmitter->view,
@ -136,124 +136,67 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
},
true);
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
subghz_custom_btn_set(0);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
model->draw_temp_button = false;
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
if(can_be_sent) {
if(event->key == InputKeyOk && event->type == InputTypePress) {
subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
model->draw_temp_button = false;
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(event->key == InputKeyOk && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
} // Finish "OK" key processing
// Temp Buttons (UP)
if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) {
subghz_custom_btn_set(1);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 1) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyUp && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Down
if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) {
subghz_custom_btn_set(2);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 2) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyDown && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Left
if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) {
subghz_custom_btn_set(3);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 3) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
// Right
if(can_be_sent && event->key == InputKeyRight && event->type == InputTypePress) {
subghz_custom_btn_set(4);
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_get() == 4) {
furi_string_printf(
model->temp_button_id, "%01X", subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(can_be_sent && event->key == InputKeyRight && event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
if(subghz_custom_btn_is_allowed()) {
uint8_t temp_btn_id;
if(event->key == InputKeyUp) {
temp_btn_id = SUBGHZ_CUSTOM_BTN_UP;
} else if(event->key == InputKeyDown) {
temp_btn_id = SUBGHZ_CUSTOM_BTN_DOWN;
} else if(event->key == InputKeyLeft) {
temp_btn_id = SUBGHZ_CUSTOM_BTN_LEFT;
} else if(event->key == InputKeyRight) {
temp_btn_id = SUBGHZ_CUSTOM_BTN_RIGHT;
} else {
// Finish processing if the button is different
return true;
}
if(event->type == InputTypePress) {
with_view_model(
subghz_transmitter->view,
SubGhzViewTransmitterModel * model,
{
furi_string_reset(model->temp_button_id);
if(subghz_custom_btn_get_original() != 0) {
if(subghz_custom_btn_set(temp_btn_id)) {
furi_string_printf(
model->temp_button_id,
"%01X",
subghz_custom_btn_get_original());
model->draw_temp_button = true;
}
}
},
true);
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
return true;
} else if(event->type == InputTypeRelease) {
subghz_transmitter->callback(
SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
return true;
}
}
}
return true;

View File

@ -12,7 +12,9 @@
#include <flipper_format/flipper_format_i.h>
#include <lib/toolbox/path.h>
#include <applications/main/subghz/subghz_i.h>
#include <lib/subghz/receiver.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/subghz_setting.h>
#include <lib/subghz/protocols/raw.h>
#include <lib/subghz/protocols/protocol_items.h>
@ -354,7 +356,7 @@ bool subghz_remote_key_load(
bool res = false;
subghz_custom_btn_set(0);
subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK);
keeloq_reset_original_btn();
subghz_custom_btns_reset();

View File

@ -2703,7 +2703,8 @@ Function,+,subghz_block_generic_get_preset_name,void,"const char*, FuriString*"
Function,+,subghz_block_generic_serialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*"
Function,-,subghz_custom_btn_get,uint8_t,
Function,-,subghz_custom_btn_get_original,uint8_t,
Function,-,subghz_custom_btn_set,void,uint8_t
Function,-,subghz_custom_btn_is_allowed,_Bool,
Function,-,subghz_custom_btn_set,_Bool,uint8_t
Function,-,subghz_custom_btn_set_max,void,uint8_t
Function,-,subghz_custom_btn_set_original,void,uint8_t
Function,-,subghz_custom_btns_reset,void,

1 entry status name type params
2703 Function + subghz_block_generic_serialize SubGhzProtocolStatus SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*
2704 Function - subghz_custom_btn_get uint8_t
2705 Function - subghz_custom_btn_get_original uint8_t
2706 Function - subghz_custom_btn_set subghz_custom_btn_is_allowed void _Bool uint8_t
2707 Function - subghz_custom_btn_set _Bool uint8_t
2708 Function - subghz_custom_btn_set_max void uint8_t
2709 Function - subghz_custom_btn_set_original void uint8_t
2710 Function - subghz_custom_btns_reset void

View File

@ -1,14 +1,16 @@
#include "custom_btn.h"
static uint8_t custom_btn_id = 0;
static uint8_t custom_btn_id = SUBGHZ_CUSTOM_BTN_OK;
static uint8_t custom_btn_original = 0;
static uint8_t custom_btn_max_btns = 0;
void subghz_custom_btn_set(uint8_t b) {
if(b > custom_btn_max_btns) {
custom_btn_id = 0;
bool subghz_custom_btn_set(uint8_t btn_id) {
if(btn_id > custom_btn_max_btns) {
custom_btn_id = SUBGHZ_CUSTOM_BTN_OK;
return false;
} else {
custom_btn_id = b;
custom_btn_id = btn_id;
return true;
}
}
@ -16,8 +18,8 @@ uint8_t subghz_custom_btn_get() {
return custom_btn_id;
}
void subghz_custom_btn_set_original(uint8_t b) {
custom_btn_original = b;
void subghz_custom_btn_set_original(uint8_t btn_code) {
custom_btn_original = btn_code;
}
uint8_t subghz_custom_btn_get_original() {
@ -31,4 +33,8 @@ void subghz_custom_btn_set_max(uint8_t b) {
void subghz_custom_btns_reset() {
custom_btn_original = 0;
custom_btn_max_btns = 0;
}
bool subghz_custom_btn_is_allowed() {
return custom_btn_max_btns != 0;
}

View File

@ -4,14 +4,23 @@
#include <stdint.h>
#include <stddef.h>
void subghz_custom_btn_set(uint8_t b);
// Default btn ID
#define SUBGHZ_CUSTOM_BTN_OK (0U)
#define SUBGHZ_CUSTOM_BTN_UP (1U)
#define SUBGHZ_CUSTOM_BTN_DOWN (2U)
#define SUBGHZ_CUSTOM_BTN_LEFT (3U)
#define SUBGHZ_CUSTOM_BTN_RIGHT (4U)
bool subghz_custom_btn_set(uint8_t btn_id);
uint8_t subghz_custom_btn_get();
void subghz_custom_btn_set_original(uint8_t b);
void subghz_custom_btn_set_original(uint8_t btn_code);
uint8_t subghz_custom_btn_get_original();
void subghz_custom_btn_set_max(uint8_t b);
void subghz_custom_btns_reset();
void subghz_custom_btns_reset();
bool subghz_custom_btn_is_allowed();

View File

@ -308,8 +308,8 @@ bool subghz_protocol_alutech_at_4n_create_data(
instance->generic.data_count_bit = 72;
bool res = subghz_protocol_alutech_at_4n_gen_data(instance, btn);
if(res) {
res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
if((res == SubGhzProtocolStatusOk) &&
if((subghz_block_generic_serialize(&instance->generic, flipper_format, preset) !=
SubGhzProtocolStatusOk) ||
!flipper_format_write_uint32(flipper_format, "CRC", &instance->crc, 1)) {
FURI_LOG_E(TAG, "Unable to add CRC");
res = false;
@ -318,6 +318,13 @@ bool subghz_protocol_alutech_at_4n_create_data(
return res;
}
/**
* Defines the button value for the current btn_id
* Basic set | 0x11 | 0x22 | 0xFF | 0x44 | 0x33 |
* @return Button code
*/
static uint8_t subghz_protocol_alutech_at_4n_get_btn_code();
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderAlutech instance
@ -333,102 +340,8 @@ static bool subghz_protocol_encoder_alutech_at_4n_get_upload(
subghz_custom_btn_set_original(btn);
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
btn = subghz_protocol_alutech_at_4n_get_btn_code();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x11:
btn = 0x22;
break;
case 0x22:
btn = 0x11;
break;
case 0xFF:
btn = 0x11;
break;
case 0x44:
btn = 0x11;
break;
case 0x33:
btn = 0x11;
break;
default:
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x11:
btn = 0x44;
break;
case 0x22:
btn = 0x44;
break;
case 0xFF:
btn = 0x44;
break;
case 0x44:
btn = 0xFF;
break;
case 0x33:
btn = 0x44;
break;
default:
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x11:
btn = 0x33;
break;
case 0x22:
btn = 0x33;
break;
case 0xFF:
btn = 0x33;
break;
case 0x44:
btn = 0x33;
break;
case 0x33:
btn = 0x22;
break;
default:
break;
}
}
if(custom_btn_id == 4) {
switch(original_btn_num) {
case 0x11:
btn = 0xFF;
break;
case 0x22:
btn = 0xFF;
break;
case 0xFF:
btn = 0x22;
break;
case 0x44:
btn = 0x22;
break;
case 0x33:
btn = 0xFF;
break;
default:
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
btn = original_btn_num;
}
// Gen new key
if(!subghz_protocol_alutech_at_4n_gen_data(instance, btn)) {
return false;
@ -788,6 +701,104 @@ SubGhzProtocolStatus subghz_protocol_decoder_alutech_at_4n_deserialize(
return ret;
}
static uint8_t subghz_protocol_alutech_at_4n_get_btn_code() {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x11:
btn = 0x22;
break;
case 0x22:
btn = 0x11;
break;
case 0xFF:
btn = 0x11;
break;
case 0x44:
btn = 0x11;
break;
case 0x33:
btn = 0x11;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x11:
btn = 0x44;
break;
case 0x22:
btn = 0x44;
break;
case 0xFF:
btn = 0x44;
break;
case 0x44:
btn = 0xFF;
break;
case 0x33:
btn = 0x44;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x11:
btn = 0x33;
break;
case 0x22:
btn = 0x33;
break;
case 0xFF:
btn = 0x33;
break;
case 0x44:
btn = 0x33;
break;
case 0x33:
btn = 0x22;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_RIGHT) {
switch(original_btn_code) {
case 0x11:
btn = 0xFF;
break;
case 0x22:
btn = 0xFF;
break;
case 0xFF:
btn = 0x22;
break;
case 0x44:
btn = 0x22;
break;
case 0x33:
btn = 0xFF;
break;
default:
break;
}
}
return btn;
}
void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderAlutech_at_4n* instance = context;

View File

@ -14,6 +14,10 @@
#define TAG "SubGhzProtocolKeeloq"
#define KEELOQ_PROG_MODE_OFF (0U)
#define KEELOQ_PROG_MODE_BFT (1U)
#define KEELOQ_PROG_MODE_APRIMATIC (2U)
static const SubGhzBlockConst subghz_protocol_keeloq_const = {
.te_short = 400,
.te_long = 800,
@ -92,10 +96,9 @@ static uint8_t klq_prog_mode;
static uint16_t temp_counter;
void keeloq_reset_original_btn() {
subghz_custom_btn_set_original(0);
subghz_custom_btn_set_max(0);
subghz_custom_btns_reset();
temp_counter = 0;
klq_prog_mode = 0;
klq_prog_mode = KEELOQ_PROG_MODE_OFF;
}
void keeloq_reset_mfname() {
@ -146,6 +149,7 @@ void subghz_protocol_encoder_keeloq_free(void* context) {
* Key generation from simple data
* @param instance Pointer to a SubGhzProtocolEncoderKeeloq* instance
* @param btn Button number, 4 bit
* @param counter_up increasing the counter if the value is true
*/
static bool subghz_protocol_keeloq_gen_data(
SubGhzProtocolEncoderKeeloq* instance,
@ -160,29 +164,30 @@ static bool subghz_protocol_keeloq_gen_data(
instance->manufacture_name = "";
}
// BFT programming mode on / off conditions
if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn == 0xF)) {
klq_prog_mode = 1;
}
if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && (klq_prog_mode == 1)) {
klq_prog_mode = 0;
}
// Aprimatic programming mode on / off conditions
if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn == 0xF)) {
klq_prog_mode = 2;
}
if((strcmp(instance->manufacture_name, "Aprimatic") == 0) && (btn != 0xF) &&
(klq_prog_mode == 2)) {
klq_prog_mode = 0;
// programming mode on / off conditions
if(strcmp(instance->manufacture_name, "BFT") == 0) {
// BFT programming mode on / off conditions
if(btn == 0xF) {
klq_prog_mode = KEELOQ_PROG_MODE_BFT;
} else if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) {
klq_prog_mode = KEELOQ_PROG_MODE_OFF;
}
} else if(strcmp(instance->manufacture_name, "Aprimatic") == 0) {
// Aprimatic programming mode on / off conditions
if(btn == 0xF) {
klq_prog_mode = KEELOQ_PROG_MODE_APRIMATIC;
} else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) {
klq_prog_mode = KEELOQ_PROG_MODE_OFF;
}
}
// If we using BFT programming mode we will trasmit its seed in hop part like original remote
if(klq_prog_mode == 1) {
if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) {
hop = instance->generic.seed;
} else if(klq_prog_mode == 2) {
} else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) {
// If we using Aprimatic programming mode we will trasmit some strange looking hop value, why? cuz manufacturer did it this way :)
hop = 0x1A2B3C4D;
}
if(counter_up && klq_prog_mode == 0) {
if(counter_up && klq_prog_mode == KEELOQ_PROG_MODE_OFF) {
if(instance->generic.cnt < 0xFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) {
instance->generic.cnt = 0;
@ -193,50 +198,8 @@ static bool subghz_protocol_keeloq_gen_data(
instance->generic.cnt = 0;
}
}
if(klq_prog_mode == 0) {
uint32_t decrypt = (uint32_t)btn << 28 |
(instance->generic.serial & 0x3FF)
<< 16 | //ToDo in some protocols the discriminator is 0
instance->generic.cnt;
if(strcmp(instance->manufacture_name, "Aprimatic") == 0) {
// Aprimatic uses 12bit serial number + 2bit APR1 "parity" bit in front of it replacing first 2 bits of serial
// Thats in theory! We need to check if this is true for all Aprimatic remotes but we got only 3 recordings to test
// For now lets assume that this is true for all Aprimatic remotes, if not we will need to add some more code here
uint32_t apri_serial = instance->generic.serial;
uint8_t apr1 = 0;
for(uint16_t i = 1; i != 0b10000000000; i <<= 1) {
if(apri_serial & i) apr1++;
}
apri_serial &= 0b00001111111111;
if(apr1 % 2 == 0) {
apri_serial |= 0b110000000000;
}
decrypt = btn << 28 | (apri_serial & 0xFFF) << 16 | instance->generic.cnt;
}
// DTM Neo, Came_Space uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode, Stilmatic(Schellenberg) -> 12bit normal learning
if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) ||
(strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) ||
(strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0) ||
(strcmp(instance->manufacture_name, "Stilmatic") == 0) ||
(strcmp(instance->manufacture_name, "Came_Space") == 0)) {
decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt;
}
// Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning
if((strcmp(instance->manufacture_name, "NICE_Smilo") == 0) ||
(strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) ||
(strcmp(instance->manufacture_name, "JCM_Tech") == 0) ||
(strcmp(instance->manufacture_name, "Normstahl") == 0)) {
decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt;
}
// Beninca / Allmatic -> no serial - simple XOR
if(strcmp(instance->manufacture_name, "Beninca") == 0) {
decrypt = btn << 28 | (0x000) << 16 | instance->generic.cnt;
}
if(klq_prog_mode == KEELOQ_PROG_MODE_OFF) {
// Protocols that do not use encryption
if(strcmp(instance->manufacture_name, "Unknown") == 0) {
code_found_reverse = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
@ -247,72 +210,120 @@ static bool subghz_protocol_keeloq_gen_data(
} else if(strcmp(instance->manufacture_name, "HCS101") == 0) {
hop = instance->generic.cnt << 16 | (btn & 0xF) << 12 | 0x000;
} else {
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
break;
case KEELOQ_LEARNING_NORMAL:
//Simple Learning
man =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_SECURE:
//Secure Learning
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->generic.seed, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
//Magic XOR type-1 Learning
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
instance->generic.serial, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1:
//Magic Serial Type 1 learning
man = subghz_protocol_keeloq_common_magic_serial_type1_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
if(kl_type == 1) {
hop =
subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
}
if(kl_type == 2) {
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
if(kl_type == 3) {
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->generic.seed, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
if(kl_type == 4) {
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
instance->generic.serial, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
break;
// Protocols that use encryption
uint32_t decrypt = (uint32_t)btn << 28 |
(instance->generic.serial & 0x3FF)
<< 16 | //ToDo in some protocols the discriminator is 0
instance->generic.cnt;
if(strcmp(instance->manufacture_name, "Aprimatic") == 0) {
// Aprimatic uses 12bit serial number + 2bit APR1 "parity" bit in front of it replacing first 2 bits of serial
// Thats in theory! We need to check if this is true for all Aprimatic remotes but we got only 3 recordings to test
// For now lets assume that this is true for all Aprimatic remotes, if not we will need to add some more code here
uint32_t apri_serial = instance->generic.serial;
uint8_t apr1 = 0;
for(uint16_t i = 1; i != 0b10000000000; i <<= 1) {
if(apri_serial & i) apr1++;
}
break;
apri_serial &= 0b00001111111111;
if(apr1 % 2 == 0) {
apri_serial |= 0b110000000000;
}
decrypt = btn << 28 | (apri_serial & 0xFFF) << 16 | instance->generic.cnt;
} else if(
(strcmp(instance->manufacture_name, "DTM_Neo") == 0) ||
(strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) ||
(strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0) ||
(strcmp(instance->manufacture_name, "Stilmatic") == 0) ||
(strcmp(instance->manufacture_name, "Came_Space") == 0)) {
// DTM Neo, Came_Space uses 12bit serial -> simple learning
// FAAC_RC,XT , Mutanco_Mutancode, Stilmatic(Schellenberg) 12bit serial -> normal learning
decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 |
instance->generic.cnt;
} else if(
(strcmp(instance->manufacture_name, "NICE_Smilo") == 0) ||
(strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) ||
(strcmp(instance->manufacture_name, "JCM_Tech") == 0) ||
(strcmp(instance->manufacture_name, "Normstahl") == 0)) {
// Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning
decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 |
instance->generic.cnt;
} else if(strcmp(instance->manufacture_name, "Beninca") == 0) {
decrypt = btn << 28 | (0x000) << 16 | instance->generic.cnt;
// Beninca / Allmatic -> no serial - simple XOR
}
}
for
M_EACH(
manufacture_code,
*subghz_keystore_get_data(instance->keystore),
SubGhzKeyArray_t) {
res = strcmp(
furi_string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop = subghz_protocol_keeloq_common_encrypt(
decrypt, manufacture_code->key);
break;
case KEELOQ_LEARNING_NORMAL:
//Simple Learning
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_SECURE:
//Secure Learning
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->generic.seed, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
//Magic XOR type-1 Learning
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
instance->generic.serial, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1:
//Magic Serial Type 1 learning
man = subghz_protocol_keeloq_common_magic_serial_type1_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
if(kl_type == 1) {
hop = subghz_protocol_keeloq_common_encrypt(
decrypt, manufacture_code->key);
}
if(kl_type == 2) {
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
if(kl_type == 3) {
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->generic.seed, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
if(kl_type == 4) {
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
instance->generic.serial, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
break;
}
break;
}
}
}
}
if(hop) {
uint64_t yek = (uint64_t)fix << 32 | hop;
instance->generic.data =
subghz_protocol_blocks_reverse_key(yek, instance->generic.data_count_bit);
}
return true;
} // What should happen if seed = 0 in bft programming mode
return true; // Always return true
}
bool subghz_protocol_keeloq_create_data(
@ -363,6 +374,14 @@ bool subghz_protocol_keeloq_bft_create_data(
return res;
}
/**
* Defines the button value for the current btn_id
* Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code |
* @param last_btn_code Candidate for the last button
* @return Button code
*/
static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code);
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance
@ -380,9 +399,9 @@ static bool
if(instance->manufacture_name == 0x0) {
instance->manufacture_name = "";
}
if(klq_prog_mode == 1) {
if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) {
instance->manufacture_name = "BFT";
} else if(klq_prog_mode == 2) {
} else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) {
instance->manufacture_name = "Aprimatic";
}
uint8_t klq_last_custom_btn = 0xA;
@ -391,118 +410,9 @@ static bool
klq_last_custom_btn = 0xF;
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0xA:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
case 0xF:
btn = 0x1;
break;
btn = subghz_protocol_keeloq_get_btn_code(klq_last_custom_btn);
default:
btn = 0x1;
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0xA:
btn = 0x4;
break;
case 0x4:
btn = klq_last_custom_btn;
break;
case 0x8:
btn = 0x4;
break;
case 0xF:
btn = 0x4;
break;
default:
btn = 0x4;
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0xA:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
case 0xF:
btn = 0x8;
break;
default:
btn = 0x8;
break;
}
}
if(custom_btn_id == 4) {
switch(original_btn_num) {
case 0x1:
btn = klq_last_custom_btn;
break;
case 0x2:
btn = klq_last_custom_btn;
break;
case 0xA:
btn = 0x2;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = klq_last_custom_btn;
break;
case 0xF:
btn = 0x2;
break;
default:
btn = 0x2;
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
btn = original_btn_num;
}
// Generate new key
if(subghz_protocol_keeloq_gen_data(instance, btn, true)) {
// OK
} else {
@ -669,7 +579,7 @@ void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) {
instance->keystore = subghz_environment_get_keystore(environment);
instance->manufacture_from_file = furi_string_alloc();
klq_prog_mode = 0;
klq_prog_mode = KEELOQ_PROG_MODE_OFF;
return instance;
}
@ -829,185 +739,19 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
uint8_t btn = (uint8_t)(fix >> 28);
uint32_t decrypt = 0;
uint64_t man;
int res = 0;
bool mf_not_set = false;
if(mfname == 0x0) {
mfname = "";
}
if(strcmp(mfname, "") == 0) {
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_NORMAL:
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_SECURE:
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->seed, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1:
man = subghz_protocol_keeloq_common_magic_serial_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2:
man = subghz_protocol_keeloq_common_magic_serial_type2_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3:
man = subghz_protocol_keeloq_common_magic_serial_type3_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 1;
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 1;
return 1;
}
//###########################
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 2;
return 1;
}
// Check for mirrored man
man = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 2;
return 1;
}
// Secure Learning
man = subghz_protocol_keeloq_common_secure_learning(
fix, instance->seed, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 3;
return 1;
}
// Check for mirrored man
man = subghz_protocol_keeloq_common_secure_learning(fix, instance->seed, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 3;
return 1;
}
// Magic xor type1 learning
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 4;
return 1;
}
// Check for mirrored man
man = subghz_protocol_keeloq_common_magic_xor_type1_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 4;
return 1;
}
break;
}
}
} else if(strcmp(mfname, "Unknown") == 0) {
if(strcmp(mfname, "Unknown") == 0) {
return 1;
} else {
} else if(strcmp(mfname, "") == 0) {
mf_not_set = true;
}
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), mfname);
if(res == 0) {
if(mf_not_set || (strcmp(furi_string_get_cstr(manufacture_code->name), mfname) == 0)) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
@ -1060,6 +804,26 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_2:
man = subghz_protocol_keeloq_common_magic_serial_type2_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_3:
man = subghz_protocol_keeloq_common_magic_serial_type3_learning(
fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
@ -1069,6 +833,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
kl_type = 1;
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
@ -1076,6 +841,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
@ -1083,6 +849,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
kl_type = 1;
return 1;
}
//###########################
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
@ -1153,7 +920,6 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
}
}
}
}
*manufacture_name = "Unknown";
mfname = "Unknown";
@ -1170,8 +936,8 @@ static void subghz_protocol_keeloq_check_remote_controller(
uint32_t key_fix = key >> 32;
uint32_t key_hop = key & 0x00000000ffffffff;
// If we are in BFT programming mode we will set previous remembered counter and skip mf keys check
if(klq_prog_mode == 0) {
// If we are in BFT / Aprimatic programming mode we will set previous remembered counter and skip mf keys check
if(klq_prog_mode == KEELOQ_PROG_MODE_OFF) {
// Check key AN-Motors
if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) &&
(key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) {
@ -1188,11 +954,11 @@ static void subghz_protocol_keeloq_check_remote_controller(
}
temp_counter = instance->cnt;
} else if(klq_prog_mode == 1) {
} else if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) {
*manufacture_name = "BFT";
mfname = *manufacture_name;
instance->cnt = temp_counter;
} else if(klq_prog_mode == 2) {
} else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) {
*manufacture_name = "Aprimatic";
mfname = *manufacture_name;
instance->cnt = temp_counter;
@ -1302,6 +1068,125 @@ SubGhzProtocolStatus
return res;
}
static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
if(last_btn_code == 0) {
last_btn_code = 0xA;
}
// Set custom button
// Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code |
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0xA:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
case 0xF:
btn = 0x1;
break;
default:
btn = 0x1;
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0xA:
btn = 0x4;
break;
case 0x4:
btn = last_btn_code;
break;
case 0x8:
btn = 0x4;
break;
case 0xF:
btn = 0x4;
break;
default:
btn = 0x4;
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0xA:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
case 0xF:
btn = 0x8;
break;
default:
btn = 0x8;
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_RIGHT) {
switch(original_btn_code) {
case 0x1:
btn = last_btn_code;
break;
case 0x2:
btn = last_btn_code;
break;
case 0xA:
btn = 0x2;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = last_btn_code;
break;
case 0xF:
btn = 0x2;
break;
default:
btn = 0x2;
break;
}
}
return btn;
}
void subghz_protocol_decoder_keeloq_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderKeeloq* instance = context;

View File

@ -117,6 +117,13 @@ void subghz_protocol_encoder_nice_flor_s_free(void* context) {
static void subghz_protocol_nice_one_get_data(uint8_t* p, uint8_t num_parcel, uint8_t hold_bit);
/**
* Defines the button value for the current btn_id
* Basic set | 0x1 | 0x2 | 0x4 | 0x8 |
* @return Button code
*/
static uint8_t subghz_protocol_nice_flor_s_get_btn_code();
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderNiceFlorS instance
@ -135,71 +142,7 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload(
subghz_custom_btn_set_original(btn);
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
default:
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = 0x4;
break;
default:
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
default:
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
btn = original_btn_num;
}
btn = subghz_protocol_nice_flor_s_get_btn_code();
size_t size_upload = ((instance->generic.data_count_bit * 2) + ((37 + 2 + 2) * 2) * 16);
if(size_upload > instance->encoder.size_upload) {
@ -808,6 +751,74 @@ SubGhzProtocolStatus
return ret;
}
static uint8_t subghz_protocol_nice_flor_s_get_btn_code() {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = 0x4;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
default:
break;
}
}
return btn;
}
void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderNiceFlorS* instance = context;

View File

@ -375,6 +375,13 @@ static uint64_t subghz_protocol_secplus_v2_encode_half(uint8_t roll_array[], uin
return data;
}
/**
* Defines the button value for the current btn_id
* Basic set | 0x68 | 0x80 | 0x81 | 0xE2 |
* @return Button code
*/
static uint8_t subghz_protocol_secplus_v2_get_btn_code();
/**
* Security+ 2.0 message encoding
* @param instance SubGhzProtocolEncoderSecPlus_v2*
@ -386,70 +393,8 @@ static void subghz_protocol_secplus_v2_encode(SubGhzProtocolEncoderSecPlus_v2* i
subghz_custom_btn_set_original(instance->generic.btn);
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
instance->generic.btn = subghz_protocol_secplus_v2_get_btn_code();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x68:
instance->generic.btn = 0x80;
break;
case 0x80:
instance->generic.btn = 0x68;
break;
case 0x81:
instance->generic.btn = 0x80;
break;
case 0xE2:
instance->generic.btn = 0x80;
break;
default:
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x68:
instance->generic.btn = 0x81;
break;
case 0x80:
instance->generic.btn = 0x81;
break;
case 0x81:
instance->generic.btn = 0x68;
break;
case 0xE2:
instance->generic.btn = 0x81;
break;
default:
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x68:
instance->generic.btn = 0xE2;
break;
case 0x80:
instance->generic.btn = 0xE2;
break;
case 0x81:
instance->generic.btn = 0xE2;
break;
case 0xE2:
instance->generic.btn = 0x68;
break;
default:
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
instance->generic.btn = original_btn_num;
}
uint32_t fixed_1[1] = {instance->generic.btn << 12 | instance->generic.serial >> 20};
uint32_t fixed_2[1] = {instance->generic.serial & 0xFFFFF};
uint8_t rolling_digits[18] = {0};
@ -888,6 +833,74 @@ SubGhzProtocolStatus
return ret;
}
static uint8_t subghz_protocol_secplus_v2_get_btn_code() {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x68:
btn = 0x80;
break;
case 0x80:
btn = 0x68;
break;
case 0x81:
btn = 0x80;
break;
case 0xE2:
btn = 0x80;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x68:
btn = 0x81;
break;
case 0x80:
btn = 0x81;
break;
case 0x81:
btn = 0x68;
break;
case 0xE2:
btn = 0x81;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x68:
btn = 0xE2;
break;
case 0x80:
btn = 0xE2;
break;
case 0x81:
btn = 0xE2;
break;
case 0xE2:
btn = 0x68;
break;
default:
break;
}
}
return btn;
}
void subghz_protocol_decoder_secplus_v2_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderSecPlus_v2* instance = context;

View File

@ -97,6 +97,13 @@ void subghz_protocol_encoder_somfy_telis_free(void* context) {
free(instance);
}
/**
* Defines the button value for the current btn_id
* Basic set | 0x1 | 0x2 | 0x4 | 0x8 |
* @return Button code
*/
static uint8_t subghz_protocol_somfy_telis_get_btn_code();
static bool subghz_protocol_somfy_telis_gen_data(
SubGhzProtocolEncoderSomfyTelis* instance,
uint8_t btn,
@ -115,71 +122,7 @@ static bool subghz_protocol_somfy_telis_gen_data(
subghz_custom_btn_set_original(btn);
}
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_num = subghz_custom_btn_get_original();
// Set custom button
if(custom_btn_id == 1) {
switch(original_btn_num) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
default:
break;
}
}
if(custom_btn_id == 2) {
switch(original_btn_num) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = 0x4;
break;
default:
break;
}
}
if(custom_btn_id == 3) {
switch(original_btn_num) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
default:
break;
}
}
if((custom_btn_id == 0) && (original_btn_num != 0)) {
btn = original_btn_num;
}
btn = subghz_protocol_somfy_telis_get_btn_code();
if(instance->generic.cnt < 0xFFFF) {
if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) {
@ -725,6 +668,74 @@ SubGhzProtocolStatus
subghz_protocol_somfy_telis_const.min_count_bit_for_found);
}
static uint8_t subghz_protocol_somfy_telis_get_btn_code() {
uint8_t custom_btn_id = subghz_custom_btn_get();
uint8_t original_btn_code = subghz_custom_btn_get_original();
uint8_t btn = original_btn_code;
// Set custom button
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
// Restore original button code
btn = original_btn_code;
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {
switch(original_btn_code) {
case 0x1:
btn = 0x2;
break;
case 0x2:
btn = 0x1;
break;
case 0x4:
btn = 0x1;
break;
case 0x8:
btn = 0x1;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_DOWN) {
switch(original_btn_code) {
case 0x1:
btn = 0x4;
break;
case 0x2:
btn = 0x4;
break;
case 0x4:
btn = 0x2;
break;
case 0x8:
btn = 0x4;
break;
default:
break;
}
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_LEFT) {
switch(original_btn_code) {
case 0x1:
btn = 0x8;
break;
case 0x2:
btn = 0x8;
break;
case 0x4:
btn = 0x8;
break;
case 0x8:
btn = 0x2;
break;
default:
break;
}
}
return btn;
}
void subghz_protocol_decoder_somfy_telis_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderSomfyTelis* instance = context;

View File

@ -163,36 +163,41 @@ static bool
instance->generic.data, instance->generic.data_count_bit);
hop = code_found_reverse & 0x00000000ffffffff;
} else {
for
M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
break;
case KEELOQ_LEARNING_NORMAL:
//Normal Learning
man =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
if(kl_type == 1) {
for
M_EACH(
manufacture_code,
*subghz_keystore_get_data(instance->keystore),
SubGhzKeyArray_t) {
res = strcmp(
furi_string_get_cstr(manufacture_code->name), instance->manufacture_name);
if(res == 0) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
//Simple Learning
hop =
subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
}
if(kl_type == 2) {
break;
case KEELOQ_LEARNING_NORMAL:
//Normal Learning
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
break;
case KEELOQ_LEARNING_UNKNOWN:
if(kl_type == 1) {
hop = subghz_protocol_keeloq_common_encrypt(
decrypt, manufacture_code->key);
}
if(kl_type == 2) {
man = subghz_protocol_keeloq_common_normal_learning(
fix, manufacture_code->key);
hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
}
break;
}
break;
}
break;
}
}
}
if(hop) {
uint64_t yek = (uint64_t)fix << 32 | hop;
@ -517,90 +522,19 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector(
uint8_t btn = (uint8_t)(fix >> 24);
uint32_t decrypt = 0;
uint64_t man_normal_learning;
int res = 0;
bool mf_not_set = false;
if(mfname == 0x0) {
mfname = "";
}
if(strcmp(mfname, "") == 0) {
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_NORMAL:
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
return 1;
}
break;
case KEELOQ_LEARNING_UNKNOWN:
// Simple Learning
decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 1;
return 1;
}
// Check for mirrored man
uint64_t man_rev = 0;
uint64_t man_rev_byte = 0;
for(uint8_t i = 0; i < 64; i += 8) {
man_rev_byte = (uint8_t)(manufacture_code->key >> i);
man_rev = man_rev | man_rev_byte << (56 - i);
}
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 1;
return 1;
}
//###########################
// Normal Learning
// https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 2;
return 1;
}
// Check for mirrored man
man_normal_learning = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_normal_learning);
if(subghz_protocol_star_line_check_decrypt(instance, decrypt, btn, end_serial)) {
*manufacture_name = furi_string_get_cstr(manufacture_code->name);
mfname = *manufacture_name;
kl_type = 2;
return 1;
}
break;
}
}
} else if(strcmp(mfname, "Unknown") == 0) {
if(strcmp(mfname, "Unknown") == 0) {
return 1;
} else {
} else if(strcmp(mfname, "") == 0) {
mf_not_set = true;
}
for
M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
res = strcmp(furi_string_get_cstr(manufacture_code->name), mfname);
if(res == 0) {
if(mf_not_set || (strcmp(furi_string_get_cstr(manufacture_code->name), mfname) == 0)) {
switch(manufacture_code->type) {
case KEELOQ_LEARNING_SIMPLE:
// Simple Learning
@ -663,7 +597,6 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector(
kl_type = 2;
return 1;
}
// Check for mirrored man
man_normal_learning =
subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
@ -679,7 +612,6 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector(
}
}
}
}
*manufacture_name = "Unknown";
mfname = "Unknown";