Procházet zdrojové kódy

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

git-subtree-dir: morse_code
git-subtree-mainline: 7035bc4bbe13321924c61d81625e7e3b3718a531
git-subtree-split: 84a75c09c74aeb42d7f659acc2d40952c503cab1
Willy-JL před 2 roky
rodič
revize
67a9f4b0b2

+ 1 - 0
morse_code/.gitsubtree

@@ -0,0 +1 @@
+https://github.com/xMasterX/all-the-plugins dev base_pack/morse_code

+ 16 - 0
morse_code/application.fam

@@ -0,0 +1,16 @@
+App(
+    appid="morse_code",
+    name="Morse Code",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="morse_code_app",
+    requires=[
+        "gui",
+    ],
+    stack_size=1 * 1024,
+    order=20,
+    fap_icon="morse_code_10px.png",
+    fap_category="Media",
+    fap_author="@wh00hw & @xMasterX",
+    fap_version="1.1",
+    fap_description="Simple Morse Code parser",
+)

binární
morse_code/img/1.png


+ 166 - 0
morse_code/morse_code.c

@@ -0,0 +1,166 @@
+#include "morse_code_worker.h"
+#include <furi.h>
+#include <gui/gui.h>
+#include <gui/elements.h>
+#include <input/input.h>
+#include <stdlib.h>
+#include <furi_hal.h>
+#include <string.h>
+
+static const float MORSE_CODE_VOLUMES[] = {0, .25, .5, .75, 1};
+
+typedef struct {
+    FuriString* words;
+    uint8_t volume;
+    uint32_t dit_delta;
+} MorseCodeModel;
+
+typedef struct {
+    MorseCodeModel* model;
+    FuriMutex** model_mutex;
+
+    FuriMessageQueue* input_queue;
+
+    ViewPort* view_port;
+    Gui* gui;
+
+    MorseCodeWorker* worker;
+} MorseCode;
+
+static void render_callback(Canvas* const canvas, void* ctx) {
+    MorseCode* morse_code = ctx;
+    furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
+    // border around the edge of the screen
+    canvas_set_font(canvas, FontPrimary);
+
+    //write words
+    elements_multiline_text_aligned(
+        canvas, 64, 30, AlignCenter, AlignCenter, furi_string_get_cstr(morse_code->model->words));
+
+    // volume view_port
+    uint8_t vol_bar_x_pos = 124;
+    uint8_t vol_bar_y_pos = 0;
+    const uint8_t volume_h = (64 / (COUNT_OF(MORSE_CODE_VOLUMES) - 1)) * morse_code->model->volume;
+    canvas_draw_frame(canvas, vol_bar_x_pos, vol_bar_y_pos, 4, 64);
+    canvas_draw_box(canvas, vol_bar_x_pos, vol_bar_y_pos + (64 - volume_h), 4, volume_h);
+
+    //dit bpms
+    FuriString* ditbpm = furi_string_alloc_printf("Dit: %ld ms", morse_code->model->dit_delta);
+    canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignCenter, furi_string_get_cstr(ditbpm));
+    furi_string_free(ditbpm);
+
+    //button info
+    elements_button_center(canvas, "Press/Hold");
+    furi_mutex_release(morse_code->model_mutex);
+}
+
+static void input_callback(InputEvent* input_event, void* ctx) {
+    MorseCode* morse_code = ctx;
+    furi_message_queue_put(morse_code->input_queue, input_event, FuriWaitForever);
+}
+
+static void morse_code_worker_callback(FuriString* words, void* context) {
+    MorseCode* morse_code = context;
+    furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
+    furi_string_set(morse_code->model->words, words);
+    furi_mutex_release(morse_code->model_mutex);
+    view_port_update(morse_code->view_port);
+}
+
+MorseCode* morse_code_alloc() {
+    MorseCode* instance = malloc(sizeof(MorseCode));
+
+    instance->model = malloc(sizeof(MorseCodeModel));
+    instance->model->words = furi_string_alloc_set_str("");
+    instance->model->volume = 3;
+    instance->model->dit_delta = 150;
+    instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
+
+    instance->input_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
+
+    instance->worker = morse_code_worker_alloc();
+
+    morse_code_worker_set_callback(instance->worker, morse_code_worker_callback, instance);
+
+    instance->view_port = view_port_alloc();
+    view_port_draw_callback_set(instance->view_port, render_callback, instance);
+    view_port_input_callback_set(instance->view_port, input_callback, instance);
+
+    // Open GUI and register view_port
+    instance->gui = furi_record_open(RECORD_GUI);
+    gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen);
+
+    return instance;
+}
+
+void morse_code_free(MorseCode* instance) {
+    gui_remove_view_port(instance->gui, instance->view_port);
+    furi_record_close(RECORD_GUI);
+    view_port_free(instance->view_port);
+
+    morse_code_worker_free(instance->worker);
+
+    furi_message_queue_free(instance->input_queue);
+
+    furi_mutex_free(instance->model_mutex);
+
+    furi_string_free(instance->model->words);
+    free(instance->model);
+    free(instance);
+}
+
+int32_t morse_code_app() {
+    MorseCode* morse_code = morse_code_alloc();
+    InputEvent input;
+
+    morse_code_worker_start(morse_code->worker);
+    morse_code_worker_set_volume(
+        morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
+    morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
+
+    while(furi_message_queue_get(morse_code->input_queue, &input, FuriWaitForever) ==
+          FuriStatusOk) {
+        furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
+        if(input.key == InputKeyBack && input.type == InputTypeLong) {
+            furi_mutex_release(morse_code->model_mutex);
+            break;
+        } else if(input.key == InputKeyBack && input.type == InputTypeShort) {
+            morse_code_worker_reset_text(morse_code->worker);
+            furi_string_reset(morse_code->model->words);
+        } else if(input.key == InputKeyOk) {
+            if(input.type == InputTypePress)
+                morse_code_worker_play(morse_code->worker, true);
+            else if(input.type == InputTypeRelease)
+                morse_code_worker_play(morse_code->worker, false);
+        } else if(input.key == InputKeyUp && input.type == InputTypePress) {
+            if(morse_code->model->volume < COUNT_OF(MORSE_CODE_VOLUMES) - 1)
+                morse_code->model->volume++;
+            morse_code_worker_set_volume(
+                morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
+        } else if(input.key == InputKeyDown && input.type == InputTypePress) {
+            if(morse_code->model->volume > 0) morse_code->model->volume--;
+            morse_code_worker_set_volume(
+                morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
+        } else if(input.key == InputKeyLeft && input.type == InputTypePress) {
+            if(morse_code->model->dit_delta > 10) morse_code->model->dit_delta -= 10;
+            morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
+        } else if(input.key == InputKeyRight && input.type == InputTypePress) {
+            if(morse_code->model->dit_delta >= 10) morse_code->model->dit_delta += 10;
+            morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
+        }
+
+        FURI_LOG_D(
+            "Input",
+            "%s %s %ld",
+            input_get_key_name(input.key),
+            input_get_type_name(input.type),
+            input.sequence);
+
+        furi_mutex_release(morse_code->model_mutex);
+        view_port_update(morse_code->view_port);
+    }
+
+    morse_code_worker_stop(morse_code->worker);
+    morse_code_free(morse_code);
+    return 0;
+}

binární
morse_code/morse_code_10px.png


+ 183 - 0
morse_code/morse_code_worker.c

@@ -0,0 +1,183 @@
+#include "morse_code_worker.h"
+#include <furi_hal.h>
+#include <lib/flipper_format/flipper_format.h>
+
+#define TAG "MorseCodeWorker"
+
+#define MORSE_CODE_VERSION 0
+
+//A-Z0-1
+const char morse_array[36][6] = {".-",    "-...",  "-.-.",  "-..",   ".",     "..-.",
+                                 "--.",   "....",  "..",    ".---",  "-.-",   ".-..",
+                                 "--",    "-.",    "---",   ".--.",  "--.-",  ".-.",
+                                 "...",   "-",     "..-",   "...-",  ".--",   "-..-",
+                                 "-.--",  "--..",  ".----", "..---", "...--", "....-",
+                                 ".....", "-....", "--...", "---..", "----.", "-----"};
+const char symbol_array[36] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+                               'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+                               'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
+
+struct MorseCodeWorker {
+    FuriThread* thread;
+    MorseCodeWorkerCallback callback;
+    void* callback_context;
+    bool is_running;
+    bool play;
+    float volume;
+    uint32_t dit_delta;
+    FuriString* buffer;
+    FuriString* words;
+};
+
+void morse_code_worker_fill_buffer(MorseCodeWorker* instance, uint32_t duration) {
+    FURI_LOG_D("MorseCode: Duration", "%ld", duration);
+    if(duration <= instance->dit_delta)
+        furi_string_push_back(instance->buffer, *DOT);
+    else if(duration <= (instance->dit_delta * 3))
+        furi_string_push_back(instance->buffer, *LINE);
+    else
+        furi_string_reset(instance->buffer);
+    if(furi_string_size(instance->buffer) > 5) furi_string_reset(instance->buffer);
+    FURI_LOG_D("MorseCode: Buffer", "%s", furi_string_get_cstr(instance->buffer));
+}
+
+void morse_code_worker_fill_letter(MorseCodeWorker* instance) {
+    if(furi_string_size(instance->words) > 63) furi_string_reset(instance->words);
+    for(size_t i = 0; i < sizeof(morse_array); i++) {
+        if(furi_string_cmp_str(instance->buffer, morse_array[i]) == 0) {
+            furi_string_push_back(instance->words, symbol_array[i]);
+            break;
+        }
+    }
+    furi_string_reset(instance->buffer);
+    FURI_LOG_D("MorseCode: Words", "%s", furi_string_get_cstr(instance->words));
+}
+
+static int32_t morse_code_worker_thread_callback(void* context) {
+    furi_assert(context);
+    MorseCodeWorker* instance = context;
+    bool was_playing = false;
+    uint32_t start_tick = 0;
+    uint32_t end_tick = 0;
+    bool pushed = true;
+    bool spaced = true;
+    while(instance->is_running) {
+        furi_delay_ms(SLEEP);
+
+        if(instance->play) {
+            if(!was_playing) {
+                start_tick = furi_get_tick();
+                if(furi_hal_speaker_acquire(1000)) {
+                    furi_hal_speaker_start(FREQUENCY, instance->volume);
+                }
+                was_playing = true;
+            }
+        } else {
+            if(was_playing) {
+                pushed = false;
+                spaced = false;
+                if(furi_hal_speaker_is_mine()) {
+                    furi_hal_speaker_stop();
+                    furi_hal_speaker_release();
+                }
+                end_tick = furi_get_tick();
+                was_playing = false;
+                morse_code_worker_fill_buffer(instance, end_tick - start_tick);
+                start_tick = 0;
+            }
+        }
+        if(!pushed) {
+            if(end_tick + (instance->dit_delta * 3) < furi_get_tick()) {
+                //NEW LETTER
+                if(!furi_string_empty(instance->buffer)) {
+                    morse_code_worker_fill_letter(instance);
+                    if(instance->callback)
+                        instance->callback(instance->words, instance->callback_context);
+                } else {
+                    spaced = true;
+                }
+                pushed = true;
+            }
+        }
+        if(!spaced) {
+            if(end_tick + (instance->dit_delta * 7) < furi_get_tick()) {
+                //NEW WORD
+                furi_string_push_back(instance->words, *SPACE);
+                if(instance->callback)
+                    instance->callback(instance->words, instance->callback_context);
+                spaced = true;
+            }
+        }
+    }
+    return 0;
+}
+
+MorseCodeWorker* morse_code_worker_alloc() {
+    MorseCodeWorker* instance = malloc(sizeof(MorseCodeWorker));
+    instance->thread = furi_thread_alloc();
+    furi_thread_set_name(instance->thread, "MorseCodeWorker");
+    furi_thread_set_stack_size(instance->thread, 1024);
+    furi_thread_set_context(instance->thread, instance);
+    furi_thread_set_callback(instance->thread, morse_code_worker_thread_callback);
+    instance->play = false;
+    instance->volume = 1.0f;
+    instance->dit_delta = 150;
+    instance->buffer = furi_string_alloc_set_str("");
+    instance->words = furi_string_alloc_set_str("");
+    return instance;
+}
+
+void morse_code_worker_free(MorseCodeWorker* instance) {
+    furi_assert(instance);
+    furi_string_free(instance->buffer);
+    furi_string_free(instance->words);
+    furi_thread_free(instance->thread);
+    free(instance);
+}
+
+void morse_code_worker_set_callback(
+    MorseCodeWorker* instance,
+    MorseCodeWorkerCallback callback,
+    void* context) {
+    furi_assert(instance);
+    instance->callback = callback;
+    instance->callback_context = context;
+}
+
+void morse_code_worker_play(MorseCodeWorker* instance, bool play) {
+    furi_assert(instance);
+    instance->play = play;
+}
+
+void morse_code_worker_set_volume(MorseCodeWorker* instance, float level) {
+    furi_assert(instance);
+    instance->volume = level;
+}
+
+void morse_code_worker_set_dit_delta(MorseCodeWorker* instance, uint32_t delta) {
+    furi_assert(instance);
+    instance->dit_delta = delta;
+}
+
+void morse_code_worker_reset_text(MorseCodeWorker* instance) {
+    furi_assert(instance);
+    furi_string_reset(instance->buffer);
+    furi_string_reset(instance->words);
+}
+
+void morse_code_worker_start(MorseCodeWorker* instance) {
+    furi_assert(instance);
+    furi_assert(instance->is_running == false);
+    instance->is_running = true;
+    furi_thread_start(instance->thread);
+    FURI_LOG_D("MorseCode: Start", "is Running");
+}
+
+void morse_code_worker_stop(MorseCodeWorker* instance) {
+    furi_assert(instance);
+    furi_assert(instance->is_running == true);
+    instance->play = false;
+    instance->is_running = false;
+    furi_thread_join(instance->thread);
+    FURI_LOG_D("MorseCode: Stop", "Stop");
+}

+ 36 - 0
morse_code/morse_code_worker.h

@@ -0,0 +1,36 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <furi.h>
+
+#define FREQUENCY 261.63f
+#define SLEEP 10
+#define DOT "."
+#define LINE "-"
+#define SPACE " "
+
+typedef void (*MorseCodeWorkerCallback)(FuriString* buffer, void* context);
+
+typedef struct MorseCodeWorker MorseCodeWorker;
+
+MorseCodeWorker* morse_code_worker_alloc();
+
+void morse_code_worker_free(MorseCodeWorker* instance);
+
+void morse_code_worker_set_callback(
+    MorseCodeWorker* instance,
+    MorseCodeWorkerCallback callback,
+    void* context);
+
+void morse_code_worker_start(MorseCodeWorker* instance);
+
+void morse_code_worker_stop(MorseCodeWorker* instance);
+
+void morse_code_worker_play(MorseCodeWorker* instance, bool play);
+
+void morse_code_worker_reset_text(MorseCodeWorker* instance);
+
+void morse_code_worker_set_volume(MorseCodeWorker* instance, float level);
+
+void morse_code_worker_set_dit_delta(MorseCodeWorker* instance, uint32_t delta);