Przeglądaj źródła

Add pc_monitor from https://github.com/xMasterX/all-the-plugins

git-subtree-dir: pc_monitor
git-subtree-mainline: e5315fea28059aff5051e69fe3b4d0e56d69cce5
git-subtree-split: 450aae07dc1c3ecde02addce81bd2267d203ec05
Willy-JL 1 rok temu
rodzic
commit
f1ba0216b5

+ 2 - 0
pc_monitor/.gitattributes

@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto

+ 2 - 0
pc_monitor/.gitsubtree

@@ -0,0 +1,2 @@
+https://github.com/TheSainEyereg/flipper-pc-monitor master /
+https://github.com/xMasterX/all-the-plugins dev non_catalog_apps/pc_monitor

+ 5 - 0
pc_monitor/BLEConsole examples.txt

@@ -0,0 +1,5 @@
+fmt dec
+w #00 76 159 0 16 0 0 71 66 17 120 0 20 0 0 71 66
+
+fmt hex
+w #00 64 3F 01 53 47 42 00 00 0C 78 00 24 47 42 00 00

+ 3 - 0
pc_monitor/CHANGELOG.md

@@ -0,0 +1,3 @@
+## v1.0
+
+- Stable release.

+ 21 - 0
pc_monitor/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 TheSainEyereg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 4 - 0
pc_monitor/README.md

