standardise on formatting

custom
jacqueline 3 years ago
parent efd5392f6c
commit 3726fb750a
  1. 5
      .clang-format
  2. 17
      main/CMakeLists.txt
  3. 4
      main/battery.cpp
  4. 36
      main/dac.cpp
  5. 16
      main/dac.h
  6. 34
      main/gay-ipod-fw.cpp
  7. 10
      main/gpio-expander.cpp
  8. 17
      main/gpio-expander.h
  9. 2
      main/i2c.cpp
  10. 7
      main/i2c.h
  11. 5
      main/storage.cpp
  12. 24
      main/storage.h

@ -0,0 +1,5 @@
---
BasedOnStyle: Chromium
UseTab: Never
...

@ -1,5 +1,12 @@
idf_component_register( idf_component_register(SRCS
SRCS "gay-ipod-fw.cpp" "dac.cpp" "gpio-expander.cpp" "battery.cpp" "storage.cpp" "i2c.cpp" "gay-ipod-fw.cpp"
INCLUDE_DIRS "." "dac.cpp"
REQUIRES "esp_adc_cal" "fatfs" "audio_pipeline" "audio_stream" "result" "gpio-expander.cpp"
) "battery.cpp"
"storage.cpp"
"i2c.cpp" INCLUDE_DIRS "." REQUIRES
"esp_adc_cal"
"fatfs"
"audio_pipeline"
"audio_stream"
"result")

