Sfoglia il codice sorgente

Merge pull request #8 from jblanked/dev_1.4

FlipWiFi - v1.4
JBlanked 9 mesi fa
parent
commit
e5b11b4877
9 ha cambiato i file con 1035 aggiunte e 1178 eliminazioni
  1. 5 0
      CHANGELOG.md
  2. 1 1
      README.md
  3. 1 1
      alloc/flip_wifi_alloc.c
  4. 21 22
      app.c
  5. 1 1
      application.fam
  6. BIN
      assets/01-home.png
  7. 114 168
      callback/flip_wifi_callback.c
  8. 756 706
      flipper_http/flipper_http.c
  9. 136 279
      flipper_http/flipper_http.h

+ 5 - 0
CHANGELOG.md

@@ -1,3 +1,8 @@
+## v1.4
+- Updated to the latest FlipperHTTP library.
+- Added a check to verify the WiFi connection was successful.
+- Updated the WiFi scan to use JSON for handling unconventional network names.
+
 ## v1.3.2
 - Fixed a crash that occurred when deleting a network from the Saved APs list.
 - Updated to connect to the network after clicking "Set" on the selected SSID in the Saved APs list.

+ 1 - 1
README.md

@@ -2,7 +2,7 @@ FlipWiFi is the companion app for the popular FlipperHTTP flash, originally intr
 
 ## Requirements
 
-- WiFi Developer Board, Raspberry Pi, or ESP32 Device with FlipperHTTP Flash: https://github.com/jblanked/FlipperHTTP
+- WiFi Developer Board, Raspberry Pi, or ESP32 Device flashed with FlipperHTTP v1.8.2 or higher: https://github.com/jblanked/FlipperHTTP
 - 2.4 GHz WiFi Access Point
 
 ## Features

+ 1 - 1
alloc/flip_wifi_alloc.c

@@ -14,7 +14,7 @@ FlipWiFiApp *flip_wifi_app_alloc()
     }
 
     // Submenu
-    if (!easy_flipper_set_submenu(&app->submenu_main, FlipWiFiViewSubmenuMain, "FlipWiFi v1.3.2", callback_exit_app, &app->view_dispatcher))
+    if (!easy_flipper_set_submenu(&app->submenu_main, FlipWiFiViewSubmenuMain, "FlipWiFi v1.4", callback_exit_app, &app->view_dispatcher))
     {
         return NULL;
     }

+ 21 - 22
app.c

@@ -15,33 +15,32 @@ int32_t flip_wifi_main(void *p)
     }
 
     // check if board is connected (Derek Jamison)
-    // initialize the http
-    if (flipper_http_init(flipper_http_rx_callback, app))
+    FlipperHTTP *fhttp = flipper_http_alloc();
+    if (!fhttp)
     {
-        if (!flipper_http_ping())
-        {
-            FURI_LOG_E(TAG, "Failed to ping the device");
-            return -1;
-        }
-
-        // Try to wait for pong response.
-        uint8_t counter = 10;
-        while (fhttp.state == INACTIVE && --counter > 0)
-        {
-            FURI_LOG_D(TAG, "Waiting for PONG");
-            furi_delay_ms(100);
-        }
-
-        if (counter == 0)
-            easy_flipper_dialog("FlipperHTTP Error", "Ensure your WiFi Developer\nBoard or Pico W is connected\nand the latest FlipperHTTP\nfirmware is installed.");
-
-        flipper_http_deinit();
+        easy_flipper_dialog("FlipperHTTP Error", "The UART is likely busy.\nEnsure you have the correct\nflash for your board then\nrestart your Flipper Zero.");
+        return -1;
     }
-    else
+
+    if (!flipper_http_send_command(fhttp, HTTP_CMD_PING))
     {
-        easy_flipper_dialog("FlipperHTTP Error", "The UART is likely busy.\nEnsure you have the correct\nflash for your board then\nrestart your Flipper Zero.");
+        FURI_LOG_E(TAG, "Failed to ping the device");
+        flipper_http_free(fhttp);
+        return -1;
     }
 
+    // Try to wait for pong response.
+    uint32_t counter = 10;
+    while (fhttp->state == INACTIVE && --counter > 0)
+    {
+        FURI_LOG_D(TAG, "Waiting for PONG");
+        furi_delay_ms(100); // this causes a BusFault
+    }
+    flipper_http_free(fhttp);
+
+    if (counter == 0)
+        easy_flipper_dialog("FlipperHTTP Error", "Ensure your WiFi Developer\nBoard or Pico W is connected\nand the latest FlipperHTTP\nfirmware is installed.");
+
     // Run the view dispatcher
     view_dispatcher_run(app->view_dispatcher);
 

+ 1 - 1
application.fam

@@ -9,6 +9,6 @@ App(
     fap_icon_assets="assets",
     fap_author="JBlanked",
     fap_weburl="https://github.com/jblanked/FlipWiFi",
-    fap_version="1.3.2",
+    fap_version="1.4",
     fap_description="FlipperHTTP companion app.",
 )

BIN
assets/01-home.png


+ 114 - 168
callback/flip_wifi_callback.c

