/** * @file audio.c * @brief Audio driver implementation */ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "driver/ledc.h" #include "esp_log.h" #include "audio.h" static const char *TAG = "audio"; static uint8_t audio_volume = 50; esp_err_t audio_init(int gpio) { /* Configure LEDC PWM for audio output */ ledc_timer_config_t timer_cfg = { .speed_mode = LEDC_LOW_SPEED_MODE, .duty_resolution = LEDC_TIMER_8_BIT, .timer_num = LEDC_TIMER_0, .freq_hz = AUDIO_SAMPLE_RATE, .clk_cfg = LEDC_AUTO_CLK, }; ESP_ERROR_CHECK(ledc_timer_config(&timer_cfg)); ledc_channel_config_t channel_cfg = { .gpio_num = gpio, .speed_mode = LEDC_LOW_SPEED_MODE, .channel = LEDC_CHANNEL_0, .timer_sel = LEDC_TIMER_0, .duty = 0, .hpoint = 0, }; ESP_ERROR_CHECK(ledc_channel_config(&channel_cfg)); ESP_LOGI(TAG, "Audio initialized on GPIO %d", gpio); return ESP_OK; } void audio_beep(uint16_t freq_hz, uint16_t duration_ms) { if (freq_hz == 0) return; /* Set PWM frequency for the beep */ ledc_set_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0, freq_hz); /* Set duty cycle based on volume */ uint32_t duty = (audio_volume * 128) / 100; ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); vTaskDelay(pdMS_TO_TICKS(duration_ms)); /* Stop */ ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); } void audio_play_startup(void) { audio_beep(880, 100); vTaskDelay(pdMS_TO_TICKS(50)); audio_beep(1320, 150); } void audio_play_warning(void) { for (int i = 0; i < 3; i++) { audio_beep(440, 100); vTaskDelay(pdMS_TO_TICKS(100)); } } void audio_set_volume(uint8_t volume) { if (volume > 100) volume = 100; audio_volume = volume; } uint8_t audio_get_volume(void) { return audio_volume; } void audio_task(void *pvParameters) { ESP_LOGI(TAG, "Audio task started"); /* Audio processing loop - handles audio queue */ while (1) { /* TODO: Process audio queue for WAV playback */ vTaskDelay(pdMS_TO_TICKS(100)); } }