Forráskód Böngészése

Merge pull request #83 from SpenserCai/master

Support PT2262
MMX 10 hónapja
szülő
commit
6f81168be2

+ 7 - 2
.gitignore

@@ -1,3 +1,8 @@
-/.idea/.idea.subbrute.dir/.idea/workspace.xml
-
+dist/*
+.vscode
+.clang-format
+.clangd
+.editorconfig
+.env
+.ufbt
 .DS_Store

+ 0 - 11
.vscode/settings.json

@@ -1,11 +0,0 @@
-{
-    "githubPullRequests.ignoredPullRequestBranches": [
-        "master"
-    ],
-    "workbench.colorCustomizations": {
-        "list.errorForeground": "#00AA00",
-        "list.warningForeground": "#00d9ff",
-        "gitDecoration.modifiedResourceForeground": "#00ffb3",
-        "gitDecoration.untrackedResourceForeground": "#f7aeae"
-    }
-}

+ 71 - 7
helpers/subbrute_worker.c

@@ -5,9 +5,11 @@
 #include <flipper_format.h>
 #include <flipper_format_i.h>
 #include <lib/subghz/subghz_protocol_registry.h>
+// use to clear custom_btn
+#include <lib/subghz/blocks/custom_btn.h>
 
-#define TAG "SubBruteWorker"
-#define SUBBRUTE_TX_TIMEOUT 6
+#define TAG                               "SubBruteWorker"
+#define SUBBRUTE_TX_TIMEOUT               6
 #define SUBBRUTE_MANUAL_TRANSMIT_INTERVAL 250
 
 SubBruteWorker* subbrute_worker_alloc(const SubGhzDevice* radio_device) {
@@ -19,6 +21,7 @@ SubBruteWorker* subbrute_worker_alloc(const SubGhzDevice* radio_device) {
     instance->initiated = false;
     instance->last_time_tx_data = 0;
     instance->load_index = 0;
+    instance->opencode = 0;
 
     instance->thread = furi_thread_alloc();
     furi_thread_set_name(instance->thread, "SubBruteAttackWorker");
@@ -82,6 +85,34 @@ bool subbrute_worker_set_step(SubBruteWorker* instance, uint64_t step) {
     return true;
 }
 
+void subbrute_worker_set_opencode(SubBruteWorker* instance, uint8_t opencode) {
+    // furi_assert(instance);
+    // if(!subbrute_worker_can_manual_transmit(instance)) {
+    //     FURI_LOG_W(TAG, "Cannot set opencode during running mode");
+    //
+    //     return false;
+    // }
+    instance->opencode = opencode;
+
+    // return true;
+}
+
+uint8_t subbrute_worker_get_opencode(SubBruteWorker* instance) {
+    return instance->opencode;
+}
+
+bool subbrute_worker_get_is_pt2262(SubBruteWorker* instance) {
+    if(instance->attack == SubBruteAttackPT226224bit315 ||
+       instance->attack == SubBruteAttackPT226224bit418 ||
+       instance->attack == SubBruteAttackPT226224bit430 ||
+       instance->attack == SubBruteAttackPT226224bit4305 ||
+       instance->attack == SubBruteAttackPT226224bit433) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
 bool subbrute_worker_init_default_attack(
     SubBruteWorker* instance,
     SubBruteAttacks attack_type,
@@ -102,6 +133,7 @@ bool subbrute_worker_init_default_attack(
     instance->step = step;
     instance->bits = protocol->bits;
     instance->te = protocol->te;
+    instance->opencode = protocol->opencode;
     instance->repeat = repeats;
     instance->load_index = 0;
     instance->file_key = 0;
@@ -207,7 +239,6 @@ void subbrute_worker_stop(SubBruteWorker* instance) {
     furi_assert(instance);
 
     if(!instance->worker_running) {
-
         return;
     }
 
@@ -264,16 +295,21 @@ bool subbrute_worker_transmit_current_key(SubBruteWorker* instance, uint64_t ste
             instance->two_bytes);
     } else {
         subbrute_protocol_default_payload(
-            stream, instance->file, step, instance->bits, instance->te, instance->repeat);
+            stream,
+            instance->file,
+            step,
+            instance->bits,
+            instance->te,
+            instance->repeat,
+            instance->opencode);
     }
 
     subbrute_worker_subghz_transmit(instance, flipper_format);
 
     result = true;
 #ifdef FURI_DEBUG
-    FURI_LOG_D(TAG, "Manual transmit done");
+    FURI_LOG_W(TAG, "Manual transmit done");
 #endif
-
     flipper_format_free(flipper_format);
 
     return result;
@@ -316,6 +352,9 @@ void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* fl
         subghz_transmitter_free(instance->transmitter);
         instance->transmitter = NULL;
     }
+
+    // instance->protocol_name = subbrute_protocol_file(instance->file);
+
     instance->transmitter =
         subghz_transmitter_alloc_init(instance->environment, instance->protocol_name);
     subghz_transmitter_deserialize(instance->transmitter, flipper_format);
@@ -342,6 +381,12 @@ void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* fl
     instance->transmitter = NULL;
 
     instance->transmit_mode = false;
+
+    Stream* stream = flipper_format_get_raw_stream(flipper_format);
+    stream_rewind(stream);
+    //test_read_full_stream(stream, "Transmit data");
+
+    subghz_custom_btns_reset();
 }
 
 void subbrute_worker_send_callback(SubBruteWorker* instance) {
@@ -402,7 +447,8 @@ int32_t subbrute_worker_thread(void* context) {
                 instance->step,
                 instance->bits,
                 instance->te,
-                instance->repeat);
+                instance->repeat,
+                instance->opencode);
         }
 #ifdef FURI_DEBUG
         //FURI_LOG_I(TAG, "Payload: %s", furi_string_get_cstr(payload));
@@ -476,3 +522,21 @@ bool subbrute_worker_is_tx_allowed(SubBruteWorker* instance, uint32_t value) {
 
     return res;
 }
+
+/*
+void test_read_full_stream(Stream* stream, const char* msg) {
+    // read data
+    // 循环读取stream中的数据每次读取一个字节(uint8_t)
+    size_t size_2 = stream_size(stream);
+    // read data
+    // 循环读取stream中的数据每次读取一个字节(uint8_t)
+    char* data_2 = (char*)malloc(size_2 + 1);
+    for(size_t i = 0; i < size_2; i++) {
+        stream_read(stream, (uint8_t*)&data_2[i], 1);
+    }
+    data_2[size_2] = '\0';
+
+    FURI_LOG_W(TAG, "%s Transmit data: %s", msg, data_2);
+    free(data_2);
+}
+*/