@@ -133,7 +133,7 @@ static bool flip_wifi_alloc_widgets(void *context, uint32_t widget)
     case FlipWiFiViewAbout:
         if (!app->widget_info)
         {
-            if (!easy_flipper_set_widget(&app->widget_info, FlipWiFiViewAbout, "FlipWiFi v1.3.2\n-----\nFlipperHTTP companion app.\nScan and save WiFi networks.\n-----\nwww.github.com/jblanked", callback_to_submenu_main, &app->view_dispatcher))
+            if (!easy_flipper_set_widget(&app->widget_info, FlipWiFiViewAbout, "FlipWiFi v1.4\n-----\nFlipperHTTP companion app.\nScan and save WiFi networks.\n-----\nwww.github.com/jblanked", callback_to_submenu_main, &app->view_dispatcher))
             {
                 return false;
             }
@@ -263,17 +263,23 @@ static void flip_wifi_custom_command_updated(void *context)
         FURI_LOG_E(TAG, "Text input buffer is empty");
         return;
     }
+    FlipperHTTP *fhttp = flipper_http_alloc();
+    if (!fhttp)
+    {
+        FURI_LOG_E(TAG, "Failed to allocate FlipperHTTP");
+        return;
+    }
     // Send the custom command
-    flipper_http_send_data(app->uart_text_input_temp_buffer);
-    while (fhttp.last_response == NULL || strlen(fhttp.last_response) == 0)
+    flipper_http_send_data(fhttp, app->uart_text_input_temp_buffer);
+    while (fhttp->last_response == NULL || strlen(fhttp->last_response) == 0)
     {
         furi_delay_ms(100);
     }
     // Switch to the view
     char response[100];
-    snprintf(response, sizeof(response), "%s", fhttp.last_response);
+    snprintf(response, sizeof(response), "%s", fhttp->last_response);
     easy_flipper_dialog("", response);
-    flipper_http_deinit();
+    flipper_http_free(fhttp);
     view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
 }
 
@@ -564,28 +570,38 @@ static bool flip_wifi_view_input_callback_saved(InputEvent *event, void *context
         save_settings(wifi_playlist->ssids[ssid_index], wifi_playlist->passwords[ssid_index]);
 
         // initialize uart
-        if (!flipper_http_init(flipper_http_rx_callback, app))
+        FlipperHTTP *fhttp = flipper_http_alloc();
+        if (!fhttp)
         {
             easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
             return false;
         }
 
         // clear response
-        if (fhttp.last_response)
-            snprintf(fhttp.last_response, RX_BUF_SIZE, "%s", "");
+        if (fhttp->last_response)
+            snprintf(fhttp->last_response, RX_BUF_SIZE, "%s", "");
 
-        if (!flipper_http_save_wifi(wifi_playlist->ssids[ssid_index], wifi_playlist->passwords[ssid_index]))
+        if (!flipper_http_save_wifi(fhttp, wifi_playlist->ssids[ssid_index], wifi_playlist->passwords[ssid_index]))
         {
             easy_flipper_dialog("[ERROR]", "Failed to save WiFi settings");
             return false;
         }
 
-        while (!fhttp.last_response || strlen(fhttp.last_response) == 0)
+        while (!fhttp->last_response || strlen(fhttp->last_response) == 0)
         {
             furi_delay_ms(100);
         }
 
-        flipper_http_deinit();
+        flipper_http_free(fhttp);
+
+        // check success (if [SUCCESS] is in the response)
+        if (strstr(fhttp->last_response, "[SUCCESS]") == NULL)
+        {
+            char response[512];
+            snprintf(response, sizeof(response), "Failed to save WiFi settings:\n%s", fhttp->last_response);
+            easy_flipper_dialog("[ERROR]", response);
+            return false;
+        }
 
         easy_flipper_dialog("[SUCCESS]", "All FlipperHTTP apps will now\nuse the selected network.");
         return true;
@@ -622,171 +638,108 @@ static bool flip_wifi_view_input_callback_saved(InputEvent *event, void *context
     }
     return false;
 }
