Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork1.8k
Morse Code FAP#144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
Uh oh!
There was an error while loading.Please reload this page.
Merged
Morse Code FAP#144
Changes fromall commits
Commits
Show all changes
2 commits Select commitHold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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" | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
Loading
Sorry, something went wrong.Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.