Просмотр исходного кода

Merge pull request #76 from derskythe/feat/refactor

feat: Some refactoring to clean-up the code
DerSkythe 1 год назад
Родитель
Сommit
def1d0fba4

+ 126 - 0
.github/workflows/pr-build.yaml

@@ -0,0 +1,126 @@
+name: "PR Build"
+run-name: "PR Build ${{ inputs.DEPLOY_TARGET }} triggered by ${{ github.EVENT_NAME }} (@${{ github.ACTOR }})"
+
+on:
+  pull_request:
+    types: [opened, reopened]
+
+jobs:
+  build-for-pr:
+    runs-on: ubuntu-latest
+    env:
+      REPO_SELF: ${{ vars.REPO_SELF }}
+      APP_PATH: "applications_user/subbrute"
+      RELATIVE_PATH: "applications/external/subbrute"
+      PREV_TAG: ""
+      APP_NAME: ""
+      ZIP_NAME: ""
+      ZIP_TAG: ""
+      TGZ_NAME: ""
+      TGZ_TAG: ""
+      SHA: ""
+      FW_VERSION: ""
+      RELEASE_VERSION: ""
+    strategy:
+      fail-fast: false
+      matrix:
+        firmware: [unlshd, official]
+        include:
+          - firmware: unlshd
+            url: ${{ vars.REPO_UNLEASHED }}
+            version: ${{ vars.FIRMWARE_VERSION }}
+            src-included: 0
+          - firmware: official
+            url: ${{ vars.REPO_OFFICIAL }}
+            version: official
+            src-included: 0
+    steps:
+      - name: Copy Firmware Files
+        uses: actions/checkout@v4
+        with:
+          repository: ${{ matrix.url }}
+          clean: true
+          submodules: true
+          ref: dev
+
+      - name: Copy Repo Files
+        if: ${{ matrix.src-included == 0 }}
+        uses: actions/checkout@v4
+        with:
+          repository: ${{ vars.REPO_SELF }}
+          clean: true
+          submodules: true
+          path: ${{ env.APP_PATH }}
+
+      - name: Remove other apps
+        shell: pwsh
+        # rm to remove problem FAP which includes non-existent files
+        run: |
+          Remove-Item -Force -Recurse ./applications/debug -ErrorAction SilentlyContinue
+          Remove-Item -Force -Recurse ./applications/examples -ErrorAction SilentlyContinue
+          Remove-Item -Force -Recurse ${{ env.RELATIVE_PATH }} -ErrorAction SilentlyContinue
+
+      - name: Get SHA of our application and release version
+        shell: pwsh
+        env:
+          GITHUB_TOKEN: ${{ secrets.FLIPPER_TOKEN }}
+          INPUT_VERSION: ${{ inputs.version }}
+        run: |
+          Write-Output "::notice title=${{ matrix.firmware }} Input Version Number::v${{ inputs.version }}"
+          $fwInfo = ((gh release view --json tagName,url -R ${{ matrix.url }}) | ConvertFrom-Json)
+          cd '${{ env.APP_PATH }}'
+          $sha = (git rev-parse --verify HEAD)
+          
+          $releaseVersion = ''
+          $latestTag = ((gh release view --json tagName,url -R ${{ vars.REPO_SELF }}) | ConvertFrom-Json ).tagName
+
+          if ( [string]::IsNullOrWhitespace($env:INPUT_VERSION) ) {            
+            Write-Output "::notice title=${{ matrix.firmware }} Latest tag::$latestTag"
+            
+            $lastIndex = $latestTag.LastIndexOf('.')
+            
+            $minorValue = $latestTag.Substring($latestTag.LastIndexOf('.') + 1)
+            $minorValue = [Convert]::ToInt32($minorValue) + 1
+            $newTag = $latestTag.Substring(0, $lastIndex)
+            
+            $releaseVersion = ('{0}.{1}' -f $newTag, $minorValue)
+          } else {
+            $releaseVersion = "$env:INPUT_VERSION"
+          }
+          
+          if ( $releaseVersion.StartsWith('v') ) {
+            $releaseVersion = $releaseVersion.Substring(1)
+          }
+          
+          Write-Output "::notice title=${{ matrix.firmware }} PREV_TAG::$latestTag"
+          Write-Output "::notice title=${{ matrix.firmware }} RELEASE_VERSION::$releaseVersion"
+          Write-Output "::notice title=${{ matrix.firmware }} SHA::$sha"
+          Write-Output ('::notice title=${{ matrix.firmware }} FW_VERSION::{0}' -f $fwInfo.tagName)
+          
+          Write-Output ('RELEASE_VERSION={0}' -f $releaseVersion) >> $env:GITHUB_ENV
+          Write-Output ('SHA={0}' -f $sha) >> $env:GITHUB_ENV
+          Write-Output ('FW_VERSION={0}' -f $fwInfo.tagName) >> $env:GITHUB_ENV
+          Write-Output ('PREV_TAG={0}' -f $latestTag) >> $env:GITHUB_ENV
+
+      - name: Build Firmware
+        shell: bash
+        if: ${{ success() }}
+        env:
+          FBT_NO_SYNC: 0
+          DIST_SUFFIX: ${{ matrix.version }}
+          WORKFLOW_BRANCH_OR_TAG: release-cfw
+        run: |
+          ./fbt COMPACT=1 DEBUG=0 FBT_NO_SYNC=0
+
+      - name: Build FAPs
+        shell: bash
+        if: ${{ success() }}
+        env:
+          FBT_NO_SYNC: 0
+          DIST_SUFFIX: ${{ matrix.version }}
+          WORKFLOW_BRANCH_OR_TAG: release-cfw
+          # rm to remove problem FAP which includes non-existent files
+        run: |
+          ./fbt COMPACT=1 DEBUG=0 FBT_NO_SYNC=0 fap_dist
+
+#EOF