-
-// Function to trim leading and trailing whitespace
-// Returns the trimmed start pointer and updates the length
-static char *trim_whitespace(char *start, size_t *length)
-{
-    // Trim leading whitespace
-    while (*length > 0 && isspace((unsigned char)*start))
-    {
-        start++;
-        (*length)--;
-    }
-
-    // Trim trailing whitespace
-    while (*length > 0 && isspace((unsigned char)start[*length - 1]))
-    {
-        (*length)--;
-    }
-
-    return start;
-}
-
-static bool flip_wifi_handle_scan(void *context)
+void callback_submenu_choices(void *context, uint32_t index)
 {
     FlipWiFiApp *app = (FlipWiFiApp *)context;
     if (!app)
     {
         FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
-        return false;
+        return;
     }
-    // load the received data from the saved file
-    FuriString *scan_data = flipper_http_load_from_file(fhttp.file_path);
-    if (scan_data == NULL)
+    // initialize uart
+    FlipperHTTP *fhttp = flipper_http_alloc();
+    if (!fhttp)
     {
-        FURI_LOG_E(TAG, "Failed to load received data from file.");
-        fhttp.state = ISSUE;
-        easy_flipper_dialog("[ERROR]", "Failed to load data from /apps_data/flip_wifi/data/scan.txt");
-        return false;
+        easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
+        return;
     }
-
-    uint32_t ssid_count = 0;
-
-    char *current_position = (char *)furi_string_get_cstr(scan_data);
-    char *next_comma = NULL;
-
-    // Manually split the string on commas
-    while ((next_comma = strchr(current_position, ',')) != NULL)
+    switch (index)
     {
-        // Calculate length of the SSID
-        size_t ssid_length = next_comma - current_position;
-
-        // Trim leading and trailing whitespace
-        size_t trimmed_length = ssid_length;
-        char *trim_start = trim_whitespace(current_position, &trimmed_length);
-
-        // Handle empty SSIDs resulting from consecutive commas
-        if (trimmed_length == 0)
+    case FlipWiFiSubmenuIndexWiFiScan:
+        flip_wifi_free_all(app);
+        if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuScan))
         {
-            current_position = next_comma + 1; // Move past the comma
-            continue;
+            easy_flipper_dialog("[ERROR]", "Failed to allocate submenus for WiFi Scan");
+            return;
         }
 
-        // Allocate memory for the SSID and copy it
-        ssid_list[ssid_count] = malloc(trimmed_length + 1);
-        if (ssid_list[ssid_count] == NULL)
+        // scan for wifi ad parse the results
+        bool _flip_wifi_scan()
         {
-            FURI_LOG_E(TAG, "Memory allocation failed");
-            easy_flipper_dialog("[ERROR]", "Memory allocation failed");
-            furi_string_free(scan_data);
-            return false;
-        }
-        strncpy(ssid_list[ssid_count], trim_start, trimmed_length);
-        ssid_list[ssid_count][trimmed_length] = '\0'; // Null-terminate the string
+            // storage setup
+            Storage *storage = furi_record_open(RECORD_STORAGE);
 
-        ssid_count++;
-        if (ssid_count >= MAX_SCAN_NETWORKS)
-        {
-            FURI_LOG_E(TAG, "Maximum SSID limit reached");
-            break;
-        }
+            snprintf(fhttp->file_path, sizeof(fhttp->file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_wifi/data/scan.txt");
+            storage_simply_remove_recursive(storage, fhttp->file_path); // ensure the file is empty
 
-        current_position = next_comma + 1; // Move past the comma
-    }
+            // ensure flip_wifi directory is there
+            char directory_path[128];
+            snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_wifi");
+            storage_common_mkdir(storage, directory_path);
 
-    // Handle the last SSID after the last comma (if any)
-    if (*current_position != '\0' && ssid_count < MAX_SCAN_NETWORKS)
-    {
-        size_t ssid_length = strlen(current_position);
+            snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_wifi/data");
+            storage_common_mkdir(storage, directory_path);
 
-        // Trim leading and trailing whitespace
-        size_t trimmed_length = ssid_length;
-        char *trim_start = trim_whitespace(current_position, &trimmed_length);
+            furi_record_close(RECORD_STORAGE);
 
-        // Handle empty SSIDs
-        if (trimmed_length > 0)
+            fhttp->just_started = true;
+            fhttp->save_received_data = true;
+            return flipper_http_send_command(fhttp, HTTP_CMD_SCAN);
+        }
+
+        bool _flip_wifi_handle_scan()
         {
-            ssid_list[ssid_count] = malloc(trimmed_length + 1);
-            if (ssid_list[ssid_count] == NULL)
+            // load the received data from the saved file
+            FuriString *scan_data = flipper_http_load_from_file(fhttp->file_path);
+            if (scan_data == NULL)
             {
-                FURI_LOG_E(TAG, "Memory allocation failed for the last SSID");
-                easy_flipper_dialog("[ERROR]", "Memory allocation failed for the last SSID");
+                FURI_LOG_E(TAG, "Failed to load received data from file.");
+                easy_flipper_dialog("[ERROR]", "Failed to load data from /apps_data/flip_wifi/data/scan.txt");
                 return false;
             }
-            strncpy(ssid_list[ssid_count], trim_start, trimmed_length);
-            ssid_list[ssid_count][trimmed_length] = '\0'; // Null-terminate the string
-            ssid_count++;
-        }
-    }
 
