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

Merge bpmtapper from https://github.com/ezod/flipperzero-bpm-tapper

Willy-JL 2 лет назад
Родитель
Сommit
1c862494ed
7 измененных файлов с 246 добавлено и 151 удалено
  1. 34 0
      bpmtapper/.github/workflows/build.yml
  2. 57 0
      bpmtapper/.gitignore
  3. 12 6
      bpmtapper/README.md
  4. 0 1
      bpmtapper/application.fam
  5. 143 144
      bpmtapper/bpm.c
  6. BIN
      bpmtapper/img/screenshot.png
  7. BIN
      bpmtapper/ui.png

+ 34 - 0
bpmtapper/.github/workflows/build.yml

@@ -0,0 +1,34 @@
+name: "FAP Build"
+on:
+  push:
+    branches:
+      - main 
+  pull_request:
+  schedule:
+    - cron: "1 1 * * *"
+jobs:
+  ufbt-build-action:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        include:
+          - name: dev channel
+            sdk-channel: dev
+          - name: release channel
+            sdk-channel: release
+    name: 'ufbt: Build for ${{ matrix.name }}'
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          submodules: recursive
+      - name: Build with ufbt
+        uses: flipperdevices/flipperzero-ufbt-action@v0.1.2
+        id: build-app
+        with:
+          sdk-channel: ${{ matrix.sdk-channel }}
+      - name: Upload app artifacts
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ github.event.repository.name }}-${{ steps.build-app.outputs.suffix }}
+          path: ${{ steps.build-app.outputs.fap-artifacts }}

+ 57 - 0
bpmtapper/.gitignore

@@ -0,0 +1,57 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+# uFBT
+.vscode
+.clang-format
+dist/

+ 12 - 6
bpmtapper/README.md

@@ -1,14 +1,20 @@
 # BPM Tapper
 # BPM Tapper
 
 