@ -11,8 +11,8 @@ static esp_adc_cal_characteristics_t calibration;
esp_err_t init_adc(void) { esp_err_t init_adc(void) {
// Calibration should already be fused into the chip from the factory, so // Calibration should already be fused into the chip from the factory, so
// we should only need to read it back out again. // we should only need to read it back out again.
esp_adc_cal_characterize( esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 0,
ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 0, &calibration); &calibration);
// Max battery voltage should be a little over 2V due to our divider, so // Max battery voltage should be a little over 2V due to our divider, so
// we need the max attenuation to properly handle the full range. // we need the max attenuation to properly handle the full range.

@ -1,26 +1,27 @@
#include "dac.h" #include "dac.h"
#include "esp_err.h" #include <cstdint>
#include "i2c.h"
#include "esp_log.h"
#include "assert.h" #include "assert.h"
#include "driver/i2c.h" #include "driver/i2c.h"
#include "esp_err.h"
#include "esp_log.h"
#include "gpio-expander.h" #include "gpio-expander.h"
#include "hal/i2c_types.h" #include "hal/i2c_types.h"
#include <cstdint> #include "i2c.h"
namespace gay_ipod { namespace gay_ipod {
static const char* TAG = "AUDIODAC"; static const char* TAG = "AUDIODAC";
AudioDac::AudioDac(GpioExpander *gpio) { AudioDac::AudioDac(GpioExpander* gpio) {
this->gpio_ = gpio; this->gpio_ = gpio;
}; };
AudioDac::~AudioDac() {}; AudioDac::~AudioDac(){};
esp_err_t AudioDac::Start() { esp_err_t AudioDac::Start() {
bool is_booted = WaitForPowerState([](bool booted, PowerState state){ return booted; }); bool is_booted =
WaitForPowerState([](bool booted, PowerState state) { return booted; });
if (!is_booted) { if (!is_booted) {
ESP_LOGE(TAG, "Timed out waiting for boot"); ESP_LOGE(TAG, "Timed out waiting for boot");
return ESP_ERR_TIMEOUT; return ESP_ERR_TIMEOUT;
@ -29,8 +30,9 @@ esp_err_t AudioDac::Start() {
WriteRegister(Register::DE_EMPHASIS, 1 << 4); WriteRegister(Register::DE_EMPHASIS, 1 << 4);
WriteVolume(100); WriteVolume(100);
WaitForPowerState([](bool booted, PowerState state){ WaitForPowerState([](bool booted, PowerState state) {
return state == WAIT_FOR_CP || state == RAMP_UP || state == RUN || state == STANDBY; return state == WAIT_FOR_CP || state == RAMP_UP || state == RUN ||
state == STANDBY;
}); });
return ESP_OK; return ESP_OK;
@ -45,8 +47,7 @@ std::pair<bool, AudioDac::PowerState> AudioDac::ReadPowerState() {
uint8_t result = 0; uint8_t result = 0;
I2CTransaction transaction; I2CTransaction transaction;
transaction transaction.start()
.start()
.write_addr(kPCM5122Address, I2C_MASTER_WRITE) .write_addr(kPCM5122Address, I2C_MASTER_WRITE)
.write_ack(DSP_BOOT_POWER_STATE) .write_ack(DSP_BOOT_POWER_STATE)
.start() .start()
@ -57,19 +58,21 @@ std::pair<bool, AudioDac::PowerState> AudioDac::ReadPowerState() {
ESP_ERROR_CHECK(transaction.Execute()); ESP_ERROR_CHECK(transaction.Execute());
bool is_booted = result >> 7; bool is_booted = result >> 7;
PowerState detail = (PowerState) (result & 0b1111); PowerState detail = (PowerState)(result & 0b1111);
return std::pair(is_booted, detail); return std::pair(is_booted, detail);
} }
bool AudioDac::WaitForPowerState(std::function<bool(bool,AudioDac::PowerState)> predicate) { bool AudioDac::WaitForPowerState(
std::function<bool(bool, AudioDac::PowerState)> predicate) {
bool has_matched = false; bool has_matched = false;
for (int i=0; i<10; i++) { for (int i = 0; i < 10; i++) {
std::pair<bool, PowerState> result = ReadPowerState(); std::pair<bool, PowerState> result = ReadPowerState();
has_matched = predicate(result.first, result.second); has_matched = predicate(result.first, result.second);
if (has_matched) { if (has_matched) {
break; break;
} else { } else {
ESP_LOGI(TAG, "Waiting for power state (was %d %x)", result.first, (uint8_t) result.second); ESP_LOGI(TAG, "Waiting for power state (was %d %x)", result.first,
(uint8_t)result.second);
vTaskDelay(pdMS_TO_TICKS(1)); vTaskDelay(pdMS_TO_TICKS(1));
} }
} }
@ -78,8 +81,7 @@ bool AudioDac::WaitForPowerState(std::function<bool(bool,AudioDac::PowerState)>
void AudioDac::WriteRegister(Register reg, uint8_t val) { void AudioDac::WriteRegister(Register reg, uint8_t val) {
I2CTransaction transaction; I2CTransaction transaction;
transaction transaction.start()
.start()
.write_addr(kPCM5122Address, I2C_MASTER_WRITE) .write_addr(kPCM5122Address, I2C_MASTER_WRITE)
.write_ack(reg, val) .write_ack(reg, val)
.stop(); .stop();

@ -1,21 +1,21 @@
#pragma once #pragma once
#include "esp_err.h"
#include "gpio-expander.h"
#include <stdint.h> #include <stdint.h>
#include <functional> #include <functional>
#include "esp_err.h"
#include "gpio-expander.h"
namespace gay_ipod { namespace gay_ipod {
static const uint8_t kPCM5122Address = 0x4C; static const uint8_t kPCM5122Address = 0x4C;
static const uint8_t kPCM5122Timeout = 100 / portTICK_RATE_MS; static const uint8_t kPCM5122Timeout = 100 / portTICK_RATE_MS;
/** /**
* Interface for a PCM5122PWR DAC, configured over I2C. * Interface for a PCM5122PWR DAC, configured over I2C.
*/ */
class AudioDac { class AudioDac {
public: public:
AudioDac(GpioExpander *gpio); AudioDac(GpioExpander* gpio);
~AudioDac(); ~AudioDac();
/** /**
@ -43,20 +43,20 @@ class AudioDac {
}; };
/* Returns the current boot-up status and internal state of the DAC */ /* Returns the current boot-up status and internal state of the DAC */
std::pair<bool,PowerState> ReadPowerState(); std::pair<bool, PowerState> ReadPowerState();
// Not copyable or movable. // Not copyable or movable.
AudioDac(const AudioDac&) = delete; AudioDac(const AudioDac&) = delete;
AudioDac& operator=(const AudioDac&) = delete; AudioDac& operator=(const AudioDac&) = delete;
private: private:
GpioExpander *gpio_; GpioExpander* gpio_;
/* /*
* Pools the power state for up to 10ms, waiting for the given predicate to * Pools the power state for up to 10ms, waiting for the given predicate to
* be true. * be true.
*/ */
bool WaitForPowerState(std::function<bool(bool,PowerState)> predicate); bool WaitForPowerState(std::function<bool(bool, PowerState)> predicate);
enum Register { enum Register {
PAGE_SELECT = 0, PAGE_SELECT = 0,

@ -1,6 +1,6 @@
#include <cstdint>
#include <stdio.h>
#include <dirent.h> #include <dirent.h>
#include <stdio.h>
#include <cstdint>
#include "battery.h" #include "battery.h"
#include "dac.h" #include "dac.h"
@ -21,9 +21,9 @@
#include "hal/spi_types.h" #include "hal/spi_types.h"
#include "storage.h" #include "storage.h"
#include "audio_common.h"
#include "audio_element.h" #include "audio_element.h"
#include "audio_pipeline.h" #include "audio_pipeline.h"
#include "audio_common.h"
#include "fatfs_stream.h" #include "fatfs_stream.h"
#include "i2s_stream.h" #include "i2s_stream.h"
#include "mp3_decoder.h" #include "mp3_decoder.h"
@ -53,7 +53,8 @@ esp_err_t init_i2c(void) {
.scl_io_num = I2C_SCL_IO, .scl_io_num = I2C_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE, .sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE,
.master = { .master =
{
.clk_speed = I2C_CLOCK_HZ, .clk_speed = I2C_CLOCK_HZ,
}, },
// No requirements for the clock. // No requirements for the clock.
@ -93,8 +94,7 @@ esp_err_t init_spi(void) {
return ESP_OK; return ESP_OK;
} }
extern "C" void app_main(void) extern "C" void app_main(void) {
{
ESP_LOGI(TAG, "Initialising peripherals"); ESP_LOGI(TAG, "Initialising peripherals");
ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LOWMED)); ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LOWMED));
@ -105,7 +105,7 @@ extern "C" void app_main(void)
gay_ipod::GpioExpander expander; gay_ipod::GpioExpander expander;
// for debugging usb ic // for debugging usb ic
//expander.set_sd_mux(gay_ipod::GpioExpander::USB); // expander.set_sd_mux(gay_ipod::GpioExpander::USB);
ESP_LOGI(TAG, "Init ADC"); ESP_LOGI(TAG, "Init ADC");
ESP_ERROR_CHECK(gay_ipod::init_adc()); ESP_ERROR_CHECK(gay_ipod::init_adc());
@ -148,17 +148,19 @@ extern "C" void app_main(void)
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
}; };
//ESP_ERROR_CHECK(i2s_driver_install(port, &i2s_config, 0, NULL)); // ESP_ERROR_CHECK(i2s_driver_install(port, &i2s_config, 0, NULL));
audio_pipeline_handle_t pipeline; audio_pipeline_handle_t pipeline;
audio_element_handle_t fatfs_stream_reader, i2s_stream_writer, audio_decoder; audio_element_handle_t fatfs_stream_reader, i2s_stream_writer, audio_decoder;
audio_pipeline_cfg_t pipeline_config = audio_pipeline_cfg_t(DEFAULT_AUDIO_PIPELINE_CONFIG()); audio_pipeline_cfg_t pipeline_config =
audio_pipeline_cfg_t(DEFAULT_AUDIO_PIPELINE_CONFIG());
pipeline = audio_pipeline_init(&pipeline_config); pipeline = audio_pipeline_init(&pipeline_config);
assert(pipeline != NULL); assert(pipeline != NULL);
ESP_LOGI(TAG, "Made pipeline okay."); ESP_LOGI(TAG, "Made pipeline okay.");
fatfs_stream_cfg_t fatfs_stream_config = fatfs_stream_cfg_t(FATFS_STREAM_CFG_DEFAULT()); fatfs_stream_cfg_t fatfs_stream_config =
fatfs_stream_cfg_t(FATFS_STREAM_CFG_DEFAULT());
fatfs_stream_config.type = AUDIO_STREAM_READER; fatfs_stream_config.type = AUDIO_STREAM_READER;
fatfs_stream_reader = fatfs_stream_init(&fatfs_stream_config); fatfs_stream_reader = fatfs_stream_init(&fatfs_stream_config);
assert(fatfs_stream_reader != NULL); assert(fatfs_stream_reader != NULL);
@ -185,19 +187,17 @@ extern "C" void app_main(void)
assert(i2s_stream_writer != NULL); assert(i2s_stream_writer != NULL);
ESP_LOGI(TAG, "Made i2s stream okay."); ESP_LOGI(TAG, "Made i2s stream okay.");
ESP_LOGI(TAG, "Init i2s pins"); ESP_LOGI(TAG, "Init i2s pins");
i2s_pin_config_t pin_config = { i2s_pin_config_t pin_config = {.mck_io_num = GPIO_NUM_0,
.mck_io_num = GPIO_NUM_0,
.bck_io_num = GPIO_NUM_26, .bck_io_num = GPIO_NUM_26,
.ws_io_num = GPIO_NUM_27, .ws_io_num = GPIO_NUM_27,
.data_out_num = GPIO_NUM_5, .data_out_num = GPIO_NUM_5,
.data_in_num = I2S_PIN_NO_CHANGE .data_in_num = I2S_PIN_NO_CHANGE};
};
ESP_ERROR_CHECK(i2s_set_pin(port, &pin_config)); ESP_ERROR_CHECK(i2s_set_pin(port, &pin_config));
mp3_decoder_cfg_t decoder_config = mp3_decoder_cfg_t(DEFAULT_MP3_DECODER_CONFIG()); mp3_decoder_cfg_t decoder_config =
mp3_decoder_cfg_t(DEFAULT_MP3_DECODER_CONFIG());
audio_decoder = mp3_decoder_init(&decoder_config); audio_decoder = mp3_decoder_init(&decoder_config);
assert(audio_decoder != NULL); assert(audio_decoder != NULL);
ESP_LOGI(TAG, "Made mp3 decoder okay."); ESP_LOGI(TAG, "Made mp3 decoder okay.");
@ -209,7 +209,7 @@ extern "C" void app_main(void)
audio_pipeline_register(pipeline, audio_decoder, "dec"); audio_pipeline_register(pipeline, audio_decoder, "dec");
audio_pipeline_register(pipeline, i2s_stream_writer, "i2s"); audio_pipeline_register(pipeline, i2s_stream_writer, "i2s");
const char *link_tag[3] = {"file", "dec", "i2s"}; const char* link_tag[3] = {"file", "dec", "i2s"};
audio_pipeline_link(pipeline, &link_tag[0], 3); audio_pipeline_link(pipeline, &link_tag[0], 3);
ESP_LOGI(TAG, "Trying to play something??"); ESP_LOGI(TAG, "Trying to play something??");

@ -55,7 +55,7 @@ esp_err_t GpioExpander::Read() {
} }
void GpioExpander::set_pin(ChipSelect cs, bool value) { void GpioExpander::set_pin(ChipSelect cs, bool value) {
set_pin((Pin) cs, value); set_pin((Pin)cs, value);
} }
void GpioExpander::set_pin(Pin pin, bool value) { void GpioExpander::set_pin(Pin pin, bool value) {
@ -76,15 +76,11 @@ GpioExpander::SpiLock GpioExpander::AcquireSpiBus(ChipSelect cs) {
GpioExpander::SpiLock::SpiLock(GpioExpander& gpio, ChipSelect cs) GpioExpander::SpiLock::SpiLock(GpioExpander& gpio, ChipSelect cs)
: lock_(gpio.cs_mutex_), gpio_(gpio), cs_(cs) { : lock_(gpio.cs_mutex_), gpio_(gpio), cs_(cs) {
gpio_.with([&](auto& gpio) { gpio_.with([&](auto& gpio) { gpio.set_pin(cs_, 0); });
gpio.set_pin(cs_, 0);
});
} }
GpioExpander::SpiLock::~SpiLock() { GpioExpander::SpiLock::~SpiLock() {
gpio_.with([&](auto& gpio) { gpio_.with([&](auto& gpio) { gpio.set_pin(cs_, 1); });
gpio.set_pin(cs_, 1);
});
} }
} // namespace gay_ipod } // namespace gay_ipod

@ -1,16 +1,16 @@
#pragma once #pragma once
#include <stdint.h>
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <stdint.h>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include "driver/i2c.h"
#include "esp_check.h" #include "esp_check.h"
#include "esp_log.h"
#include "esp_err.h" #include "esp_err.h"
#include "driver/i2c.h" #include "esp_log.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
namespace gay_ipod { namespace gay_ipod {
@ -61,16 +61,14 @@ class GpioExpander {
* Convenience mehod for packing the port a and b bytes into a single 16 bit * Convenience mehod for packing the port a and b bytes into a single 16 bit
* value. * value.
*/ */
static uint16_t pack(uint8_t a, uint8_t b) { static uint16_t pack(uint8_t a, uint8_t b) { return ((uint16_t)b) << 8 | a; }
return ((uint16_t) b) << 8 | a;
}
/* /*
* Convenience mehod for unpacking the result of `pack` back into two single * Convenience mehod for unpacking the result of `pack` back into two single
* byte port datas. * byte port datas.
*/ */
static std::pair<uint8_t, uint8_t> unpack(uint16_t ba) { static std::pair<uint8_t, uint8_t> unpack(uint16_t ba) {
return std::pair((uint8_t) ba, (uint8_t) (ba >> 8)); return std::pair((uint8_t)ba, (uint8_t)(ba >> 8));
} }
/* /*
@ -170,13 +168,14 @@ class GpioExpander {
*/ */
class SpiLock { class SpiLock {
public: public:
SpiLock(GpioExpander &gpio, ChipSelect cs); SpiLock(GpioExpander& gpio, ChipSelect cs);
~SpiLock(); ~SpiLock();
SpiLock(const SpiLock&) = delete; SpiLock(const SpiLock&) = delete;
private: private:
std::scoped_lock<std::mutex> lock_; std::scoped_lock<std::mutex> lock_;
GpioExpander &gpio_; GpioExpander& gpio_;
ChipSelect cs_; ChipSelect cs_;
}; };

@ -36,7 +36,7 @@ I2CTransaction& I2CTransaction::write_ack(uint8_t data) {
return *this; return *this;
} }
I2CTransaction& I2CTransaction::read(uint8_t *dest, i2c_ack_type_t ack) { I2CTransaction& I2CTransaction::read(uint8_t* dest, i2c_ack_type_t ack) {
ESP_ERROR_CHECK(i2c_master_read_byte(handle_, dest, ack)); ESP_ERROR_CHECK(i2c_master_read_byte(handle_, dest, ack));
return *this; return *this;
} }

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <cstdint>
#include "driver/i2c.h" #include "driver/i2c.h"
#include "hal/i2c_types.h" #include "hal/i2c_types.h"
#include <cstdint>
namespace gay_ipod { namespace gay_ipod {
@ -53,7 +53,7 @@ class I2CTransaction {
* an ACK to be returned before writing the next byte. * an ACK to be returned before writing the next byte.
*/ */
I2CTransaction& write_ack(uint8_t data); I2CTransaction& write_ack(uint8_t data);
template <typename ...More> template <typename... More>
I2CTransaction& write_ack(uint8_t data, More... more) { I2CTransaction& write_ack(uint8_t data, More... more) {
write_ack(data); write_ack(data);
write_ack(more...); write_ack(more...);
@ -64,7 +64,7 @@ class I2CTransaction {
* Enqueues a read of one byte into the given uint8. Responds with the given * Enqueues a read of one byte into the given uint8. Responds with the given
* ACK/NACK type. * ACK/NACK type.
*/ */
I2CTransaction& read(uint8_t *dest, i2c_ack_type_t ack); I2CTransaction& read(uint8_t* dest, i2c_ack_type_t ack);
/* Returns the underlying command buffer. */ /* Returns the underlying command buffer. */
i2c_cmd_handle_t handle() { return handle_; } i2c_cmd_handle_t handle() { return handle_; }
@ -73,6 +73,7 @@ class I2CTransaction {
// reference instead. // reference instead.
I2CTransaction(const I2CTransaction&) = delete; I2CTransaction(const I2CTransaction&) = delete;
I2CTransaction& operator=(const I2CTransaction&) = delete; I2CTransaction& operator=(const I2CTransaction&) = delete;
private: private:
i2c_cmd_handle_t handle_; i2c_cmd_handle_t handle_;
}; };

@ -19,7 +19,7 @@ namespace gay_ipod {
static const char* TAG = "SDSTORAGE"; static const char* TAG = "SDSTORAGE";
SdStorage::SdStorage(GpioExpander *gpio) { SdStorage::SdStorage(GpioExpander* gpio) {
this->gpio_ = gpio; this->gpio_ = gpio;
} }
@ -49,7 +49,8 @@ SdStorage::Error SdStorage::Acquire(void) {
// with our own that acquires the CS mutex for the duration of the SPI // with our own that acquires the CS mutex for the duration of the SPI
// transaction. // transaction.
auto src = host_.do_transaction; auto src = host_.do_transaction;
sdspi::do_transaction_wrapper = [=](sdspi_dev_handle_t handle, sdmmc_command_t *cmd) -> esp_err_t { sdspi::do_transaction_wrapper = [=](sdspi_dev_handle_t handle,
sdmmc_command_t* cmd) -> esp_err_t {
auto lock = gpio_->AcquireSpiBus(GpioExpander::SD_CARD); auto lock = gpio_->AcquireSpiBus(GpioExpander::SD_CARD);
return src(handle, cmd); return src(handle, cmd);
}; };

@ -11,23 +11,25 @@ namespace gay_ipod {
// Static functions for interrop with the ESP IDF API, which requires a function // Static functions for interrop with the ESP IDF API, which requires a function
// pointer. // pointer.
namespace sdspi { namespace sdspi {
// Holds a lambda created by SdStorage. // Holds a lambda created by SdStorage.
static std::function<esp_err_t(sdspi_dev_handle_t,sdmmc_command_t*)> do_transaction_wrapper; static std::function<esp_err_t(sdspi_dev_handle_t, sdmmc_command_t*)>
do_transaction_wrapper;
// Fits the required function pointer signature, but just delegates to the // Fits the required function pointer signature, but just delegates to the
// wrapper function. Does that make this the wrapper? Who knows. // wrapper function. Does that make this the wrapper? Who knows.
__attribute__ ((unused)) // (gcc incorrectly thinks this is unused) __attribute__((unused)) // (gcc incorrectly thinks this is unused)
static esp_err_t do_transaction(sdspi_dev_handle_t handle, sdmmc_command_t *cmdinfo) { static esp_err_t
do_transaction(sdspi_dev_handle_t handle, sdmmc_command_t* cmdinfo) {
return do_transaction_wrapper(handle, cmdinfo); return do_transaction_wrapper(handle, cmdinfo);
} }
} // namespace sdspi } // namespace sdspi
static const char *kStoragePath = "/sdcard"; static const char* kStoragePath = "/sdcard";
static const uint8_t kMaxOpenFiles = 8; static const uint8_t kMaxOpenFiles = 8;
class SdStorage { class SdStorage {
public: public:
SdStorage(GpioExpander *gpio); SdStorage(GpioExpander* gpio);
~SdStorage(); ~SdStorage();
enum Error { enum Error {
@ -59,7 +61,7 @@ class SdStorage {
SdStorage& operator=(const SdStorage&) = delete; SdStorage& operator=(const SdStorage&) = delete;
private: private:
GpioExpander *gpio_; GpioExpander* gpio_;
// SPI and SD driver info // SPI and SD driver info
sdspi_dev_handle_t handle_; sdspi_dev_handle_t handle_;
@ -67,7 +69,7 @@ class SdStorage {
sdmmc_card_t card_; sdmmc_card_t card_;
// Filesystem info // Filesystem info
FATFS *fs_ = nullptr; FATFS* fs_ = nullptr;
}; };
} // namespace gay_ipod } // namespace gay_ipod

Loading…
Cancel
Save