#include #include #include #include #include #include #include #include #include // Header-file for boolean data-type. #include #include /* generated by fbt from .png files in images folder */ #include #define WIDTH 64 #define HEIGHT 144 enum { up, down, left, right, } direction; typedef struct { bool isPlayerTurn; } SimonSaysData; // Sequence to indicate that this is the beginning of a turn const NotificationSequence sequence_begin_turn = { &message_display_backlight_on, &message_vibro_on, &message_note_g5, &message_delay_50, &message_note_c6, &message_delay_50, &message_note_e5, &message_vibro_off, &message_sound_off, NULL, }; // sequence to indicate that we've reached the end of a turn const NotificationSequence sequence_end_turn = { &message_display_backlight_on, &message_red_0, &message_vibro_on, &message_note_g5, &message_delay_50, &message_note_e5, &message_delay_50, &message_vibro_off, &message_sound_off, &message_do_not_reset, NULL, }; // Indicate that drawing is enabled. const NotificationSequence sequence_player_turn_enabled = { &message_red_255, &message_do_not_reset, NULL, }; // Indicate that drawing is disabled. const NotificationSequence sequence_player_turn_disabled = { &message_red_0, &message_do_not_reset, NULL, }; const NotificationSequence sequence_cleanup = { &message_red_0, &message_green_0, &message_blue_0, &message_sound_off, &message_vibro_off, NULL, }; void simon_says_draw_callback(Canvas* canvas, void* ctx) { const SimonSaysData* game_state = acquire_mutex((ValueMutex*)ctx, 25); UNUSED(ctx); canvas_clear(canvas); canvas_draw_icon(canvas, 2, 2, &I_board); // Draw board //release the mutex release_mutex((ValueMutex*)ctx, game_state); } void game_tick(void* ctx) { SimonSaysData* game_state = acquire_mutex((ValueMutex*)ctx, 25); UNUSED(ctx); //release the mutex release_mutex((ValueMutex*)ctx, game_state); } void simon_says_input_callback(InputEvent* input_event, void* ctx) { furi_assert(ctx); FuriMessageQueue* event_queue = ctx; furi_message_queue_put(event_queue, input_event, FuriWaitForever); } int32_t simon_says_app(void* p) { UNUSED(p); FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); SimonSaysData* simon_says_state = malloc(sizeof(SimonSaysData)); ValueMutex simon_value_mutex; if(!init_mutex(&simon_value_mutex, simon_says_state, sizeof(SimonSaysData))) { FURI_LOG_E("simon_says", "cannot create mutex\r\n"); free(simon_says_state); return -1; } // Configure view port ViewPort* view_port = view_port_alloc(); view_port_draw_callback_set(view_port, simon_says_draw_callback, &simon_value_mutex); view_port_input_callback_set(view_port, simon_says_input_callback, event_queue); // Register view port in GUI Gui* gui = furi_record_open(RECORD_GUI); gui_add_view_port(gui, view_port, GuiLayerFullscreen); NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); InputEvent event; /* Create a timer. We do data analysis in the callback. */ FuriTimer* timer = furi_timer_alloc(game_tick, FuriTimerTypePeriodic, simon_says_state); furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { //break out of the loop if the back key is pressed if(event.key == InputKeyBack && event.type == InputTypeLong) { break; } // Placholder button states if(event.key == InputKeyBack && event.type == InputTypeLong) { view_port_update(view_port); } // Keep LED on while drawing if(simon_says_state->isPlayerTurn) { notification_message(notification, &sequence_player_turn_enabled); } else { notification_message(notification, &sequence_player_turn_disabled); } // Placholder button states if(event.key == InputKeyOk && event.type == InputTypeShort) { // Do Nothing } // Placholder button states if(event.key == InputKeyOk && event.type == InputTypeLong) { // notification_message(furi_record_open(RECORD_NOTIFICATION), &sequence_begin_turn); notification_message(notification, &sequence_begin_turn); view_port_update(view_port); } // Placholder button states if(event.type == InputTypeShort || event.type == InputTypeRepeat || event.type == InputTypeLong) { switch(event.key) { case InputKeyUp: break; case InputKeyDown: break; case InputKeyLeft: break; case InputKeyRight: break; default: break; } view_port_update(view_port); } } furi_timer_free(timer); notification_message(notification, &sequence_cleanup); gui_remove_view_port(gui, view_port); view_port_free(view_port); furi_message_queue_free(event_queue); free(simon_says_state); furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_GUI); return 0; }