-    // Add each SSID as a submenu item
-    submenu_reset(app->submenu_wifi);
-    submenu_set_header(app->submenu_wifi, "WiFi Nearby");
-    for (uint32_t i = 0; i < ssid_count; i++)
-    {
-        char *ssid_item = ssid_list[i];
-        if (ssid_item == NULL)
-        {
-            // skip any NULL entries
-            continue;
-        }
-        char ssid[64];
-        snprintf(ssid, sizeof(ssid), "%s", ssid_item);
-        submenu_add_item(app->submenu_wifi, ssid, FlipWiFiSubmenuIndexWiFiScanStart + i, callback_submenu_choices, app);
-    }
-    furi_string_free(scan_data);
-    return true;
-}
-void callback_submenu_choices(void *context, uint32_t index)
-{
-    FlipWiFiApp *app = (FlipWiFiApp *)context;
-    if (!app)
-    {
-        FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
-        return;
-    }
-    switch (index)
-    {
-    case FlipWiFiSubmenuIndexWiFiScan:
-        flip_wifi_free_all(app);
-        if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuScan))
-        {
-            easy_flipper_dialog("[ERROR]", "Failed to allocate submenus for WiFi Scan");
-            return;
-        }
-        // initialize uart
-        if (!flipper_http_init(flipper_http_rx_callback, app))
-        {
-            easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
-            return;
-        }
-        bool _flip_wifi_handle_scan()
-        {
-            return flip_wifi_handle_scan(app);
+            uint8_t ssid_count = 0;
+
+            for (uint8_t i = 0; i < MAX_SCAN_NETWORKS; i++)
+            {
+                char *ssid_item = get_json_array_value("networks", i, furi_string_get_cstr(scan_data));
+                if (ssid_item == NULL)
+                {
+                    // end of the list
+                    break;
+                }
+                ssid_list[i] = malloc(MAX_SSID_LENGTH);
+                if (ssid_list[i] == NULL)
+                {
+                    FURI_LOG_E(TAG, "Failed to allocate memory for SSID");
+                    furi_string_free(scan_data);
+                    return false;
+                }
+                snprintf(ssid_list[i], MAX_SSID_LENGTH, "%s", ssid_item);
+                free(ssid_item);
+                ssid_count++;
+            }
+
+            // Add each SSID as a submenu item
+            submenu_reset(app->submenu_wifi);
+            submenu_set_header(app->submenu_wifi, "WiFi Nearby");
+            for (uint8_t i = 0; i < ssid_count; i++)
+            {
+                char *ssid_item = ssid_list[i];
+                if (ssid_item == NULL)
+                {
+                    // end of the list
+                    break;
+                }
+                char ssid[64];
+                snprintf(ssid, sizeof(ssid), "%s", ssid_item);
+                submenu_add_item(app->submenu_wifi, ssid, FlipWiFiSubmenuIndexWiFiScanStart + i, callback_submenu_choices, app);
+            }
+            furi_string_free(scan_data);
+            return true;
         }
-        Storage *storage = furi_record_open(RECORD_STORAGE);
-        // ensure flip_wifi directory is there
-        char directory_path[128];
-        snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_wifi");
-        storage_common_mkdir(storage, directory_path);
-        // ensure directory is there for saving data
-        snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_wifi/data");
-        storage_common_mkdir(storage, directory_path);
-        furi_record_close(RECORD_STORAGE);
-        // scan for wifi ad parse the results
-        flipper_http_loading_task(flipper_http_scan_wifi, _flip_wifi_handle_scan, FlipWiFiViewSubmenu, FlipWiFiViewSubmenuMain, &app->view_dispatcher);
-        flipper_http_deinit();
+
+        flipper_http_loading_task(fhttp, _flip_wifi_scan, _flip_wifi_handle_scan, FlipWiFiViewSubmenu, FlipWiFiViewSubmenuMain, &app->view_dispatcher);
         break;
     case FlipWiFiSubmenuIndexWiFiSaved:
         flip_wifi_free_all(app);
@@ -825,12 +778,6 @@ void callback_submenu_choices(void *context, uint32_t index)
         view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
         break;
     case FlipWiFiSubmenuIndexFastCommandStart ... FlipWiFiSubmenuIndexFastCommandStart + 4:
-        // initialize uart
-        if (!flipper_http_init(flipper_http_rx_callback, app))
-        {
-            easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
-            return;
-        }
         // Handle fast commands
         switch (index)
         {
@@ -846,35 +793,34 @@ void callback_submenu_choices(void *context, uint32_t index)
             return;
         case FlipWiFiSubmenuIndexFastCommandStart + 1:
             // PING
-            flipper_http_ping();
+            flipper_http_send_command(fhttp, HTTP_CMD_PING);
             break;
         case FlipWiFiSubmenuIndexFastCommandStart + 2:
             // LIST
-            flipper_http_list_commands();
+            flipper_http_send_command(fhttp, HTTP_CMD_LIST_COMMANDS);
             break;
         case FlipWiFiSubmenuIndexFastCommandStart + 3:
             // IP/ADDRESS
-            flipper_http_ip_address();
+            flipper_http_send_command(fhttp, HTTP_CMD_IP_ADDRESS);
             break;
         case FlipWiFiSubmenuIndexFastCommandStart + 4:
             // WIFI/IP
-            flipper_http_ip_wifi();
+            flipper_http_send_command(fhttp, HTTP_CMD_IP_WIFI);
             break;
         default:
             break;
         }
-        while (fhttp.last_response == NULL || strlen(fhttp.last_response) == 0)
+        while (fhttp->last_response == NULL || strlen(fhttp->last_response) == 0)
         {
             // Wait for the response
             furi_delay_ms(100);
         }
-        if (fhttp.last_response != NULL)
+        if (fhttp->last_response != NULL)
         {
             char response[100];
-            snprintf(response, sizeof(response), "%s", fhttp.last_response);
+            snprintf(response, sizeof(response), "%s", fhttp->last_response);
             easy_flipper_dialog("", response);
         }