@@ -0,0 +1,4 @@
+# PC Monitor
+Flipper Application for monitoring PC resources
+
+**[A backend running on your PC is required](https://github.com/TheSainEyereg/flipper-pc-monitor-backend/releases)**

+ 13 - 0
pc_monitor/application.fam

@@ -0,0 +1,13 @@
+App(
+    appid="pc_monitor",
+    name="PC monitor",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="pc_monitor_app",
+    requires=["bt", "gui"],
+    stack_size=1 * 1024,
+    fap_description="Application for monitoring PC resources",
+    fap_category="Bluetooth",
+    fap_icon="icons/icon_10px.png",
+    fap_version="1.0",
+    fap_author="Olejka",
+)

+ 114 - 0
pc_monitor/helpers/ble_serial.c

@@ -0,0 +1,114 @@
+#include "ble_serial.h"
+
+#include <gap.h>
+#include <furi_ble/profile_interface.h>
+#include <services/serial_service.h>
+#include <furi.h>
+
+typedef struct {
+    FuriHalBleProfileBase base;
+
+    BleServiceSerial* serial_svc;
+} BleProfileSerial;
+_Static_assert(offsetof(BleProfileSerial, base) == 0, "Wrong layout");
+
+static FuriHalBleProfileBase* ble_profile_serial_start(FuriHalBleProfileParams profile_params) {
+    UNUSED(profile_params);
+
+    BleProfileSerial* profile = malloc(sizeof(BleProfileSerial));
+
+    profile->base.config = ble_profile_serial;
+
+    profile->serial_svc = ble_svc_serial_start();
+
+    return &profile->base;
+}
+
+static void ble_profile_serial_stop(FuriHalBleProfileBase* profile) {
+    furi_check(profile);
+    furi_check(profile->config == ble_profile_serial);
+
+    BleProfileSerial* serial_profile = (BleProfileSerial*)profile;
+    ble_svc_serial_stop(serial_profile->serial_svc);
+}
+
+static GapConfig serial_template_config = {
+    .adv_service_uuid = 0x3080,
+    .appearance_char = 0x8600,
+    .bonding_mode = true,
+    .pairing_method = GapPairingPinCodeShow,
+    .conn_param = {
+        .conn_int_min = 0x18, // 30 ms
+        .conn_int_max = 0x24, // 45 ms
+        .slave_latency = 0,
+        .supervisor_timeout = 0,
+    }};
+
+static void
+    ble_profile_serial_get_config(GapConfig* config, FuriHalBleProfileParams profile_params) {
+    BleProfileSerialParams* serial_profile_params = profile_params;
+
+    furi_check(config);
+    memcpy(config, &serial_template_config, sizeof(GapConfig));
+    // Set mac address
+    memcpy(config->mac_address, furi_hal_version_get_ble_mac(), sizeof(config->mac_address));
+
+    // Change MAC address for HID profile
+    config->mac_address[2]++;
+    if(serial_profile_params) {
+        config->mac_address[0] ^= serial_profile_params->mac_xor;
+        config->mac_address[1] ^= serial_profile_params->mac_xor >> 8;
+    }
+
+    // Set advertise name
+    memset(config->adv_name, 0, sizeof(config->adv_name));
+
+    const char* clicker_str = "Serial";
+    if(serial_profile_params && serial_profile_params->device_name_prefix) {
+        clicker_str = serial_profile_params->device_name_prefix;
+    }
+    // We don't have Flipper in BLE name, use printf instead of replace
+    FuriString* name = furi_string_alloc_printf(
+        "%c%s %s",
+        furi_hal_version_get_ble_local_device_name_ptr()[0],
+        clicker_str,
+        furi_hal_version_get_ble_local_device_name_ptr() + 1);
+    if(furi_string_size(name) >= sizeof(config->adv_name)) {
+        furi_string_left(name, sizeof(config->adv_name) - 1);
+    }
+    memcpy(config->adv_name, furi_string_get_cstr(name), furi_string_size(name));
+    furi_string_free(name);
+
+    config->adv_service_uuid |= furi_hal_version_get_hw_color();
+}
+
+static const FuriHalBleProfileTemplate profile_callbacks = {
+    .start = ble_profile_serial_start,
+    .stop = ble_profile_serial_stop,
+    .get_gap_config = ble_profile_serial_get_config,
+};
+
+const FuriHalBleProfileTemplate* ble_profile_serial = &profile_callbacks;
+
+void ble_profile_serial_set_event_callback(
+    FuriHalBleProfileBase* profile,
+    uint16_t buff_size,
+    FuriHalBtSerialCallback callback,
+    void* context) {
+    furi_check(profile && (profile->config == ble_profile_serial));
+
+    BleProfileSerial* serial_profile = (BleProfileSerial*)profile;
+    ble_svc_serial_set_callbacks(serial_profile->serial_svc, buff_size, callback, context);
+}
+
+bool ble_profile_serial_tx(FuriHalBleProfileBase* profile, uint8_t* data, uint16_t size) {
+    furi_check(profile && (profile->config == ble_profile_serial));
+
+    BleProfileSerial* serial_profile = (BleProfileSerial*)profile;
+
+    if(size > BLE_PROFILE_SERIAL_PACKET_SIZE_MAX) {
+        return false;
+    }
+
+    return ble_svc_serial_update_tx(serial_profile->serial_svc, data, size);
+}

+ 53 - 0
pc_monitor/helpers/ble_serial.h

@@ -0,0 +1,53 @@
+#pragma once
+
+#include <furi_ble/profile_interface.h>
+
+#include <services/serial_service.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** 
+ * Optional arguments to pass along with profile template as 
+ * FuriHalBleProfileParams for tuning profile behavior 
+ **/
+typedef struct {
+    const char* device_name_prefix; /**< Prefix for device name. Length must be less than 8 */
+    uint16_t mac_xor; /**< XOR mask for device address, for uniqueness */
+} BleProfileSerialParams;
+
+#define BLE_PROFILE_SERIAL_PACKET_SIZE_MAX BLE_SVC_SERIAL_DATA_LEN_MAX
+
+/** Serial service callback type */
+typedef SerialServiceEventCallback FuriHalBtSerialCallback;
+
+/** Serial profile descriptor */
+extern const FuriHalBleProfileTemplate* ble_profile_serial;
+
+/** Send data through BLE
+ *
+ * @param profile       Profile instance
+ * @param data          data buffer
+ * @param size          data buffer size
+ *
+ * @return      true on success
+ */
+bool ble_profile_serial_tx(FuriHalBleProfileBase* profile, uint8_t* data, uint16_t size);
+
+/** Set Serial service events callback
+ *
+ * @param profile       Profile instance
+ * @param buffer_size   Applicaition buffer size
+ * @param calback       FuriHalBtSerialCallback instance
+ * @param context       pointer to context
+ */
+void ble_profile_serial_set_event_callback(
+    FuriHalBleProfileBase* profile,
+    uint16_t buff_size,
+    FuriHalBtSerialCallback callback,
+    void* context);
+
+#ifdef __cplusplus
+}
+#endif

BIN
pc_monitor/icons/icon_10px.pdn


BIN
pc_monitor/icons/icon_10px.png


+ 214 - 0
pc_monitor/pc_monitor.c

