morse_code.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include "morse_code_worker.h"
  2. #include <furi.h>
  3. #include <gui/gui.h>
  4. #include <gui/elements.h>
  5. #include <input/input.h>
  6. #include <stdlib.h>
  7. #include <furi_hal.h>
  8. #include <string.h>
  9. static const float MORSE_CODE_VOLUMES[] = {0, .25, .5, .75, 1};
  10. typedef struct {
  11. FuriString* words;
  12. uint8_t volume;
  13. uint32_t dit_delta;
  14. } MorseCodeModel;
  15. typedef struct {
  16. MorseCodeModel* model;
  17. FuriMutex* model_mutex;
  18. FuriMessageQueue* input_queue;
  19. ViewPort* view_port;
  20. Gui* gui;
  21. MorseCodeWorker* worker;
  22. } MorseCode;
  23. static void render_callback(Canvas* const canvas, void* ctx) {
  24. MorseCode* morse_code = ctx;
  25. furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
  26. // border around the edge of the screen
  27. canvas_set_font(canvas, FontPrimary);
  28. //write words
  29. elements_multiline_text_aligned(
  30. canvas, 64, 30, AlignCenter, AlignCenter, furi_string_get_cstr(morse_code->model->words));
  31. // volume view_port
  32. uint8_t vol_bar_x_pos = 124;
  33. uint8_t vol_bar_y_pos = 0;
  34. const uint8_t volume_h = (64 / (COUNT_OF(MORSE_CODE_VOLUMES) - 1)) * morse_code->model->volume;
  35. canvas_draw_frame(canvas, vol_bar_x_pos, vol_bar_y_pos, 4, 64);
  36. canvas_draw_box(canvas, vol_bar_x_pos, vol_bar_y_pos + (64 - volume_h), 4, volume_h);
  37. //dit bpms
  38. FuriString* ditbpm = furi_string_alloc_printf("Dit: %ld ms", morse_code->model->dit_delta);
  39. canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignCenter, furi_string_get_cstr(ditbpm));
  40. furi_string_free(ditbpm);
  41. //button info
  42. elements_button_center(canvas, "Press/Hold");
  43. furi_mutex_release(morse_code->model_mutex);
  44. }
  45. static void input_callback(InputEvent* input_event, void* ctx) {
  46. MorseCode* morse_code = ctx;
  47. furi_message_queue_put(morse_code->input_queue, input_event, FuriWaitForever);
  48. }
  49. static void morse_code_worker_callback(FuriString* words, void* context) {
  50. MorseCode* morse_code = context;
  51. furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
  52. furi_string_set(morse_code->model->words, words);
  53. furi_mutex_release(morse_code->model_mutex);
  54. view_port_update(morse_code->view_port);
  55. }
  56. MorseCode* morse_code_alloc() {
  57. MorseCode* instance = malloc(sizeof(MorseCode));
  58. instance->model = malloc(sizeof(MorseCodeModel));
  59. instance->model->words = furi_string_alloc_set_str("");
  60. instance->model->volume = 3;
  61. instance->model->dit_delta = 150;
  62. instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  63. instance->input_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
  64. instance->worker = morse_code_worker_alloc();
  65. morse_code_worker_set_callback(instance->worker, morse_code_worker_callback, instance);
  66. instance->view_port = view_port_alloc();
  67. view_port_draw_callback_set(instance->view_port, render_callback, instance);
  68. view_port_input_callback_set(instance->view_port, input_callback, instance);
  69. // Open GUI and register view_port
  70. instance->gui = furi_record_open(RECORD_GUI);
  71. gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen);
  72. return instance;
  73. }
  74. void morse_code_free(MorseCode* instance) {
  75. gui_remove_view_port(instance->gui, instance->view_port);
  76. furi_record_close(RECORD_GUI);
  77. view_port_free(instance->view_port);
  78. morse_code_worker_free(instance->worker);
  79. furi_message_queue_free(instance->input_queue);
  80. furi_mutex_free(instance->model_mutex);
  81. furi_string_free(instance->model->words);
  82. free(instance->model);
  83. free(instance);
  84. }
  85. int32_t morse_code_app() {
  86. MorseCode* morse_code = morse_code_alloc();
  87. InputEvent input;
  88. morse_code_worker_start(morse_code->worker);
  89. morse_code_worker_set_volume(
  90. morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
  91. morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
  92. while(furi_message_queue_get(morse_code->input_queue, &input, FuriWaitForever) ==
  93. FuriStatusOk) {
  94. furi_check(furi_mutex_acquire(morse_code->model_mutex, FuriWaitForever) == FuriStatusOk);
  95. if(input.key == InputKeyBack && input.type == InputTypeLong) {
  96. furi_mutex_release(morse_code->model_mutex);
  97. break;
  98. } else if(input.key == InputKeyBack && input.type == InputTypeShort) {
  99. morse_code_worker_reset_text(morse_code->worker);
  100. furi_string_reset(morse_code->model->words);
  101. } else if(input.key == InputKeyOk) {
  102. if(input.type == InputTypePress)
  103. morse_code_worker_play(morse_code->worker, true);
  104. else if(input.type == InputTypeRelease)
  105. morse_code_worker_play(morse_code->worker, false);
  106. } else if(input.key == InputKeyUp && input.type == InputTypePress) {
  107. if(morse_code->model->volume < COUNT_OF(MORSE_CODE_VOLUMES) - 1)
  108. morse_code->model->volume++;
  109. morse_code_worker_set_volume(
  110. morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
  111. } else if(input.key == InputKeyDown && input.type == InputTypePress) {
  112. if(morse_code->model->volume > 0) morse_code->model->volume--;
  113. morse_code_worker_set_volume(
  114. morse_code->worker, MORSE_CODE_VOLUMES[morse_code->model->volume]);
  115. } else if(input.key == InputKeyLeft && input.type == InputTypePress) {
  116. if(morse_code->model->dit_delta > 10) morse_code->model->dit_delta -= 10;
  117. morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
  118. } else if(input.key == InputKeyRight && input.type == InputTypePress) {
  119. if(morse_code->model->dit_delta >= 10) morse_code->model->dit_delta += 10;
  120. morse_code_worker_set_dit_delta(morse_code->worker, morse_code->model->dit_delta);
  121. }
  122. FURI_LOG_D(
  123. "Input",
  124. "%s %s %ld",
  125. input_get_key_name(input.key),
  126. input_get_type_name(input.type),
  127. input.sequence);
  128. furi_mutex_release(morse_code->model_mutex);
  129. view_port_update(morse_code->view_port);
  130. }
  131. morse_code_worker_stop(morse_code->worker);
  132. morse_code_free(morse_code);
  133. return 0;
  134. }