+ 8 - 0
helpers/subbrute_worker.h

@@ -275,3 +275,11 @@ void subbrute_worker_set_te(SubBruteWorker* instance, uint32_t te);
   * @return True if transmission is allowed for the given value, false otherwise.
   */
 bool subbrute_worker_is_tx_allowed(SubBruteWorker* instance, uint32_t value);
+
+void subbrute_worker_set_opencode(SubBruteWorker* instance, uint8_t opencode);
+
+uint8_t subbrute_worker_get_opencode(SubBruteWorker* instance);
+
+bool subbrute_worker_get_is_pt2262(SubBruteWorker* instance);
+
+//void test_read_full_stream(Stream* stream, const char* msg);

+ 6 - 0
helpers/subbrute_worker_private.h

@@ -1,3 +1,8 @@
+/*
+ * @LastEditors: SpenserCai
+ * @LastEditTime: 2025-03-04 14:21:29
+ * @Description: file content
+ */
 #pragma once
 
 #include "subbrute_worker.h"
@@ -43,6 +48,7 @@ struct SubBruteWorker {
     uint8_t load_index; /**< Index of group to bruteforce in loaded file */
     uint64_t file_key; /**< Key from file */
     uint64_t max_value; /**< Max step */
+    uint8_t opencode; /**< Opencode */
     bool two_bytes; /**< Two bytes key */
 
     // Manual transmit

+ 1 - 1
scenes/subbrute_scene_run_attack.c

@@ -27,7 +27,7 @@ static void
 void subbrute_scene_run_attack_on_exit(void* context) {
     furi_assert(context);
     SubBruteState* instance = (SubBruteState*)context;
-
+    // FURI_LOG_W(TAG, "subbrute_scene_run_attack_on_exit");
     notification_message(instance->notifications, &sequence_blink_stop);
     subbrute_worker_stop(instance->worker);
 }

+ 30 - 4
scenes/subbrute_scene_setup_extra.c

@@ -3,17 +3,18 @@
 
 #define TAG "SubBruteSceneLoadFile"
 
-#define MIN_TD 0
-#define MAX_TD 255
+#define MIN_TD  0
+#define MAX_TD  255
 #define MIN_REP 1
 #define MAX_REP 100
-#define MIN_TE 100
-#define MAX_TE 600
+#define MIN_TE  100
+#define MAX_TE  600
 
 enum SubBruteVarListIndex {
     SubBruteVarListIndexTimeDelay,
     SubBruteVarListIndexRepeatOrOnExtra,
     SubBruteVarListIndexTe,
+    SubBruteVarListIndexOpenCode,
 };
 
 static void setup_extra_enter_callback(void* context, uint32_t index);
@@ -180,6 +181,20 @@ static void setup_extra_te_callback(VariableItem* item) {
     }
 }
 