@@ -0,0 +1,214 @@
+#include "pc_monitor.h"
+
+static void render_callback(Canvas* canvas, void* ctx) {
+    furi_assert(ctx);
+    PcMonitorApp* app = ctx;
+
+    if(app->bt_state == BtStateRecieving) {
+        canvas_clear(canvas);
+        canvas_set_color(canvas, ColorBlack);
+        canvas_set_font(canvas, FontKeyboard);
+
+        uint8_t line = 0;
+        uint8_t spacing = app->lines_count ? SCREEN_HEIGHT / app->lines_count : 0;
+        uint8_t margin_top = spacing ? (spacing - LINE_HEIGHT) / 2 : 0;
+        char str[32];
+
+        if(app->data.cpu_usage <= 100) {
+            if(app->lines_count) {
+                canvas_draw_str(canvas, 1, margin_top + line * spacing + 9, "CPU");
+                snprintf(str, 32, "%d%%", app->data.cpu_usage);
+                elements_progress_bar_with_text(
+                    canvas,
+                    BAR_X,
+                    margin_top + line * spacing,
+                    BAR_WIDTH,
+                    app->data.cpu_usage / 100.0f,
+                    str);
+            }
+
+            line++;
+        }
+
+        if(app->data.ram_usage <= 100) {
+            if(app->lines_count) {
+                canvas_draw_str(canvas, 1, margin_top + line * spacing + 9, "RAM");
+                snprintf(
+                    str,
+                    32,
+                    "%.1f/%.1f %s",
+                    (double)(app->data.ram_max * 0.1f * app->data.ram_usage * 0.01f),
+                    (double)(app->data.ram_max * 0.1f),
+                    app->data.ram_unit);
+                elements_progress_bar_with_text(
+                    canvas,
+                    BAR_X,
+                    margin_top + line * spacing,
+                    BAR_WIDTH,
+                    app->data.ram_usage * 0.01f,
+                    str);
+            }
+
+            line++;
+        }
+
+        if(app->data.gpu_usage <= 100) {
+            if(app->lines_count) {
+                canvas_draw_str(canvas, 1, margin_top + line * spacing + 9, "GPU");
+                snprintf(str, 32, "%d%%", app->data.gpu_usage);
+                elements_progress_bar_with_text(
+                    canvas,
+                    BAR_X,
+                    margin_top + line * spacing,
+                    BAR_WIDTH,
+                    app->data.gpu_usage / 100.0f,
+                    str);
+            }
+
+            line++;
+        }
+
+        if(app->data.vram_usage <= 100) {
+            if(app->lines_count) {
+                canvas_draw_str(canvas, 1, margin_top + line * spacing + 9, "VRAM");
+                snprintf(
+                    str,
+                    32,
+                    "%.1f/%.1f %s",
+                    (double)(app->data.vram_max * 0.1f * app->data.vram_usage * 0.01f),
+                    (double)(app->data.vram_max * 0.1f),
+                    app->data.vram_unit);
+                elements_progress_bar_with_text(
+                    canvas,
+                    BAR_X,
+                    margin_top + line * spacing,
+                    BAR_WIDTH,
+                    app->data.vram_usage * 0.01f,
+                    str);
+            }
+
+            line++;
+        }
+
+        if(line == 0) app->bt_state = BtStateNoData;
+        app->lines_count = line;
+    } else {
+        canvas_draw_str_aligned(
+            canvas,
+            64,
+            32,
+            AlignCenter,
+            AlignCenter,
+            app->bt_state == BtStateChecking ? "Checking BLE..." :
+            app->bt_state == BtStateInactive ? "BLE inactive!" :
+            app->bt_state == BtStateWaiting  ? "Waiting for data..." :
+            app->bt_state == BtStateLost     ? "Connection lost!" :
+                                               "No data!");
+    }
+}
+
+static void input_callback(InputEvent* input_event, void* ctx) {
+    furi_assert(ctx);
+    FuriMessageQueue* event_queue = ctx;
+    furi_message_queue_put(event_queue, input_event, FuriWaitForever);
+}
+
+static uint16_t bt_serial_callback(SerialServiceEvent event, void* ctx) {
+    furi_assert(ctx);
+    PcMonitorApp* app = ctx;
+
+    if(event.event == SerialServiceEventTypeDataReceived) {
+        FURI_LOG_D(
+            TAG,
+            "SerialServiceEventTypeDataReceived. Size: %u/%u. Data: %s",
+            event.data.size,
+            sizeof(DataStruct),
+            (char*)event.data.buffer);
+
+        if(event.data.size == sizeof(DataStruct)) {
+            memcpy(&app->data, event.data.buffer, sizeof(DataStruct));
+            app->bt_state = BtStateRecieving;
+            app->last_packet = furi_hal_rtc_get_timestamp();
+        }
+    }
+
+    return 0;
+}
+
+static PcMonitorApp* pc_monitor_alloc() {
+    PcMonitorApp* app = malloc(sizeof(PcMonitorApp));
+    app->view_port = view_port_alloc();
+    app->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
+    app->notification = furi_record_open(RECORD_NOTIFICATION);
+    app->gui = furi_record_open(RECORD_GUI);
+    app->bt = furi_record_open(RECORD_BT);
+
+    gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);
+    view_port_draw_callback_set(app->view_port, render_callback, app);
+    view_port_input_callback_set(app->view_port, input_callback, app->event_queue);
+    return app;
+}
+
+static void pc_monitor_free(PcMonitorApp* app) {
+    gui_remove_view_port(app->gui, app->view_port);
+    view_port_free(app->view_port);
+    furi_message_queue_free(app->event_queue);
+    furi_record_close(RECORD_NOTIFICATION);
+    furi_record_close(RECORD_GUI);
+    furi_record_close(RECORD_BT);
+    free(app);
+}
+
+int32_t pc_monitor_app(void* p) {
+    UNUSED(p);
+    PcMonitorApp* app = pc_monitor_alloc();
+
+    bt_disconnect(app->bt);
+
+    // Wait 2nd core to update nvm storage
+    furi_delay_ms(200);
+
+    bt_keys_storage_set_storage_path(app->bt, APP_DATA_PATH(".bt_serial.keys"));
+
+    BleProfileSerialParams params = {
+        .device_name_prefix = "PC Mon",
+        .mac_xor = 0x0002,
+    };
+    app->ble_serial_profile = bt_profile_start(app->bt, ble_profile_serial, &params);
+
+    furi_check(app->ble_serial_profile);
+
+    ble_profile_serial_set_event_callback(
+        app->ble_serial_profile, BT_SERIAL_BUFFER_SIZE, bt_serial_callback, app);
+    furi_hal_bt_start_advertising();
+
+    app->bt_state = BtStateWaiting;
+    FURI_LOG_D(TAG, "Bluetooth is active!");
+
+    // Main loop
+    InputEvent event;
+    while(true) {
+        if(furi_message_queue_get(app->event_queue, &event, 1) == FuriStatusOk) {
+            if(event.type == InputTypeShort && event.key == InputKeyBack) break;
+        }
+
+        if(app->bt_state == BtStateRecieving &&
+           (furi_hal_rtc_get_timestamp() - app->last_packet > 5))
+            app->bt_state = BtStateLost;
+    }
+
+    ble_profile_serial_set_event_callback(app->ble_serial_profile, 0, NULL, NULL);
+
+    bt_disconnect(app->bt);
+
+    // Wait 2nd core to update nvm storage
+    furi_delay_ms(200);
+
+    bt_keys_storage_set_default_path(app->bt);
+
+    furi_check(bt_profile_restore_default(app->bt));
+
+    pc_monitor_free(app);
+
+    return 0;
+}

