Skip to content

Commit 67e191b

Browse files
committed
Keeloq ultimate, and some fixes and improvements [ci skip]
- fix repeat values - fix endless tx missing - add mode 7 aka counter bypass - take some ram - free some ram - fix comments
1 parent 1088e34 commit 67e191b

File tree

10 files changed

+144
-96
lines changed

10 files changed

+144
-96
lines changed

applications/main/subghz/scenes/subghz_scene_signal_settings.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ static uint8_t* btn_byte_ptr = NULL;
2222

2323
static uint8_t submenu_called = 0;
2424

25-
#define COUNTER_MODE_COUNT 7
25+
#define COUNTER_MODE_COUNT 8
2626
static const char* const counter_mode_text[COUNTER_MODE_COUNT] = {
2727
"System",
2828
"Mode 1",
@@ -31,6 +31,7 @@ static const char* const counter_mode_text[COUNTER_MODE_COUNT] = {
3131
"Mode 4",
3232
"Mode 5",
3333
"Mode 6",
34+
"Mode 7",
3435
};
3536

3637
static const int32_t counter_mode_value[COUNTER_MODE_COUNT] = {
@@ -41,6 +42,7 @@ static const int32_t counter_mode_value[COUNTER_MODE_COUNT] = {
4142
4,
4243
5,
4344
6,
45+
7,
4446
};
4547

4648
typedef struct {
@@ -53,7 +55,7 @@ static Protocols protocols[] = {
5355
{"Nice FloR-S", 3},
5456
{"CAME Atomo", 4},
5557
{"Alutech AT-4N", 3},
56-
{"KeeLoq", 7},
58+
{"KeeLoq", 8},
5759
{"Phoenix_V2", 3},
5860
};
5961

lib/subghz/protocols/came_twee.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment) {
110110
instance->generic.protocol_name = instance->base.protocol->name;
111111

112112
instance->encoder.repeat = 3;
113-
instance->encoder.size_upload = 1536; //max upload 92*14 = 1288 !!!!
113+
instance->encoder.size_upload = 1536; // 1308
114114
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
115115
instance->encoder.is_running = false;
116116
return instance;

lib/subghz/protocols/elplast.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void* subghz_protocol_encoder_elplast_alloc(SubGhzEnvironment* environment) {
7474
instance->generic.protocol_name = instance->base.protocol->name;
7575

7676
instance->encoder.repeat = 3;
77-
instance->encoder.size_upload = 256;
77+
instance->encoder.size_upload = 64;
7878
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
7979
instance->encoder.is_running = false;
8080
return instance;

lib/subghz/protocols/hay21.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ void* subghz_protocol_encoder_hay21_alloc(SubGhzEnvironment* environment) {
7676
instance->generic.protocol_name = instance->base.protocol->name;
7777

7878
instance->encoder.repeat = 3;
79-
instance->encoder.size_upload = 256;
79+
instance->encoder.size_upload = 64;
8080
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
8181
instance->encoder.is_running = false;
8282
return instance;

lib/subghz/protocols/hollarm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ void* subghz_protocol_encoder_hollarm_alloc(SubGhzEnvironment* environment) {
7777
instance->generic.protocol_name = instance->base.protocol->name;
7878

7979
instance->encoder.repeat = 3;
80-
instance->encoder.size_upload = 256;
80+
instance->encoder.size_upload = 128;
8181
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
8282
instance->encoder.is_running = false;
8383
return instance;

lib/subghz/protocols/hormann.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) {
8080
instance->base.protocol = &subghz_protocol_hormann;
8181
instance->generic.protocol_name = instance->base.protocol->name;
8282

83-
instance->encoder.repeat = 3;
84-
instance->encoder.size_upload = 2048;
83+
instance->encoder.repeat = 1;
84+
instance->encoder.size_upload = 1850; // 1801
8585
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
8686
instance->encoder.is_running = false;
8787
return instance;
@@ -110,7 +110,6 @@ static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHorm
110110
} else {
111111
instance->encoder.size_upload = size_upload;
112112
}
113-
instance->encoder.repeat = 3; //original remote does 10 repeats
114113

115114
for(size_t repeat = 0; repeat < 20; repeat++) {
116115
//Send start bit
@@ -137,6 +136,7 @@ static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHorm
137136
}
138137
instance->encoder.upload[index++] =
139138
level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 24);
139+
140140
return true;
141141
}
142142

lib/subghz/protocols/keeloq.c

Lines changed: 130 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,23 @@ static uint32_t subghz_protocol_keeloq_check_remote_controller(
100100
SubGhzKeystore* keystore,
101101
const char** manufacture_name);
102102

103+
/**
104+
* Defines the button value for the current btn_id
105+
* Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code |
106+
* @param last_btn_code Candidate for the last button
107+
* @return Button code
108+
*/
109+
static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code);
110+
103111
void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment) {
104112
SubGhzProtocolEncoderKeeloq* instance = malloc(sizeof(SubGhzProtocolEncoderKeeloq));
105113

106114
instance->base.protocol = &subghz_protocol_keeloq;
107115
instance->generic.protocol_name = instance->base.protocol->name;
108116
instance->keystore = subghz_environment_get_keystore(environment);
109117

110-
instance->encoder.repeat = 100;
111-
instance->encoder.size_upload = 256;
118+
instance->encoder.repeat = 3;
119+
instance->encoder.size_upload = 1100;
112120
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
113121
instance->encoder.is_running = false;
114122

@@ -134,7 +142,57 @@ void subghz_protocol_encoder_keeloq_free(void* context) {
134142
static bool subghz_protocol_keeloq_gen_data(
135143
SubGhzProtocolEncoderKeeloq* instance,
136144
uint8_t btn,
137-
bool counter_up) {
145+
bool counter_up,
146+
bool skip_btn_check) {
147+
// No mf name set? -> set to ""
148+
if(instance->manufacture_name == 0x0) {
149+
instance->manufacture_name = "";
150+
}
151+
// add gendata part
152+
ProgMode prog_mode = subghz_custom_btn_get_prog_mode();
153+
if(!skip_btn_check && (keeloq_counter_mode != 7)) {
154+
// Save original button
155+
if(subghz_custom_btn_get_original() == 0) {
156+
subghz_custom_btn_set_original(btn);
157+
}
158+
159+
// Prog mode checks and extra fixage of MF Names
160+
if(prog_mode == PROG_MODE_KEELOQ_BFT) {
161+
instance->manufacture_name = "BFT";
162+
} else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) {
163+
instance->manufacture_name = "Aprimatic";
164+
} else if(prog_mode == PROG_MODE_KEELOQ_DEA_MIO) {
165+
instance->manufacture_name = "Dea_Mio";
166+
}
167+
// Custom button (programming mode button) for BFT, Aprimatic, Dea_Mio
168+
uint8_t klq_last_custom_btn = 0xA;
169+
if((strcmp(instance->manufacture_name, "BFT") == 0) ||
170+
(strcmp(instance->manufacture_name, "Aprimatic") == 0) ||
171+
(strcmp(instance->manufacture_name, "Dea_Mio") == 0) ||
172+
(strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0)) {
173+
klq_last_custom_btn = 0xF;
174+
} else if(
175+
(strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) ||
176+
(strcmp(instance->manufacture_name, "Monarch") == 0) ||
177+
(strcmp(instance->manufacture_name, "NICE_Smilo") == 0)) {
178+
klq_last_custom_btn = 0xB;
179+
} else if(
180+
(strcmp(instance->manufacture_name, "Novoferm") == 0) ||
181+
(strcmp(instance->manufacture_name, "Stilmatic") == 0)) {
182+
klq_last_custom_btn = 0x9;
183+
} else if(
184+
(strcmp(instance->manufacture_name, "EcoStar") == 0) ||
185+
(strcmp(instance->manufacture_name, "Sommer") == 0)) {
186+
klq_last_custom_btn = 0x6;
187+
} else if((strcmp(instance->manufacture_name, "AN-Motors") == 0)) {
188+
klq_last_custom_btn = 0xC;
189+
} else if((strcmp(instance->manufacture_name, "Cardin_S449") == 0)) {
190+
klq_last_custom_btn = 0xD;
191+
}
192+
193+
btn = subghz_protocol_keeloq_get_btn_code(klq_last_custom_btn);
194+
}
195+
// end gendata part
138196
// override button if we change it with signal settings button editor
139197
if(subghz_block_generic_global_button_override_get(&btn))
140198
FURI_LOG_D(TAG, "Button sucessfully changed to 0x%X", btn);
@@ -150,7 +208,6 @@ static bool subghz_protocol_keeloq_gen_data(
150208
}
151209

152210
// programming mode on / off conditions
153-
ProgMode prog_mode = subghz_custom_btn_get_prog_mode();
154211
if(strcmp(instance->manufacture_name, "BFT") == 0) {
155212
// BFT programming mode on / off conditions
156213
if(btn == 0xF) {
@@ -259,8 +316,16 @@ static bool subghz_protocol_keeloq_gen_data(
259316
} else {
260317
instance->generic.cnt = 0xFFFF;
261318
}
262-
} else {
319+
} else if(keeloq_counter_mode == 6) {
263320
// Mode 6 - Freeze counter
321+
} else {
322+
// Mode 7 - Make 12 signals in row with mode 2
323+
// + 0x3333 each time
324+
if((instance->generic.cnt + 0x3333) > 0xFFFF) {
325+
instance->generic.cnt = 0;
326+
} else {
327+
instance->generic.cnt += 0x3333;
328+
}
264329
}
265330
}
266331
if(prog_mode == PROG_MODE_OFF) {
@@ -437,7 +502,7 @@ bool subghz_protocol_keeloq_create_data(
437502
instance->generic.cnt = cnt;
438503
instance->manufacture_name = manufacture_name;
439504
instance->generic.data_count_bit = 64;
440-
if(subghz_protocol_keeloq_gen_data(instance, btn, false)) {
505+
if(subghz_protocol_keeloq_gen_data(instance, btn, false, true)) {
441506
return (
442507
subghz_block_generic_serialize(&instance->generic, flipper_format, preset) ==
443508
SubGhzProtocolStatusOk);
@@ -463,96 +528,30 @@ bool subghz_protocol_keeloq_bft_create_data(
463528
instance->manufacture_name = manufacture_name;
464529
instance->generic.data_count_bit = 64;
465530
// hehehehe
466-
if(subghz_protocol_keeloq_gen_data(instance, btn, false)) {
531+
if(subghz_protocol_keeloq_gen_data(instance, btn, false, true)) {
467532
return (
468533
subghz_block_generic_serialize(&instance->generic, flipper_format, preset) ==
469534
SubGhzProtocolStatusOk);
470535
}
471536
return false;
472537
}
473538

474-
/**
475-
* Defines the button value for the current btn_id
476-
* Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code |
477-
* @param last_btn_code Candidate for the last button
478-
* @return Button code
479-
*/
480-
static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code);
481-
482-
/**
483-
* Generating an upload from data.
484-
* @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance
485-
* @return true On success
486-
*/
487-
static bool
488-
subghz_protocol_encoder_keeloq_get_upload(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) {
539+
static size_t subghz_protocol_encoder_keeloq_encode_to_timings(
540+
SubGhzProtocolEncoderKeeloq* instance,
541+
uint8_t btn,
542+
bool counter_up,
543+
size_t index) {
489544
furi_assert(instance);
490-
491-
// Save original button
492-
if(subghz_custom_btn_get_original() == 0) {
493-
subghz_custom_btn_set_original(btn);
494-
}
495-
496-
// No mf name set? -> set to ""
497-
if(instance->manufacture_name == 0x0) {
498-
instance->manufacture_name = "";
499-
}
500-
// Prog mode checks and extra fixage of MF Names
501-
ProgMode prog_mode = subghz_custom_btn_get_prog_mode();
502-
if(prog_mode == PROG_MODE_KEELOQ_BFT) {
503-
instance->manufacture_name = "BFT";
504-
} else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) {
505-
instance->manufacture_name = "Aprimatic";
506-
} else if(prog_mode == PROG_MODE_KEELOQ_DEA_MIO) {
507-
instance->manufacture_name = "Dea_Mio";
508-
}
509-
// Custom button (programming mode button) for BFT, Aprimatic, Dea_Mio
510-
uint8_t klq_last_custom_btn = 0xA;
511-
if((strcmp(instance->manufacture_name, "BFT") == 0) ||
512-
(strcmp(instance->manufacture_name, "Aprimatic") == 0) ||
513-
(strcmp(instance->manufacture_name, "Dea_Mio") == 0) ||
514-
(strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0)) {
515-
klq_last_custom_btn = 0xF;
516-
} else if(
517-
(strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) ||
518-
(strcmp(instance->manufacture_name, "Monarch") == 0) ||
519-
(strcmp(instance->manufacture_name, "NICE_Smilo") == 0)) {
520-
klq_last_custom_btn = 0xB;
521-
} else if(
522-
(strcmp(instance->manufacture_name, "Novoferm") == 0) ||
523-
(strcmp(instance->manufacture_name, "Stilmatic") == 0)) {
524-
klq_last_custom_btn = 0x9;
525-
} else if(
526-
(strcmp(instance->manufacture_name, "EcoStar") == 0) ||
527-
(strcmp(instance->manufacture_name, "Sommer") == 0)) {
528-
klq_last_custom_btn = 0x6;
529-
} else if((strcmp(instance->manufacture_name, "AN-Motors") == 0)) {
530-
klq_last_custom_btn = 0xC;
531-
} else if((strcmp(instance->manufacture_name, "Cardin_S449") == 0)) {
532-
klq_last_custom_btn = 0xD;
533-
}
534-
535-
uint32_t gap_duration = subghz_protocol_keeloq_const.te_short * 40;
536-
if((strcmp(instance->manufacture_name, "Sommer") == 0)) {
537-
gap_duration = subghz_protocol_keeloq_const.te_short * 29;
538-
}
539-
540-
btn = subghz_protocol_keeloq_get_btn_code(klq_last_custom_btn);
541-
542545
// Generate new key
543-
if(subghz_protocol_keeloq_gen_data(instance, btn, true)) {
546+
if(subghz_protocol_keeloq_gen_data(instance, btn, counter_up, false)) {
544547
// OK
545548
} else {
546549
return false;
547550
}
548551

549-
size_t index = 0;
550-
size_t size_upload = 11 * 2 + 2 + (instance->generic.data_count_bit * 2) + 4;
551-
if(size_upload > instance->encoder.size_upload) {
552-
FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
553-
return false;
554-
} else {
555-
instance->encoder.size_upload = size_upload;
552+
uint32_t gap_duration = subghz_protocol_keeloq_const.te_short * 40;
553+
if((strcmp(instance->manufacture_name, "Sommer") == 0)) {
554+
gap_duration = subghz_protocol_keeloq_const.te_short * 29;
556555
}
557556

558557
//Send header
@@ -593,6 +592,52 @@ static bool
593592
level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
594593
instance->encoder.upload[index++] = level_duration_make(false, gap_duration);
595594

595+
return index;
596+
}
597+
598+
/**
599+
* Generating an upload from data.
600+
* @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance
601+
* @return true On success
602+
*/
603+
static bool
604+
subghz_protocol_encoder_keeloq_get_upload(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) {
605+
furi_assert(instance);
606+
607+
instance->encoder.size_upload = 0;
608+
size_t upindex = 0;
609+
610+
if(keeloq_counter_mode == 7) {
611+
uint16_t temp_cnt = instance->generic.cnt;
612+
instance->encoder.repeat = 1;
613+
for(uint8_t i = 7; i > 0; i--) {
614+
if(i == 3) {
615+
instance->generic.cnt = 0x0000;
616+
upindex = subghz_protocol_encoder_keeloq_encode_to_timings(
617+
instance, (uint8_t)0x00, false, upindex);
618+
continue;
619+
} else if(i == 2) {
620+
instance->generic.cnt = temp_cnt;
621+
upindex = subghz_protocol_encoder_keeloq_encode_to_timings(
622+
instance, btn, false, upindex);
623+
continue;
624+
} else if(i == 1) {
625+
instance->generic.cnt = temp_cnt + 1;
626+
upindex = subghz_protocol_encoder_keeloq_encode_to_timings(
627+
instance, btn, false, upindex);
628+
continue;
629+
}
630+
upindex = subghz_protocol_encoder_keeloq_encode_to_timings(
631+
instance, (uint8_t)0x00, true, upindex);
632+
}
633+
instance->encoder.size_upload = upindex;
634+
return true;
635+
} else {
636+
instance->encoder.repeat = 3;
637+
instance->encoder.size_upload =
638+
subghz_protocol_encoder_keeloq_encode_to_timings(instance, btn, true, upindex);
639+
}
640+
596641
return true;
597642
}
598643

@@ -719,7 +764,7 @@ LevelDuration subghz_protocol_encoder_keeloq_yield(void* context) {
719764
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
720765

721766
if(++instance->encoder.front == instance->encoder.size_upload) {
722-
instance->encoder.repeat--;
767+
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
723768
instance->encoder.front = 0;
724769
}
725770

@@ -1366,7 +1411,8 @@ static uint8_t subghz_protocol_keeloq_get_btn_code(uint8_t last_btn_code) {
13661411

13671412
// Set custom button
13681413
// Basic set | 0x1 | 0x2 | 0x4 | 0x8 | 0xA or Special Learning Code |
1369-
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0)) {
1414+
if((custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) && (original_btn_code != 0) &&
1415+
(keeloq_counter_mode != 7)) {
13701416
// Restore original button code
13711417
btn = original_btn_code;
13721418
} else if(custom_btn_id == SUBGHZ_CUSTOM_BTN_UP) {

0 commit comments

Comments
 (0)