// button_task.c #include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "driver/gpio.h" #include "esp_log.h" // For ESP_LOG macros #include "button_task.h" // For start_button_monitor_task declaration #include "button_led_comm.h" // For LED_COMMAND_ON/OFF and send_led_command // Removed game-specific includes, as the queue is now passed generically // #include "game/jump_bird_game.h" // #include "game/jump_bird_game_input_queue.h" static const char *TAG = "BUTTON_TASK"; #define BUTTON_GPIO 37 // Structure to pass multiple parameters to the FreeRTOS task typedef struct { QueueHandle_t game_input_queue; QueueHandle_t led_control_queue; } button_task_params_t; /** * @brief FreeRTOS task to monitor the button state and send jump signals to the game * and control signals to the LED task. * * This task configures the button GPIO as an input with an internal pull-down * resistor. It continuously reads the button's state. When the button * is pressed (goes HIGH), it sends a 'true' signal to the game_input_queue, * triggering a jump action. It also sends a command to the led_control_queue * to toggle the LED state. It specifically detects a button press (rising edge) * to ensure a single jump/LED toggle per press. * * @param pvParameters A pointer to a button_task_params_t structure containing * the game input queue handle and the LED control queue handle. */ static void button_monitor_task(void *pvParameters) { button_task_params_t *params = (button_task_params_t *)pvParameters; QueueHandle_t game_input_queue = params->game_input_queue; QueueHandle_t led_control_queue = params->led_control_queue; // --- Button Configuration --- gpio_reset_pin(BUTTON_GPIO); gpio_set_direction(BUTTON_GPIO, GPIO_MODE_INPUT); gpio_set_pull_mode(BUTTON_GPIO, GPIO_PULLDOWN_ONLY); int last_button_state = gpio_get_level(BUTTON_GPIO); // Initialize with current state int current_button_state; bool jump_signal = true; // Value to send to the game queue for a jump event bool led_state = false; // Initial LED state for toggling ESP_LOGI(TAG, "Button Monitor Task started. Monitoring GPIO %d.", BUTTON_GPIO); while (1) { current_button_state = gpio_get_level(BUTTON_GPIO); // Detect a button press (rising edge: went from LOW to HIGH) if (current_button_state == 1 && last_button_state == 0) // Button was just pressed { ESP_LOGI(TAG, "Button PRESSED detected (rising edge)."); // --- Game Input Logic --- if (game_input_queue != NULL) { // Attempt to send the signal to the game queue (non-blocking) if (xQueueSend(game_input_queue, &jump_signal, 0) != pdTRUE) { ESP_LOGW(TAG, "Failed to send jump signal to game input queue (queue full?)."); } else { ESP_LOGI(TAG, "Jump signal SENT successfully!"); } } else { ESP_LOGE(TAG, "Game input queue is NULL! Cannot send jump signal."); } // --- END Game Input Logic --- // --- LED Control Logic --- if (led_control_queue != NULL) { led_state = !led_state; // Toggle LED state if (xQueueSend(led_control_queue, &led_state, 0) != pdTRUE) { ESP_LOGW(TAG, "Failed to send LED control signal to queue (queue full?)."); } else { ESP_LOGI(TAG, "LED control signal SENT: %s", led_state ? "ON" : "OFF"); } } else { ESP_LOGE(TAG, "LED control queue is NULL! Cannot send LED signal."); } // --- END LED Control Logic --- } last_button_state = current_button_state; // Update the last known state // A small delay is still recommended to prevent busy-waiting, // even without debounce logic. This allows other tasks to run. vTaskDelay(pdMS_TO_TICKS(50)); // Check button every 50ms } // If the task ever exits (which it shouldn't in an embedded loop), free allocated memory free(params); vTaskDelete(NULL); } /** * @brief Initializes and starts the button monitoring task. * @param game_input_queue Handle to the queue for sending game input signals. * @param led_control_queue Handle to the queue for sending LED control signals. * @return ESP_OK on success, ESP_FAIL on failure. */ esp_err_t start_button_monitor_task(QueueHandle_t game_input_queue, QueueHandle_t led_control_queue) { // Allocate memory for task parameters button_task_params_t *params = (button_task_params_t *)malloc(sizeof(button_task_params_t)); if (params == NULL) { ESP_LOGE(TAG, "Failed to allocate memory for button task parameters!"); return ESP_FAIL; } params->game_input_queue = game_input_queue; params->led_control_queue = led_control_queue; // Create the button monitor task, passing the parameters struct if (xTaskCreate(button_monitor_task, "Button_Monitor_Task", configMINIMAL_STACK_SIZE * 3, (void*)params, 5, NULL) != pdPASS) { ESP_LOGE(TAG, "Failed to create Button Monitor task!"); free(params); // Free allocated memory on failure return ESP_FAIL; } ESP_LOGI(TAG, "Button Monitor task created successfully!"); return ESP_OK; }