-        flipper_http_deinit();
         break;
     case 100 ... 199:
         ssid_index = index - FlipWiFiSubmenuIndexWiFiScanStart;
@@ -901,6 +847,7 @@ void callback_submenu_choices(void *context, uint32_t index)
     default:
         break;
     }
+    flipper_http_free(fhttp);
 }
 
 void flip_wifi_text_updated_password_scan(void *context)
@@ -936,8 +883,7 @@ void flip_wifi_text_updated_password_scan(void *context)
         FURI_LOG_E(TAG, "Playlist is full. Cannot add more entries.");
         return;
     }
-    FURI_LOG_I(TAG, "Adding SSID: %s", ssid_list[ssid_index]);
-    FURI_LOG_I(TAG, "Count: %d", wifi_playlist->count);
+
     // Add the SSID and password to the playlist
     snprintf(wifi_playlist->ssids[wifi_playlist->count], MAX_SSID_LENGTH, "%s", ssid_list[ssid_index]);
     snprintf(wifi_playlist->passwords[wifi_playlist->count], MAX_SSID_LENGTH, "%s", app->uart_text_input_buffer);

File diff suppressed because it is too large
+ 756 - 706
flipper_http/flipper_http.c


+ 136 - 279
flipper_http/flipper_http.h

@@ -1,6 +1,8 @@
-// flipper_http.h
-#ifndef FLIPPER_HTTP_H
-#define FLIPPER_HTTP_H
+// Description: Flipper HTTP API (For use with Flipper Zero and the FlipperHTTP flash: https://github.com/jblanked/FlipperHTTP)
+// License: MIT
+// Author: JBlanked
+// File: flipper_http.h
+#pragma once
 
 #include <gui/gui.h>
 #include <gui/view.h>
@@ -12,17 +14,15 @@
 #include <furi_hal_serial.h>
 #include <storage/storage.h>
 
-// STORAGE_EXT_PATH_PREFIX is defined in the Furi SDK as /ext
-
-#define HTTP_TAG "FlipWiFi"               // change this to your app name
-#define http_tag "flip_wifi"              // change this to your app id
-#define UART_CH (FuriHalSerialIdUsart)    // UART channel
-#define TIMEOUT_DURATION_TICKS (5 * 1000) // 5 seconds
-#define BAUDRATE (115200)                 // UART baudrate
-#define RX_BUF_SIZE 2048                  // UART RX buffer size
-#define RX_LINE_BUFFER_SIZE 4096          // UART RX line buffer size (increase for large responses)
-#define MAX_FILE_SHOW 4096                // Maximum data from file to show
-#define FILE_BUFFER_SIZE 512              // File buffer size
+#define HTTP_TAG "FlipWiFi"                // change this to your app name
+#define http_tag "flip_wifi"               // change this to your app id
+#define UART_CH (FuriHalSerialIdUsart)     // UART channel
+#define TIMEOUT_DURATION_TICKS (15 * 1000) // 15 seconds (for WiFi scanning)
+#define BAUDRATE (115200)                  // UART baudrate
+#define RX_BUF_SIZE 2048                   // UART RX buffer size
+#define RX_LINE_BUFFER_SIZE 4096           // UART RX line buffer size (increase for large responses)
+#define MAX_FILE_SHOW 4096                 // Maximum data from file to show
+#define FILE_BUFFER_SIZE 512               // File buffer size
 
 // Forward declaration for callback
 typedef void (*FlipperHTTP_Callback)(const char *line, void *context);
@@ -35,7 +35,7 @@ typedef enum
     RECEIVING, // Receiving data
     SENDING,   // Sending data
     ISSUE,     // Issue with connection
-} SerialState;
+} HTTPState;
 
 // Event Flags for UART Worker Thread
 typedef enum
@@ -44,342 +44,199 @@ typedef enum
     WorkerEvtRxDone = (1 << 1),
 } WorkerEvtFlags;
 
-// FlipperHTTP Structure
-typedef struct
+typedef enum
 {
-    FuriStreamBuffer *flipper_http_stream;  // Stream buffer for UART communication
-    FuriHalSerialHandle *serial_handle;     // Serial handle for UART communication
-    FuriThread *rx_thread;                  // Worker thread for UART
-    FuriThreadId rx_thread_id;              // Worker thread ID
-    FlipperHTTP_Callback handle_rx_line_cb; // Callback for received lines
-    void *callback_context;                 // Context for the callback
-    SerialState state;                      // State of the UART
-
-    // variable to store the last received data from the UART
-    char *last_response;
-    char file_path[256]; // Path to save the received data
-
-    // Timer-related members
-    FuriTimer *get_timeout_timer; // Timer for HTTP request timeout
-
-    bool started_receiving_get; // Indicates if a GET request has started
-    bool just_started_get;      // Indicates if GET data reception has just started
-
-    bool started_receiving_post; // Indicates if a POST request has started
-    bool just_started_post;      // Indicates if POST data reception has just started
+    GET,    // GET request
+    POST,   // POST request
+    PUT,    // PUT request
+    DELETE, // DELETE request
+    //
+    BYTES,      // Stream bytes to file
+    BYTES_POST, // Stream bytes to file after a POST request
+} HTTPMethod;
 