+const char* const opencode_names[] =
+    {"0001", "0010", "0100", "1000", "1100", "0F00", "00F0", "F000", "1001"};
+const uint8_t opencode_values[COUNT_OF(opencode_names)] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
+
+static void setup_extra_opencode_callback(VariableItem* item) {
+    furi_assert(item);
+    SubBruteState* instance = variable_item_get_context(item);
+    furi_assert(instance);
+    const uint8_t value_index = variable_item_get_current_value_index(item);
+    subbrute_worker_set_opencode(instance->worker, opencode_values[value_index]);
+    instance->device->opencode = opencode_values[value_index];
+    variable_item_set_current_value_text(item, opencode_names[value_index]);
+}
+
 static void subbrute_scene_setup_extra_init_var_list(SubBruteState* instance, bool on_extra) {
     furi_assert(instance);
     char str[6] = {0};
@@ -243,11 +258,22 @@ static void subbrute_scene_setup_extra_init_var_list(SubBruteState* instance, bo
                 break;
             }
         }
+
+        if(subbrute_worker_get_is_pt2262(instance->worker)) {
+            uint8_t value_index;
+            item = variable_item_list_add(
+                var_list, "PT2262Code", 9, setup_extra_opencode_callback, instance);
+            value_index = subbrute_worker_get_opencode(instance->worker);
+            variable_item_set_current_value_index(item, value_index);
+            variable_item_set_current_value_text(item, opencode_names[value_index]);
+        }
     } else {
         item = variable_item_list_add(var_list, "Show Extra", 0, NULL, NULL);
         variable_item_set_current_value_index(item, 0);
     }
 
+    variable_item_list_set_selected_item(var_list, 0);
+
     variable_item_list_set_enter_callback(var_list, setup_extra_enter_callback, instance);
     view_dispatcher_switch_to_view(instance->view_dispatcher, SubBruteViewVarList);
 }

+ 8 - 2
subbrute_device.c

@@ -30,7 +30,11 @@ void subbrute_device_free(SubBruteDevice* instance) {
     furi_assert(instance);
 
     // I don't know how to free this
-    instance->decoder_result = NULL;
+    // instance->decoder_result = NULL;
+    if(instance->decoder_result != NULL) {
+        free(instance->decoder_result);
+        instance->decoder_result = NULL;
+    }
 
     if(instance->receiver != NULL) {
         subghz_receiver_free(instance->receiver);
@@ -80,6 +84,7 @@ bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_na
 
 #ifdef FURI_DEBUG
     FURI_LOG_D(TAG, "subbrute_device_save_file: %s", dev_file_name);
+    FURI_LOG_D(TAG, "opencode: %d", instance->opencode);
 #endif
 
     Storage* storage = furi_record_open(RECORD_STORAGE);
@@ -111,7 +116,8 @@ bool subbrute_device_save_file(SubBruteDevice* instance, const char* dev_file_na
                 instance->protocol_info->file,
                 instance->current_step,
                 instance->protocol_info->bits,
-                instance->protocol_info->te);
+                instance->protocol_info->te,
+                instance->opencode);
         }
 
         result = true;

+ 4 - 4
subbrute_device.h

@@ -9,8 +9,8 @@
 #include <lib/subghz/environment.h>
 
 #define SUBBRUTE_MAX_LEN_NAME 64
-#define SUBBRUTE_PATH EXT_PATH("subghz")
-#define SUBBRUTE_FILE_EXT ".sub"
+#define SUBBRUTE_PATH         EXT_PATH("subghz")
+#define SUBBRUTE_FILE_EXT     ".sub"
 
 /**
  * @enum SubBruteFileResult
@@ -51,7 +51,7 @@ typedef struct {
 
     uint64_t current_step; /**< Current step */
 
