#include <stdio.h> #include <inttypes.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" // Needed for xQueueCreate #include "esp_chip_info.h" #include "esp_flash.h" #include "esp_system.h" #include "esp_log.h" // For ESP_LOG macros // Include our modular task headers #include "tasks/button_led_comm.h" // Keep this for LED queue #include "tasks/button_task.h" // Now expects a game input queue handle #include "tasks/led_task.h" // Keep this for LED task #include "tasks/display_task.h" // Generic display task #include "tasks/game/jump_bird_game.h" // Jump Bird game instance header #include "tasks/game/arkanoid_game.h" // Arkanoid game instance header #include "tasks/game/game_menu.h" // New: Game menu header static const char *TAG_MAIN = "APP_MAIN"; // Define the global LED control queue here (its definition) QueueHandle_t xLedControlQueue; // Keep this definition /** * @brief Main application entry point. * Initializes the system, prints chip information, and starts the necessary tasks. */ void app_main(void) { // --- 1. Create the LED control queue --- xLedControlQueue = xQueueCreate(1, sizeof(bool)); if (xLedControlQueue == NULL) { ESP_LOGE(TAG_MAIN, "Failed to create LED control queue! Halting."); while (1) { vTaskDelay(100); // Fatal error, halt } } ESP_LOGI(TAG_MAIN, "LED control queue created successfully."); // --- 2. Start the LED control task --- ESP_LOGI(TAG_MAIN, "Attempting to start LED control task..."); if (start_led_control_task() != ESP_OK) { ESP_LOGE(TAG_MAIN, "Failed to start LED control task! Halting."); vQueueDelete(xLedControlQueue); while (1) { vTaskDelay(100); // Fatal error, halt } } ESP_LOGI(TAG_MAIN, "LED control task created successfully."); // --- 3. Create a generic button input queue for the menu and games --- // This queue will be used by button_task to send input, and by menu/game to receive. QueueHandle_t button_input_queue = xQueueCreate(1, sizeof(int)); // Size of int for -1, 0, 1 signals if (button_input_queue == NULL) { ESP_LOGE(TAG_MAIN, "Failed to create generic button input queue! Halting."); vQueueDelete(xLedControlQueue); while (1) { vTaskDelay(100); } } ESP_LOGI(TAG_MAIN, "Generic button input queue created successfully."); // --- 4. Start the button monitor task --- // This task will send input signals to the generic button_input_queue ESP_LOGI(TAG_MAIN, "Attempting to start button monitor task..."); if (start_button_monitor_task(button_input_queue, xLedControlQueue) != ESP_OK) { ESP_LOGE(TAG_MAIN, "Failed to start button monitor task! Halting."); vQueueDelete(xLedControlQueue); vQueueDelete(button_input_queue); while (1) { vTaskDelay(100); // Fatal error, halt } } ESP_LOGI(TAG_MAIN, "Button Monitor task created successfully."); // --- 5. Start the display task early, so it can display the menu --- ESP_LOGI(TAG_MAIN, "Starting display task for menu display..."); // Pass the button_input_queue to the display task so it can handle game over screen input if (start_display_task(button_input_queue) != ESP_OK) { ESP_LOGE(TAG_MAIN, "Failed to start display task! Halting."); vQueueDelete(xLedControlQueue); vQueueDelete(button_input_queue); while (1) { vTaskDelay(100); // Fatal error, halt } } ESP_LOGI(TAG_MAIN, "Display task created successfully, ready for menu."); // --- 6. Define the menu items --- const menu_item_t game_menu_items[] = { {.name = "JUMP BIRD", .game_instance = &JumpBirdGame}, {.name = "ARKANOID", .game_instance = &ArkanoidGame}, }; const size_t num_menu_items = sizeof(game_menu_items) / sizeof(game_menu_items[0]); // --- Main application loop to manage game and menu transitions --- while (true) { // --- 7. Run the game selection menu --- ESP_LOGI(TAG_MAIN, "Running game selection menu..."); const menu_item_t *selected_menu_item = run_game_menu(game_menu_items, num_menu_items, button_input_queue); if (selected_menu_item == NULL) { ESP_LOGE(TAG_MAIN, "No game selected from menu! This should not happen. Restarting menu."); continue; // Go back to the start of the loop } ESP_LOGI(TAG_MAIN, "Game selected from menu: %s", selected_menu_item->name); // --- 8. Tell the display task to switch to the selected game --- ESP_LOGI(TAG_MAIN, "Setting display to active game: %s...", selected_menu_item->name); display_set_game_active(selected_menu_item->game_instance); // Use the new function // --- 9. Wait for the game to finish and signal return to menu --- ESP_LOGI(TAG_MAIN, "Waiting for game to finish..."); display_event_t event_from_display; // Block until display_task signals a return to menu if (xQueueReceive(display_event_queue, &event_from_display, portMAX_DELAY) == pdTRUE) { if (event_from_display == DISPLAY_EVENT_RETURN_TO_MENU) { ESP_LOGI(TAG_MAIN, "Received signal to return to menu. Looping back."); // Loop will restart, showing the menu again } else { ESP_LOGW(TAG_MAIN, "Received unknown event from display queue: %d", event_from_display); } } else { ESP_LOGE(TAG_MAIN, "Failed to receive event from display queue. This should not happen."); // Consider error handling or reset here } // Loop will now continue to the next iteration, re-running the menu } }