+ 21 - 7
helpers/gui_top_buttons.h

@@ -7,15 +7,29 @@
 #include <gui/icon_animation.h>
 
 /**
- * Thanks to the author of metronome
- * @param canvas
- * @param str
+ * @brief This function draws a button in the top left corner of the canvas with icon and string.
+ *
+ * The design and layout of the button is defined within this function.
+ *
+ *
+ * @param[in] canvas This is a pointer to the @c Canvas structure where the button will be drawn.
+ * @param[in] str This is a pointer to the character string that will be drawn within the button.
+ *
+ * @note Thanks to the author of metronome @see https://github.com/panki27/Metronome
+ *
  */
 void elements_button_top_left(Canvas* canvas, const char* str);
 
 /**
- * Thanks to the author of metronome
- * @param canvas
- * @param str
+ * @brief This function draws a button in the top right corner of the canvas with icon and string.
+ *
+ * The design and layout of the button is defined within this function.
+ *
+ *
+ * @param[in] canvas This is a pointer to the @c Canvas structure where the button will be drawn.
+ * @param[in] str This is a pointer to the character string that will be drawn within the button.
+ *
+ * @note Thanks to the author of metronome @see https://github.com/panki27/Metronome
+ *
  */
-void elements_button_top_right(Canvas* canvas, const char* str);
+void elements_button_top_right(Canvas* canvas, const char* str);

+ 41 - 4
helpers/subbrute_radio_device_loader.c

@@ -1,12 +1,28 @@
-#include <furi/core/check.h>
+#include "subbrute_radio_device_loader.h"
 
-#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
+#include <furi/core/check.h>
 #include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
 
-#include "subbrute_radio_device_loader.h"
+#include "applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h"
 
 #define TAG "SubBruteRadioDeviceLoader"
 