-     /** @see @c SubGhz service for more info */
+    /** @see @c SubGhz service for more info */
     SubGhzReceiver* receiver; /**< Receiver */
     SubGhzProtocolDecoderBase* decoder_result; /**< Decoder result */
     SubGhzEnvironment* environment; /**< Environment */
@@ -65,7 +65,7 @@ typedef struct {
     uint64_t key_from_file; /**< Key from file */
     uint64_t current_key_from_file; /**< Current key from file */
     bool two_bytes; /**< Two bytes key */
-
+    uint8_t opencode; /**< Opencode */
     uint8_t bit_index; /**< Index of a group to bruteforce in loaded file */
 } SubBruteDevice;
 

+ 1 - 1
subbrute_i.h

@@ -31,7 +31,7 @@
 #include "views/subbrute_attack_view.h"
 #include "views/subbrute_main_view.h"
 
-#define SUB_BRUTE_FORCER_VERSION "Sub-GHz BruteForcer 3.F"
+#define SUB_BRUTE_FORCER_VERSION "Sub-GHz BruteForcer 4.0"
 
 #ifdef FURI_DEBUG
 //#define SUBBRUTE_FAST_TRACK false

+ 125 - 7
subbrute_protocols.c

@@ -366,6 +366,63 @@ const SubBruteProtocol subbrute_protocol_pt2260_24bit_433 = {
     .preset = FuriHalSubGhzPresetOok650Async,
     .file = PT2260FileProtocol};
 
+/**
+ * PT2262 (Princeton) 24bit 315MHz
+ */
+const SubBruteProtocol subbrute_protocol_pt2262_24bit_315 = {
+    .frequency = 315000000,
+    .bits = 24,
+    .te = 350,
+    .repeat = 4,
+    .preset = FuriHalSubGhzPresetOok650Async,
+    .file = PT2262FileProtocol};
+
+/**
+ * PT2262 (Princeton) 24bit 418MHz
+ */
+const SubBruteProtocol subbrute_protocol_pt2262_24bit_418 = {
+    .frequency = 418000000,
+    .bits = 24,
+    .te = 350,
+    .repeat = 4,
+    .preset = FuriHalSubGhzPresetOok650Async,
+    .file = PT2262FileProtocol};
+
+/**
+ * PT2262 (Princeton) 24bit 430MHz
+ */
+const SubBruteProtocol subbrute_protocol_pt2262_24bit_430 = {
+    .frequency = 430000000,
+    .bits = 24,
+    .te = 350,
+    .repeat = 4,
+    .preset = FuriHalSubGhzPresetOok650Async,
+    .file = PT2262FileProtocol};
+
+/**
+ * PT2262 (Princeton) 24bit 430.5MHz
+ *
+ * 
+ */
+const SubBruteProtocol subbrute_protocol_pt2262_24bit_430_5 = {
+    .frequency = 430500000,
+    .bits = 24,
+    .te = 350,
+    .repeat = 4,
+    .preset = FuriHalSubGhzPresetOok650Async,
+    .file = PT2262FileProtocol};
+
+/**
+ * PT2262 (Princeton) 24bit 433MHz
+ */
+const SubBruteProtocol subbrute_protocol_pt2262_24bit_433 = {
+    .frequency = 433920000,
+    .bits = 24,
+    .te = 350,
+    .repeat = 4,
+    .preset = FuriHalSubGhzPresetOok650Async,
+    .file = PT2262FileProtocol};
+
 /**
  * Holtek FM 12bit 433MHz
  */