-    bool started_receiving_put; // Indicates if a PUT request has started
-    bool just_started_put;      // Indicates if PUT data reception has just started
-
-    bool started_receiving_delete; // Indicates if a DELETE request has started
-    bool just_started_delete;      // Indicates if DELETE data reception has just started
-
-    // Buffer to hold the raw bytes received from the UART
-    uint8_t *received_bytes;
-    size_t received_bytes_len; // Length of the received bytes
-    bool is_bytes_request;     // Flag to indicate if the request is for bytes
-    bool save_bytes;           // Flag to save the received data to a file
-    bool save_received_data;   // Flag to save the received data to a file
+typedef enum
+{
+    HTTP_CMD_WIFI_CONNECT,
+    HTTP_CMD_WIFI_DISCONNECT,
+    HTTP_CMD_IP_ADDRESS,
+    HTTP_CMD_IP_WIFI,
+    HTTP_CMD_SCAN,
+    HTTP_CMD_LIST_COMMANDS,
+    HTTP_CMD_LED_ON,
+    HTTP_CMD_LED_OFF,
+    HTTP_CMD_PING
+} HTTPCommand; // list of non-input commands
 
-    bool just_started_bytes; // Indicates if bytes data reception has just started
+// FlipperHTTP Structure
+typedef struct
+{
+    FuriStreamBuffer *flipper_http_stream;    // Stream buffer for UART communication
+    FuriHalSerialHandle *serial_handle;       // Serial handle for UART communication
+    FuriThread *rx_thread;                    // Worker thread for UART
+    FuriThreadId rx_thread_id;                // Worker thread ID
+    FlipperHTTP_Callback handle_rx_line_cb;   // Callback for received lines
+    void *callback_context;                   // Context for the callback
+    HTTPState state;                          // State of the UART
+    HTTPMethod method;                        // HTTP method
+    char *last_response;                      // variable to store the last received data from the UART
+    char file_path[256];                      // Path to save the received data
+    FuriTimer *get_timeout_timer;             // Timer for HTTP request timeout
+    bool started_receiving;                   // Indicates if a request has started
+    bool just_started;                        // Indicates if data reception has just started
+    bool is_bytes_request;                    // Flag to indicate if the request is for bytes
+    bool save_bytes;                          // Flag to save the received data to a file
+    bool save_received_data;                  // Flag to save the received data to a file
+    bool just_started_bytes;                  // Indicates if bytes data reception has just started
+    size_t bytes_received;                    // Number of bytes received
+    char rx_line_buffer[RX_LINE_BUFFER_SIZE]; // Buffer for received lines
+    uint8_t file_buffer[FILE_BUFFER_SIZE];    // Buffer for file data
+    size_t file_buffer_len;                   // Length of the file buffer
+    size_t content_length;                    // Length of the content received
+    int status_code;                          // HTTP status code
 } FlipperHTTP;
 
-extern FlipperHTTP fhttp;
-// Global static array for the line buffer
-extern char rx_line_buffer[RX_LINE_BUFFER_SIZE];
-extern uint8_t file_buffer[FILE_BUFFER_SIZE];
-extern size_t file_buffer_len;
-
-// fhttp.last_response holds the last received data from the UART
-
-// Function to append received data to file
-// make sure to initialize the file path before calling this function
-bool flipper_http_append_to_file(
-    const void *data,
-    size_t data_size,
-    bool start_new_file,
-    char *file_path);
-
-FuriString *flipper_http_load_from_file(char *file_path);
-
-// UART worker thread
-/**
- * @brief      Worker thread to handle UART data asynchronously.
- * @return     0
- * @param      context   The context to pass to the callback.
- * @note       This function will handle received data asynchronously via the callback.
- */
-// UART worker thread
-int32_t flipper_http_worker(void *context);
-
-// Timer callback function
-/**
- * @brief      Callback function for the GET timeout timer.
- * @return     0
- * @param      context   The context to pass to the callback.
- * @note       This function will be called when the GET request times out.
- */
-void get_timeout_timer_callback(void *context);
-
-// UART RX Handler Callback (Interrupt Context)
-/**
- * @brief      A private callback function to handle received data asynchronously.
- * @return     void
- * @param      handle    The UART handle.
- * @param      event     The event type.
- * @param      context   The context to pass to the callback.
- * @note       This function will handle received data asynchronously via the callback.
- */
-void _flipper_http_rx_callback(
-    FuriHalSerialHandle *handle,
-    FuriHalSerialRxEvent event,
-    void *context);
-
-// UART initialization function
 /**
  * @brief      Initialize UART.
- * @return     true if the UART was initialized successfully, false otherwise.
- * @param      callback  The callback function to handle received data (ex. flipper_http_rx_callback).
- * @param      context   The context to pass to the callback.
+ * @return     FlipperHTTP context if the UART was initialized successfully, NULL otherwise.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_init(FlipperHTTP_Callback callback, void *context);
+FlipperHTTP *flipper_http_alloc();
 
-// Deinitialize UART
 /**
  * @brief      Deinitialize UART.
  * @return     void
+ * @param fhttp The FlipperHTTP context
  * @note       This function will stop the asynchronous RX, release the serial handle, and free the resources.
  */
