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

Add pc_monitor from https://github.com/TheSainEyereg/flipper-pc-monitor

git-subtree-dir: pc_monitor
git-subtree-mainline: f05a4ba59b4fbbd496582e016e767cd77ffd98a5
git-subtree-split: 6e3498f7aa0ff0e8198e2c4e53554c568eb0a43c
Willy-JL 1 год назад
Родитель
Сommit
a350b09d4c

+ 2 - 0
pc_monitor/.gitattributes

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

+ 41 - 0
pc_monitor/.github/workflows/build.yml

@@ -0,0 +1,41 @@
+name: "FAP: Build for multiple SDK sources"
+# This will build your app for dev and release channels on GitHub. 
+# It will also build your app every day to make sure it's up to date with the latest SDK changes.
+# See https://github.com/marketplace/actions/build-flipper-application-package-fap for more information
+
+on:
+  push:
+    ## put your main branch name under "braches"
+    #branches: 
+    #  - master 
+  pull_request:
+  schedule: 
+    # do a build every day
+    - cron: "1 1 * * *"
+
+jobs:
+  ufbt-build:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        include:
+          - name: dev channel
+            sdk-channel: dev
+          - name: release channel
+            sdk-channel: release
+          # You can add unofficial channels here. See ufbt action docs for more info.
+    name: 'ufbt: Build for ${{ matrix.name }}'
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Build with ufbt
+        uses: flipperdevices/flipperzero-ufbt-action@v0.1.1
+        id: build-app
+        with:
+          sdk-channel: ${{ matrix.sdk-channel }}
+      - name: Upload app artifacts
+        uses: actions/upload-artifact@v3
+        with:
+          # See ufbt action docs for other output variables
+          name: ${{ github.event.repository.name }}-${{ steps.build-app.outputs.suffix }}
+          path: ${{ steps.build-app.outputs.fap-artifacts }}

+ 1 - 0
pc_monitor/.gitsubtree

@@ -0,0 +1 @@
+https://github.com/TheSainEyereg/flipper-pc-monitor master /

+ 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",
+)

BIN
pc_monitor/icons/icon_10px.pdn


BIN
pc_monitor/icons/icon_10px.png


+ 194 - 0
pc_monitor/pc_monitor.c

@@ -0,0 +1,194 @@
+#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();
+
+    if(furi_hal_bt_is_active()) {
+        furi_hal_bt_serial_set_event_callback(BT_SERIAL_BUFFER_SIZE, bt_serial_callback, app);
+        furi_hal_bt_start_advertising();
+
+        app->bt_state = BtStateWaiting;
+        FURI_LOG_D(TAG, "Bluetooth is active!");
+    } else {
+        app->bt_state = BtStateInactive;
+        FURI_LOG_W(TAG, "Please, enable the Bluetooth and restart the app");
+    }
+
+    // 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;
+    }
+
+    furi_hal_bt_serial_set_event_callback(0, NULL, NULL);
+
+    pc_monitor_free(app);
+
+    return 0;
+}

+ 56 - 0
pc_monitor/pc_monitor.h

@@ -0,0 +1,56 @@
+#pragma once
+
+#include <furi.h>
+#include <furi_hal.h>
+#include <furi_hal_bt.h>
+#include <furi_hal_bt_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>
+
+#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;
+
+    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