wrap driver instance ownership + di in a class

custom
jacqueline 2 years ago
parent 130009eb14
commit 7083459cf3
  1. 16
      src/audio/audio_playback.cpp
  2. 22
      src/audio/i2s_audio_output.cpp
  3. 7
      src/audio/include/audio_playback.hpp
  4. 8
      src/audio/include/i2s_audio_output.hpp
  5. 2
      src/drivers/CMakeLists.txt
  6. 5
      src/drivers/dac.cpp
  7. 4
      src/drivers/display.cpp
  8. 3
      src/drivers/include/dac.hpp
  9. 3
      src/drivers/include/display.hpp
  10. 7
      src/drivers/include/storage.hpp
  11. 17
      src/drivers/storage.cpp
  12. 42
      src/main/main.cpp
  13. 5
      src/ui/include/lvgl_task.hpp
  14. 17
      src/ui/lvgl_task.cpp

@ -5,6 +5,7 @@
#include <memory>
#include <string_view>
#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<std::unique_ptr<AudioPlayback>, Error> {
auto sink_res = I2SAudioOutput::create(expander);
if (sink_res.has_error()) {
return cpp::fail(ERR_INIT_ELEMENT);
}
return std::make_unique<AudioPlayback>(std::move(sink_res.value()));
}
AudioPlayback::AudioPlayback(std::unique_ptr<I2SAudioOutput> output)
AudioPlayback::AudioPlayback(drivers::DriverCache* drivers)
: file_source_(std::make_unique<FatfsAudioInput>()),
i2s_output_(std::move(output)) {
i2s_output_(std::make_unique<I2SAudioOutput>(drivers->AcquireGpios(),
drivers->AcquireDac())) {
AudioDecoder* codec = new AudioDecoder();
elements_.emplace_back(codec);

@ -2,6 +2,7 @@
#include <algorithm>
#include <cstddef>
#include <memory>
#include <variant>
#include "esp_err.h"
@ -18,27 +19,10 @@ static const char* kTag = "I2SOUT";
namespace audio {
auto I2SAudioOutput::create(drivers::GpioExpander* expander)
-> cpp::result<std::unique_ptr<I2SAudioOutput>, 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<drivers::AudioDac> 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<I2SAudioOutput>(expander, std::move(dac));
}
I2SAudioOutput::I2SAudioOutput(drivers::GpioExpander* expander,
std::unique_ptr<drivers::AudioDac> dac)
std::shared_ptr<drivers::AudioDac> dac)
: expander_(expander), dac_(std::move(dac)), current_config_() {
dac->WriteVolume(127); // for testing
dac_->SetSource(buffer());
}

@ -6,6 +6,7 @@
#include <vector>
#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<std::unique_ptr<AudioPlayback>, Error>;
explicit AudioPlayback(std::unique_ptr<I2SAudioOutput> output);
explicit AudioPlayback(drivers::DriverCache* drivers);
~AudioPlayback();
/*

@ -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<std::unique_ptr<I2SAudioOutput>, Error>;
I2SAudioOutput(drivers::GpioExpander* expander,
std::unique_ptr<drivers::AudioDac> dac);
std::shared_ptr<drivers::AudioDac> 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<drivers::AudioDac> dac_;
std::shared_ptr<drivers::AudioDac> dac_;
std::optional<StreamInfo::Pcm> current_config_;
};

@ -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})

@ -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<std::unique_ptr<AudioDac>, Error> {
auto AudioDac::create(GpioExpander* expander) -> cpp::result<AudioDac*, Error> {
// 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)

@ -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> {
-> 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)

@ -117,8 +117,7 @@ class AudioDac {
FAILED_TO_INSTALL_I2S,
};
static auto create(GpioExpander* expander)
-> cpp::result<std::unique_ptr<AudioDac>, Error>;
static auto create(GpioExpander* expander) -> cpp::result<AudioDac*, Error>;
AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle);
~AudioDac();

@ -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<Display>;
const displays::InitialisationData& init_data) -> Display*;
Display(GpioExpander* gpio, spi_device_handle_t handle);
~Display();

@ -25,14 +25,13 @@ class SdStorage {
FAILED_TO_MOUNT,
};
static auto create(GpioExpander* gpio)
-> cpp::result<std::shared_ptr<SdStorage>, Error>;
static auto create(GpioExpander* gpio) -> cpp::result<SdStorage*, Error>;
SdStorage(GpioExpander* gpio,
esp_err_t (*do_transaction)(sdspi_dev_handle_t, sdmmc_command_t*),
sdspi_dev_handle_t handle_,
std::unique_ptr<sdmmc_host_t>& host_,
std::unique_ptr<sdmmc_card_t>& card_,
std::unique_ptr<sdmmc_host_t> host_,
std::unique_ptr<sdmmc_card_t> card_,
FATFS* fs_);
~SdStorage();

@ -49,8 +49,9 @@ static esp_err_t do_transaction(sdspi_dev_handle_t handle,
}
} // namespace callback
auto SdStorage::create(GpioExpander* gpio)
-> cpp::result<std::shared_ptr<SdStorage>, Error> {
auto SdStorage::create(GpioExpander* gpio) -> cpp::result<SdStorage*, Error> {
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<SdStorage>(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<sdmmc_host_t>& host,
std::unique_ptr<sdmmc_card_t>& card,
std::unique_ptr<sdmmc_host_t> host,
std::unique_ptr<sdmmc_card_t> 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,

@ -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::DriverCache> drivers =
std::make_unique<drivers::DriverCache>();
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<drivers::SdStorage> 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<drivers::TouchWheel> touchwheel =
std::make_unique<drivers::TouchWheel>();
std::shared_ptr<drivers::TouchWheel> touchwheel =
drivers->AcquireTouchWheel();
std::atomic<bool> lvgl_quit;
TaskHandle_t lvgl_task_handle;
ui::StartLvgl(expander, &lvgl_quit, &lvgl_task_handle);
std::unique_ptr<audio::AudioPlayback> 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<audio::AudioPlayback> playback =
std::make_unique<audio::AudioPlayback>(drivers.get());
ESP_LOGI(TAG, "Waiting for background tasks before launching console...");
vTaskDelay(pdMS_TO_TICKS(1000));

@ -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<bool>* quit,
TaskHandle_t* handle) -> bool;

@ -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<bool>* quit;
};
void LvglMain(void* voidArgs) {
LvglArgs* args = (LvglArgs*)voidArgs;
drivers::GpioExpander* gpio_expander = args->gpio_expander;
LvglArgs* args = reinterpret_cast<LvglArgs*>(voidArgs);
drivers::DriverCache* drivers = args->drivers;
std::atomic<bool>* 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<drivers::Display> display =
drivers::Display::create(gpio_expander, drivers::displays::kST7735R);
std::shared_ptr<drivers::Display> 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<bool>* quit,
TaskHandle_t* handle) -> bool {
LvglArgs* args = new LvglArgs();
args->gpio_expander = gpios;
args->drivers = drivers;
args->quit = quit;
return xTaskCreateStaticPinnedToCore(&LvglMain, "LVGL", kLvglStackSize,

Loading…
Cancel
Save