+ 58 - 0
pc_monitor/pc_monitor.h

@@ -0,0 +1,58 @@
+#pragma once
+
+#include <furi.h>
+#include <furi_hal.h>
+#include <furi_hal_bt.h>
+#include "helpers/ble_serial.h"
+#include <bt/bt_service/bt.h>
+#include <gui/gui.h>
+#include <gui/elements.h>
+#include <notification/notification_messages.h>
+#include <input/input.h>
+#include <storage/storage.h>
+
+#define TAG "PCMonitor"
+#define BT_SERIAL_BUFFER_SIZE 128
+
+#define SCREEN_HEIGHT 64
+#define LINE_HEIGHT 11
+
+#define BAR_X 30
+#define BAR_WIDTH 97
+
+typedef enum {
+    BtStateChecking,
+    BtStateInactive,
+    BtStateWaiting,
+    BtStateRecieving,
+    BtStateNoData,
+    BtStateLost
+} BtState;
+
+#pragma pack(push, 1)
+typedef struct {
+    uint8_t cpu_usage;
+    uint16_t ram_max;
+    uint8_t ram_usage;
+    char ram_unit[4];
+    uint8_t gpu_usage;
+    uint16_t vram_max;
+    uint8_t vram_usage;
+    char vram_unit[4];
+} DataStruct;
+#pragma pack(pop)
+
+typedef struct {
+    Bt* bt;
+    Gui* gui;
+    ViewPort* view_port;
+    FuriMutex* app_mutex;
+    FuriMessageQueue* event_queue;
+    NotificationApp* notification;
+    FuriHalBleProfileBase* ble_serial_profile;
+
+    BtState bt_state;
+    DataStruct data;
+    uint8_t lines_count;
+    uint32_t last_packet;
+} PcMonitorApp;

BIN
pc_monitor/screenshots/1.png


BIN
pc_monitor/screenshots/2.png


BIN
pc_monitor/screenshots/qFlipper.png