+[![FAP Build](https://github.com/ezod/flipperzero-bpm-tapper/actions/workflows/build.yml/badge.svg)](https://github.com/ezod/flipperzero-bpm-tapper/actions/workflows/build.yml)
+
 A BPM Tapper for the Flipper Zero.
 A BPM Tapper for the Flipper Zero.
 
 
-![screenshot](img/screenshot.png)
+![ui](ui.png)
 
 
-Hit any button other than back repeatedly. Calculates based on the average of the last 8 inputs.
+## Installation
 
 
-## Compiling
+1. Navigate to the [FAP Build](https://github.com/ezod/flipperzero-bpm-tapper/actions/workflows/build.yml)
+   GitHub action workflow, and select the most recent run.
+2. The FAP is built for both the `dev` and `release` channels of the official
+   firmware. Download the artifact corresponding to your firmware version.
+3. Extract `bpm_tapper.fap` from the ZIP file to `apps/Media` on your Flipper
+   Zero SD card.
 
 
-```
-./fbt fap_bpm_tapper
-```
+## Usage
 
 
+Hit any button other than back repeatedly. Calculates based on the average of the last 8 inputs.

+ 0 - 1
bpmtapper/application.fam

@@ -3,7 +3,6 @@ App(
     name="BPM Tapper",
     name="BPM Tapper",
     apptype=FlipperAppType.EXTERNAL,
     apptype=FlipperAppType.EXTERNAL,
     entry_point="bpm_tapper_app",
     entry_point="bpm_tapper_app",
-    cdefines=["APP_BPM_TAPPER"],
     requires=["gui"],
     requires=["gui"],
     stack_size=2 * 1024,
     stack_size=2 * 1024,
     fap_icon="bpm_10px.png",
     fap_icon="bpm_10px.png",

+ 143 - 144
bpmtapper/bpm.c

@@ -3,7 +3,7 @@
 #include <dialogs/dialogs.h>
 #include <dialogs/dialogs.h>
 #include <gui/gui.h>
 #include <gui/gui.h>
 #include <input/input.h>
 #include <input/input.h>
-
+#include <core/string.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include "bpm_tapper_icons.h"
 #include "bpm_tapper_icons.h"
 
 
@@ -19,70 +19,69 @@ typedef struct {
     InputEvent input;
     InputEvent input;
 } PluginEvent;
 } PluginEvent;
 
 
-
 //QUEUE
 //QUEUE
 
 
 struct node {
 struct node {
     int interval;
     int interval;
-    struct node *next;
+    struct node* next;
 };
 };
 typedef struct node node;
 typedef struct node node;
 
 
 typedef struct {
 typedef struct {
     int size;
     int size;
     int max_size;
     int max_size;
-    node *front;
-    node *rear;
+    node* front;
+    node* rear;
 } queue;
 } queue;
 
 
-static void init_queue(queue *q) {
-  q->size = 0;
-  q->max_size = 8;
-  q->front = NULL;
-  q->rear = NULL;
+static void init_queue(queue* q) {
+    q->size = 0;
+    q->max_size = 8;
+    q->front = NULL;
+    q->rear = NULL;
 }
 }
 
 
-static void queue_remove(queue *q) {
-    node *tmp;
+static void queue_remove(queue* q) {
+    node* tmp;
     tmp = q->front;
     tmp = q->front;
     q->front = q->front->next;
     q->front = q->front->next;
     q->size--;
     q->size--;
     free(tmp);
     free(tmp);
 }
 }
 
 
-static void queue_add(queue *q, int value) {
-    node *tmp = malloc(sizeof(node));
+static void queue_add(queue* q, int value) {
+    node* tmp = malloc(sizeof(node));
     tmp->interval = value;
     tmp->interval = value;
     tmp->next = NULL;
     tmp->next = NULL;
-    if (q->size == q->max_size) {
-      queue_remove(q);
-    } 
+    if(q->size == q->max_size) {
+        queue_remove(q);
+    }
     // check if empty
     // check if empty
-    if (q->rear == NULL) {
-      q->front = tmp;
-      q->rear = tmp;
+    if(q->rear == NULL) {
+        q->front = tmp;
+        q->rear = tmp;
     } else {
     } else {
-      q->rear->next = tmp;
-      q->rear = tmp;
+        q->rear->next = tmp;
+        q->rear = tmp;
     }
     }
     q->size++;
     q->size++;
 }
 }
 
 
-static float queue_avg(queue *q) {
+static float queue_avg(queue* q) {
     float avg = 0.0;
     float avg = 0.0;
-    if (q->size == 0){
-      return avg;
+    if(q->size == 0) {
+        return avg;
     } else {
     } else {
-      node *tmp;
-      float sum = 0.0;
-      tmp = q->front;
-      while (tmp != NULL) {
-          sum = sum + tmp->interval;
-          tmp = tmp->next;
-      } 
-      avg = sum / q->size;
-      FURI_LOG_D("BPM-Tapper", "Sum: %.2f Avg: %.2f", (double)sum, (double)avg);
-      return avg;
+        node* tmp;
+        float sum = 0.0;
+        tmp = q->front;
+        while(tmp != NULL) {
+            sum = sum + tmp->interval;
+            tmp = tmp->next;
+        }
+        avg = sum / q->size;
+        FURI_LOG_D("BPM-Tapper", "Sum: %.2f Avg: %.2f", (double)sum, (double)avg);
+        return avg;
     }
     }
 }
 }
 
 
@@ -99,33 +98,33 @@ typedef struct {
     double bpm;
     double bpm;
     uint32_t last_stamp;
     uint32_t last_stamp;
     uint32_t interval;
     uint32_t interval;
-    queue *tap_queue;
+    queue* tap_queue;
+    FuriMutex* mutex;
 } BPMTapper;
 } BPMTapper;
 
 
 static void show_hello() {
 static void show_hello() {
+    // BEGIN HELLO DIALOG
+    DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
+    DialogMessage* message = dialog_message_alloc();
 
 
-  // BEGIN HELLO DIALOG
-  DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
-  DialogMessage* message = dialog_message_alloc();
-
-  const char* header_text = "BPM Tapper";
-  const char* message_text = "Tap center to start";
+    const char* header_text = "BPM Tapper";
+    const char* message_text = "Tap center to start";
 
 
-  dialog_message_set_header(message, header_text, 63, 3, AlignCenter, AlignTop);
-  dialog_message_set_text(message, message_text, 0, 17, AlignLeft, AlignTop);
-  dialog_message_set_buttons(message, NULL, "Tap", NULL);
+    dialog_message_set_header(message, header_text, 63, 3, AlignCenter, AlignTop);
+    dialog_message_set_text(message, message_text, 0, 17, AlignLeft, AlignTop);
+    dialog_message_set_buttons(message, NULL, "Tap", NULL);
 
 
-  dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
+    dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
 
 
-  dialog_message_show(dialogs, message);
+    dialog_message_show(dialogs, message);
 
 
-  dialog_message_free(message);
-  furi_record_close(RECORD_DIALOGS);
-  // END HELLO DIALOG
+    dialog_message_free(message);
+    furi_record_close(RECORD_DIALOGS);
+    // END HELLO DIALOG
 }
 }
 
 
 static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
 static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
-    furi_assert(event_queue); 
+    furi_assert(event_queue);
 
 
     PluginEvent event = {.type = EventTypeKey, .input = *input_event};
     PluginEvent event = {.type = EventTypeKey, .input = *input_event};
     furi_message_queue_put(event_queue, &event, FuriWaitForever);
     furi_message_queue_put(event_queue, &event, FuriWaitForever);
@@ -134,9 +133,9 @@ static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queu
 static void render_callback(Canvas* const canvas, void* ctx) {
 static void render_callback(Canvas* const canvas, void* ctx) {
     FuriString* tempStr;
     FuriString* tempStr;
 
 
-    furi_assert(ctx);
     const BPMTapper* bpm_state = ctx;
     const BPMTapper* bpm_state = ctx;
     furi_mutex_acquire(bpm_state->mutex, FuriWaitForever);
     furi_mutex_acquire(bpm_state->mutex, FuriWaitForever);
+
     // border
     // border
     //canvas_draw_frame(canvas, 0, 0, 128, 64);
     //canvas_draw_frame(canvas, 0, 0, 128, 64);
     canvas_set_font(canvas, FontPrimary);
     canvas_set_font(canvas, FontPrimary);
@@ -151,17 +150,19 @@ static void render_callback(Canvas* const canvas, void* ctx) {
     canvas_draw_str_aligned(canvas, 70, 10, AlignLeft, AlignBottom, furi_string_get_cstr(tempStr));
     canvas_draw_str_aligned(canvas, 70, 10, AlignLeft, AlignBottom, furi_string_get_cstr(tempStr));
     furi_string_reset(tempStr);
     furi_string_reset(tempStr);
 
 
-    furi_string_printf(tempStr, "Interval: %ldms", bpm_state->interval);
+    furi_string_printf(tempStr, "Interval: %dms", (int)bpm_state->interval);
     canvas_draw_str_aligned(canvas, 5, 20, AlignLeft, AlignBottom, furi_string_get_cstr(tempStr));
     canvas_draw_str_aligned(canvas, 5, 20, AlignLeft, AlignBottom, furi_string_get_cstr(tempStr));
     furi_string_reset(tempStr);
     furi_string_reset(tempStr);
 
 
     furi_string_printf(tempStr, "x2 %.2f /2 %.2f", bpm_state->bpm * 2, bpm_state->bpm / 2);
     furi_string_printf(tempStr, "x2 %.2f /2 %.2f", bpm_state->bpm * 2, bpm_state->bpm / 2);
-    canvas_draw_str_aligned(canvas, 64, 60, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
+    canvas_draw_str_aligned(
+        canvas, 64, 60, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
     furi_string_reset(tempStr);
     furi_string_reset(tempStr);
 
 
     furi_string_printf(tempStr, "%.2f", bpm_state->bpm);
     furi_string_printf(tempStr, "%.2f", bpm_state->bpm);
     canvas_set_font(canvas, FontBigNumbers);
     canvas_set_font(canvas, FontBigNumbers);
-    canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
+    canvas_draw_str_aligned(
+        canvas, 64, 40, AlignCenter, AlignCenter, furi_string_get_cstr(tempStr));
     furi_string_reset(tempStr);
     furi_string_reset(tempStr);
 
 
     furi_string_free(tempStr);
     furi_string_free(tempStr);
@@ -169,99 +170,97 @@ static void render_callback(Canvas* const canvas, void* ctx) {
     furi_mutex_release(bpm_state->mutex);
     furi_mutex_release(bpm_state->mutex);
 }
 }
 
 
-
 static void bpm_state_init(BPMTapper* const plugin_state) {
 static void bpm_state_init(BPMTapper* const plugin_state) {
-  plugin_state->taps = 0; 
-  plugin_state->bpm = 120.0;
-  plugin_state->last_stamp = 0;// furi_get_tick();
-  plugin_state->interval = 0;
-  queue *q;
-  q = malloc(sizeof(queue));
-  init_queue(q);
-  plugin_state->tap_queue = q;
+    plugin_state->taps = 0;
+    plugin_state->bpm = 120.0;
+    plugin_state->last_stamp = 0; // furi_get_tick();
+    plugin_state->interval = 0;
+    queue* q;
+    q = malloc(sizeof(queue));
+    init_queue(q);
+    plugin_state->tap_queue = q;
+    plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
 }
 }
 
 
 int32_t bpm_tapper_app(void* p) {
 int32_t bpm_tapper_app(void* p) {
-  UNUSED(p);
-
-  FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
-  
-  BPMTapper* bpm_state = malloc(sizeof(BPMTapper));
-  // setup
-  bpm_state_init(bpm_state);
-  
-  bpm_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
-  if(!bpm_state->mutex) {
-      FURI_LOG_E("BPM-Tapper", "cannot create mutex\r\n");
-      free(bpm_state);
-      return 255;
-  }
-  show_hello();
-
-  // BEGIN IMPLEMENTATION
-
-  // Set system callbacks
-  ViewPort* view_port = view_port_alloc(); 
-  view_port_draw_callback_set(view_port, render_callback, bpm_state);
-  view_port_input_callback_set(view_port, input_callback, event_queue);
-  
-  // Open GUI and register view_port
-  Gui* gui = furi_record_open("gui"); 
-  gui_add_view_port(gui, view_port, GuiLayerFullscreen);
-
-  PluginEvent event;
-  for (bool processing = true; processing;) {
-    FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
-    furi_mutex_acquire(bpm_state->mutex, FuriWaitForever);
-    if(event_status == FuriStatusOk) {
-      // press events
-      if(event.type == EventTypeKey) {
-        if(event.input.type == InputTypePress) {  
-          switch(event.input.key) {
-            case InputKeyUp:
-            case InputKeyDown:
-            case InputKeyRight:
-            case InputKeyLeft:
-            case InputKeyOk:
-              bpm_state->taps++;
-              uint32_t new_stamp = furi_get_tick();
-              if (bpm_state->last_stamp == 0) {
-                  bpm_state->last_stamp = new_stamp;
-                  break;
-              }
-              bpm_state->interval = new_stamp - bpm_state->last_stamp;
-              bpm_state->last_stamp = new_stamp;
-              queue_add(bpm_state->tap_queue, bpm_state->interval);
-              float avg = queue_avg(bpm_state->tap_queue);
-              float bps = 1.0 / (avg / 1000.0);
-              bpm_state->bpm = bps * 60.0;
-              break;
-            case InputKeyBack:
-                // Exit the plugin
-                processing = false;
-                break;
-            default:
-                break;
-          }
+    UNUSED(p);
+
+    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
+
+    BPMTapper* bpm_state = malloc(sizeof(BPMTapper));
+    // setup
+    bpm_state_init(bpm_state);
+
+    if(!bpm_state->mutex) {
+        FURI_LOG_E("BPM-Tapper", "cannot create mutex\r\n");
+        free(bpm_state);
+        return 255;
+    }
+    show_hello();
+
+    // BEGIN IMPLEMENTATION
+
+    // Set system callbacks
+    ViewPort* view_port = view_port_alloc();
+    view_port_draw_callback_set(view_port, render_callback, bpm_state);
+    view_port_input_callback_set(view_port, input_callback, event_queue);
+
+    // Open GUI and register view_port
+    Gui* gui = furi_record_open("gui");
+    gui_add_view_port(gui, view_port, GuiLayerFullscreen);
+
+    PluginEvent event;
+    for(bool processing = true; processing;) {
+        FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
+        furi_mutex_acquire(bpm_state->mutex, FuriWaitForever);
+        if(event_status == FuriStatusOk) {
+            // press events
+            if(event.type == EventTypeKey) {
+                if(event.input.type == InputTypePress) {
+                    switch(event.input.key) {
+                    case InputKeyUp:
+                    case InputKeyDown:
+                    case InputKeyRight:
+                    case InputKeyLeft:
+                    case InputKeyOk:
+                        bpm_state->taps++;
+                        uint32_t new_stamp = furi_get_tick();
+                        if(bpm_state->last_stamp == 0) {
+                            bpm_state->last_stamp = new_stamp;
+                            break;
+                        }
+                        bpm_state->interval = new_stamp - bpm_state->last_stamp;
+                        bpm_state->last_stamp = new_stamp;
+                        queue_add(bpm_state->tap_queue, bpm_state->interval);
+                        float avg = queue_avg(bpm_state->tap_queue);
+                        float bps = 1.0 / (avg / 1000.0);
+                        bpm_state->bpm = bps * 60.0;
+                        break;
+                    case InputKeyBack:
+                        // Exit the plugin
+                        processing = false;
+                        break;
+                    default:
+                        break;
+                    }
+                }
+            }
+        // } else {
+        //     FURI_LOG_D("BPM-Tapper", "FuriMessageQueue: event timeout");
+        // event timeout
         }
         }
-      } 
-    // } else {
-    //   FURI_LOG_D("BPM-Tapper", "FuriMessageQueue: event timeout");
-    // event timeout
+        view_port_update(view_port);
+        furi_mutex_release(bpm_state->mutex);
     }
     }
-    view_port_update(view_port);
-    furi_mutex_release(bpm_state->mutex);
-  }
-  view_port_enabled_set(view_port, false);
-  gui_remove_view_port(gui, view_port);
-  furi_record_close("gui");
-  view_port_free(view_port);
-  furi_message_queue_free(event_queue);
-  furi_mutex_free(bpm_state->mutex);
-  queue *q = bpm_state->tap_queue;
-  free(q);
-  free(bpm_state);
-
-  return 0;
+    view_port_enabled_set(view_port, false);
+    gui_remove_view_port(gui, view_port);
+    furi_record_close("gui");
+    view_port_free(view_port);
+    furi_message_queue_free(event_queue);
+    queue* q = bpm_state->tap_queue;
+    free(q);
+    furi_mutex_free(bpm_state->mutex);
+    free(bpm_state);
+
+    return 0;
 }
 }
-

BIN
bpmtapper/img/screenshot.png


BIN
bpmtapper/ui.png