From cb0d9ec591c19e76e57a252de9df15aec7128a15 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 14 Oct 2022 01:49:32 +0300 Subject: [PATCH] add sec+ 1.0/2.0 433mhz in add manually, and run fbt fmt --- .../main/subghz/helpers/subghz_custom_event.h | 2 + .../subghz/scenes/subghz_scene_set_type.c | 44 + applications/plugins/minesweeper/assets.h | 120 ++- .../plugins/minesweeper/minesweeper.c | 875 +++++++++--------- 4 files changed, 598 insertions(+), 443 deletions(-) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 39acf5fd6..158ef623c 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -24,9 +24,11 @@ typedef enum { SubmenuIndexLinear_300_00, SubmenuIndexLiftMaster_315_00, SubmenuIndexLiftMaster_390_00, + SubmenuIndexLiftMaster_433_00, SubmenuIndexSecPlus_v2_310_00, SubmenuIndexSecPlus_v2_315_00, SubmenuIndexSecPlus_v2_390_00, + SubmenuIndexSecPlus_v2_433_00, //SubGhzCustomEvent SubGhzCustomEventSceneDeleteSuccess = 100, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 1771c984b..dd36ad08c 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -167,6 +167,12 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexLiftMaster_390_00, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Security+1.0 433MHz", + SubmenuIndexLiftMaster_433_00, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "Security+2.0 310MHz", @@ -185,6 +191,12 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexSecPlus_v2_390_00, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Security+2.0 433MHz", + SubmenuIndexSecPlus_v2_433_00, + subghz_scene_set_type_submenu_callback, + subghz); submenu_set_selected_item( subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType)); @@ -359,6 +371,20 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { generated_protocol = true; } break; + case SubmenuIndexLiftMaster_433_00: + while(!subghz_protocol_secplus_v1_check_fixed(key)) { + key = subghz_random_serial(); + } + if(subghz_scene_set_type_submenu_gen_data_protocol( + subghz, + SUBGHZ_PROTOCOL_SECPLUS_V1_NAME, + (uint64_t)key << 32 | 0xE6000000, + 42, + 433920000, + "AM650")) { + generated_protocol = true; + } + break; case SubmenuIndexSecPlus_v2_310_00: subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); @@ -413,6 +439,24 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { } subghz_transmitter_free(subghz->txrx->transmitter); break; + case SubmenuIndexSecPlus_v2_433_00: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME); + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_secplus_v2_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + key, + 0x68, + 0xE500000, + subghz->txrx->preset); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + break; default: return false; break; diff --git a/applications/plugins/minesweeper/assets.h b/applications/plugins/minesweeper/assets.h index 403c8de29..b734f240f 100644 --- a/applications/plugins/minesweeper/assets.h +++ b/applications/plugins/minesweeper/assets.h @@ -1,48 +1,144 @@ #define tile_0_width 8 #define tile_0_height 8 static uint8_t tile_0_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; #define tile_1_width 8 #define tile_1_height 8 static uint8_t tile_1_bits[] = { - 0x00, 0x10, 0x18, 0x10, 0x10, 0x10, 0x10, 0x00, }; + 0x00, + 0x10, + 0x18, + 0x10, + 0x10, + 0x10, + 0x10, + 0x00, +}; #define tile_2_width 8 #define tile_2_height 8 static uint8_t tile_2_bits[] = { - 0x00, 0x1C, 0x20, 0x20, 0x18, 0x04, 0x3C, 0x00, }; + 0x00, + 0x1C, + 0x20, + 0x20, + 0x18, + 0x04, + 0x3C, + 0x00, +}; #define tile_3_width 8 #define tile_3_height 8 static uint8_t tile_3_bits[] = { - 0x00, 0x1C, 0x20, 0x20, 0x18, 0x20, 0x1C, 0x00, }; + 0x00, + 0x1C, + 0x20, + 0x20, + 0x18, + 0x20, + 0x1C, + 0x00, +}; #define tile_4_width 8 #define tile_4_height 8 static uint8_t tile_4_bits[] = { - 0x00, 0x04, 0x14, 0x14, 0x3C, 0x10, 0x10, 0x00, }; + 0x00, + 0x04, + 0x14, + 0x14, + 0x3C, + 0x10, + 0x10, + 0x00, +}; #define tile_5_width 8 #define tile_5_height 8 static uint8_t tile_5_bits[] = { - 0x00, 0x3C, 0x04, 0x1C, 0x20, 0x20, 0x1C, 0x00, }; + 0x00, + 0x3C, + 0x04, + 0x1C, + 0x20, + 0x20, + 0x1C, + 0x00, +}; #define tile_6_width 8 #define tile_6_height 8 static uint8_t tile_6_bits[] = { - 0x00, 0x18, 0x24, 0x04, 0x1C, 0x24, 0x18, 0x00, }; + 0x00, + 0x18, + 0x24, + 0x04, + 0x1C, + 0x24, + 0x18, + 0x00, +}; #define tile_7_width 8 #define tile_7_height 8 static uint8_t tile_7_bits[] = { - 0x00, 0x3C, 0x20, 0x20, 0x10, 0x08, 0x08, 0x00, }; + 0x00, + 0x3C, + 0x20, + 0x20, + 0x10, + 0x08, + 0x08, + 0x00, +}; #define tile_8_width 8 #define tile_8_height 8 static uint8_t tile_8_bits[] = { - 0x00, 0x18, 0x24, 0x18, 0x24, 0x24, 0x18, 0x00, }; + 0x00, + 0x18, + 0x24, + 0x18, + 0x24, + 0x24, + 0x18, + 0x00, +}; #define tile_flag_width 8 #define tile_flag_height 8 static uint8_t tile_flag_bits[] = { - 0xFF, 0x81, 0xB9, 0x89, 0x89, 0x9D, 0x81, 0xFF, }; + 0xFF, + 0x81, + 0xB9, + 0x89, + 0x89, + 0x9D, + 0x81, + 0xFF, +}; #define tile_mine_width 8 #define tile_mine_height 8 static uint8_t tile_mine_bits[] = { - 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, }; + 0x55, + 0xAA, + 0x55, + 0xAA, + 0x55, + 0xAA, + 0x55, + 0xAA, +}; #define tile_uncleared_width 8 #define tile_uncleared_height 8 static uint8_t tile_uncleared_bits[] = { - 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, }; + 0xFF, + 0x81, + 0x81, + 0x81, + 0x81, + 0x81, + 0x81, + 0xFF, +}; diff --git a/applications/plugins/minesweeper/minesweeper.c b/applications/plugins/minesweeper/minesweeper.c index 6dd9bb89b..6d29bab2d 100644 --- a/applications/plugins/minesweeper/minesweeper.c +++ b/applications/plugins/minesweeper/minesweeper.c @@ -28,18 +28,18 @@ typedef struct { } PluginEvent; typedef enum { - TileType0, // this HAS to be in order, for hint assignment to be ez pz - TileType1, - TileType2, - TileType3, - TileType4, - TileType5, - TileType6, - TileType7, - TileType8, - TileTypeUncleared, - TileTypeFlag, - TileTypeMine + TileType0, // this HAS to be in order, for hint assignment to be ez pz + TileType1, + TileType2, + TileType3, + TileType4, + TileType5, + TileType6, + TileType7, + TileType8, + TileTypeUncleared, + TileTypeFlag, + TileTypeMine } TileType; typedef enum { @@ -48,23 +48,23 @@ typedef enum { } Field; typedef struct { - Field minefield[PLAYFIELD_WIDTH][PLAYFIELD_HEIGHT]; - TileType playfield[PLAYFIELD_WIDTH][PLAYFIELD_HEIGHT]; - FuriTimer* timer; - int cursor_x; - int cursor_y; - int mines_left; - int fields_cleared; - int flags_set; - bool game_started; - uint32_t game_started_tick; + Field minefield[PLAYFIELD_WIDTH][PLAYFIELD_HEIGHT]; + TileType playfield[PLAYFIELD_WIDTH][PLAYFIELD_HEIGHT]; + FuriTimer* timer; + int cursor_x; + int cursor_y; + int mines_left; + int fields_cleared; + int flags_set; + bool game_started; + uint32_t game_started_tick; } Minesweeper; static void timer_callback(void* ctx) { - UNUSED(ctx); - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - notification_message(notification, &sequence_reset_vibro); - furi_record_close(RECORD_NOTIFICATION); + UNUSED(ctx); + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + notification_message(notification, &sequence_reset_vibro); + furi_record_close(RECORD_NOTIFICATION); } static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { @@ -76,8 +76,8 @@ static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queu static void render_callback(Canvas* const canvas, void* ctx) { const Minesweeper* minesweeper_state = acquire_mutex((ValueMutex*)ctx, 25); - if (minesweeper_state == NULL) { - return; + if(minesweeper_state == NULL) { + return; } FuriString* mineStr; FuriString* timeStr; @@ -90,134 +90,134 @@ static void render_callback(Canvas* const canvas, void* ctx) { int seconds = 0; int minutes = 0; - if (minesweeper_state->game_started) { - uint32_t ticks_elapsed = furi_get_tick() - minesweeper_state->game_started_tick; - seconds = (int) ticks_elapsed / furi_kernel_get_tick_frequency(); - minutes = (int) seconds / 60; - seconds = seconds % 60; + if(minesweeper_state->game_started) { + uint32_t ticks_elapsed = furi_get_tick() - minesweeper_state->game_started_tick; + seconds = (int)ticks_elapsed / furi_kernel_get_tick_frequency(); + minutes = (int)seconds / 60; + seconds = seconds % 60; } furi_string_printf(timeStr, "%01d:%02d", minutes, seconds); canvas_draw_str_aligned(canvas, 128, 0, AlignRight, AlignTop, furi_string_get_cstr(timeStr)); - for (int y = 0; y < PLAYFIELD_HEIGHT; y++) { - for (int x = 0; x < PLAYFIELD_WIDTH; x++) { - if ( x == minesweeper_state->cursor_x && y == minesweeper_state->cursor_y) { - canvas_invert_color(canvas); + for(int y = 0; y < PLAYFIELD_HEIGHT; y++) { + for(int x = 0; x < PLAYFIELD_WIDTH; x++) { + if(x == minesweeper_state->cursor_x && y == minesweeper_state->cursor_y) { + canvas_invert_color(canvas); + } + switch(minesweeper_state->playfield[x][y]) { + case TileType0: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_0_bits); + break; + case TileType1: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_1_bits); + break; + case TileType2: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_2_bits); + break; + case TileType3: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_3_bits); + break; + case TileType4: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_4_bits); + break; + case TileType5: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_5_bits); + break; + case TileType6: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_6_bits); + break; + case TileType7: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_7_bits); + break; + case TileType8: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_8_bits); + break; + case TileTypeFlag: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_flag_bits); + break; + case TileTypeUncleared: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_uncleared_bits); + break; + case TileTypeMine: + canvas_draw_xbm( + canvas, + x * TILE_HEIGHT, // x + 8 + (y * TILE_WIDTH), // y + TILE_WIDTH, + TILE_HEIGHT, + tile_mine_bits); + break; + } + if(x == minesweeper_state->cursor_x && y == minesweeper_state->cursor_y) { + canvas_invert_color(canvas); + } } - switch (minesweeper_state->playfield[x][y]) { - case TileType0: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_0_bits); - break; - case TileType1: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_1_bits); - break; - case TileType2: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_2_bits); - break; - case TileType3: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_3_bits); - break; - case TileType4: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_4_bits); - break; - case TileType5: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_5_bits); - break; - case TileType6: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_6_bits); - break; - case TileType7: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_7_bits); - break; - case TileType8: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_8_bits); - break; - case TileTypeFlag: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_flag_bits); - break; - case TileTypeUncleared: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_uncleared_bits); - break; - case TileTypeMine: - canvas_draw_xbm( - canvas, - x*TILE_HEIGHT, // x - 8 + (y * TILE_WIDTH), // y - TILE_WIDTH, - TILE_HEIGHT, - tile_mine_bits); - break; - } - if ( x == minesweeper_state->cursor_x && y == minesweeper_state->cursor_y) { - canvas_invert_color(canvas); - } - } } furi_string_free(mineStr); @@ -226,336 +226,349 @@ static void render_callback(Canvas* const canvas, void* ctx) { } static void setup_playfield(Minesweeper* minesweeper_state) { - int mines_left = MINECOUNT; - for (int y = 0; y < PLAYFIELD_HEIGHT; y++) { - for (int x = 0; x < PLAYFIELD_WIDTH; x++){ - minesweeper_state->minefield[x][y] = FieldEmpty; - minesweeper_state->playfield[x][y] = TileTypeUncleared; + int mines_left = MINECOUNT; + for(int y = 0; y < PLAYFIELD_HEIGHT; y++) { + for(int x = 0; x < PLAYFIELD_WIDTH; x++) { + minesweeper_state->minefield[x][y] = FieldEmpty; + minesweeper_state->playfield[x][y] = TileTypeUncleared; + } } - } - while(mines_left > 0) { - int rand_x = rand() % PLAYFIELD_WIDTH; - int rand_y = rand() % PLAYFIELD_HEIGHT; - // make sure first guess isn't a mine - if (minesweeper_state->minefield[rand_x][rand_y] == FieldEmpty && - (minesweeper_state->cursor_x != rand_x && minesweeper_state->cursor_y != rand_y )) { - minesweeper_state->minefield[rand_x][rand_y] = FieldMine; - mines_left--; + while(mines_left > 0) { + int rand_x = rand() % PLAYFIELD_WIDTH; + int rand_y = rand() % PLAYFIELD_HEIGHT; + // make sure first guess isn't a mine + if(minesweeper_state->minefield[rand_x][rand_y] == FieldEmpty && + (minesweeper_state->cursor_x != rand_x && minesweeper_state->cursor_y != rand_y)) { + minesweeper_state->minefield[rand_x][rand_y] = FieldMine; + mines_left--; + } } - } - minesweeper_state->mines_left = MINECOUNT; - minesweeper_state->fields_cleared = 0; - minesweeper_state->flags_set = 0; - minesweeper_state->game_started_tick = furi_get_tick(); - minesweeper_state->game_started = false; + minesweeper_state->mines_left = MINECOUNT; + minesweeper_state->fields_cleared = 0; + minesweeper_state->flags_set = 0; + minesweeper_state->game_started_tick = furi_get_tick(); + minesweeper_state->game_started = false; } static void place_flag(Minesweeper* minesweeper_state) { - if (minesweeper_state->playfield[minesweeper_state->cursor_x][minesweeper_state->cursor_y] == TileTypeUncleared) { - minesweeper_state->playfield[minesweeper_state->cursor_x][minesweeper_state->cursor_y] = TileTypeFlag; - minesweeper_state->flags_set++; - } else if (minesweeper_state->playfield[minesweeper_state->cursor_x][minesweeper_state->cursor_y] == TileTypeFlag) { - minesweeper_state->playfield[minesweeper_state->cursor_x][minesweeper_state->cursor_y] = TileTypeUncleared; - minesweeper_state->flags_set--; - } + if(minesweeper_state->playfield[minesweeper_state->cursor_x][minesweeper_state->cursor_y] == + TileTypeUncleared) { + minesweeper_state->playfield[minesweeper_state->cursor_x][minesweeper_state->cursor_y] = + TileTypeFlag; + minesweeper_state->flags_set++; + } else if( + minesweeper_state->playfield[minesweeper_state->cursor_x][minesweeper_state->cursor_y] == + TileTypeFlag) { + minesweeper_state->playfield[minesweeper_state->cursor_x][minesweeper_state->cursor_y] = + TileTypeUncleared; + minesweeper_state->flags_set--; + } } static bool game_lost(Minesweeper* minesweeper_state) { - // returns true if the player wants to restart, otherwise false - DialogsApp *dialogs = furi_record_open(RECORD_DIALOGS); + // returns true if the player wants to restart, otherwise false + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); - DialogMessage* message = dialog_message_alloc(); - const char* header_text = "Game Over"; - const char* message_text = "You hit a mine!"; + DialogMessage* message = dialog_message_alloc(); + const char* header_text = "Game Over"; + const char* message_text = "You hit a mine!"; - dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop); - dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter); - dialog_message_set_buttons(message, NULL, "Play again", NULL); + dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop); + dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter); + dialog_message_set_buttons(message, NULL, "Play again", NULL); - dialog_message_set_icon(message, NULL, 0, 10); + dialog_message_set_icon(message, NULL, 0, 10); - NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); - notification_message(notifications, &sequence_set_vibro_on); - furi_record_close(RECORD_NOTIFICATION); - furi_timer_start(minesweeper_state->timer, (uint32_t) furi_kernel_get_tick_frequency() * 0.2); + NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); + notification_message(notifications, &sequence_set_vibro_on); + furi_record_close(RECORD_NOTIFICATION); + furi_timer_start(minesweeper_state->timer, (uint32_t)furi_kernel_get_tick_frequency() * 0.2); - DialogMessageButton choice = dialog_message_show(dialogs, message); - dialog_message_free(message); - furi_record_close(RECORD_DIALOGS); + DialogMessageButton choice = dialog_message_show(dialogs, message); + dialog_message_free(message); + furi_record_close(RECORD_DIALOGS); - return choice == DialogMessageButtonCenter; + return choice == DialogMessageButtonCenter; } static bool game_won(Minesweeper* minesweeper_state) { - DialogsApp *dialogs = furi_record_open(RECORD_DIALOGS); + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); - FuriString* tempStr; - tempStr = furi_string_alloc(); + FuriString* tempStr; + tempStr = furi_string_alloc(); - int seconds = 0; - int minutes = 0; - uint32_t ticks_elapsed = furi_get_tick() - minesweeper_state->game_started_tick; - seconds = (int) ticks_elapsed / furi_kernel_get_tick_frequency(); - minutes = (int) seconds / 60; - seconds = seconds % 60; + int seconds = 0; + int minutes = 0; + uint32_t ticks_elapsed = furi_get_tick() - minesweeper_state->game_started_tick; + seconds = (int)ticks_elapsed / furi_kernel_get_tick_frequency(); + minutes = (int)seconds / 60; + seconds = seconds % 60; - DialogMessage* message = dialog_message_alloc(); - const char* header_text = "Game won!"; - furi_string_cat_printf(tempStr, "Minefield cleared in %01d:%02d", minutes, seconds); - dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop); - dialog_message_set_text(message, furi_string_get_cstr(tempStr), 64, 32, AlignCenter, AlignCenter); - dialog_message_set_buttons(message, NULL, "Play again", NULL); - dialog_message_set_icon(message, NULL, 72, 17); + DialogMessage* message = dialog_message_alloc(); + const char* header_text = "Game won!"; + furi_string_cat_printf(tempStr, "Minefield cleared in %01d:%02d", minutes, seconds); + dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop); + dialog_message_set_text( + message, furi_string_get_cstr(tempStr), 64, 32, AlignCenter, AlignCenter); + dialog_message_set_buttons(message, NULL, "Play again", NULL); + dialog_message_set_icon(message, NULL, 72, 17); - DialogMessageButton choice = dialog_message_show(dialogs, message); - dialog_message_free(message); - furi_string_free(tempStr); - furi_record_close(RECORD_DIALOGS); - return choice == DialogMessageButtonCenter; + DialogMessageButton choice = dialog_message_show(dialogs, message); + dialog_message_free(message); + furi_string_free(tempStr); + furi_record_close(RECORD_DIALOGS); + return choice == DialogMessageButtonCenter; } // returns false if the move loses the game - otherwise true static bool play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y) { - if (minesweeper_state->playfield[cursor_x][cursor_y] == TileTypeFlag) { - // we're on a flagged field, do nothing - return true; - } - if (minesweeper_state->minefield[cursor_x][cursor_y] == FieldMine) { - // player loses - draw mine - minesweeper_state->playfield[cursor_x][cursor_y] = TileTypeMine; - return false; - } - - if (minesweeper_state->playfield[cursor_x][cursor_y] >= TileType1 && minesweeper_state->playfield[cursor_x][cursor_y] <= TileType8) { - // click on a cleared cell with a number - // count the flags around - int flags = 0; - for (int y = cursor_y-1; y <= cursor_y+1; y++) { - for (int x = cursor_x-1; x <= cursor_x+1; x++) { - if ( x == cursor_x && y == cursor_y ) { - // we're on the cell the user selected, so ignore. - continue; - } - // make sure we don't go OOB - if ( x >= 0 && x < PLAYFIELD_WIDTH && y >= 0 && y < PLAYFIELD_HEIGHT) { - if (minesweeper_state->playfield[x][y] == TileTypeFlag) { - flags ++; - } - } - } + if(minesweeper_state->playfield[cursor_x][cursor_y] == TileTypeFlag) { + // we're on a flagged field, do nothing + return true; } - int mines = minesweeper_state->playfield[cursor_x][cursor_y]; // ¯\_(ツ)_/¯ - if (flags == mines) { - // auto uncover all non-flags around (to win faster ;) - for (int auto_y = cursor_y-1; auto_y <= cursor_y+1; auto_y++) { - for (int auto_x = cursor_x-1; auto_x <= cursor_x+1; auto_x++) { - if ( auto_x == cursor_x && auto_y == cursor_y ) { - continue; - } - if ( auto_x >= 0 && auto_x < PLAYFIELD_WIDTH && auto_y >= 0 && auto_y < PLAYFIELD_HEIGHT) { - if (minesweeper_state->playfield[auto_x][auto_y] == TileTypeUncleared) { - if(!play_move(minesweeper_state, auto_x, auto_y)) { - // flags were wrong, we got a mine! - return false; - } + if(minesweeper_state->minefield[cursor_x][cursor_y] == FieldMine) { + // player loses - draw mine + minesweeper_state->playfield[cursor_x][cursor_y] = TileTypeMine; + return false; + } + + if(minesweeper_state->playfield[cursor_x][cursor_y] >= TileType1 && + minesweeper_state->playfield[cursor_x][cursor_y] <= TileType8) { + // click on a cleared cell with a number + // count the flags around + int flags = 0; + for(int y = cursor_y - 1; y <= cursor_y + 1; y++) { + for(int x = cursor_x - 1; x <= cursor_x + 1; x++) { + if(x == cursor_x && y == cursor_y) { + // we're on the cell the user selected, so ignore. + continue; + } + // make sure we don't go OOB + if(x >= 0 && x < PLAYFIELD_WIDTH && y >= 0 && y < PLAYFIELD_HEIGHT) { + if(minesweeper_state->playfield[x][y] == TileTypeFlag) { + flags++; + } + } } - } } - } - // we're done without hitting a mine - so return - return true; + int mines = minesweeper_state->playfield[cursor_x][cursor_y]; // ¯\_(ツ)_/¯ + if(flags == mines) { + // auto uncover all non-flags around (to win faster ;) + for(int auto_y = cursor_y - 1; auto_y <= cursor_y + 1; auto_y++) { + for(int auto_x = cursor_x - 1; auto_x <= cursor_x + 1; auto_x++) { + if(auto_x == cursor_x && auto_y == cursor_y) { + continue; + } + if(auto_x >= 0 && auto_x < PLAYFIELD_WIDTH && auto_y >= 0 && + auto_y < PLAYFIELD_HEIGHT) { + if(minesweeper_state->playfield[auto_x][auto_y] == TileTypeUncleared) { + if(!play_move(minesweeper_state, auto_x, auto_y)) { + // flags were wrong, we got a mine! + return false; + } + } + } + } + } + // we're done without hitting a mine - so return + return true; + } } - } - // calculate number of surrounding mines. - int hint = 0; - for (int y = cursor_y-1; y <= cursor_y+1; y++) { - for (int x = cursor_x-1; x <= cursor_x+1; x++) { - if ( x == cursor_x && y == cursor_y ) { - // we're on the cell the user selected, so ignore. - continue; - } - // make sure we don't go OOB - if ( x >= 0 && x < PLAYFIELD_WIDTH && y >= 0 && y < PLAYFIELD_HEIGHT) { - if(minesweeper_state->minefield[x][y] == FieldMine) { - hint ++; + // calculate number of surrounding mines. + int hint = 0; + for(int y = cursor_y - 1; y <= cursor_y + 1; y++) { + for(int x = cursor_x - 1; x <= cursor_x + 1; x++) { + if(x == cursor_x && y == cursor_y) { + // we're on the cell the user selected, so ignore. + continue; + } + // make sure we don't go OOB + if(x >= 0 && x < PLAYFIELD_WIDTH && y >= 0 && y < PLAYFIELD_HEIGHT) { + if(minesweeper_state->minefield[x][y] == FieldMine) { + hint++; + } + } } - } } - } - // 〜( ̄▽ ̄〜) don't judge me (〜 ̄▽ ̄)〜 - minesweeper_state->playfield[cursor_x][cursor_y] = hint; - minesweeper_state->fields_cleared++; - FURI_LOG_D("Minesweeper", "Setting %d,%d to %d", cursor_x, cursor_y, hint); - if (hint == 0) { - // the field is "empty" - // auto open surrounding fields. - for (int auto_y = cursor_y-1; auto_y <= cursor_y+1; auto_y++) { - for (int auto_x = cursor_x-1; auto_x <= cursor_x+1; auto_x++) { - if ( auto_x == cursor_x && auto_y == cursor_y ) { - continue; + // 〜( ̄▽ ̄〜) don't judge me (〜 ̄▽ ̄)〜 + minesweeper_state->playfield[cursor_x][cursor_y] = hint; + minesweeper_state->fields_cleared++; + FURI_LOG_D("Minesweeper", "Setting %d,%d to %d", cursor_x, cursor_y, hint); + if(hint == 0) { + // the field is "empty" + // auto open surrounding fields. + for(int auto_y = cursor_y - 1; auto_y <= cursor_y + 1; auto_y++) { + for(int auto_x = cursor_x - 1; auto_x <= cursor_x + 1; auto_x++) { + if(auto_x == cursor_x && auto_y == cursor_y) { + continue; + } + if(auto_x >= 0 && auto_x < PLAYFIELD_WIDTH && auto_y >= 0 && + auto_y < PLAYFIELD_HEIGHT) { + if(minesweeper_state->playfield[auto_x][auto_y] == TileTypeUncleared) { + play_move(minesweeper_state, auto_x, auto_y); + } + } + } } - if ( auto_x >= 0 && auto_x < PLAYFIELD_WIDTH && auto_y >= 0 && auto_y < PLAYFIELD_HEIGHT) { - if (minesweeper_state->playfield[auto_x][auto_y] == TileTypeUncleared) { - play_move(minesweeper_state, auto_x, auto_y); - } - } - } } - } - return true; + return true; } static void minesweeper_state_init(Minesweeper* const minesweeper_state) { minesweeper_state->cursor_x = minesweeper_state->cursor_y = 0; minesweeper_state->game_started = false; - for (int y = 0; y < PLAYFIELD_HEIGHT; y++) { - for (int x = 0; x < PLAYFIELD_WIDTH; x++){ - minesweeper_state->playfield[x][y] = TileTypeUncleared; - } + for(int y = 0; y < PLAYFIELD_HEIGHT; y++) { + for(int x = 0; x < PLAYFIELD_WIDTH; x++) { + minesweeper_state->playfield[x][y] = TileTypeUncleared; + } } } int32_t minesweeper_app(void* p) { - UNUSED(p); - DialogsApp *dialogs = furi_record_open(RECORD_DIALOGS); + UNUSED(p); + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); - DialogMessage* message = dialog_message_alloc(); - const char* header_text = "Minesweeper"; - const char* message_text = "Hold OK pressed to toggle flags.\ngithub.com/panki27"; + DialogMessage* message = dialog_message_alloc(); + const char* header_text = "Minesweeper"; + const char* message_text = "Hold OK pressed to toggle flags.\ngithub.com/panki27"; - dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop); - dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter); - dialog_message_set_buttons(message, NULL, "Play", NULL); + dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop); + dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter); + dialog_message_set_buttons(message, NULL, "Play", NULL); - dialog_message_set_icon(message, NULL, 0, 10); + dialog_message_set_icon(message, NULL, 0, 10); - dialog_message_show(dialogs, message); - dialog_message_free(message); - furi_record_close(RECORD_DIALOGS); + dialog_message_show(dialogs, message); + dialog_message_free(message); + furi_record_close(RECORD_DIALOGS); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); - Minesweeper* minesweeper_state = malloc(sizeof(Minesweeper)); - // setup - minesweeper_state_init(minesweeper_state); + Minesweeper* minesweeper_state = malloc(sizeof(Minesweeper)); + // setup + minesweeper_state_init(minesweeper_state); - ValueMutex state_mutex; - if (!init_mutex(&state_mutex, minesweeper_state, sizeof(minesweeper_state))) { - FURI_LOG_E("Minesweeper", "cannot create mutex\r\n"); - free(minesweeper_state); - return 255; - } - // BEGIN IMPLEMENTATION - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, &state_mutex); - view_port_input_callback_set(view_port, input_callback, event_queue); - minesweeper_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, &state_mutex); - - // Open GUI and register view_port - Gui* gui = furi_record_open("gui"); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - PluginEvent event; - for (bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - Minesweeper* minesweeper_state = (Minesweeper*)acquire_mutex_block(&state_mutex); - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypeShort) { - switch(event.input.key) { - case InputKeyUp: - minesweeper_state->cursor_y--; - if(minesweeper_state->cursor_y < 0) { - minesweeper_state->cursor_y = 0; - } - break; - case InputKeyDown: - minesweeper_state->cursor_y++; - if(minesweeper_state->cursor_y >= PLAYFIELD_HEIGHT) { - minesweeper_state->cursor_y = PLAYFIELD_HEIGHT-1; - } - break; - case InputKeyRight: - minesweeper_state->cursor_x++; - if(minesweeper_state->cursor_x >= PLAYFIELD_WIDTH) { - minesweeper_state->cursor_x = PLAYFIELD_WIDTH-1; - } - break; - case InputKeyLeft: - minesweeper_state->cursor_x--; - if(minesweeper_state->cursor_x < 0) { - minesweeper_state->cursor_x = 0; - } - break; - case InputKeyOk: - if (!minesweeper_state->game_started) { - setup_playfield(minesweeper_state); - minesweeper_state->game_started = true; - } - if (!play_move(minesweeper_state, minesweeper_state->cursor_x, minesweeper_state->cursor_y)) { - // ooops. looks like we hit a mine! - if (game_lost(minesweeper_state)) { - // player wants to restart. - setup_playfield(minesweeper_state); - } else { - // player wants to exit :( - processing = false; - } - } else { - // check win condition. - if (minesweeper_state->fields_cleared == (PLAYFIELD_HEIGHT*PLAYFIELD_WIDTH) - MINECOUNT){ - if (game_won(minesweeper_state)) { - //player wants to restart - setup_playfield(minesweeper_state); - } else { - processing = false; - } - } - } - break; - case InputKeyBack: - // Exit the plugin - processing = false; - break; - } - } else if (event.input.type == InputTypeLong) { - // hold events - FURI_LOG_D("Minesweeper", "Got a long press!"); - switch(event.input.key) { - case InputKeyUp: - case InputKeyDown: - case InputKeyRight: - case InputKeyLeft: - break; - case InputKeyOk: - FURI_LOG_D("Minesweeper", "Toggling flag"); - place_flag(minesweeper_state); - break; - case InputKeyBack: - processing = false; - break; - } - } - } - } else { - // event timeout - ; + ValueMutex state_mutex; + if(!init_mutex(&state_mutex, minesweeper_state, sizeof(minesweeper_state))) { + FURI_LOG_E("Minesweeper", "cannot create mutex\r\n"); + free(minesweeper_state); + return 255; } - view_port_update(view_port); - release_mutex(&state_mutex, minesweeper_state); - } - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close("gui"); - view_port_free(view_port); - furi_message_queue_free(event_queue); - delete_mutex(&state_mutex); - furi_timer_free(minesweeper_state->timer); - free(minesweeper_state); + // BEGIN IMPLEMENTATION - return 0; + // Set system callbacks + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, render_callback, &state_mutex); + view_port_input_callback_set(view_port, input_callback, event_queue); + minesweeper_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, &state_mutex); + + // Open GUI and register view_port + Gui* gui = furi_record_open("gui"); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + PluginEvent event; + for(bool processing = true; processing;) { + FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); + Minesweeper* minesweeper_state = (Minesweeper*)acquire_mutex_block(&state_mutex); + if(event_status == FuriStatusOk) { + // press events + if(event.type == EventTypeKey) { + if(event.input.type == InputTypeShort) { + switch(event.input.key) { + case InputKeyUp: + minesweeper_state->cursor_y--; + if(minesweeper_state->cursor_y < 0) { + minesweeper_state->cursor_y = 0; + } + break; + case InputKeyDown: + minesweeper_state->cursor_y++; + if(minesweeper_state->cursor_y >= PLAYFIELD_HEIGHT) { + minesweeper_state->cursor_y = PLAYFIELD_HEIGHT - 1; + } + break; + case InputKeyRight: + minesweeper_state->cursor_x++; + if(minesweeper_state->cursor_x >= PLAYFIELD_WIDTH) { + minesweeper_state->cursor_x = PLAYFIELD_WIDTH - 1; + } + break; + case InputKeyLeft: + minesweeper_state->cursor_x--; + if(minesweeper_state->cursor_x < 0) { + minesweeper_state->cursor_x = 0; + } + break; + case InputKeyOk: + if(!minesweeper_state->game_started) { + setup_playfield(minesweeper_state); + minesweeper_state->game_started = true; + } + if(!play_move( + minesweeper_state, + minesweeper_state->cursor_x, + minesweeper_state->cursor_y)) { + // ooops. looks like we hit a mine! + if(game_lost(minesweeper_state)) { + // player wants to restart. + setup_playfield(minesweeper_state); + } else { + // player wants to exit :( + processing = false; + } + } else { + // check win condition. + if(minesweeper_state->fields_cleared == + (PLAYFIELD_HEIGHT * PLAYFIELD_WIDTH) - MINECOUNT) { + if(game_won(minesweeper_state)) { + //player wants to restart + setup_playfield(minesweeper_state); + } else { + processing = false; + } + } + } + break; + case InputKeyBack: + // Exit the plugin + processing = false; + break; + } + } else if(event.input.type == InputTypeLong) { + // hold events + FURI_LOG_D("Minesweeper", "Got a long press!"); + switch(event.input.key) { + case InputKeyUp: + case InputKeyDown: + case InputKeyRight: + case InputKeyLeft: + break; + case InputKeyOk: + FURI_LOG_D("Minesweeper", "Toggling flag"); + place_flag(minesweeper_state); + break; + case InputKeyBack: + processing = false; + break; + } + } + } + } else { + // event timeout + ; + } + view_port_update(view_port); + release_mutex(&state_mutex, minesweeper_state); + } + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + furi_record_close("gui"); + view_port_free(view_port); + furi_message_queue_free(event_queue); + delete_mutex(&state_mutex); + furi_timer_free(minesweeper_state->timer); + free(minesweeper_state); + + return 0; }