simon_says.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <gui/gui.h>
  4. #include <gui/elements.h>
  5. #include <gui/icon.h>
  6. #include <input/input.h>
  7. #include <notification/notification.h>
  8. #include <notification/notification_messages.h>
  9. #include <stdbool.h> // Header-file for boolean data-type.
  10. #include <stdio.h>
  11. #include <string.h>
  12. /* generated by fbt from .png files in images folder */
  13. #include <simon_says_icons.h>
  14. #define WIDTH 64
  15. #define HEIGHT 144
  16. enum {
  17. up,
  18. down,
  19. left,
  20. right,
  21. } direction;
  22. typedef struct {
  23. bool isPlayerTurn;
  24. } SimonSaysData;
  25. // Sequence to indicate that this is the beginning of a turn
  26. const NotificationSequence sequence_begin_turn = {
  27. &message_display_backlight_on,
  28. &message_vibro_on,
  29. &message_note_g5,
  30. &message_delay_50,
  31. &message_note_c6,
  32. &message_delay_50,
  33. &message_note_e5,
  34. &message_vibro_off,
  35. &message_sound_off,
  36. NULL,
  37. };
  38. // sequence to indicate that we've reached the end of a turn
  39. const NotificationSequence sequence_end_turn = {
  40. &message_display_backlight_on,
  41. &message_red_0,
  42. &message_vibro_on,
  43. &message_note_g5,
  44. &message_delay_50,
  45. &message_note_e5,
  46. &message_delay_50,
  47. &message_vibro_off,
  48. &message_sound_off,
  49. &message_do_not_reset,
  50. NULL,
  51. };
  52. // Indicate that drawing is enabled.
  53. const NotificationSequence sequence_player_turn_enabled = {
  54. &message_red_255,
  55. &message_do_not_reset,
  56. NULL,
  57. };
  58. // Indicate that drawing is disabled.
  59. const NotificationSequence sequence_player_turn_disabled = {
  60. &message_red_0,
  61. &message_do_not_reset,
  62. NULL,
  63. };
  64. const NotificationSequence sequence_cleanup = {
  65. &message_red_0,
  66. &message_green_0,
  67. &message_blue_0,
  68. &message_sound_off,
  69. &message_vibro_off,
  70. NULL,
  71. };
  72. void simon_says_draw_callback(Canvas* canvas, void* ctx) {
  73. const SimonSaysData* game_state = acquire_mutex((ValueMutex*)ctx, 25);
  74. UNUSED(ctx);
  75. canvas_clear(canvas);
  76. canvas_draw_icon(canvas, 2, 2, &I_board); // Draw board
  77. //release the mutex
  78. release_mutex((ValueMutex*)ctx, game_state);
  79. }
  80. void game_tick(void* ctx) {
  81. SimonSaysData* game_state = acquire_mutex((ValueMutex*)ctx, 25);
  82. UNUSED(ctx);
  83. //release the mutex
  84. release_mutex((ValueMutex*)ctx, game_state);
  85. }
  86. void simon_says_input_callback(InputEvent* input_event, void* ctx) {
  87. furi_assert(ctx);
  88. FuriMessageQueue* event_queue = ctx;
  89. furi_message_queue_put(event_queue, input_event, FuriWaitForever);
  90. }
  91. int32_t simon_says_app(void* p) {
  92. UNUSED(p);
  93. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
  94. SimonSaysData* simon_says_state = malloc(sizeof(SimonSaysData));
  95. ValueMutex simon_value_mutex;
  96. if(!init_mutex(&simon_value_mutex, simon_says_state, sizeof(SimonSaysData))) {
  97. FURI_LOG_E("simon_says", "cannot create mutex\r\n");
  98. free(simon_says_state);
  99. return -1;
  100. }
  101. // Configure view port
  102. ViewPort* view_port = view_port_alloc();
  103. view_port_draw_callback_set(view_port, simon_says_draw_callback, &simon_value_mutex);
  104. view_port_input_callback_set(view_port, simon_says_input_callback, event_queue);
  105. // Register view port in GUI
  106. Gui* gui = furi_record_open(RECORD_GUI);
  107. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  108. NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
  109. InputEvent event;
  110. /* Create a timer. We do data analysis in the callback. */
  111. FuriTimer* timer = furi_timer_alloc(game_tick, FuriTimerTypePeriodic, simon_says_state);
  112. furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10);
  113. while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
  114. //break out of the loop if the back key is pressed
  115. if(event.key == InputKeyBack && event.type == InputTypeLong) {
  116. break;
  117. }
  118. // Placholder button states
  119. if(event.key == InputKeyBack && event.type == InputTypeLong) {
  120. view_port_update(view_port);
  121. }
  122. // Keep LED on while drawing
  123. if(simon_says_state->isPlayerTurn) {
  124. notification_message(notification, &sequence_player_turn_enabled);
  125. } else {
  126. notification_message(notification, &sequence_player_turn_disabled);
  127. }
  128. // Placholder button states
  129. if(event.key == InputKeyOk && event.type == InputTypeShort) {
  130. // Do Nothing
  131. }
  132. // Placholder button states
  133. if(event.key == InputKeyOk && event.type == InputTypeLong) {
  134. // notification_message(furi_record_open(RECORD_NOTIFICATION), &sequence_begin_turn);
  135. notification_message(notification, &sequence_begin_turn);
  136. view_port_update(view_port);
  137. }
  138. // Placholder button states
  139. if(event.type == InputTypeShort || event.type == InputTypeRepeat ||
  140. event.type == InputTypeLong) {
  141. switch(event.key) {
  142. case InputKeyUp:
  143. break;
  144. case InputKeyDown:
  145. break;
  146. case InputKeyLeft:
  147. break;
  148. case InputKeyRight:
  149. break;
  150. default:
  151. break;
  152. }
  153. view_port_update(view_port);
  154. }
  155. }
  156. furi_timer_free(timer);
  157. notification_message(notification, &sequence_cleanup);
  158. gui_remove_view_port(gui, view_port);
  159. view_port_free(view_port);
  160. furi_message_queue_free(event_queue);
  161. free(simon_says_state);
  162. furi_record_close(RECORD_NOTIFICATION);
  163. furi_record_close(RECORD_GUI);
  164. return 0;
  165. }