-void flipper_http_deinit();
-
-// Function to send data over UART with newline termination
-/**
- * @brief      Send data over UART with newline termination.
- * @return     true if the data was sent successfully, false otherwise.
- * @param      data  The data to send over UART.
- * @note       The data will be sent over UART with a newline character appended.
- */
-bool flipper_http_send_data(const char *data);
+void flipper_http_free(FlipperHTTP *fhttp);
 
-// Function to send a PING request
 /**
- * @brief      Send a PING request to check if the Wifi Dev Board is connected.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- * @note       This is best used to check if the Wifi Dev Board is connected.
- * @note       The state will remain INACTIVE until a PONG is received.
+ * @brief      Append received data to a file.
+ * @return     true if the data was appended successfully, false otherwise.
+ * @param      data        The data to append to the file.
+ * @param      data_size   The size of the data to append.
+ * @param      start_new_file  Flag to indicate if a new file should be created.
+ * @param      file_path   The path to the file.
+ * @note       Make sure to initialize the file path before calling this function.
  */
-bool flipper_http_ping();
+bool flipper_http_append_to_file(const void *data, size_t data_size, bool start_new_file, char *file_path);
 
-// Function to list available commands
 /**
- * @brief      Send a command to list available commands.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief      Load data from a file.
+ * @return     The loaded data as a FuriString.
+ * @param      file_path The path to the file to load.
  */
-bool flipper_http_list_commands();
+FuriString *flipper_http_load_from_file(char *file_path);
 
-// Function to turn on the LED
 /**
- * @brief      Allow the LED to display while processing.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief      Load data from a file with a size limit.
+ * @return     The loaded data as a FuriString.
+ * @param      file_path The path to the file to load.
+ * @param      limit     The size limit for loading data.
  */
-bool flipper_http_led_on();
+FuriString *flipper_http_load_from_file_with_limit(char *file_path, size_t limit);
 
-// Function to turn off the LED
 /**
- * @brief      Disable the LED from displaying while processing.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief Perform a task while displaying a loading screen
+ * @param fhttp The FlipperHTTP context
+ * @param http_request The function to send the request
+ * @param parse_response The function to parse the response
+ * @param success_view_id The view ID to switch to on success
+ * @param failure_view_id The view ID to switch to on failure
+ * @param view_dispatcher The view dispatcher to use
+ * @return
  */
-bool flipper_http_led_off();
+void flipper_http_loading_task(FlipperHTTP *fhttp,
+                               bool (*http_request)(void),
+                               bool (*parse_response)(void),
+                               uint32_t success_view_id,
+                               uint32_t failure_view_id,
+                               ViewDispatcher **view_dispatcher);
 
-// Function to parse JSON data
 /**
  * @brief      Parse JSON data.
  * @return     true if the JSON data was parsed successfully, false otherwise.
+ * @param fhttp The FlipperHTTP context
  * @param      key       The key to parse from the JSON data.
  * @param      json_data The JSON data to parse.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_parse_json(const char *key, const char *json_data);
+bool flipper_http_parse_json(FlipperHTTP *fhttp, const char *key, const char *json_data);
 
-// Function to parse JSON array data
 /**
  * @brief      Parse JSON array data.
  * @return     true if the JSON array data was parsed successfully, false otherwise.
+ * @param fhttp The FlipperHTTP context
  * @param      key       The key to parse from the JSON array data.
  * @param      index     The index to parse from the JSON array data.
  * @param      json_data The JSON array data to parse.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_parse_json_array(const char *key, int index, const char *json_data);
-
-// Function to scan for WiFi networks
-/**
- * @brief      Send a command to scan for WiFi networks.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_scan_wifi();
+bool flipper_http_parse_json_array(FlipperHTTP *fhttp, const char *key, int index, const char *json_data);
 
-// Function to save WiFi settings (returns true if successful)
 /**
- * @brief      Send a command to save WiFi settings.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_save_wifi(const char *ssid, const char *password);
-
-// Function to get IP address of WiFi Devboard
-/**
- * @brief      Send a command to get the IP address of the WiFi Devboard
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_ip_address();
-
-// Function to get IP address of the connected WiFi network
-/**
- * @brief      Send a command to get the IP address of the connected WiFi network.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_ip_wifi();
-
-// Function to disconnect from WiFi (returns true if successful)
-/**
- * @brief      Send a command to disconnect from WiFi.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_disconnect_wifi();
-
-// Function to connect to WiFi (returns true if successful)
-/**
- * @brief      Send a command to connect to WiFi.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_connect_wifi();
-
-// Function to send a GET request
-/**
- * @brief      Send a GET request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the GET request to.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief Process requests and parse JSON data asynchronously
+ * @param fhttp The FlipperHTTP context
+ * @param http_request The function to send the request
+ * @param parse_json The function to parse the JSON
+ * @return true if successful, false otherwise
  */
