diff --git a/src/audio/audio_playback.cpp b/src/audio/audio_playback.cpp index fac4bfab..c51e41fb 100644 --- a/src/audio/audio_playback.cpp +++ b/src/audio/audio_playback.cpp @@ -5,6 +5,7 @@ #include #include +#include "driver_cache.hpp" #include "freertos/portmacro.h" #include "audio_decoder.hpp" @@ -21,19 +22,10 @@ #include "stream_message.hpp" namespace audio { - -auto AudioPlayback::create(drivers::GpioExpander* expander) - -> cpp::result, Error> { - auto sink_res = I2SAudioOutput::create(expander); - if (sink_res.has_error()) { - return cpp::fail(ERR_INIT_ELEMENT); - } - return std::make_unique(std::move(sink_res.value())); -} - -AudioPlayback::AudioPlayback(std::unique_ptr output) +AudioPlayback::AudioPlayback(drivers::DriverCache* drivers) : file_source_(std::make_unique()), - i2s_output_(std::move(output)) { + i2s_output_(std::make_unique(drivers->AcquireGpios(), + drivers->AcquireDac())) { AudioDecoder* codec = new AudioDecoder(); elements_.emplace_back(codec); diff --git a/src/audio/i2s_audio_output.cpp b/src/audio/i2s_audio_output.cpp index e5c672f9..e69cc5ac 100644 --- a/src/audio/i2s_audio_output.cpp +++ b/src/audio/i2s_audio_output.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "esp_err.h" @@ -18,27 +19,10 @@ static const char* kTag = "I2SOUT"; namespace audio { -auto I2SAudioOutput::create(drivers::GpioExpander* expander) - -> cpp::result, Error> { - // First, we need to perform initial configuration of the DAC chip. - auto dac_result = drivers::AudioDac::create(expander); - if (dac_result.has_error()) { - ESP_LOGE(kTag, "failed to init dac: %d", dac_result.error()); - return cpp::fail(DAC_CONFIG); - } - std::unique_ptr dac = std::move(dac_result.value()); - - // Soft mute immediately, in order to minimise any clicks and pops caused by - // the initial output element and pipeline configuration. - // dac->WriteVolume(255); - dac->WriteVolume(127); // for testing - - return std::make_unique(expander, std::move(dac)); -} - I2SAudioOutput::I2SAudioOutput(drivers::GpioExpander* expander, - std::unique_ptr dac) + std::shared_ptr dac) : expander_(expander), dac_(std::move(dac)), current_config_() { + dac->WriteVolume(127); // for testing dac_->SetSource(buffer()); } diff --git a/src/audio/include/audio_playback.hpp b/src/audio/include/audio_playback.hpp index 88dc29aa..cd4be3e7 100644 --- a/src/audio/include/audio_playback.hpp +++ b/src/audio/include/audio_playback.hpp @@ -6,6 +6,7 @@ #include #include "audio_task.hpp" +#include "driver_cache.hpp" #include "esp_err.h" #include "fatfs_audio_input.hpp" #include "i2s_audio_output.hpp" @@ -25,11 +26,7 @@ namespace audio { */ class AudioPlayback { public: - enum Error { ERR_INIT_ELEMENT, ERR_MEM }; - static auto create(drivers::GpioExpander* expander) - -> cpp::result, Error>; - - explicit AudioPlayback(std::unique_ptr output); + explicit AudioPlayback(drivers::DriverCache* drivers); ~AudioPlayback(); /* diff --git a/src/audio/include/i2s_audio_output.hpp b/src/audio/include/i2s_audio_output.hpp index 31510a91..07430777 100644 --- a/src/audio/include/i2s_audio_output.hpp +++ b/src/audio/include/i2s_audio_output.hpp @@ -17,12 +17,8 @@ namespace audio { class I2SAudioOutput : public IAudioSink { public: - enum Error { DAC_CONFIG, I2S_CONFIG, STREAM_INIT }; - static auto create(drivers::GpioExpander* expander) - -> cpp::result, Error>; - I2SAudioOutput(drivers::GpioExpander* expander, - std::unique_ptr dac); + std::shared_ptr dac); ~I2SAudioOutput(); auto Configure(const StreamInfo::Format& format) -> bool override; @@ -36,7 +32,7 @@ class I2SAudioOutput : public IAudioSink { auto SetVolume(uint8_t volume) -> void; drivers::GpioExpander* expander_; - std::unique_ptr dac_; + std::shared_ptr dac_; std::optional current_config_; }; diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt index bf8f0c4e..072a8b68 100644 --- a/src/drivers/CMakeLists.txt +++ b/src/drivers/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register( SRCS "touchwheel.cpp" "dac.cpp" "gpio_expander.cpp" "battery.cpp" "storage.cpp" "i2c.cpp" - "spi.cpp" "display.cpp" "display_init.cpp" + "spi.cpp" "display.cpp" "display_init.cpp" "driver_cache.cpp" INCLUDE_DIRS "include" REQUIRES "esp_adc" "fatfs" "result" "lvgl" "span") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/drivers/dac.cpp b/src/drivers/dac.cpp index ac283600..e82f0d27 100644 --- a/src/drivers/dac.cpp +++ b/src/drivers/dac.cpp @@ -27,8 +27,7 @@ static const char* kTag = "AUDIODAC"; static const uint8_t kPcm5122Address = 0x4C; static const i2s_port_t kI2SPort = I2S_NUM_0; -auto AudioDac::create(GpioExpander* expander) - -> cpp::result, Error> { +auto AudioDac::create(GpioExpander* expander) -> cpp::result { // TODO: tune. i2s_chan_handle_t i2s_handle; i2s_chan_config_t channel_config = @@ -111,7 +110,7 @@ auto AudioDac::create(GpioExpander* expander) return state == RUN || state == STANDBY; }); - return dac; + return dac.release(); } AudioDac::AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle) diff --git a/src/drivers/display.cpp b/src/drivers/display.cpp index 56bd6e60..f8594a5a 100644 --- a/src/drivers/display.cpp +++ b/src/drivers/display.cpp @@ -63,7 +63,7 @@ extern "C" void FlushDataCallback(lv_disp_drv_t* disp_drv, auto Display::create(GpioExpander* expander, const displays::InitialisationData& init_data) - -> std::unique_ptr { + -> Display* { ESP_LOGI(kTag, "Init I/O pins"); gpio_config_t dr_config{ .pin_bit_mask = 1ULL << kDisplayDr, @@ -134,7 +134,7 @@ auto Display::create(GpioExpander* expander, ESP_LOGI(kTag, "Registering driver"); display->display_ = lv_disp_drv_register(&display->driver_); - return display; + return display.release(); } Display::Display(GpioExpander* gpio, spi_device_handle_t handle) diff --git a/src/drivers/include/dac.hpp b/src/drivers/include/dac.hpp index acdd1743..4952c992 100644 --- a/src/drivers/include/dac.hpp +++ b/src/drivers/include/dac.hpp @@ -117,8 +117,7 @@ class AudioDac { FAILED_TO_INSTALL_I2S, }; - static auto create(GpioExpander* expander) - -> cpp::result, Error>; + static auto create(GpioExpander* expander) -> cpp::result; AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle); ~AudioDac(); diff --git a/src/drivers/include/display.hpp b/src/drivers/include/display.hpp index 8157c3a5..9e4a0224 100644 --- a/src/drivers/include/display.hpp +++ b/src/drivers/include/display.hpp @@ -23,8 +23,7 @@ class Display { * us back any kind of signal to tell us we're actually using them correctly. */ static auto create(GpioExpander* expander, - const displays::InitialisationData& init_data) - -> std::unique_ptr; + const displays::InitialisationData& init_data) -> Display*; Display(GpioExpander* gpio, spi_device_handle_t handle); ~Display(); diff --git a/src/drivers/include/storage.hpp b/src/drivers/include/storage.hpp index 64ce4782..c19ec935 100644 --- a/src/drivers/include/storage.hpp +++ b/src/drivers/include/storage.hpp @@ -25,14 +25,13 @@ class SdStorage { FAILED_TO_MOUNT, }; - static auto create(GpioExpander* gpio) - -> cpp::result, Error>; + static auto create(GpioExpander* gpio) -> cpp::result; SdStorage(GpioExpander* gpio, esp_err_t (*do_transaction)(sdspi_dev_handle_t, sdmmc_command_t*), sdspi_dev_handle_t handle_, - std::unique_ptr& host_, - std::unique_ptr& card_, + std::unique_ptr host_, + std::unique_ptr card_, FATFS* fs_); ~SdStorage(); diff --git a/src/drivers/storage.cpp b/src/drivers/storage.cpp index 88159744..d90bd811 100644 --- a/src/drivers/storage.cpp +++ b/src/drivers/storage.cpp @@ -49,8 +49,9 @@ static esp_err_t do_transaction(sdspi_dev_handle_t handle, } } // namespace callback -auto SdStorage::create(GpioExpander* gpio) - -> cpp::result, Error> { +auto SdStorage::create(GpioExpander* gpio) -> cpp::result { + gpio->set_pin(GpioExpander::SD_CARD_POWER_ENABLE, 0); + gpio->set_pin(GpioExpander::SD_MUX_EN_ACTIVE_LOW, 0); gpio->set_pin(GpioExpander::SD_MUX_SWITCH, GpioExpander::SD_MUX_ESP); gpio->Write(); @@ -103,16 +104,16 @@ auto SdStorage::create(GpioExpander* gpio) return cpp::fail(Error::FAILED_TO_MOUNT); } - return std::make_unique(gpio, do_transaction, handle, host, card, - fs); + return new SdStorage(gpio, do_transaction, handle, std::move(host), + std::move(card), fs); } SdStorage::SdStorage(GpioExpander* gpio, esp_err_t (*do_transaction)(sdspi_dev_handle_t, sdmmc_command_t*), sdspi_dev_handle_t handle, - std::unique_ptr& host, - std::unique_ptr& card, + std::unique_ptr host, + std::unique_ptr card, FATFS* fs) : gpio_(gpio), do_transaction_(do_transaction), @@ -136,6 +137,10 @@ SdStorage::~SdStorage() { // Uninstall the SPI driver sdspi_host_remove_device(this->handle_); sdspi_host_deinit(); + + gpio_->set_pin(GpioExpander::SD_CARD_POWER_ENABLE, 0); + gpio_->set_pin(GpioExpander::SD_MUX_EN_ACTIVE_LOW, 1); + gpio_->Write(); } auto SdStorage::HandleTransaction(sdspi_dev_handle_t handle, diff --git a/src/main/main.cpp b/src/main/main.cpp index 796c70f3..2a345899 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -11,6 +11,7 @@ #include "driver/sdspi_host.h" #include "driver/spi_common.h" #include "driver/spi_master.h" +#include "driver_cache.hpp" #include "esp_freertos_hooks.h" #include "esp_intr_alloc.h" #include "esp_log.h" @@ -39,50 +40,37 @@ extern "C" void app_main(void) { ESP_ERROR_CHECK(drivers::init_i2c()); ESP_ERROR_CHECK(drivers::init_spi()); + std::unique_ptr drivers = + std::make_unique(); ESP_LOGI(TAG, "Init GPIOs"); - drivers::GpioExpander* expander = new drivers::GpioExpander(); + drivers::GpioExpander* expander = drivers->AcquireGpios(); ESP_LOGI(TAG, "Enable power rails for development"); - expander->with([&](auto& gpio) { - gpio.set_pin(drivers::GpioExpander::SD_MUX_EN_ACTIVE_LOW, 0); - gpio.set_pin(drivers::GpioExpander::SD_MUX_SWITCH, - drivers::GpioExpander::SD_MUX_ESP); - gpio.set_pin(drivers::GpioExpander::SD_CARD_POWER_ENABLE, 0); - gpio.set_pin(drivers::GpioExpander::AMP_EN, 1); - }); + expander->with( + [&](auto& gpio) { gpio.set_pin(drivers::GpioExpander::AMP_EN, 1); }); ESP_LOGI(TAG, "Init battery measurement"); drivers::Battery* battery = new drivers::Battery(); ESP_LOGI(TAG, "it's reading %d mV!", (int)battery->Millivolts()); ESP_LOGI(TAG, "Init SD card"); - auto storage_res = drivers::SdStorage::create(expander); - std::shared_ptr storage; - if (storage_res.has_error()) { + auto storage = drivers->AcquireStorage(); + if (!storage) { ESP_LOGE(TAG, "Failed! Do you have an SD card?"); - } else { - storage = std::move(storage_res.value()); } ESP_LOGI(TAG, "Init touch wheel"); - std::unique_ptr touchwheel = - std::make_unique(); + std::shared_ptr touchwheel = + drivers->AcquireTouchWheel(); std::atomic lvgl_quit; TaskHandle_t lvgl_task_handle; - ui::StartLvgl(expander, &lvgl_quit, &lvgl_task_handle); - - std::unique_ptr playback; - if (storage) { - ESP_LOGI(TAG, "Init audio pipeline"); - auto playback_res = audio::AudioPlayback::create(expander); - if (playback_res.has_error()) { - ESP_LOGE(TAG, "Failed! Playback will not work."); - } else { - playback = std::move(playback_res.value()); - } - } + ui::StartLvgl(drivers.get(), &lvgl_quit, &lvgl_task_handle); + + ESP_LOGI(TAG, "Init audio pipeline"); + std::unique_ptr playback = + std::make_unique(drivers.get()); ESP_LOGI(TAG, "Waiting for background tasks before launching console..."); vTaskDelay(pdMS_TO_TICKS(1000)); diff --git a/src/ui/include/lvgl_task.hpp b/src/ui/include/lvgl_task.hpp index 1a2f425c..ca3fc771 100644 --- a/src/ui/include/lvgl_task.hpp +++ b/src/ui/include/lvgl_task.hpp @@ -5,11 +5,12 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "gpio_expander.hpp" + +#include "driver_cache.hpp" namespace ui { -auto StartLvgl(drivers::GpioExpander* gpios, +auto StartLvgl(drivers::DriverCache* drivers, std::atomic* quit, TaskHandle_t* handle) -> bool; diff --git a/src/ui/lvgl_task.cpp b/src/ui/lvgl_task.cpp index d66f6282..12dfd34e 100644 --- a/src/ui/lvgl_task.cpp +++ b/src/ui/lvgl_task.cpp @@ -26,7 +26,7 @@ #include "widgets/lv_label.h" #include "display.hpp" -#include "display_init.hpp" +#include "driver_cache.hpp" #include "gpio_expander.hpp" namespace ui { @@ -38,16 +38,14 @@ auto tick_hook(TimerHandle_t xTimer) -> void { } struct LvglArgs { - drivers::GpioExpander* gpio_expander; + drivers::DriverCache* drivers; std::atomic* quit; }; void LvglMain(void* voidArgs) { - LvglArgs* args = (LvglArgs*)voidArgs; - drivers::GpioExpander* gpio_expander = args->gpio_expander; + LvglArgs* args = reinterpret_cast(voidArgs); + drivers::DriverCache* drivers = args->drivers; std::atomic* quit = args->quit; - - // Dispose of the args now that we've gotten everything out of them. delete args; { @@ -59,8 +57,7 @@ void LvglMain(void* voidArgs) { xTimerCreate("lv_tick", pdMS_TO_TICKS(1), pdTRUE, NULL, &tick_hook); ESP_LOGI(kTag, "init display"); - std::unique_ptr display = - drivers::Display::create(gpio_expander, drivers::displays::kST7735R); + std::shared_ptr display = drivers->AcquireDisplay(); lv_style_t style; lv_style_init(&style); @@ -96,11 +93,11 @@ static const size_t kLvglStackSize = 8 * 1024; static StaticTask_t sLvglTaskBuffer = {}; static StackType_t sLvglStack[kLvglStackSize] = {0}; -auto StartLvgl(drivers::GpioExpander* gpios, +auto StartLvgl(drivers::DriverCache* drivers, std::atomic* quit, TaskHandle_t* handle) -> bool { LvglArgs* args = new LvglArgs(); - args->gpio_expander = gpios; + args->drivers = drivers; args->quit = quit; return xTaskCreateStaticPinnedToCore(&LvglMain, "LVGL", kLvglStackSize,