+/**
+ * @brief This function is responsible for powering on the radio device loader.
+ *
+ * This function is responsible for powering on the radio device loader.
+ * It attempts to enable the OTG (On-The-Go) power.
+ * The function uses a @c `while` loop with a maximum of 5 attempts to enable the OTG power.
+ * If it succeeds, it will break out of the loop.
+ * If the maximum number of attempts is reached and the OTG power is not enabled,
+ * the function checks the USB voltage using @c `furi_hal_power_get_usb_voltage()`.
+ *
+ * If the voltage is below 4.5 volts, an error message is logged using @c `FURI_LOG_E()`
+ * with a message includes the value of @c `furi_hal_power_check_otg_fault()`
+ * (converted to 1 if true, 0 if false),
+ * which checks the OTG fault status using the BQ2589 chip.
+ *
+*/
 static void subbrute_radio_device_loader_power_on() {
     uint8_t attempts = 5;
     while(--attempts > 0) {
@@ -24,13 +40,34 @@ static void subbrute_radio_device_loader_power_on() {
     }
 }
 
+/**
+ * @brief Turns off the power of the radio device loader.
+ *
+ * This function checks if OTG (On-The-Go) power is enabled, and if so, it disables it.
+ *
+ * @note This function is static and used internally by the radio device loader module.
+ *
+ */
 static void subbrute_radio_device_loader_power_off() {
     if(furi_hal_power_is_otg_enabled()) {
         furi_hal_power_disable_otg();
     }
 }
 
-bool subbrute_radio_device_loader_is_connect_external(const char* name) {
+/**
+ * @brief Checks if a radio device of the given name is connected externally.
+ *
+ * This function checks if a radio device with the specified name is connected externally.
+ * If the OTG power is not enabled, it attempts to power on the radio device loader.
+ * It then retrieves the device information using the provided name and checks if it is connected.
+ * Finally, if the OTG power was initially disabled, it powers off the radio device loader.
+ *
+ * @param[in] name The name of the radio device to check.
+ *
+ * @return true if the device is connected externally, false otherwise.
+ *
+ */
+static bool subbrute_radio_device_loader_is_connect_external(const char* name) {
     bool is_connect = false;
     bool is_otg_enabled = furi_hal_power_is_otg_enabled();
 

+ 14 - 6
helpers/subbrute_radio_device_loader.h

@@ -16,25 +16,33 @@ typedef enum {
  *
  * This function is used to set the SubGhz radio device type for the SubBrute radio device loader.
  *
- * @param current_radio_device Pointer to the current SubGhz radio device.
- * @param radio_device_type The desired SubGhz radio device type.
- * @return const SubGhzDevice* Pointer to the new SubGhz radio device.
+ * @param [in] current_radio_device Pointer to the current SubGhz radio device.
+ * @param [in] radio_device_type The desired SubGhz radio device type.
+ *
+ * @return @c const SubGhzDevice* Pointer to the new SubGhz radio device.
  *
  * @remark This function sets the SubGhz radio device type for the SubBrute radio device loader.
  *         The current radio device will be replaced with a new instance of the specified radio device type.
  *         If @p current_radio_device is NULL, a new instance of the specified radio device type will be created.
  *
  * @note The caller is responsible for handling memory deallocation of the returned pointer.
+ *
  */
 const SubGhzDevice* subbrute_radio_device_loader_set(
     const SubGhzDevice* current_radio_device,
     SubGhzRadioDeviceType radio_device_type);
 
 /**
- * @brief Unloads a SubGhz radio device.
+ * @brief Unloads the radio device in the subbrute radio device loader.
+ *
+ * This function is called to unload the specified radio device in the
+ * subbrute radio device loader.
+ * It first checks if the radio device is valid and then performs the necessary steps to
+ * power off the device.
+ * If the radio device is not the CC1101 internal device, it calls @c subghz_devices_end()
+ * function to terminate the radio device.
  *
- * This function unloads a SubGhz radio device and performs any necessary cleanup.
+ * @param[in] radio_device A pointer to the radio device to unload.
  *
- * @param radio_device Pointer to the SubGhzDevice structure representing the radio device to be unloaded.
  */
 void subbrute_radio_device_loader_end(const SubGhzDevice* radio_device);

+ 3 - 2
helpers/subbrute_worker.h

@@ -32,8 +32,9 @@ typedef struct SubBruteWorker SubBruteWorker;
  * This function creates a new SubBruteWorker object by allocating memory for it on the heap and
  * initializes it with the provided radio_device. The radio_device parameter must not be NULL.
  *
- * @param radio_device A pointer to a valid SubGhzDevice object.
- * @return A pointer to the newly allocated SubBruteWorker object, or NULL if memory allocation failed.
+ * @param[in] radio_device A pointer to a valid SubGhzDevice object.
+ * @return A pointer to the newly allocated SubBruteWorker object, or @c NULL if memory
+ *         allocation was failed.
  */
 SubBruteWorker* subbrute_worker_alloc(const SubGhzDevice* radio_device);
 

+ 28 - 27
helpers/subbrute_worker_private.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "subbrute_worker.h"
+
 #include <lib/subghz/protocols/base.h>
 #include <lib/subghz/transmitter.h>
 #include <lib/subghz/receiver.h>
@@ -14,41 +15,41 @@
  * It manages the state, configuration and execution of the sub-brute forcing algorithm.
  */
 struct SubBruteWorker {
-    SubBruteWorkerState state;
-    volatile bool worker_running;
-    volatile bool initiated;
-    volatile bool transmit_mode;
+    SubBruteWorkerState state; /**< State of the worker */
+    volatile bool worker_running; /**< Worker running state */
+    volatile bool initiated; /**< Initiated state */
+    volatile bool transmit_mode; /**< Transmit mode */
+
+    uint64_t step; /**< Current step */
 
-    // Current step
-    uint64_t step;
+    FuriThread* thread; /**< Thread */
 
-    // SubGhz
-    FuriThread* thread;
+    /** @see @c SubGhz service for more info */
+    SubGhzEnvironment* environment; /**< Environment */
     SubGhzProtocolDecoderBase* decoder_result;
-    SubGhzEnvironment* environment;
-    SubGhzTransmitter* transmitter;
-    const char* protocol_name;
-    uint8_t tx_timeout_ms;
-    const SubGhzDevice* radio_device;
+    SubGhzTransmitter* transmitter; /**< Transmitter */
+    const char* protocol_name; /**< Name of the protocol */
+    uint8_t tx_timeout_ms; /**< Timeout for transmit */
+    const SubGhzDevice* radio_device; /**< Radio device */
 
     // Initiated values
-    SubBruteAttacks attack; // Attack state
-    uint32_t frequency;
-    FuriHalSubGhzPreset preset;
-    SubBruteFileProtocol file;
-    uint8_t bits;
-    uint32_t te;
-    uint8_t repeat;
-    uint8_t load_index; // Index of group to bruteforce in loaded file
-    uint64_t file_key;
-    uint64_t max_value; // Max step
-    bool two_bytes;
+    SubBruteAttacks attack; /**< Attack state */
+    uint32_t frequency; /**< Frequency */
+    FuriHalSubGhzPreset preset; /**< Preset */
+    SubBruteFileProtocol file; /**< File protocol */
+    uint8_t bits; /**< Number of bits in key */
+    uint32_t te; /**< Time to wait for response */
+    uint8_t repeat; /**< Number of extra repeats */
+    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 */
+    bool two_bytes; /**< Two bytes key */
 
     // Manual transmit
-    uint32_t last_time_tx_data;
+    uint32_t last_time_tx_data; /**< Last time data was transmitted */
 
     // Callback for changed states
-    SubBruteWorkerCallback callback;
+    SubBruteWorkerCallback callback; /**< Callback for changed states */
     void* context;
 };
 
@@ -85,4 +86,4 @@ void subbrute_worker_subghz_transmit(SubBruteWorker* instance, FlipperFormat* fl
  *
  * @note This function does not return any values.
  */
-void subbrute_worker_send_callback(SubBruteWorker* instance);
+void subbrute_worker_send_callback(SubBruteWorker* instance);

+ 2 - 3
subbrute.c

@@ -107,8 +107,6 @@ SubBruteState* subbrute_alloc() {
 
     instance->settings = subbrute_settings_alloc();
     subbrute_settings_load(instance->settings);
-    //instance->flipper_format = flipper_format_string_alloc();
-    //instance->environment = subghz_environment_alloc();
 
     // Uncomment to enable Debug pin output on PIN 17(1W)
     // subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_ibutton);
@@ -166,7 +164,7 @@ void subbrute_free(SubBruteState* instance) {
     view_dispatcher_remove_view(instance->view_dispatcher, SubBruteViewStack);
     view_stack_free(instance->view_stack);
 
-    //Dialog
+    // Dialog
     furi_record_close(RECORD_DIALOGS);
     instance->dialogs = NULL;
 
@@ -216,5 +214,6 @@ int32_t subbrute_app(void* p) {
     subbrute_free(instance);
 
     furi_hal_power_suppress_charge_exit();
+
     return 0;
 }

+ 2 - 2
subbrute_custom_event.h

@@ -71,7 +71,7 @@
  * Event type for the load file event.
  */
 typedef enum {
-    // Reserve first 100 events for button types and indexes, starting from 0
+    /** Reserve first 100 events for button types and indexes, starting from 0 */
     SubBruteCustomEventTypeReserved = 100,
 
     SubBruteCustomEventTypeBackPressed,
@@ -94,4 +94,4 @@ typedef enum {
     SubBruteCustomEventTypePopupClosed,
 
     SubBruteCustomEventTypeLoadFile,
-} SubBruteCustomEvent;
+} SubBruteCustomEvent;

+ 30 - 46
subbrute_device.c

@@ -246,14 +246,14 @@ uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* fil
             break;
         }
         if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
-            FURI_LOG_E(TAG, "Missing or incorrect header");
+            FURI_LOG_E(TAG, error_device_missing_header);
             result = SubBruteFileResultMissingOrIncorrectHeader;
             break;
         }
 
         // Frequency
         if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
-            FURI_LOG_E(TAG, "Missing or incorrect Frequency");
+            FURI_LOG_E(TAG, error_device_incorrect_frequency);
             result = SubBruteFileResultMissingOrIncorrectFrequency;
             break;
         }
@@ -276,7 +276,7 @@ uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* fil
 
         // Preset
         if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
-            FURI_LOG_E(TAG, "Preset FAIL");
+            FURI_LOG_E(TAG, error_device_preset_fail);
             result = SubBruteFileResultPresetInvalid;
             break;
         }
@@ -285,7 +285,7 @@ uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* fil
         const char* protocol_file = NULL;
         // Protocol
         if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
-            FURI_LOG_E(TAG, "Missing Protocol");
+            FURI_LOG_E(TAG, error_device_missing_protocol);
             result = SubBruteFileResultMissingProtocol;
             break;
         }
@@ -300,7 +300,7 @@ uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* fil
 
         if((!instance->decoder_result) || (strcmp(protocol_file, "RAW") == 0) ||
            (strcmp(protocol_file, "Unknown") == 0)) {
-            FURI_LOG_E(TAG, "Protocol unsupported");
+            FURI_LOG_E(TAG, error_device_protocol_unsupported);
             result = SubBruteFileResultProtocolNotSupported;
             break;
         }
@@ -316,7 +316,7 @@ uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* fil
 
         // Bit
         if(!flipper_format_read_uint32(fff_data_file, "Bit", &temp_data32, 1)) {
-            FURI_LOG_E(TAG, "Missing or incorrect Bit");
+            FURI_LOG_E(TAG, error_device_missing_bit);
             result = SubBruteFileResultMissingOrIncorrectBit;
             break;
         }
@@ -342,7 +342,7 @@ uint8_t subbrute_device_load_from_file(SubBruteDevice* instance, const char* fil
 
         // TE
         if(!flipper_format_read_uint32(fff_data_file, "TE", &temp_data32, 1)) {
-            FURI_LOG_E(TAG, "Missing or incorrect TE");
+            FURI_LOG_E(TAG, error_device_missing_te);
             //result = SubBruteFileResultMissingOrIncorrectTe;
             //break;
         } else {
@@ -406,61 +406,45 @@ void subbrute_device_attack_set_default_values(
     }
 }
 
+void subbrute_device_free_protocol_info(SubBruteDevice* instance) {
+    furi_assert(instance);
+    instance->protocol_info = NULL;
+    if(instance->file_protocol_info) {
+        free(instance->file_protocol_info);
+    }
+    instance->file_protocol_info = NULL;
+}
+
 const char* subbrute_device_error_get_desc(SubBruteFileResult error_id) {
-    const char* result;
     switch(error_id) {
     case(SubBruteFileResultOk):
-        result = "OK";
-        break;
+        return error_device_ok;
     case(SubBruteFileResultErrorOpenFile):
-        result = "invalid name/path";
-        break;
+        return error_device_invalid_path;
     case(SubBruteFileResultMissingOrIncorrectHeader):
-        result = "Missing or incorrect header";
-        break;
+        return error_device_missing_header;
     case(SubBruteFileResultFrequencyNotAllowed):
-        result = "Invalid frequency!";
-        break;
+        return error_device_invalid_frequency;
     case(SubBruteFileResultMissingOrIncorrectFrequency):
-        result = "Missing or incorrect Frequency";
-        break;
+        return error_device_incorrect_frequency;
     case(SubBruteFileResultPresetInvalid):
-        result = "Preset FAIL";
-        break;
+        return error_device_preset_fail;
     case(SubBruteFileResultMissingProtocol):
-        result = "Missing Protocol";
-        break;
+        return error_device_missing_protocol;
     case(SubBruteFileResultProtocolNotSupported):
-        result = "Protocol unsupported";
-        break;
+        return error_device_protocol_unsupported;
     case(SubBruteFileResultDynamicProtocolNotValid):
-        result = "Dynamic protocol unsupported";
-        break;
+        return error_device_dynamic_protocol_unsupported;
     case(SubBruteFileResultProtocolNotFound):
-        result = "Protocol not found";
-        break;
+        return error_device_protocol_not_found;
     case(SubBruteFileResultMissingOrIncorrectBit):
-        result = "Missing or incorrect Bit";
-        break;
+        return error_device_missing_bit;
     case(SubBruteFileResultMissingOrIncorrectKey):
-        result = "Missing or incorrect Key";
-        break;
+        return error_device_missing_key;
     case(SubBruteFileResultMissingOrIncorrectTe):
-        result = "Missing or incorrect TE";
-        break;
+        return error_device_missing_te;
     case SubBruteFileResultUnknown:
     default:
-        result = "Unknown error";
-        break;
+        return error_device_unknown;
     }
-    return result;
-}
-
-void subbrute_device_free_protocol_info(SubBruteDevice* instance) {
-    furi_assert(instance);
-    instance->protocol_info = NULL;
-    if(instance->file_protocol_info) {
-        free(instance->file_protocol_info);
-    }
-    instance->file_protocol_info = NULL;
 }

+ 45 - 27
subbrute_device.h

@@ -1,11 +1,12 @@
 #pragma once
 
 #include "subbrute_protocols.h"
+#include "helpers/subbrute_radio_device_loader.h"
+
 #include <lib/subghz/protocols/base.h>
 #include <lib/subghz/transmitter.h>
 #include <lib/subghz/receiver.h>
 #include <lib/subghz/environment.h>
-#include "helpers/subbrute_radio_device_loader.h"
 
 #define SUBBRUTE_MAX_LEN_NAME 64
 #define SUBBRUTE_PATH EXT_PATH("subghz")
@@ -42,41 +43,57 @@ typedef enum {
  *
  * This structure contains information and state variables required for performing
  * a SubBrute attack.
+ *
  */
 typedef struct {
-    const SubBruteProtocol* protocol_info;
-    SubBruteProtocol* file_protocol_info;
-
-    // Current step
-    uint64_t current_step;
-
-    // SubGhz
-    SubGhzReceiver* receiver;
-    SubGhzProtocolDecoderBase* decoder_result;
-    SubGhzEnvironment* environment;
-    const SubGhzDevice* radio_device;
-
-    // Attack state
-    SubBruteAttacks attack;
-    uint64_t max_value;
-    uint8_t extra_repeats;
-
-    // Loaded info for attack type
-    uint64_t key_from_file;
-    uint64_t current_key_from_file;
-    bool two_bytes;
-
-    // Index of group to bruteforce in loaded file
-    uint8_t bit_index;
+    const SubBruteProtocol* protocol_info; /**< Protocol info */
+    SubBruteProtocol* file_protocol_info; /**< File protocol info */
+
+    uint64_t current_step; /**< Current step */
+
+     /** @see @c SubGhz service for more info */
+    SubGhzReceiver* receiver; /**< Receiver */
+    SubGhzProtocolDecoderBase* decoder_result; /**< Decoder result */
+    SubGhzEnvironment* environment; /**< Environment */
+    const SubGhzDevice* radio_device; /**< Radio device */
+
+    SubBruteAttacks attack; /**< Attack state */
+    uint64_t max_value; /**< Max step */
+    uint8_t extra_repeats; /**< Extra repeats */
+
+    /** @brief Loaded info for the attack type */
+    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 bit_index; /**< Index of a group to bruteforce in loaded file */
 } SubBruteDevice;
 
+/**
+ * @brief Response messages
+ * */
+static char* const error_device_ok = "OK";
+static char* const error_device_invalid_path = "invalid name/path";
+static char* const error_device_missing_header = "Missing or incorrect header";
+static char* const error_device_invalid_frequency = "Invalid frequency!";
+static char* const error_device_incorrect_frequency = "Missing or incorrect Frequency";
+static char* const error_device_preset_fail = "Preset FAIL";
+static char* const error_device_missing_protocol = "Missing Protocol";
+static char* const error_device_protocol_unsupported = "Protocol unsupported";
+static char* const error_device_dynamic_protocol_unsupported = "Dynamic protocol unsupported";
+static char* const error_device_protocol_not_found = "Protocol not found";
+static char* const error_device_missing_bit = "Missing or incorrect Bit";
+static char* const error_device_missing_key = "Missing or incorrect Key";
+static char* const error_device_missing_te = "Missing or incorrect TE";
+static char* const error_device_unknown = "Unknown error";
+
 /**
  * @brief Allocates memory for a SubBruteDevice structure.
  *
  * This function allocates memory for a SubBruteDevice structure and
  * initializes it using the given SubGhzDevice.
  *
- * @param radio_device The SubGhzDevice used to initialize the SubBruteDevice.
+ * @param[in] radio_device The SubGhzDevice used to initialize the SubBruteDevice.
  * @return A pointer to the allocated SubBruteDevice structure.
  */
 SubBruteDevice* subbrute_device_alloc(const SubGhzDevice* radio_device);
@@ -87,7 +104,8 @@ SubBruteDevice* subbrute_device_alloc(const SubGhzDevice* radio_device);
  * This function frees the memory allocated for a SubBruteDevice instance.
  * After calling this function, the instance is no longer valid and should not be used.
  *
- * @param instance Pointer to the SubBruteDevice instance to be freed.
+ * @param[out] instance Pointer to the SubBruteDevice instance to be freed.
+ *
  */
 void subbrute_device_free(SubBruteDevice* instance);
 

+ 16 - 19
subbrute_i.h

@@ -17,7 +17,7 @@
 #include <gui/modules/loading.h>
 #include <gui/modules/variable_item_list.h>
 
-#include "subghz_bruteforcer_icons.h"
+#include <subghz_bruteforcer_icons.h>
 
 #include <dialogs/dialogs.h>
 
@@ -31,7 +31,7 @@
 #include "views/subbrute_attack_view.h"
 #include "views/subbrute_main_view.h"
 
-#define SUBBRUTEFORCER_VER "Sub-GHz BruteForcer 3.C"
+#define SUB_BRUTE_FORCER_VERSION "Sub-GHz BruteForcer 3.D"
 
 #ifdef FURI_DEBUG
 //#define SUBBRUTE_FAST_TRACK false
@@ -45,11 +45,11 @@
  * corresponds to a specific screen or UI element in the application.
  */
 typedef enum {
-    SubBruteViewNone,
+    SubBruteViewNone, /**< Not used */
     SubBruteViewMain,
     SubBruteViewAttack,
     SubBruteViewTextInput,
-    SubBruteViewDialogEx,
+    SubBruteViewDialogEx, /**< Not used */
     SubBruteViewPopup,
     SubBruteViewWidget,
     SubBruteViewStack,
@@ -63,7 +63,7 @@ typedef enum {
  * This class contains the various elements and variables necessary for the functioning of a SubBrute application.
  */
 struct SubBruteState {
-    // GUI elements
+    /** GUI elements */
     NotificationApp* notifications;
     Gui* gui;
     ViewDispatcher* view_dispatcher;
@@ -73,26 +73,23 @@ struct SubBruteState {
     Widget* widget;
     VariableItemList* var_list;
     DialogsApp* dialogs;
-    const SubGhzDevice* radio_device;
 
-    // Text store
-    char text_store[SUBBRUTE_MAX_LEN_NAME];
+
+    char text_store[SUBBRUTE_MAX_LEN_NAME]; /**< Text store */
     FuriString* file_path;
 
-    // Views
-    SubBruteMainView* view_main;
-    SubBruteAttackView* view_attack;
+    const SubGhzDevice* radio_device; /**< Radio device */
+
+    /** Views */
+    SubBruteMainView* view_main; /**< Main menu */
+    SubBruteAttackView* view_attack; /**< View for attack and setup current protocol */
     SubBruteView current_view;
 
-    // Scene
-    SceneManager* scene_manager;
+    SceneManager* scene_manager; /**< Scene manager */
 
-    // SubBruteDevice
-    SubBruteDevice* device;
-    // SubBruteWorker
-    SubBruteWorker* worker;
-    // Last used settings
-    SubBruteSettings* settings;
+    SubBruteDevice* device; /**< SubBruteDevice to get value of transmission */
+    SubBruteWorker* worker; /**< SubBruteWorker worker for background job */
+    SubBruteSettings* settings; /**< Last used settings */
 };
 
 /**

+ 24 - 25
subbrute_protocols.c

@@ -555,6 +555,20 @@ static const char* subbrute_key_small_no_tail = "Bit: %d\nKey: %s\nRepeat: %d\n"
 //    "Filetype: Flipper SubGhz Key File\nVersion: 1\nFrequency: %u\nPreset: %s\nProtocol: %s\nBit: %d\n";
 static const char* subbrute_key_small_with_tail = "Bit: %d\nKey: %s\nTE: %d\nRepeat: %d\n";
 
+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 uint64_t gate_smsc = 0x01D5; // 111010101
+//const uint8_t gate2 = 0x0175; // 101110101
+
+const uint64_t gate_pt2260 = 0x03; // 11
+//const uint8_t button_lock = 0x0C; // 1100
+//const uint8_t button_stop = 0x30; // 110000
+//const uint8_t button_close = 0xC0; // 11000000
+
+const uint64_t gate_uni_alarm = 3 << 7;
+//const uint8_t gate2 = 3 << 5;
+
 const char* subbrute_protocol_name(SubBruteAttacks index) {
     return subbrute_protocol_names[index];
 }
@@ -601,7 +615,7 @@ void subbrute_protocol_create_candidate_for_existing_file(
     size_t bit_index,
     uint64_t file_key,
     bool two_bytes) {
-    uint8_t p[8];
+    uint8_t p[8] = {0};
     for(int i = 0; i < 8; i++) {
         p[i] = (uint8_t)(file_key >> 8 * (7 - i)) & 0xFF;
     }
@@ -635,56 +649,41 @@ void subbrute_protocol_create_candidate_for_default(
     FuriString* candidate,
     SubBruteFileProtocol file,
     uint64_t step) {
-    uint8_t p[8];
-    if(file == SMC5326FileProtocol) {
-        const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11
-        const uint64_t gate1 = 0x01D5; // 111010101
-        //const uint8_t gate2 = 0x0175; // 101110101
+    uint8_t p[8] = {0};
+    uint64_t total = 0;
 
-        uint64_t total = 0;
+    if(file == SMC5326FileProtocol) {
         for(size_t j = 0; j < 8; j++) {
-            total |= lut[step % 3] << (2 * j);
+            total |= lut_uni_alarm_smsc[step % 3] << (2 * j);
             double sub_step = (double)step / 3;
             step = (uint64_t)floor(sub_step);
         }
         total <<= 9;
-        total |= gate1;
+        total |= gate_smsc;
 
         for(int i = 0; i < 8; i++) {
             p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;
         }
     } else if(file == UNILARMFileProtocol) {
-        const uint8_t lut[] = {0x00, 0x02, 0x03}; // 00, 10, 11
-        const uint64_t gate1 = 3 << 7;
-        //const uint8_t gate2 = 3 << 5;
-
-        uint64_t total = 0;
         for(size_t j = 0; j < 8; j++) {
-            total |= lut[step % 3] << (2 * j);
+            total |= lut_uni_alarm_smsc[step % 3] << (2 * j);
             double sub_step = (double)step / 3;
             step = (uint64_t)floor(sub_step);
         }
         total <<= 9;
-        total |= gate1;
+        total |= gate_uni_alarm;
 
         for(int i = 0; i < 8; i++) {
             p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;
         }
     } else if(file == PT2260FileProtocol) {
-        const uint8_t lut[] = {0x00, 0x01, 0x03}; // 00, 01, 11
-        const uint64_t button_open = 0x03; // 11
-        //const uint8_t button_lock = 0x0C; // 1100
-        //const uint8_t button_stop = 0x30; // 110000
-        //const uint8_t button_close = 0xC0; // 11000000
-
-        uint64_t total = 0;
         for(size_t j = 0; j < 8; j++) {
-            total |= lut[step % 3] << (2 * j);
+            total |= lut_pt2260[step % 3] << (2 * j);
             double sub_step = (double)step / 3;
             step = (uint64_t)floor(sub_step);
         }
         total <<= 8;
-        total |= button_open;
+        total |= gate_pt2260;
 
         for(int i = 0; i < 8; i++) {
             p[i] = (uint8_t)(total >> 8 * (7 - i)) & 0xFF;

+ 2 - 2
subbrute_settings.h

@@ -14,8 +14,8 @@
  * the last index used.
  */
 typedef struct {
-    uint8_t repeat_values[SubBruteAttackTotalCount];
-    uint32_t last_index;
+    uint8_t repeat_values[SubBruteAttackTotalCount]; /**< Array of repeat values */
+    uint32_t last_index; /**< Last index used */
 } SubBruteSettings;
 
 /**

+ 3 - 4
views/subbrute_attack_view.c

@@ -17,7 +17,6 @@ struct SubBruteAttackView {
     uint64_t max_value;
     uint64_t current_step;
     bool is_attacking;
-    // uint8_t extra_repeats;
 };
 
 typedef struct {
@@ -161,7 +160,7 @@ SubBruteAttackView* subbrute_attack_view_alloc() {
 
 void subbrute_attack_view_enter(void* context) {
     furi_assert(context);
-    SubBruteAttackView* instance = context;
+    SubBruteAttackView* instance = (SubBruteAttackView*)context;
     with_view_model(
         instance->view,
         SubBruteAttackViewModel * model,
@@ -202,8 +201,8 @@ void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_
         true);
 }
 
-// We need to call init every time, because not every time we calls enter
-// normally, call enter only once
+// We need to call init every time, because not every time we call "enter"
+// normally, so call "enter" only once
 void subbrute_attack_view_init_values(
     SubBruteAttackView* instance,
     uint8_t index,

+ 37 - 13
views/subbrute_attack_view.h

@@ -12,22 +12,21 @@ typedef struct SubBruteAttackView SubBruteAttackView;
  * @brief Sets the callback function and context for the SubBruteAttackView.
  *
  * This function sets the callback function and context that will be used by the SubBruteAttackView
- * instance. The callback function will be called when a certain event occurs in the SubBruteAttackView.
+ * instance. The callback function will be called when a particular event occurs in the SubBruteAttackView.
  * The context parameter will be passed to the callback function as an argument.
  *
- * @param instance The SubBruteAttackView instance to set the callback for.
- * @param callback The callback function to be called when the event occurs.
- * @param context The context to be passed to the callback function when it is called.
+ * @param[in] instance The SubBruteAttackView instance to set the callback for.
+ * @param[in] callback The callback function to be called when an event occurs.
+ * @param[in] context The context to be passed to the callback function when it is called.
  *
  * @note The callback function should have the following signature:
- *       void callback(void* context)
+ *       `void callback(SubBruteCustomEvent event, void* context)`
  *
  * @note The callback function should not take ownership of the instance, it should only perform
  *       the necessary logic based on the event.
  *
  * @warning The instance parameter must not be NULL.
  * @warning The callback parameter must not be NULL.
- *
  */
 void subbrute_attack_view_set_callback(
     SubBruteAttackView* instance,
@@ -37,25 +36,39 @@ void subbrute_attack_view_set_callback(
 /**
  * @brief Allocates memory for a new SubBruteAttackView object.
  *
- * This function allocates memory for a new SubBruteAttackView object on the heap and returns a pointer to it.
+ * This function allocates memory for a new @c SubBruteAttackView structure on the heap, assigns necessary properties
+ * and returns a pointer to it. The SubBruteAttackView struct is consisted of attributes attack_type, max_value,
+ * current_step, is_attacking and icon. The initial values are assigned in this function. It also sets up
+ * the necessary callbacks for view drawing, input handling, and entrance/exit events.
+ *
+ * @note As there are no input parameters, @c tag is not required for this function. Instead, the structure
+ *       SubBruteAttackView and its members are initialized within the function.
+ *
+ * @return A pointer to a newly allocated @c SubBruteAttackView object.
  *
- * @return A pointer to a newly allocated SubBruteAttackView object.
  */
 SubBruteAttackView* subbrute_attack_view_alloc();
 
 /**
  * @brief Frees the memory allocated for a SubBruteAttackView instance.
  *
- * @param instance Pointer to the SubBruteAttackView instance to free.
+ * The function verifies the provided instance, frees the icon animation in the
+ * associated view model (if any), frees the view, and finally, frees the instance itself.
+ * This effectively destroys the SubBruteAttackView instance and cleans up the associated resources.
+ * After a call to this function, the provided pointer should not be used.
+ *
+ * @param[in] instance Pointer to the SubBruteAttackView instance to free.
+ *
  */
 void subbrute_attack_view_free(SubBruteAttackView* instance);
 
 /**
  * @brief Retrieves the view associated with the SubBruteAttackView instance.
  *
- * @param instance The SubBruteAttackView instance to retrieve the view from.
+ * @param[in] instance The SubBruteAttackView instance to retrieve the view from.
  *
  * @return A pointer to the associated view.
+ *
  */
 View* subbrute_attack_view_get_view(SubBruteAttackView* instance);
 
@@ -65,8 +78,8 @@ View* subbrute_attack_view_get_view(SubBruteAttackView* instance);
  * This function sets the current step of the SubBruteAttackView instance
  * to the specified value.
  *
- * @param instance A pointer to the SubBruteAttackView instance.
- * @param current_step The value to set as the current step.
+ * @param [in] instance A pointer to the SubBruteAttackView instance.
+ * @param [in] current_step The value to set as the current step.
  *
  * @note The current step represents the current progress of the attack view.
  *       It should be an unsigned 64-bit integer.
@@ -80,6 +93,17 @@ void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_
  * The SubBruteAttackView class is used to store and initialize the values
  * of a SubBruteAttackView instance. These values include the index, maximum value,
  * current step, attack status, and extra repeats.
+ *
+ * @note We need to call init every time, because not every time we call "enter"
+ *       normally, so call "enter" only once
+ *
+ * @param[in] instance A pointer to the instance of SubBruteAttackView to be initialized.
+ * @param[in] index The starting index for attack.
+ * @param[in] max_value The maximum value that could be used for the attack.
+ * @param[in] current_step The current step of the attack.
+ * @param[in] is_attacking A boolean flag to identify if the current instance is attacking.
+ * @param[in] extra_repeats The number of extra repeats in the attack.
+ *
  */
 void subbrute_attack_view_init_values(
     SubBruteAttackView* instance,
@@ -87,4 +111,4 @@ void subbrute_attack_view_init_values(
     uint64_t max_value,
     uint64_t current_step,
     bool is_attacking,
-    uint8_t extra_repeats);
+    uint8_t extra_repeats);

+ 1 - 1
views/subbrute_main_view.c

@@ -140,7 +140,7 @@ void subbrute_main_view_draw_is_ordinary_selected(Canvas* canvas, SubBruteMainVi
     canvas_set_font(canvas, FontPrimary);
     canvas_draw_box(canvas, 0, 0, canvas_width(canvas), STATUS_BAR_Y_SHIFT);
     canvas_invert_color(canvas);
-    canvas_draw_str_aligned(canvas, 64, 3, AlignCenter, AlignTop, SUBBRUTEFORCER_VER);
+    canvas_draw_str_aligned(canvas, 64, 3, AlignCenter, AlignTop, SUB_BRUTE_FORCER_VERSION);
     canvas_invert_color(canvas);
 
     // Menu