-bool flipper_http_get_request(const char *url);
+bool flipper_http_process_response_async(FlipperHTTP *fhttp, bool (*http_request)(void), bool (*parse_json)(void));
 
-// Function to send a GET request with headers
 /**
- * @brief      Send a GET request to the specified URL.
+ * @brief      Send a request to the specified URL.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the GET request to.
- * @param      headers  The headers to send with the GET request.
+ * @param      fhttp The FlipperHTTP context
+ * @param      method The HTTP method to use.
+ * @param      url  The URL to send the request to.
+ * @param      headers  The headers to send with the request.
+ * @param      payload  The data to send with the request.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_get_request_with_headers(const char *url, const char *headers);
+bool flipper_http_request(FlipperHTTP *fhttp, HTTPMethod method, const char *url, const char *headers, const char *payload);
 
-// Function to send a GET request with headers and return bytes
 /**
- * @brief      Send a GET request to the specified URL.
+ * @brief      Send a command to save WiFi settings.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the GET request to.
- * @param      headers  The headers to send with the GET request.
+ * @param fhttp The FlipperHTTP context
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_get_request_bytes(const char *url, const char *headers);
+bool flipper_http_save_wifi(FlipperHTTP *fhttp, const char *ssid, const char *password);
 
-// Function to send a POST request with headers
 /**
- * @brief      Send a POST request to the specified URL.
+ * @brief      Send a command.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the POST request to.
- * @param      headers  The headers to send with the POST request.
- * @param      data  The data to send with the POST request.
+ * @param      fhttp The FlipperHTTP context
+ * @param      command The command to send.
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_post_request_with_headers(
-    const char *url,
-    const char *headers,
-    const char *payload);
+bool flipper_http_send_command(FlipperHTTP *fhttp, HTTPCommand command);
 
-// Function to send a POST request with headers and return bytes
 /**
- * @brief      Send a POST request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the POST request to.
- * @param      headers  The headers to send with the POST request.
- * @param      payload  The data to send with the POST request.
- * @note       The received data will be handled asynchronously via the callback.
+ * @brief      Send data over UART with newline termination.
+ * @return     true if the data was sent successfully, false otherwise.
+ * @param fhttp The FlipperHTTP context
+ * @param      data  The data to send over UART.
+ * @note       The data will be sent over UART with a newline character appended.
  */
-bool flipper_http_post_request_bytes(const char *url, const char *headers, const char *payload);
+bool flipper_http_send_data(FlipperHTTP *fhttp, const char *data);
 
-// Function to send a PUT request with headers
 /**
- * @brief      Send a PUT request to the specified URL.
+ * @brief      Send a request to the specified URL to start a WebSocket connection.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the PUT request to.
- * @param      headers  The headers to send with the PUT request.
- * @param      data  The data to send with the PUT request.
+ * @param fhttp The FlipperHTTP context
+ * @param      url  The URL to send the WebSocket request to.
+ * @param port The port to connect to
+ * @param headers The headers to send with the WebSocket request
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_put_request_with_headers(
-    const char *url,
-    const char *headers,
-    const char *payload);
+bool flipper_http_websocket_start(FlipperHTTP *fhttp, const char *url, uint16_t port, const char *headers);
 
-// Function to send a DELETE request with headers
 /**
- * @brief      Send a DELETE request to the specified URL.
+ * @brief      Send a request to stop the WebSocket connection.
  * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the DELETE request to.
- * @param      headers  The headers to send with the DELETE request.
- * @param      data  The data to send with the DELETE request.
+ * @param fhttp The FlipperHTTP context
  * @note       The received data will be handled asynchronously via the callback.
  */
-bool flipper_http_delete_request_with_headers(
-    const char *url,
-    const char *headers,
-    const char *payload);
-
-// Function to handle received data asynchronously
-/**
- * @brief      Callback function to handle received data asynchronously.
- * @return     void
- * @param      line     The received line.
- * @param      context  The context passed to the callback.
- * @note       The received data will be handled asynchronously via the callback and handles the state of the UART.
- */
-void flipper_http_rx_callback(const char *line, void *context);
-
-// Function to trim leading and trailing spaces and newlines from a constant string
-char *trim(const char *str);
-/**
- * @brief Process requests and parse JSON data asynchronously
- * @param http_request The function to send the request
- * @param parse_json The function to parse the JSON
- * @return true if successful, false otherwise
- */
-bool flipper_http_process_response_async(bool (*http_request)(void), bool (*parse_json)(void));
-
-/**
- * @brief Perform a task while displaying a loading screen
- * @param http_request The function to send the request
- * @param parse_response The function to parse the response
- * @param success_view_id The view ID to switch to on success
- * @param failure_view_id The view ID to switch to on failure
- * @param view_dispatcher The view dispatcher to use
- * @return
- */
-void flipper_http_loading_task(bool (*http_request)(void),
-                               bool (*parse_response)(void),
-                               uint32_t success_view_id,
-                               uint32_t failure_view_id,
-                               ViewDispatcher **view_dispatcher);
-
-#endif // FLIPPER_HTTP_H
+bool flipper_http_websocket_stop(FlipperHTTP *fhttp);

Some files were not shown because too many files changed in this diff