@@ -425,7 +482,7 @@ const SubBruteProtocol subbrute_protocol_holtek_12bit_am_915 = {
  * BF existing dump
  */
 const SubBruteProtocol subbrute_protocol_load_file =
-    {0, 0, 0, 3, FuriHalSubGhzPresetOok650Async, UnknownFileProtocol};
+    {0, 0, 0, 3, 0, FuriHalSubGhzPresetOok650Async, UnknownFileProtocol};
 
 static const char* subbrute_protocol_names[] = {
     [SubBruteAttackCAME12bit303] = "CAME 12bit 303MHz",
@@ -466,6 +523,11 @@ static const char* subbrute_protocol_names[] = {
     [SubBruteAttackPT226024bit330] = "PT2260 24bit 330MHz",
     [SubBruteAttackPT226024bit390] = "PT2260 24bit 390MHz",
     [SubBruteAttackPT226024bit433] = "PT2260 24bit 433MHz",
+    [SubBruteAttackPT226224bit315] = "PT2262 24bit 315MHz",
+    [SubBruteAttackPT226224bit418] = "PT2262 24bit 418MHz",
+    [SubBruteAttackPT226224bit430] = "PT2262 24bit 430MHz",
+    [SubBruteAttackPT226224bit4305] = "PT2262 24bit 430.5MHz",
+    [SubBruteAttackPT226224bit433] = "PT2262 24bit 433MHz",
     [SubBruteAttackLoadFile] = "BF existing dump",
     [SubBruteAttackTotalCount] = "Total Count",
 };
@@ -519,6 +581,11 @@ const SubBruteProtocol* subbrute_protocol_registry[] = {
     [SubBruteAttackPT226024bit330] = &subbrute_protocol_pt2260_24bit_330,
     [SubBruteAttackPT226024bit390] = &subbrute_protocol_pt2260_24bit_390,
     [SubBruteAttackPT226024bit433] = &subbrute_protocol_pt2260_24bit_433,
+    [SubBruteAttackPT226224bit315] = &subbrute_protocol_pt2262_24bit_315,
+    [SubBruteAttackPT226224bit418] = &subbrute_protocol_pt2262_24bit_418,
+    [SubBruteAttackPT226224bit430] = &subbrute_protocol_pt2262_24bit_430,
+    [SubBruteAttackPT226224bit4305] = &subbrute_protocol_pt2262_24bit_430_5,
+    [SubBruteAttackPT226224bit433] = &subbrute_protocol_pt2262_24bit_433,
     [SubBruteAttackLoadFile] = &subbrute_protocol_load_file};
 
 static const char* subbrute_protocol_file_types[] = {
@@ -539,6 +606,7 @@ static const char* subbrute_protocol_file_types[] = {
     [SMC5326FileProtocol] = "SMC5326",
     [UNILARMFileProtocol] = "SMC5326",
     [PT2260FileProtocol] = "Princeton",
+    [PT2262FileProtocol] = "Princeton",
     [HoneywellFileProtocol] = "Honeywell",
     [HoltekFileProtocol] = "Holtek_HT12X",
     [LegrandFileProtocol] = "Legrand",
@@ -561,6 +629,7 @@ static const char* subbrute_key_small_with_tail = "Bit: %d\nKey: %s\nTE: %d\nRep
 
 const uint8_t lut_uni_alarm_smsc[] = {0x00, 0x02, 0x03}; // 00, 10, 11
 const uint8_t lut_pt2260[] = {0x00, 0x01, 0x03}; // 00, 01, 11
+const uint8_t lut_pt2262[] = {0x00, 0x01, 0x03}; // 00, 01, 11
 
 const uint64_t gate_smsc = 0x01D5; // 111010101
 //const uint8_t gate2 = 0x0175; // 101110101
@@ -652,7 +721,8 @@ void subbrute_protocol_create_candidate_for_existing_file(
 void subbrute_protocol_create_candidate_for_default(
     FuriString* candidate,
     SubBruteFileProtocol file,
-    uint64_t step) {
+    uint64_t step,
+    uint8_t opencode) {
     uint8_t p[8] = {0};
     uint64_t total = 0;
 
@@ -692,6 +762,47 @@ void subbrute_protocol_create_candidate_for_default(
         for(int i = 0; i < 8; i++) {
             p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;
         }
+    } else if(file == PT2262FileProtocol) {
+        uint64_t gate_pt2262 = 0x03; // 11
+        uint8_t opencode_var = opencode;
+        if(opencode_var == 0) {
+            gate_pt2262 = 0x03; // 0001 PT2262常见抬杆码3
+        }
+        if(opencode_var == 1) {
+            gate_pt2262 = 0x0C; // 0010 PT2262常见抬杆码12
+        }
+        if(opencode_var == 2) {
+            gate_pt2262 = 0x30; // 0100 PT2262常见抬杆码48
+        }
+        if(opencode_var == 3) {
+            gate_pt2262 = 0xC0; // 1000 PT2262常见抬杆码192
+        }
+        if(opencode_var == 4) {
+            gate_pt2262 = 0xF0; // 1100 PT2262常见抬杆码240
+        }
+        if(opencode_var == 5) {
+            gate_pt2262 = 0x10; // 0F00 PT2262常见抬杆码16
+        }
+        if(opencode_var == 6) {
+            gate_pt2262 = 0x04; // 00F0 PT2262常见抬杆码4
+        }
+        if(opencode_var == 7) {
+            gate_pt2262 = 0x40; // F000 PT2262常见抬杆码64
+        }
+        if(opencode_var == 8) {
+            gate_pt2262 = 0xC3; // 1001 PT2262常见抬杆码195
+        }
+        for(size_t j = 0; j < 8; j++) {
+            total |= lut_pt2262[step % 3] << (2 * j);
+            double sub_step = (double)step / 3;
+            step = (uint64_t)floor(sub_step);
+        }
+        total <<= 8;
+        total |= gate_pt2262;
+
+        for(int i = 0; i < 8; i++) {
+            p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFFU;
+        }
     } else {
         for(int i = 0; i < 8; i++) {
             p[i] = (uint8_t)(step >> 8 * (7 - i)) & 0xFF;
@@ -722,9 +833,10 @@ void subbrute_protocol_default_payload(
     uint64_t step,
     uint8_t bits,
     uint32_t te,
-    uint8_t repeat) {
+    uint8_t repeat,
+    uint8_t opencode) {
     FuriString* candidate = furi_string_alloc();
-    subbrute_protocol_create_candidate_for_default(candidate, file, step);
+    subbrute_protocol_create_candidate_for_default(candidate, file, step, opencode);
 
 #ifdef FURI_DEBUG
     FURI_LOG_D(
@@ -799,9 +911,10 @@ void subbrute_protocol_default_generate_file(
     SubBruteFileProtocol file,
     uint64_t step,
     uint8_t bits,
-    uint32_t te) {
+    uint32_t te,
+    uint8_t opencode) {
     FuriString* candidate = furi_string_alloc();
-    subbrute_protocol_create_candidate_for_default(candidate, file, step);
+    subbrute_protocol_create_candidate_for_default(candidate, file, step, opencode);
 
 #ifdef FURI_DEBUG
     FURI_LOG_D(TAG, "candidate: %s, step: %lld", furi_string_get_cstr(candidate), step);
@@ -886,7 +999,12 @@ uint64_t
         attack_type == SubBruteAttackPT226024bit315 ||
         attack_type == SubBruteAttackPT226024bit330 ||
         attack_type == SubBruteAttackPT226024bit390 ||
-        attack_type == SubBruteAttackPT226024bit433) {
+        attack_type == SubBruteAttackPT226024bit433 ||
+        attack_type == SubBruteAttackPT226224bit315 ||
+        attack_type == SubBruteAttackPT226224bit418 ||
+        attack_type == SubBruteAttackPT226224bit430 ||
+        attack_type == SubBruteAttackPT226224bit4305 ||
+        attack_type == SubBruteAttackPT226224bit433) {
         max_value = 6561;
     } else {
         FuriString* max_value_s;

+ 11 - 2
subbrute_protocols.h

@@ -55,6 +55,7 @@ typedef enum {
     SMC5326FileProtocol,
     UNILARMFileProtocol,
     PT2260FileProtocol,
+    PT2262FileProtocol,
     HoneywellFileProtocol,
     HoltekFileProtocol,
     LegrandFileProtocol,
@@ -156,6 +157,11 @@ typedef enum {
     SubBruteAttackPT226024bit330,
     SubBruteAttackPT226024bit390,
     SubBruteAttackPT226024bit433,
+    SubBruteAttackPT226224bit315,
+    SubBruteAttackPT226224bit418,
+    SubBruteAttackPT226224bit430,
+    SubBruteAttackPT226224bit4305,
+    SubBruteAttackPT226224bit433,
     SubBruteAttackLoadFile,
     SubBruteAttackTotalCount,
 } SubBruteAttacks;
@@ -172,6 +178,7 @@ typedef struct {
     uint8_t bits;
     uint32_t te;
     uint8_t repeat;
+    uint8_t opencode;
     FuriHalSubGhzPreset preset;
     SubBruteFileProtocol file;
 } SubBruteProtocol;
@@ -271,7 +278,8 @@ void subbrute_protocol_default_payload(
     uint64_t step,
     uint8_t bits,
     uint32_t te,
-    uint8_t repeat);
+    uint8_t repeat,
+    uint8_t opencode);
 
 /**
  * @brief Performs a sub-brute force protocol operation with file payload.
@@ -321,7 +329,8 @@ void subbrute_protocol_default_generate_file(
     SubBruteFileProtocol file,
     uint64_t step,
     uint8_t bits,
-    uint32_t te);
+    uint32_t te,
+    uint8_t opencode);
 
 /**
  * @brief Generates a file for the SubBrute protocol with the given parameters.