Ver código fonte

Add morse_code from https://github.com/wh00hw/MorseCodeFAP

git-subtree-dir: morse_code
git-subtree-mainline: 68765e4c66c9cdcddd1ed61b34f9a8e5117dbf00
git-subtree-split: be002f60079714cd4f69fe56bca7802f67ec59af
Willy-JL 2 anos atrás
pai
commit
9a66556571

+ 1 - 0
morse_code/.gitsubtree

@@ -0,0 +1 @@
+https://github.com/wh00hw/MorseCodeFAP master /

+ 19 - 0
morse_code/README.md

@@ -0,0 +1,19 @@
+# Morse Code
+
+Simple Morse Code parser Flipper Application Package.
+
+![screenshot](img/screenshot.png)
+
+## Controls
+
+- Up/Down buttons to set volume
+- Left/Right buttons to set Dit length in milliseconds
+- Push center button to play Dit
+- Hold center button to play Dah
+
+
+## Compiling
+
+```
+./fbt fap_morse_code
+```

+ 15 - 0
morse_code/application.fam

@@ -0,0 +1,15 @@
+App(
+    appid="morse_code",
+    name="Morse Code",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="morse_code_app",
+    cdefines=["APP_MORSE_CODE"],
+    requires=[
+        "gui",
+    ],
+    stack_size=1 * 1024,
+    order=20,
+    fap_icon="morse_code_10px.png",
+    fap_category="Music"
+
+)

BIN
morse_code/img/screenshot.png


+ 161 - 0
morse_code/morse_code.c

@@ -0,0 +1,161 @@
+#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 bpm
+    canvas_draw_str_aligned(
+        canvas, 0, 10, AlignLeft, AlignCenter, furi_string_get_cstr(furi_string_alloc_printf("Dit: %ld ms", morse_code->model->dit_delta)));
+    
+    //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);
+    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);
+
+    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) {
+                furi_mutex_release(morse_code->model_mutex);
+                break;
+        }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
morse_code/morse_code_10px.png


+ 164 - 0
morse_code/morse_code_worker.c

@@ -0,0 +1,164 @@
+#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);
+    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]);
+                furi_string_reset(instance->buffer);
+                break;
+            }        
+        }
+    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();
+                furi_hal_speaker_start(FREQUENCY, instance->volume);
+                was_playing = true;
+            }
+        }else{
+            if(was_playing){
+                pushed = false;
+                spaced = false;
+                furi_hal_speaker_stop();
+                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
+                morse_code_worker_fill_letter(instance);
+                if(instance->callback)
+                        instance->callback(instance->words, instance->callback_context);
+                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_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_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->is_running = false;
+    furi_thread_join(instance->thread);
+    FURI_LOG_D("MorseCode: Stop", "Stop");
+}

+ 42 - 0
morse_code/morse_code_worker.h

@@ -0,0 +1,42 @@
+#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_set_volume(MorseCodeWorker* instance, float level);
+
+void morse_code_worker_set_dit_delta(MorseCodeWorker* instance, uint32_t delta);
+
+
+
+
+
+