diff --git a/README.md b/README.md index b1fa87d..5a8045c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Networked bedside clock utilising an ESP32-SOLO-1. ## Planned Features -- [ ] Audio alerts +- [x] Audio alerts - [x] 7 segment display - [x] WiFi networking - [x] Console for configuration diff --git a/components/sound/CMakeLists.txt b/components/sound/CMakeLists.txt new file mode 100644 index 0000000..0b4cd63 --- /dev/null +++ b/components/sound/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS "sound.c" + INCLUDE_DIRS "." + REQUIRES console_wrapper driver esp_timer +) diff --git a/components/sound/sound.c b/components/sound/sound.c new file mode 100644 index 0000000..6862a86 --- /dev/null +++ b/components/sound/sound.c @@ -0,0 +1,129 @@ +/* + * SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Camden Dixie O'Brien + */ + +#include "sound.h" + +#include "console.h" + +#include "driver/dac.h" +#include "esp_log.h" +#include "esp_timer.h" +#include + +#define TAG "Sound" + +#define CHANNEL DAC_CHANNEL_1 +#define SIGNAL_FREQ CONFIG_ALERT_FREQ +#define SIGNAL_AMPLITUDE CONFIG_ALERT_AMPLITUDE +#define TOGGLE_PERIOD_US (1000 * CONFIG_ALERT_TOGGLE_PERIOD_MS) + +static esp_timer_handle_t timer; +static bool signal_active; + +static void toggle_signal(void *arg) +{ + (void)arg; + if (signal_active) { + const esp_err_t error = dac_cw_generator_enable(); + if (error != ESP_OK) + ESP_LOGE(TAG, "Error enabling signal: %04x", error); + else + signal_active = false; + } else { + const esp_err_t error = dac_cw_generator_disable(); + if (error != ESP_OK) + ESP_LOGE(TAG, "Error disabling signal: %04x", error); + else + signal_active = true; + } +} + +static int alert_command_func(int argc, char **argv) +{ + if (argc != 2) { + printf("Invalid number of arguments\n"); + return 1; + } else if (strcmp(argv[1], "on") == 0) { + sound_alert_on(); + return 0; + } else if (strcmp(argv[1], "off") == 0) { + sound_alert_off(); + return 0; + } else { + printf("Invalid state %s\n", argv[1]); + return 1; + } +} + +void sound_init() +{ + esp_err_t error; + + dac_cw_config_t wave_gen_config = { + .en_ch = CHANNEL, + .scale = SIGNAL_AMPLITUDE, + .freq = SIGNAL_FREQ, + }; + error = dac_cw_generator_config(&wave_gen_config); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error configuring wave generator: %04x", error); + return; + } + + const esp_timer_create_args_t timer_config = { + .callback = &toggle_signal, + .arg = NULL, + .name = "signal toggle task", + }; + error = esp_timer_create(&timer_config, &timer); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error creating toggle timer: %04x", error); + return; + } + + console_register( + "alert", "Set alert sound on and off", "alert ", + alert_command_func); +} + +void sound_alert_on() +{ + esp_err_t error; + + error = dac_output_enable(CHANNEL); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error enabling DAC output: %04x", error); + return; + } + + signal_active = false; + toggle_signal(NULL); + + error = esp_timer_start_periodic(timer, TOGGLE_PERIOD_US); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error starting toggle timer: %04x", error); + return; + } +} + +void sound_alert_off() +{ + esp_err_t error; + + error = esp_timer_stop(timer); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error stopping toggle timer: %04x", error); + return; + } + + if (signal_active) + toggle_signal(NULL); + + error = dac_output_disable(CHANNEL); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error disabling DAC output: %04x", error); + return; + } +} diff --git a/components/sound/sound.h b/components/sound/sound.h new file mode 100644 index 0000000..e4d6ae1 --- /dev/null +++ b/components/sound/sound.h @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Camden Dixie O'Brien + */ + +#ifndef SOUND_H +#define SOUND_H + +/** + * Initialize the sound subsystem. + */ +void sound_init(void); + +/** + * Turn the alert sound on. + */ +void sound_alert_on(void); + +/** + * Turn the alert sound off. + */ +void sound_alert_off(void); + +#endif diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index d354e3d..4a475cb 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( SRCS "main.c" INCLUDE_DIRS "." - REQUIRES console_wrapper display settings time wifi + REQUIRES console_wrapper display settings sound time wifi ) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 5030b36..155bc1c 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -16,6 +16,17 @@ menu "Bedside clock settings" string "Default SNTP server domain" default "pool.ntp.org" endmenu + menu "Alert sound options" + config ALERT_FREQ + int "Frequency (in Hz) of the alert sound" + default 300 + config ALERT_AMPLITUDE + int "Amplitude (0 to 255) of the alert sound" + default 180 + config ALERT_TOGGLE_PERIOD_MS + int "Toggle period of alert sound in milliseconds" + default 300 + endmenu config WIFI_MAX_RETRIES int "Maximum number of times to retry connecting to WiFi network" default 10 diff --git a/main/main.c b/main/main.c index 0cc7cc3..73cda53 100644 --- a/main/main.c +++ b/main/main.c @@ -6,6 +6,7 @@ #include "console.h" #include "display.h" #include "settings.h" +#include "sound.h" #include "time_manager.h" #include "wifi.h" @@ -16,4 +17,5 @@ void app_main(void) display_init(); wifi_init(); time_manager_init(); + sound_init(); }