From 345d9704fd70857943df75354402a989b940a3ed Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 2 Nov 2022 23:39:54 +0300 Subject: [PATCH] Plugins: Added Game15 + run fbt format --- applications/plugins/game15/README.md | 13 + applications/plugins/game15/application.fam | 12 + applications/plugins/game15/game15.c | 469 ++++++++++++++++++ applications/plugins/game15/game15_10px.png | Bin 0 -> 152 bytes applications/plugins/game15/images/Game15.png | Bin 0 -> 2078 bytes .../plugins/game15/images/Game15Popup.png | Bin 0 -> 2267 bytes .../plugins/game15/images/Game15Restore.png | Bin 0 -> 2156 bytes applications/plugins/game15/sandbox.c | 93 ++++ applications/plugins/game15/sandbox.h | 24 + applications/plugins/gps_nmea_uart/README.md | 1 + applications/plugins/morse_code/morse_code.c | 97 ++-- .../plugins/morse_code/morse_code_worker.c | 70 ++- .../plugins/morse_code/morse_code_worker.h | 10 +- applications/plugins/totp/totp_app.c | 44 +- 14 files changed, 727 insertions(+), 106 deletions(-) create mode 100644 applications/plugins/game15/README.md create mode 100644 applications/plugins/game15/application.fam create mode 100644 applications/plugins/game15/game15.c create mode 100644 applications/plugins/game15/game15_10px.png create mode 100644 applications/plugins/game15/images/Game15.png create mode 100644 applications/plugins/game15/images/Game15Popup.png create mode 100644 applications/plugins/game15/images/Game15Restore.png create mode 100644 applications/plugins/game15/sandbox.c create mode 100644 applications/plugins/game15/sandbox.h diff --git a/applications/plugins/game15/README.md b/applications/plugins/game15/README.md new file mode 100644 index 000000000..b1710c919 --- /dev/null +++ b/applications/plugins/game15/README.md @@ -0,0 +1,13 @@ + +# Game "15" for Flipper Zero + +[Original link](https://github.com/x27/flipperzero-game15) + +Logic game [Wikipedia](https://en.wikipedia.org/wiki/15_puzzle) + +![Game screen](images/Game15.png) + +![Restore game](images/Game15Restore.png) + +![Popoup](images/Game15Popup.png) + diff --git a/applications/plugins/game15/application.fam b/applications/plugins/game15/application.fam new file mode 100644 index 000000000..ab00316c1 --- /dev/null +++ b/applications/plugins/game15/application.fam @@ -0,0 +1,12 @@ +App( + appid="game15", + name="Game 15", + apptype=FlipperAppType.EXTERNAL, + entry_point="game15_app", + cdefines=["APP_GAME15"], + requires=["gui"], + stack_size=1 * 1024, + fap_icon="game15_10px.png", + order=30, + fap_category="Games", +) diff --git a/applications/plugins/game15/game15.c b/applications/plugins/game15/game15.c new file mode 100644 index 000000000..aad5f1330 --- /dev/null +++ b/applications/plugins/game15/game15.c @@ -0,0 +1,469 @@ +#include +#include +#include +#include +#include + +#include "sandbox.h" + +#define FPS 20 +#define CELL_WIDTH 10 +#define CELL_HEIGHT 8 +#define MOVE_TICKS 5 +#define KEY_STACK_SIZE 16 +#define SAVING_DIRECTORY "/ext/apps/Games" +#define SAVING_FILENAME SAVING_DIRECTORY "/game15.save" +#define POPUP_MENU_ITEMS 2 + +typedef enum { + DirectionNone, + DirectionUp, + DirectionDown, + DirectionLeft, + DirectionRight +} direction_e; + +typedef enum { ScenePlay, SceneWin, ScenePopup } scene_e; + +typedef struct { + uint8_t cell_index; + uint8_t zero_index; + uint8_t move_direction; + uint8_t move_ticks; +} moving_cell_t; + +typedef struct { + uint16_t top_record; + scene_e scene; + uint16_t move_count; + uint32_t tick_count; + uint8_t board[16]; +} game_state_t; + +static game_state_t game_state; +static NotificationApp* notification; +static moving_cell_t moving_cell; +static uint8_t loaded_saving_ticks; +static uint8_t popup_menu_selected_item; + +static const char* popup_menu_strings[] = {"Continue", "Reset"}; + +static uint8_t keys[KEY_STACK_SIZE]; +static uint8_t key_stack_head = 0; + +static const uint8_t pic_cells[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x30, 0xfc, 0x38, 0xfc, 0x30, 0xfc, 0x30, 0xfc, 0x30, 0xfc, 0x30, 0xfc, 0x30, 0xfc, 0x30, 0xfc, + 0x78, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0x60, 0xfc, 0x30, 0xfc, 0x18, 0xfc, 0x0c, 0xfc, 0xfc, 0xfc, + 0x78, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0x60, 0xfc, 0xc0, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0x78, 0xfc, + 0x70, 0xfc, 0x78, 0xfc, 0x68, 0xfc, 0x6c, 0xfc, 0x6c, 0xfc, 0xec, 0xfc, 0xfc, 0xfc, 0x60, 0xfc, + 0xfc, 0xfc, 0x0c, 0xfc, 0x0c, 0xfc, 0x7c, 0xfc, 0xc0, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0x78, 0xfc, + 0x78, 0xfc, 0x0c, 0xfc, 0x0c, 0xfc, 0x7c, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0x78, 0xfc, + 0xfc, 0xfc, 0xc0, 0xfc, 0xc0, 0xfc, 0xc0, 0xfc, 0xc0, 0xfc, 0xc0, 0xfc, 0xc0, 0xfc, 0xc0, 0xfc, + 0x78, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0x78, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0x78, 0xfc, + 0x78, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0xcc, 0xfc, 0xf8, 0xfc, 0xc0, 0xfc, 0xc0, 0xfc, 0x78, 0xfc, + 0xe6, 0xfd, 0x37, 0xff, 0x36, 0xff, 0x36, 0xff, 0x36, 0xff, 0x36, 0xff, 0x36, 0xff, 0xe6, 0xfd, + 0x8c, 0xfd, 0xce, 0xfd, 0x8c, 0xfd, 0x8c, 0xfd, 0x8c, 0xfd, 0x8c, 0xfd, 0x8c, 0xfd, 0x8c, 0xfd, + 0xe6, 0xfd, 0x37, 0xff, 0x36, 0xff, 0x86, 0xfd, 0xc6, 0xfc, 0x66, 0xfc, 0x36, 0xfc, 0xf6, 0xff, + 0xe6, 0xfd, 0x37, 0xff, 0x36, 0xff, 0x86, 0xfd, 0x06, 0xff, 0x36, 0xff, 0x36, 0xff, 0xe6, 0xfd, + 0xc6, 0xfd, 0xe7, 0xfd, 0xa6, 0xfd, 0xb6, 0xfd, 0xb6, 0xfd, 0xb6, 0xff, 0xf6, 0xff, 0x86, 0xfd, + 0xf6, 0xff, 0x37, 0xfc, 0x36, 0xfc, 0xf6, 0xfd, 0x06, 0xff, 0x36, 0xff, 0x36, 0xff, 0xe6, 0xfd, +}; + +static const uint8_t pic_digits[] = { + 0xf0, 0xf2, 0xf2, 0xf2, 0xf2, 0xf0, 0xf9, 0xf8, 0xf9, 0xf9, 0xf9, 0xf0, 0xf0, 0xf2, 0xf3, + 0xf1, 0xfc, 0xf0, 0xf0, 0xf3, 0xf1, 0xf3, 0xf2, 0xf0, 0xf3, 0xf1, 0xf2, 0xf2, 0xf0, 0xf3, + 0xf0, 0xfc, 0xf0, 0xf3, 0xf2, 0xf0, 0x00, 0x0c, 0x00, 0x02, 0x02, 0x00, 0x00, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x03, 0x03, 0x00, +}; + +static const uint8_t pic_top[] = {11, 4, 0x88, 0xf8, 0xad, 0xfa, 0xad, 0xf8, 0x8d, 0xfe}; +static const uint8_t pic_move[] = + {17, 4, 0x2e, 0x2a, 0xfe, 0xa4, 0xaa, 0xff, 0xaa, 0x2a, 0xff, 0x2e, 0x36, 0xfe}; +static const uint8_t pic_time[] = {15, 4, 0xa8, 0x8b, 0x2d, 0xe9, 0xad, 0xca, 0xad, 0x8b}; + +static const uint8_t pic_puzzled[] = { + 0xff, 0xcf, 0x00, 0xf3, 0xff, 0xfc, 0x3f, 0x03, 0xc0, 0xff, 0xf3, 0x0f, 0xdc, 0xff, 0xcf, + 0x00, 0xf3, 0xff, 0xfc, 0x3f, 0x03, 0xc0, 0xff, 0xf3, 0x0f, 0xdc, 0x03, 0xcc, 0x00, 0x03, + 0x38, 0x00, 0x0e, 0x03, 0xc0, 0x00, 0x30, 0x30, 0xdc, 0x03, 0xcc, 0x00, 0x03, 0x1c, 0x00, + 0x07, 0x03, 0xc0, 0x00, 0x30, 0x30, 0xdc, 0xff, 0xcf, 0x00, 0x03, 0x0e, 0x80, 0x03, 0x03, + 0xc0, 0xff, 0x33, 0xc0, 0xdc, 0xff, 0xcf, 0x00, 0x03, 0x07, 0xc0, 0x01, 0x03, 0xc0, 0xff, + 0x33, 0xc0, 0xdc, 0x03, 0xc0, 0x00, 0x83, 0x03, 0xe0, 0x00, 0x03, 0xc0, 0x00, 0x30, 0xc0, + 0xd0, 0x03, 0xc0, 0x00, 0xc3, 0x01, 0x70, 0x00, 0x03, 0xc0, 0x00, 0x30, 0xc0, 0xd0, 0x03, + 0xc0, 0xff, 0xf3, 0xff, 0xfc, 0x3f, 0xff, 0xcf, 0xff, 0xf3, 0xff, 0xdc, 0x03, 0xc0, 0xff, + 0xf3, 0xff, 0xfc, 0x3f, 0xff, 0xcf, 0xff, 0xf3, 0xff, 0xdc}; + +static void key_stack_init() { + key_stack_head = 0; +} + +static uint8_t key_stack_pop() { + return keys[--key_stack_head]; +} + +static bool key_stack_is_empty() { + return key_stack_head == 0; +} + +static int key_stack_push(uint8_t value) { + if(key_stack_head != KEY_STACK_SIZE) { + keys[key_stack_head] = value; + key_stack_head++; + return key_stack_head; + } else + return -1; +} + +static bool storage_game_state_load() { + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); + + uint16_t bytes_readed = 0; + if(storage_file_open(file, SAVING_FILENAME, FSAM_READ, FSOM_OPEN_EXISTING)) + bytes_readed = storage_file_read(file, &game_state, sizeof(game_state_t)); + storage_file_close(file); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); + return bytes_readed == sizeof(game_state_t); +} + +static void storage_game_state_save() { + Storage* storage = furi_record_open(RECORD_STORAGE); + + if(storage_common_stat(storage, SAVING_DIRECTORY, NULL) == FSE_NOT_EXIST) { + if(!storage_simply_mkdir(storage, SAVING_DIRECTORY)) { + return; + } + } + + File* file = storage_file_alloc(storage); + if(storage_file_open(file, SAVING_FILENAME, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + storage_file_write(file, &game_state, sizeof(game_state_t)); + } + storage_file_close(file); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); +} + +static void set_moving_cell_by_direction(direction_e direction) { + moving_cell.move_direction = DirectionNone; + moving_cell.zero_index = 0xff; + + for(int i = 0; i < 16; i++) { + if(!game_state.board[i]) { + moving_cell.zero_index = i; + break; + } + } + if(moving_cell.zero_index == 0xff) return; + + uint8_t x = moving_cell.zero_index % 4; + uint8_t y = moving_cell.zero_index / 4; + + moving_cell.cell_index = moving_cell.zero_index; + + if(direction == DirectionUp && y < 3) + moving_cell.cell_index += 4; + else if(direction == DirectionDown && y > 0) + moving_cell.cell_index -= 4; + else if(direction == DirectionLeft && x < 3) + moving_cell.cell_index++; + else if(direction == DirectionRight && x > 0) + moving_cell.cell_index--; + else + return; + + moving_cell.move_ticks = 0; + moving_cell.move_direction = direction; +} + +static bool is_board_has_solution() { + uint8_t i, j, inv = 0; + for(i = 0; i < 16; ++i) + if(game_state.board[i]) + for(j = 0; j < i; ++j) + if(game_state.board[j] > game_state.board[i]) ++inv; + for(i = 0; i < 16; ++i) + if(game_state.board[i] == 0) inv += 1 + i / 4; + + return inv % 2 == 0; +} + +static void board_init() { + for(int i = 0; i < 16; i++) { + game_state.board[i] = (i + 1) % 16; + } + + do { + for(int i = 15; i >= 1; i--) { + int j = rand() % (i + 1); + uint8_t tmp = game_state.board[j]; + game_state.board[j] = game_state.board[i]; + game_state.board[i] = tmp; + } + } while(!is_board_has_solution()); +} + +static void game_init() { + game_state.scene = ScenePlay; + game_state.move_count = 0; + game_state.tick_count = 0; + moving_cell.move_direction = DirectionNone; + board_init(); + key_stack_init(); + popup_menu_selected_item = 0; +} + +static bool is_board_solved() { + for(int i = 0; i < 16; i++) + if(((i + 1) % 16) != game_state.board[i]) return false; + return true; +} + +static void game_tick() { + switch(game_state.scene) { + case ScenePlay: + game_state.tick_count++; + if(loaded_saving_ticks) loaded_saving_ticks--; + if(moving_cell.move_direction == DirectionNone && !key_stack_is_empty()) { + set_moving_cell_by_direction(key_stack_pop()); + if(moving_cell.move_direction == DirectionNone) { + notification_message(notification, &sequence_single_vibro); + key_stack_init(); + } + } + + if(moving_cell.move_direction != DirectionNone) { + moving_cell.move_ticks++; + if(moving_cell.move_ticks == MOVE_TICKS) { + game_state.board[moving_cell.zero_index] = + game_state.board[moving_cell.cell_index]; + game_state.board[moving_cell.cell_index] = 0; + moving_cell.move_direction = DirectionNone; + game_state.move_count++; + } + if(is_board_solved()) { + notification_message(notification, &sequence_double_vibro); + if(game_state.move_count < game_state.top_record || game_state.top_record == 0) { + game_state.top_record = game_state.move_count; + storage_game_state_save(); + } + game_state.scene = SceneWin; + } + } + break; + + case SceneWin: + if(!key_stack_is_empty()) game_init(); + break; + + case ScenePopup: + if(!key_stack_is_empty()) { + switch(key_stack_pop()) { + case DirectionDown: + popup_menu_selected_item++; + popup_menu_selected_item = popup_menu_selected_item % POPUP_MENU_ITEMS; + break; + case DirectionUp: + popup_menu_selected_item--; + popup_menu_selected_item = popup_menu_selected_item % POPUP_MENU_ITEMS; + break; + case DirectionNone: + if(popup_menu_selected_item == 0) { + game_state.scene = ScenePlay; + notification_message(notification, &sequence_single_vibro); + } else if(popup_menu_selected_item == 1) { + notification_message(notification, &sequence_single_vibro); + game_init(); + } + break; + } + } + break; + } +} + +static void draw_cell(Canvas* canvas, uint8_t x, uint8_t y, uint8_t cell_number) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_rframe(canvas, x, y, 18, 14, 1); + canvas_set_color(canvas, ColorBlack); + canvas_draw_xbm(canvas, x + 4, y + 3, CELL_WIDTH, CELL_HEIGHT, pic_cells + cell_number * 16); +} + +static void board_draw(Canvas* canvas) { + for(int i = 0; i < 16; i++) { + if(game_state.board[i]) { + if(moving_cell.move_direction == DirectionNone || moving_cell.cell_index != i) + draw_cell(canvas, (i % 4) * 20 + 7, (i / 4) * 16 + 1, game_state.board[i]); + if(moving_cell.move_direction != DirectionNone && moving_cell.cell_index == i) { + uint8_t from_x = (moving_cell.cell_index % 4) * 20 + 7; + uint8_t from_y = (moving_cell.cell_index / 4) * 16 + 1; + uint8_t to_x = (moving_cell.zero_index % 4) * 20 + 7; + uint8_t to_y = (moving_cell.zero_index / 4) * 16 + 1; + int now_x = from_x + (to_x - from_x) * moving_cell.move_ticks / MOVE_TICKS; + int now_y = from_y + (to_y - from_y) * moving_cell.move_ticks / MOVE_TICKS; + draw_cell(canvas, now_x, now_y, game_state.board[i]); + } + } + } +} + +static void number_draw(Canvas* canvas, uint8_t y, uint32_t value) { + uint8_t x = 121; + while(true) { + uint8_t digit = value % 10; + canvas_draw_xbm(canvas, x, y, 4, 6, pic_digits + digit * 6); + x -= 5; + value = value / 10; + if(!value) break; + } +} + +static void plate_draw( + Canvas* canvas, + uint8_t y, + const uint8_t* header, + uint32_t value, + bool dont_draw_zero_value) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_rbox(canvas, 92, y, 35, 19, 2); + canvas_set_color(canvas, ColorBlack); + canvas_draw_xbm(canvas, 95, y + 3, header[0], header[1], &header[2]); + if((!value && !dont_draw_zero_value) || value) number_draw(canvas, y + 10, value); +} + +static void info_draw(Canvas* canvas) { + plate_draw(canvas, 1, pic_top, game_state.top_record, true); + plate_draw(canvas, 22, pic_move, game_state.move_count, false); + plate_draw(canvas, 43, pic_time, game_state.tick_count / FPS, false); +} + +static void gray_screen(Canvas* const canvas) { + canvas_set_color(canvas, ColorWhite); + for(int x = 0; x < 128; x += 2) { + for(int y = 0; y < 64; y++) { + canvas_draw_dot(canvas, x + (y % 2 == 1 ? 0 : 1), y); + } + } +} + +static void render_callback(Canvas* const canvas) { + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 0, 0, 128, 64); + + if(game_state.scene == ScenePlay || game_state.scene == SceneWin || + game_state.scene == ScenePopup) { + canvas_set_color(canvas, ColorBlack); + board_draw(canvas); + info_draw(canvas); + + if(loaded_saving_ticks && game_state.scene != ScenePopup) { + canvas_set_color(canvas, ColorWhite); + canvas_draw_rbox(canvas, 20, 24, 88, 16, 4); + canvas_set_color(canvas, ColorBlack); + canvas_draw_rframe(canvas, 20, 24, 88, 16, 4); + canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, "Restore game ..."); + } + } + + if(game_state.scene == SceneWin) { + gray_screen(canvas); + canvas_draw_box(canvas, 7, 20, 114, 24); + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 8, 21, 112, 22); + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 10, 23, 108, 18); + canvas_set_color(canvas, ColorBlack); + canvas_draw_xbm(canvas, 14, 27, 100, 10, pic_puzzled); + } else if(game_state.scene == ScenePopup) { + gray_screen(canvas); + canvas_set_color(canvas, ColorWhite); + canvas_draw_rbox(canvas, 28, 16, 72, 32, 4); + canvas_set_color(canvas, ColorBlack); + canvas_draw_rframe(canvas, 28, 16, 72, 32, 4); + + for(int i = 0; i < POPUP_MENU_ITEMS; i++) { + if(i == popup_menu_selected_item) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, 34, 20 + 12 * i, 60, 12); + } + + canvas_set_color(canvas, i == popup_menu_selected_item ? ColorWhite : ColorBlack); + canvas_draw_str_aligned( + canvas, 64, 26 + 12 * i, AlignCenter, AlignCenter, popup_menu_strings[i]); + } + } +} + +static void game_event_handler(GameEvent const event) { + if(event.type == EventTypeKey) { + if(event.input.type == InputTypePress) { + switch(event.input.key) { + case InputKeyUp: + key_stack_push(DirectionUp); + break; + case InputKeyDown: + key_stack_push(DirectionDown); + break; + case InputKeyRight: + key_stack_push(DirectionRight); + break; + case InputKeyLeft: + key_stack_push(DirectionLeft); + break; + case InputKeyOk: + if(game_state.scene == ScenePlay) { + game_state.scene = ScenePopup; + key_stack_init(); + } else + key_stack_push(DirectionNone); + break; + case InputKeyBack: + if(game_state.scene == ScenePopup) { + game_state.scene = ScenePlay; + } else { + storage_game_state_save(); + sandbox_loop_exit(); + } + break; + default: + break; + } + } + } else if(event.type == EventTypeTick) { + game_tick(); + } +} + +static void game_alloc() { + srand(DWT->CYCCNT); + key_stack_init(); + notification = furi_record_open(RECORD_NOTIFICATION); + notification_message_block(notification, &sequence_display_backlight_enforce_on); +} + +static void game_free() { + notification_message_block(notification, &sequence_display_backlight_enforce_auto); + furi_record_close(RECORD_NOTIFICATION); +} + +int32_t game15_app() { + game_alloc(); + game_init(); + + loaded_saving_ticks = 0; + if(storage_game_state_load()) { + if(game_state.scene != ScenePlay) + game_init(); + else + loaded_saving_ticks = FPS; + } else + game_init(); + + sandbox_init( + FPS, (SandboxRenderCallback)render_callback, (SandboxEventHandler)game_event_handler); + sandbox_loop(); + sandbox_free(); + game_free(); + return 0; +} diff --git a/applications/plugins/game15/game15_10px.png b/applications/plugins/game15/game15_10px.png new file mode 100644 index 0000000000000000000000000000000000000000..16c4f103806d90d1b8b2c6467487398774db40a6 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xGmzZ=C-xtZVk{1FcVbv~PUa<$!;&U>c zv7h@-A}f&37T^=&3Z(!4|G)I+{JTIFXMsm#F#`kNVGw3Kp1&dmC@Age;us=vIhmp9 q7h78cTU&vFB)gjfTfl@yMuv<^cBUmM%QAt=7(8A5T-G@yGywn)A1I#y literal 0 HcmV?d00001 diff --git a/applications/plugins/game15/images/Game15.png b/applications/plugins/game15/images/Game15.png new file mode 100644 index 0000000000000000000000000000000000000000..f13c2907b531fa5441541ac53a96347f7684ae72 GIT binary patch literal 2078 zcmaJ?X;4#F7`+dqh_X0ztW`v?j-!=P+GYf?grJ}-Do{lzm_SiW1f-zs2@%F+T!Fd) zk+4{*gs@f#2mu0a86hN!VN;US5hMi2Lm+uVBxz6_E_T`3_;ZqOSZN7<&5%IS4 z*LF(`o=#Zvo=hG;$FLnRx+6=oFtPJ>d3NwEx5oHrO>2AKsr}~4w^BmNG~%2W?45#u zyww0~Hv*|XDdie{u11rf%ulo!zk;@>M+G+Eyr#%W^)&z%vJZbT`a(S< zvG3x&-!$^>b_ZvCV4S*hpmHg2UXOq!o&cOS2jJ#{xyQi9Wlt9sMx=3q3v){;(}}!8 z_!voEtiXSWG(C0LZ!VbCX6!6fICeCuhK4x9LYyv&A~3^l1ytJZ%Npn9W7S0#b)(+t& z4;#$&%m;~=BHq6Wfa-iUP74h(LC1go&kXCS$WmhMDq;hz zI4eC=;PE*{SLG6NeS7e}s9^b8I>b%j2`ljX>$sf?>u&#a&imPy&RKFX-Ld_y>$3I__Z!llU*Q*@2`Iu?(j!6A^!GKIi=>PUr%T3tnP z$bovDsw5aiFT-7#ruDSSno*?b)a(+q1UZAKy}7l1`AI<%a`8ksNdL68D!mO%r-Z5> zl_#?NY%!KP~q$IWQ@km1MSxDkD+0D8`s^Lwj&Ou5g z+Pc=b-mo|^+e|3nJ|K1djS|-o)MJhk6UCECh>rt&&?5Yck^SXx^vH;NAgM&k$>HP~ zwk~H4xG3pJma29GO@FRsU3fglE|V&bOU_*vTl3P94+$sodwu4O9{bRmh`!)7O0O7e zDsGpa#o%%q$-tjDScG=k6XI;GkKgk@Bn^ah8I)j0!<6Md;-RoAw@w*1c#_jWcFU*q!kW6W+?j{p9m@O=YWJLH zMIS^n8V~5f>nt7zfW^X0F7wfj{VH_gp+= z?@vjQkL+p?vNW0wto$A0Dx}rV9Ght;)Mo~jyzHlp{6s25rPB%b_M#UWi1E?kq={c4 z4OizOzUtScUiR51*BzQo)!j0hc34zr&gaWnXj$I6ELFe;+Bbj)?R=4EVyCP`C;69r ze(0lm@*C+js97Cj*|m=|8@=#~qRu!Lof_fSn}v(9Jvl!{cE`|^OTJxEH-3!3-XuBn zNOA;HGOOP>_3kaa;U82|J?{dZ4e_ose&^=v^fqQNVO%0lxCg@+iP!&HdB0ud?X9-- zD#Ju|?Yr@(u$!1EVO-_Cpuk{OR60`{m5Wv#VV5hoE`beeiaK}L!o}N+LAUe*eu!?L zoIaJqH3T`Irtin4Ryh?=gqeP*F}8J{QPO13k;AYSwfc#!rUn_$?r+ik@PWq;FW2(z HznuIBq;E*m literal 0 HcmV?d00001 diff --git a/applications/plugins/game15/images/Game15Popup.png b/applications/plugins/game15/images/Game15Popup.png new file mode 100644 index 0000000000000000000000000000000000000000..1df14729fc0e2bf59b9603ba5a0ee159ccadc6e3 GIT binary patch literal 2267 zcmZWre^3)=8vX*M@y8fw9hy50#9qfKQ_h2;9E}=4%N4O#VJZOwLU7b#;Y1(=G$D|) z?J(L?`~~Wv1d3D$7%Tzf5!qy}RuoAhN|FkMFmSS%01Lz_|L*ZPK_SXY><4p9FQr*^AZ}ehiLg?V$r3hE=udcN7n^T#lr#PX6^&avB8#rhG{L_5NXdYu2;vxGc>+uaZ<7qn zOG?L9fen}NJvRcd6AL9zw=2+_MR|}mNeCHHquJEQ0Wog_Q2PdmZnzK*gt|;FMC+BB zZn;hc15tw4((3jFnkvndEiE)af6_S8o5V=7V@BH5r6a7~2!rZ=`K>8|W~8`RldSWPNthz7uA504-&SX*FuPcT%i zRdf&j_($Uy=(m~FB#=w>)E!37wa&!WUq=GDfGd`xbLP)1A>a=yJ%kyemDiB)u9y0j zmdHJFhcHo5B1hks;tIU}qN*G@VG<0rF+?nlJXM*BRiUdzyFBF{revHnyC%|{4<=sf zW2Ke$d$Kl5QB)h$h0|2vQU&2evgR40tR}~SScWOna;K!ul`br2;B9`(qb9CL2QGAF zAtWoXR7JHfTP!K2)TAmWq?kUrvD|D&uOkLqmQmwqv@yp3_$UT%u3L=>pEoXz>my3D zet|Chm43Kr{oe#!RT%|)#WL6RkihhMk1`zvYid&IlikojC678c@vwhinbNz-Am2|~ z0(5id0@Fvbz~S`P>FOMzwM$Rv;e~Kf+mIY_etf-9X#L5OO35kq9gO7A2gMcT0bwVci}Xe4{jlUgyv7e4l165j3nl(7;}H|U!o zJzed};mqD=R%T)ojYyLC%BJ55d(Oj?H6x2V%SzB$8x@@YwP9{-*ce6*H8e-gjcWs6 zo;ll*Pk+}*6<*(06MhIe=OjH*@69YaJFbuCKrXKh7d)q_ zz1sWd{3ucTK5FB|1?MZ_qSdyEP>IAwQ;p9AR~u-mGPYoZZvGSvfNZjOtn(-f@%?l5 z(2=VI$FcI`hfgD;MTKLLZFOB=`?Dsx>TyF6Oa4IYJ+5Dr{2Uu}fC9FT+Z_kyi2z~b zbIl{^_iu0I0->4MxJ%)pM^EiLPG-g0`_1}HBvjmXm;yv5Pnn62(xU|(wqA)dN3}n| zMQNUO5MAC)Q$>8@%+vdxU2jCj2@YKlPlI6fG&S z7~x%Fh_ZY5h^9IC8ryexoe`aVY#=yX@9-WECD%}kJ2wmGHzR_dswaAM-yMUFFW36{ z>V};#wnei&l5LCJo+=CE%*Z0&=WLr5OyLqHnMMh*+78iGr?rZD`D&OQ()imqS7BZh z5Vib^AjK_&9Lg_tc#CL8`vAKhdO-l&#ElXu?$W{FV+^b!gqqupxtD|Cw>SJ9DotBX zcF7o12KsaALp~_h*CM6=Y3I!;4&iOy>uFJUdUQnYBA83D3GZoXnKrbNa6%8S0aw1T zA;uzsJAH!Q^(5tGDXGm;nszrNq0E3lK3twa+0m&qx=iY)lfo@{|3m+m$J1xpT*v$8 zzwf0dN05OCfL-o^Q_)PiVLSg!6LH4jU{2!WMoe_XM0?(Wf$Q%+~On5Hk_s_zHjXEfF3agM-R@i0#6?upOWGKC0zBu z>8viq)ru$P@GQPH)-qr>rr*#QIyyN+98E3(6`v@6-Gm@Tsf)A_W><9R0RFcE;{LKH KM!GZOr_%0p2jT8RpRf&qLG3|7O#kd%P<=;%;^ z7Evn(NEL>sC@2(!1Z-6ztr8UyC6b3j%}PQNP?BvDNE!+qFZ|fKyR&=F{l0U)^WDwa z8Ae_>|I_&ZfQ6x3H|+*smi-n3oF9p;8!rBhcbT*En)2)7pF)xYyF==)=IuMO@l*e{OJ@D*oSLM+jKd*Ccg75QMYeTr zaH%3F3xLdX_7q*ZJw%w^-=R04CZ{ znTOJ8LxemQZB?zvXDBnUXbA{jiJ9CZsmEb!RbQQPeJM}h61PLj=DF&Sg6Ba5!43rR z?@@V@$FB$8I@elkd;@nZ9-=u4oGCee~zL z7r3i^NTRBZS}w4iB9>VWe6J`cIL|$G@_)z)SfwQ6UERR7f^Uo~kkbV}avnfgnuai- zyqdk@2Z)RJASTzy9z0SZq1mhL+Xb_WQ5iuK_9;ZAn#l&9o+{N$epp&+(8u1P(5EG1%bJCjf6jNFb@ zAc*!&$Q)<`@f}A{e48Uuc^PNTQf7ZFQ+&m5?4Ibs#u0f^W0ZBr%P5)c+cIP;#J)Fb z^Rba|%N2gpFZo2TWS;;4?BU*a8L8hPpavCEUT1q=d^*O7)5fLi7hi*FVF#}Wm3ivc z*BC_aVl|#?A@Pz?;BBPXdILA#_m8w-NaJS8NCnkAYjO-^NrV}RR>{$A`FDEe3i zm=}q9Mx~u6$}|=n1UDiStE^z&@zC-$Y=fY>Oy5292%q*HLu@}jUbdz+ z%@Zom9_!Nkbiap%99Oa4-#v?F=sP3Uw;PI@OAGgU=))L?kTwdhRaZ)y(f(%}($()N zB)xk}wThG4f#AEvCU0vHtm8j9An8Jfs*Y(^m{^pak*h(E?y29_Wpm*PD|bvz)wUd> z9IW`NySLZKpWSIVtO)PrcUxy^%^+8ZO&{@p6?5^jmp)wYLe zp5_km|2psw$=BmE@YHEiT@hRqGjy}#TysQ_5GcB!A@Gnnyz1+rF-1%L_S0G@x@QSm z+v6DY`gCOtmy9|nkIOVxHz5Pk@(m8CwH$Hie>gp%yY_WBwM_9ns#4=-hwHWduNKi& zAIkKRxvWtVrB-;)EPJlcRGT9+St>#;kM(>zNjNOGss@14Wy;N%C$LI-C2c;nf3*8e zzOc9x+M#I>bHDC*jiu)T1k!F~d#MB2;o~O~DdpVmkZU@WkEC`V@Ldk9!?AiV->ag0hRvw#+QW;u` z-~Q&n5k;a^_l`x&uOx{uU^xK0rwmxuDC%19pHcV>^^TC!)t0hD+hI9K`B)Ht*l_Q3 zL34&Hb%t@E#Aqq;pr${&+Yq3LdAahsCmgy>?pS|!v5-#dytrPDCzKSb8~UStI&#pD z2xgoJLIF0uF`rFaXwB`Bq}F%7JRPvChXkAldfzml@fEHX0ts!h_P zZ!?q35mjtL4peF44ac8{bx$jsJGtrd)?{i`{f8&dh6&jwE@9&Kza3vQ)#-9of4Fop=sqpgMTI96j$<3RQTtCJWJ6MH_o@P zD_jWxC+o>Bhwa7-VjvTv@pwi0^a7*xES`?yIx21;u<_<=FgGRmwwJ*QqE&~yiL`$r zfGa +#include +#include "sandbox.h" + +FuriMessageQueue* sandbox_event_queue; +FuriMutex** sandbox_mutex; +ViewPort* sandbox_view_port; +Gui* sandbox_gui; +FuriTimer* sandbox_timer; +bool sandbox_loop_processing; +SandboxRenderCallback sandbox_user_render_callback; +SandboxEventHandler sandbox_user_event_handler; + +static void sandbox_render_callback(Canvas* const canvas, void* context) { + UNUSED(context); + if(furi_mutex_acquire(sandbox_mutex, 25) != FuriStatusOk) return; + + if(sandbox_user_render_callback) sandbox_user_render_callback(canvas); + + furi_mutex_release(sandbox_mutex); +} + +static void sandbox_input_callback(InputEvent* input_event, void* context) { + UNUSED(context); + GameEvent event = {.type = EventTypeKey, .input = *input_event}; + furi_message_queue_put(sandbox_event_queue, &event, FuriWaitForever); +} + +static void sandbox_timer_callback(void* context) { + UNUSED(context); + GameEvent event = {.type = EventTypeTick}; + furi_message_queue_put(sandbox_event_queue, &event, 0); +} + +void sandbox_loop() { + sandbox_loop_processing = true; + while(sandbox_loop_processing) { + GameEvent event; + FuriStatus event_status = furi_message_queue_get(sandbox_event_queue, &event, 100); + if(event_status != FuriStatusOk) { + // timeout + continue; + } + + furi_mutex_acquire(sandbox_mutex, FuriWaitForever); + + if(sandbox_user_event_handler) sandbox_user_event_handler(event); + + view_port_update(sandbox_view_port); + furi_mutex_release(sandbox_mutex); + } +} + +void sandbox_loop_exit() { + sandbox_loop_processing = false; +} + +void sandbox_init( + uint8_t fps, + SandboxRenderCallback u_render_callback, + SandboxEventHandler u_event_handler) { + sandbox_user_render_callback = u_render_callback; + sandbox_user_event_handler = u_event_handler; + + sandbox_event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); + sandbox_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + + sandbox_view_port = view_port_alloc(); + view_port_draw_callback_set(sandbox_view_port, sandbox_render_callback, NULL); + view_port_input_callback_set(sandbox_view_port, sandbox_input_callback, NULL); + + sandbox_gui = furi_record_open(RECORD_GUI); + gui_add_view_port(sandbox_gui, sandbox_view_port, GuiLayerFullscreen); + + if(fps > 0) { + sandbox_timer = furi_timer_alloc(sandbox_timer_callback, FuriTimerTypePeriodic, NULL); + furi_timer_start(sandbox_timer, furi_kernel_get_tick_frequency() / fps); + } else + sandbox_timer = NULL; +} + +void sandbox_free() { + if(sandbox_timer) furi_timer_free(sandbox_timer); + + gui_remove_view_port(sandbox_gui, sandbox_view_port); + view_port_enabled_set(sandbox_view_port, false); + view_port_free(sandbox_view_port); + + if(furi_mutex_acquire(sandbox_mutex, FuriWaitForever) == FuriStatusOk) { + furi_mutex_free(sandbox_mutex); + } + furi_message_queue_free(sandbox_event_queue); +} diff --git a/applications/plugins/game15/sandbox.h b/applications/plugins/game15/sandbox.h new file mode 100644 index 000000000..ea7dff37b --- /dev/null +++ b/applications/plugins/game15/sandbox.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + EventType type; + InputEvent input; +} GameEvent; + +typedef void (*SandboxRenderCallback)(Canvas* canvas); +typedef void (*SandboxEventHandler)(GameEvent event); + +void sandbox_init( + uint8_t fps, + SandboxRenderCallback render_callback, + SandboxEventHandler event_handler); +void sandbox_loop(); +void sandbox_loop_exit(); +void sandbox_free(); diff --git a/applications/plugins/gps_nmea_uart/README.md b/applications/plugins/gps_nmea_uart/README.md index 5e36dabda..7af0fa3b3 100644 --- a/applications/plugins/gps_nmea_uart/README.md +++ b/applications/plugins/gps_nmea_uart/README.md @@ -1,6 +1,7 @@ # GPS for Flipper Zero [Original link](https://github.com/ezod/flipperzero-gps) + [Adafruit Ultimate GPS Breakout]. ![ui](ui.png) diff --git a/applications/plugins/morse_code/morse_code.c b/applications/plugins/morse_code/morse_code.c index 0b4790721..a29454371 100644 --- a/applications/plugins/morse_code/morse_code.c +++ b/applications/plugins/morse_code/morse_code.c @@ -27,7 +27,6 @@ typedef struct { 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); @@ -35,20 +34,26 @@ static void render_callback(Canvas* const canvas, void* ctx) { 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 + 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; + 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))); - + 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); @@ -59,9 +64,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { furi_message_queue_put(morse_code->input_queue, input_event, FuriWaitForever); } -static void morse_code_worker_callback( - FuriString* words, - void* context) { +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; @@ -115,45 +118,45 @@ int32_t morse_code_app() { 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){ + 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); + 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); + view_port_update(morse_code->view_port); } morse_code_worker_stop(morse_code->worker); morse_code_free(morse_code); diff --git a/applications/plugins/morse_code/morse_code_worker.c b/applications/plugins/morse_code/morse_code_worker.c index 54ee747c5..b465abc5b 100644 --- a/applications/plugins/morse_code/morse_code_worker.c +++ b/applications/plugins/morse_code/morse_code_worker.c @@ -2,19 +2,20 @@ #include #include - #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'}; +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; @@ -28,31 +29,28 @@ struct MorseCodeWorker { FuriString* words; }; -void morse_code_worker_fill_buffer(MorseCodeWorker* instance, uint32_t duration){ +void morse_code_worker_fill_buffer(MorseCodeWorker* instance, uint32_t duration) { FURI_LOG_D("MorseCode: Duration", "%ld", duration); - if( duration <= instance->dit_delta) + 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); + 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; - } +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; @@ -61,16 +59,16 @@ static int32_t morse_code_worker_thread_callback(void* context) { uint32_t end_tick = 0; bool pushed = true; bool spaced = true; - while(instance->is_running){ + while(instance->is_running) { furi_delay_ms(SLEEP); - if(instance->play){ - if(!was_playing){ + 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){ + } else { + if(was_playing) { pushed = false; spaced = false; furi_hal_speaker_stop(); @@ -80,21 +78,21 @@ static int32_t morse_code_worker_thread_callback(void* context) { start_tick = 0; } } - if(!pushed){ - if(end_tick + (instance->dit_delta * 3) < furi_get_tick()){ + 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); + instance->callback(instance->words, instance->callback_context); pushed = true; } } - if(!spaced){ - if(end_tick + (instance->dit_delta * 7) < furi_get_tick()){ + 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); + instance->callback(instance->words, instance->callback_context); spaced = true; } } @@ -132,17 +130,17 @@ void morse_code_worker_set_callback( instance->callback_context = context; } -void morse_code_worker_play(MorseCodeWorker* instance, bool play){ +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){ +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){ +void morse_code_worker_set_dit_delta(MorseCodeWorker* instance, uint32_t delta) { furi_assert(instance); instance->dit_delta = delta; } diff --git a/applications/plugins/morse_code/morse_code_worker.h b/applications/plugins/morse_code/morse_code_worker.h index cc84a2674..524876476 100644 --- a/applications/plugins/morse_code/morse_code_worker.h +++ b/applications/plugins/morse_code/morse_code_worker.h @@ -10,9 +10,7 @@ #define LINE "-" #define SPACE " " -typedef void (*MorseCodeWorkerCallback)( - FuriString* buffer, - void* context); +typedef void (*MorseCodeWorkerCallback)(FuriString* buffer, void* context); typedef struct MorseCodeWorker MorseCodeWorker; @@ -34,9 +32,3 @@ 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); - - - - - - diff --git a/applications/plugins/totp/totp_app.c b/applications/plugins/totp/totp_app.c index 3bc85e211..f296a734b 100644 --- a/applications/plugins/totp/totp_app.c +++ b/applications/plugins/totp/totp_app.c @@ -24,7 +24,7 @@ static void render_callback(Canvas* const canvas, void* ctx) { PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25); - if (plugin_state != NULL && !plugin_state->changing_scene) { + if(plugin_state != NULL && !plugin_state->changing_scene) { totp_scene_director_render(canvas, plugin_state); } @@ -49,29 +49,43 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) { totp_scene_director_init_scenes(plugin_state); - if (plugin_state->crypto_verify_data == NULL) { + if(plugin_state->crypto_verify_data == NULL) { DialogMessage* message = dialog_message_alloc(); dialog_message_set_buttons(message, "No", NULL, "Yes"); - dialog_message_set_text(message, "Would you like to setup PIN?", SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter); + dialog_message_set_text( + message, + "Would you like to setup PIN?", + SCREEN_WIDTH_CENTER, + SCREEN_HEIGHT_CENTER, + AlignCenter, + AlignCenter); DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs, message); dialog_message_free(message); - if (dialog_result == DialogMessageButtonRight) { + if(dialog_result == DialogMessageButtonRight) { totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL); } else { totp_crypto_seed_iv(plugin_state, NULL, 0); totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); } - } else if (plugin_state->pin_set) { + } else if(plugin_state->pin_set) { totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL); } else { totp_crypto_seed_iv(plugin_state, NULL, 0); - if (totp_crypto_verify_key(plugin_state)) { + if(totp_crypto_verify_key(plugin_state)) { totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL); } else { - FURI_LOG_E(LOGGING_TAG, "Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other"); + FURI_LOG_E( + LOGGING_TAG, + "Digital signature verification failed. Looks like conf file was created on another flipper and can't be used on any other"); DialogMessage* message = dialog_message_alloc(); dialog_message_set_buttons(message, "Exit", NULL, NULL); - dialog_message_set_text(message, "Digital signature verification failed", SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER, AlignCenter, AlignCenter); + dialog_message_set_text( + message, + "Digital signature verification failed", + SCREEN_WIDTH_CENTER, + SCREEN_HEIGHT_CENTER, + AlignCenter, + AlignCenter); dialog_message_show(plugin_state->dialogs, message); dialog_message_free(message); return false; @@ -94,7 +108,7 @@ static void totp_plugin_state_free(PluginState* plugin_state) { ListNode* node = plugin_state->tokens_list; ListNode* tmp; - while (node != NULL) { + while(node != NULL) { tmp = node->next; TokenInfo* tokenInfo = node->data; token_info_free(tokenInfo); @@ -102,7 +116,7 @@ static void totp_plugin_state_free(PluginState* plugin_state) { node = tmp; } - if (plugin_state->crypto_verify_data != NULL) { + if(plugin_state->crypto_verify_data != NULL) { free(plugin_state->crypto_verify_data); } free(plugin_state); @@ -112,7 +126,7 @@ int32_t totp_app() { FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); PluginState* plugin_state = malloc(sizeof(PluginState)); - if (!totp_plugin_state_init(plugin_state)) { + if(!totp_plugin_state_init(plugin_state)) { FURI_LOG_E(LOGGING_TAG, "App state initialization failed\r\n"); totp_plugin_state_free(plugin_state); return 254; @@ -137,18 +151,20 @@ int32_t totp_app() { bool processing = true; uint32_t last_user_interaction_time = furi_get_tick(); while(processing) { - if (plugin_state->changing_scene) continue; + if(plugin_state->changing_scene) continue; FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); PluginState* plugin_state_m = acquire_mutex_block(&state_mutex); if(event_status == FuriStatusOk) { - if (event.type == EventTypeKey) { + if(event.type == EventTypeKey) { last_user_interaction_time = furi_get_tick(); } processing = totp_scene_director_handle_event(&event, plugin_state_m); - } else if (plugin_state_m->pin_set && plugin_state_m->current_scene != TotpSceneAuthentication && furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) { + } else if( + plugin_state_m->pin_set && plugin_state_m->current_scene != TotpSceneAuthentication && + furi_get_tick() - last_user_interaction_time > IDLE_TIMEOUT) { totp_scene_director_activate_scene(plugin_state_m, TotpSceneAuthentication, NULL); }