mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-23 13:03:13 +00:00
Add MorseCode fap
This commit is contained in:
parent
348c4c3b5f
commit
419a90aa28
6 changed files with 383 additions and 0 deletions
|
@ -95,6 +95,7 @@ Also check changelog in releases for latest updates!
|
|||
- i2c Tools [(By NaejEL)](https://github.com/NaejEL/flipperzero-i2ctools) - C0 -> SCL / C1 -> SDA / GND -> GND | 3v3 logic levels only!
|
||||
- Temperature Sensor Plugin - HTU21D / SI7021 [(By Mywk)](https://github.com/Mywk/FlipperTemperatureSensor) - [How to Connect](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/plugins/temperature_sensor/Readme.md)
|
||||
- HC-SR04 Distance sensor - Ported and modified by @xMasterX [(original by Sanqui)](https://github.com/Sanqui/flipperzero-firmware/tree/hc_sr04) - How to connect -> (5V -> VCC) / (GND -> GND) / (13|TX -> Trig) / (14|RX -> Echo)
|
||||
- Morse Code - [(by wh00hw)](https://github.com/wh00hw/MorseCodeFAP)
|
||||
|
||||
Games:
|
||||
- DOOM (fixed) [(By p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/)
|
||||
|
|
15
applications/plugins/morse_code/application.fam
Normal file
15
applications/plugins/morse_code/application.fam
Normal file
|
@ -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"
|
||||
|
||||
)
|
161
applications/plugins/morse_code/morse_code.c
Normal file
161
applications/plugins/morse_code/morse_code.c
Normal file
|
@ -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
applications/plugins/morse_code/morse_code_10px.png
Normal file
BIN
applications/plugins/morse_code/morse_code_10px.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 168 B |
164
applications/plugins/morse_code/morse_code_worker.c
Normal file
164
applications/plugins/morse_code/morse_code_worker.c
Normal file
|
@ -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
applications/plugins/morse_code/morse_code_worker.h
Normal file
42
applications/plugins/morse_code/morse_code_worker.h
Normal file
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in a new issue