From 26eb580043ad176bdc58d996f30d470e1073ef00 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Thu, 2 May 2024 21:52:59 +1000 Subject: move driver includes into a subdir as well --- src/drivers/include/a2dp_audio_output.hpp | 22 -- src/drivers/include/adc.hpp | 37 --- src/drivers/include/bluetooth.hpp | 218 -------------- src/drivers/include/bluetooth_types.hpp | 35 --- src/drivers/include/display.hpp | 81 ------ src/drivers/include/display_init.hpp | 90 ------ src/drivers/include/drivers/a2dp_audio_output.hpp | 22 ++ src/drivers/include/drivers/adc.hpp | 37 +++ src/drivers/include/drivers/bluetooth.hpp | 218 ++++++++++++++ src/drivers/include/drivers/bluetooth_types.hpp | 35 +++ src/drivers/include/drivers/display.hpp | 81 ++++++ src/drivers/include/drivers/display_init.hpp | 90 ++++++ src/drivers/include/drivers/fatfs_audio_input.hpp | 45 +++ src/drivers/include/drivers/gpios.hpp | 130 +++++++++ src/drivers/include/drivers/haptics.hpp | 331 ++++++++++++++++++++++ src/drivers/include/drivers/i2c.hpp | 93 ++++++ src/drivers/include/drivers/i2s_dac.hpp | 91 ++++++ src/drivers/include/drivers/nvs.hpp | 156 ++++++++++ src/drivers/include/drivers/samd.hpp | 75 +++++ src/drivers/include/drivers/spi.hpp | 18 ++ src/drivers/include/drivers/spiffs.hpp | 15 + src/drivers/include/drivers/storage.hpp | 71 +++++ src/drivers/include/drivers/touchwheel.hpp | 68 +++++ src/drivers/include/drivers/wm8523.hpp | 53 ++++ src/drivers/include/fatfs_audio_input.hpp | 45 --- src/drivers/include/gpios.hpp | 130 --------- src/drivers/include/haptics.hpp | 331 ---------------------- src/drivers/include/i2c.hpp | 93 ------ src/drivers/include/i2s_dac.hpp | 91 ------ src/drivers/include/nvs.hpp | 156 ---------- src/drivers/include/samd.hpp | 75 ----- src/drivers/include/spi.hpp | 18 -- src/drivers/include/spiffs.hpp | 15 - src/drivers/include/storage.hpp | 71 ----- src/drivers/include/touchwheel.hpp | 68 ----- src/drivers/include/wm8523.hpp | 53 ---- 36 files changed, 1629 insertions(+), 1629 deletions(-) delete mode 100644 src/drivers/include/a2dp_audio_output.hpp delete mode 100644 src/drivers/include/adc.hpp delete mode 100644 src/drivers/include/bluetooth.hpp delete mode 100644 src/drivers/include/bluetooth_types.hpp delete mode 100644 src/drivers/include/display.hpp delete mode 100644 src/drivers/include/display_init.hpp create mode 100644 src/drivers/include/drivers/a2dp_audio_output.hpp create mode 100644 src/drivers/include/drivers/adc.hpp create mode 100644 src/drivers/include/drivers/bluetooth.hpp create mode 100644 src/drivers/include/drivers/bluetooth_types.hpp create mode 100644 src/drivers/include/drivers/display.hpp create mode 100644 src/drivers/include/drivers/display_init.hpp create mode 100644 src/drivers/include/drivers/fatfs_audio_input.hpp create mode 100644 src/drivers/include/drivers/gpios.hpp create mode 100644 src/drivers/include/drivers/haptics.hpp create mode 100644 src/drivers/include/drivers/i2c.hpp create mode 100644 src/drivers/include/drivers/i2s_dac.hpp create mode 100644 src/drivers/include/drivers/nvs.hpp create mode 100644 src/drivers/include/drivers/samd.hpp create mode 100644 src/drivers/include/drivers/spi.hpp create mode 100644 src/drivers/include/drivers/spiffs.hpp create mode 100644 src/drivers/include/drivers/storage.hpp create mode 100644 src/drivers/include/drivers/touchwheel.hpp create mode 100644 src/drivers/include/drivers/wm8523.hpp delete mode 100644 src/drivers/include/fatfs_audio_input.hpp delete mode 100644 src/drivers/include/gpios.hpp delete mode 100644 src/drivers/include/haptics.hpp delete mode 100644 src/drivers/include/i2c.hpp delete mode 100644 src/drivers/include/i2s_dac.hpp delete mode 100644 src/drivers/include/nvs.hpp delete mode 100644 src/drivers/include/samd.hpp delete mode 100644 src/drivers/include/spi.hpp delete mode 100644 src/drivers/include/spiffs.hpp delete mode 100644 src/drivers/include/storage.hpp delete mode 100644 src/drivers/include/touchwheel.hpp delete mode 100644 src/drivers/include/wm8523.hpp (limited to 'src/drivers/include') diff --git a/src/drivers/include/a2dp_audio_output.hpp b/src/drivers/include/a2dp_audio_output.hpp deleted file mode 100644 index 010470c6..00000000 --- a/src/drivers/include/a2dp_audio_output.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include - -#include "audio_common.h" -#include "audio_element.h" -#include "audio_output.hpp" - -namespace drivers { - -class A2DPAudioOutput : IAudioOutput { - public: - virtual auto SetVolume(uint8_t volume) -> void; -}; - -} // namespace drivers diff --git a/src/drivers/include/adc.hpp b/src/drivers/include/adc.hpp deleted file mode 100644 index 3e94a9ee..00000000 --- a/src/drivers/include/adc.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include - -#include "esp_adc/adc_cali.h" -#include "esp_adc/adc_oneshot.h" -#include "esp_err.h" -#include "result.hpp" - -namespace drivers { - -/* - * Handles measuring the battery's current voltage. - */ -class AdcBattery { - public: - static auto Create() -> AdcBattery* { return new AdcBattery(); } - AdcBattery(); - ~AdcBattery(); - - /** - * Returns the current battery level in millivolts. - */ - auto Millivolts() -> uint32_t; - - private: - adc_oneshot_unit_handle_t adc_handle_; - adc_cali_handle_t adc_calibration_handle_; -}; - -} // namespace drivers diff --git a/src/drivers/include/bluetooth.hpp b/src/drivers/include/bluetooth.hpp deleted file mode 100644 index 8da5ce2e..00000000 --- a/src/drivers/include/bluetooth.hpp +++ /dev/null @@ -1,218 +0,0 @@ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "bluetooth_types.hpp" -#include "esp_a2dp_api.h" -#include "esp_avrc_api.h" -#include "esp_gap_bt_api.h" -#include "nvs.hpp" -#include "tasks.hpp" -#include "tinyfsm.hpp" -#include "tinyfsm/include/tinyfsm.hpp" - -namespace drivers { - -/* - * A handle used to interact with the bluetooth state machine. - */ -class Bluetooth { - public: - Bluetooth(NvsStorage& storage, tasks::WorkerPool&); - - auto Enable() -> bool; - auto Disable() -> void; - auto IsEnabled() -> bool; - - auto IsConnected() -> bool; - auto ConnectedDevice() -> std::optional; - - auto KnownDevices() -> std::vector; - - auto SetPreferredDevice(std::optional dev) -> void; - auto PreferredDevice() -> std::optional; - - auto SetSource(StreamBufferHandle_t) -> void; - auto SetVolumeFactor(float) -> void; - - auto SetEventHandler(std::function cb) -> void; -}; - -namespace bluetooth { - -namespace events { -struct Enable : public tinyfsm::Event {}; -struct Disable : public tinyfsm::Event {}; - -struct ConnectTimedOut : public tinyfsm::Event {}; -struct PreferredDeviceChanged : public tinyfsm::Event {}; -struct SourceChanged : public tinyfsm::Event {}; -struct DeviceDiscovered : public tinyfsm::Event { - const Device& device; -}; - -namespace internal { -struct Gap : public tinyfsm::Event { - esp_bt_gap_cb_event_t type; - esp_bt_gap_cb_param_t* param; -}; -struct A2dp : public tinyfsm::Event { - esp_a2d_cb_event_t type; - esp_a2d_cb_param_t* param; -}; -struct Avrc : public tinyfsm::Event { - esp_avrc_ct_cb_event_t type; - esp_avrc_ct_cb_param_t param; -}; -} // namespace internal -} // namespace events - -/* - * Utility for managing scanning, independent of the current connection state. - */ -class Scanner { - public: - Scanner(); - - auto ScanContinuously() -> void; - auto ScanOnce() -> void; - auto StopScanning() -> void; - auto StopScanningNow() -> void; - - auto HandleGapEvent(const events::internal::Gap&) -> void; - - private: - bool enabled_; - bool is_discovering_; - - auto HandleDeviceDiscovery(const esp_bt_gap_cb_param_t& param) -> void; -}; - -class BluetoothState : public tinyfsm::Fsm { - public: - static auto Init(NvsStorage& storage) -> void; - - static auto lock() -> std::lock_guard; - - static auto devices() -> std::vector; - - static auto preferred_device() -> std::optional; - static auto preferred_device(std::optional) -> void; - - static auto scanning() -> bool; - static auto discovery() -> bool; - static auto discovery(bool) -> void; - - static auto source() -> StreamBufferHandle_t; - static auto source(StreamBufferHandle_t) -> void; - - static auto event_handler(std::function) -> void; - - virtual ~BluetoothState(){}; - - virtual void entry() {} - virtual void exit() {} - - virtual void react(const events::Enable& ev){}; - virtual void react(const events::Disable& ev) = 0; - virtual void react(const events::ConnectTimedOut& ev){}; - virtual void react(const events::PreferredDeviceChanged& ev){}; - virtual void react(const events::SourceChanged& ev){}; - - virtual void react(const events::DeviceDiscovered&); - - virtual void react(const events::internal::Gap& ev) = 0; - virtual void react(const events::internal::A2dp& ev){}; - virtual void react(const events::internal::Avrc& ev){}; - - protected: - static NvsStorage* sStorage_; - static Scanner* sScanner_; - - static std::mutex sFsmMutex; - static std::map sDevices_; - static std::optional sPreferredDevice_; - - static std::optional sConnectingDevice_; - static int sConnectAttemptsRemaining_; - - static std::atomic sSource_; - static std::function sEventHandler_; - - auto connect(const bluetooth::MacAndName&) -> bool; -}; - -class Disabled : public BluetoothState { - public: - void entry() override; - - void react(const events::Enable& ev) override; - void react(const events::Disable& ev) override{}; - - void react(const events::internal::Gap& ev) override {} - void react(const events::internal::A2dp& ev) override {} - - using BluetoothState::react; -}; - -class Idle : public BluetoothState { - public: - void entry() override; - void exit() override; - - void react(const events::Disable& ev) override; - void react(const events::PreferredDeviceChanged& ev) override; - - void react(const events::internal::Gap& ev) override; - - using BluetoothState::react; -}; - -class Connecting : public BluetoothState { - public: - void entry() override; - void exit() override; - - void react(const events::PreferredDeviceChanged& ev) override; - - void react(const events::ConnectTimedOut& ev) override; - void react(const events::Disable& ev) override; - void react(const events::internal::Gap& ev) override; - void react(const events::internal::A2dp& ev) override; - - using BluetoothState::react; -}; - -class Connected : public BluetoothState { - public: - void entry() override; - void exit() override; - - void react(const events::PreferredDeviceChanged& ev) override; - void react(const events::SourceChanged& ev) override; - - void react(const events::Disable& ev) override; - void react(const events::internal::Gap& ev) override; - void react(const events::internal::A2dp& ev) override; - void react(const events::internal::Avrc& ev) override; - - using BluetoothState::react; - - private: - uint8_t transaction_num_; - mac_addr_t connected_to_; -}; - -} // namespace bluetooth - -} // namespace drivers diff --git a/src/drivers/include/bluetooth_types.hpp b/src/drivers/include/bluetooth_types.hpp deleted file mode 100644 index 7cfb236f..00000000 --- a/src/drivers/include/bluetooth_types.hpp +++ /dev/null @@ -1,35 +0,0 @@ - -#pragma once - -#include -#include - -#include "memory_resource.hpp" - -namespace drivers { -namespace bluetooth { - -typedef std::array mac_addr_t; - -struct MacAndName { - mac_addr_t mac; - std::string name; - - bool operator==(const MacAndName&) const = default; -}; - -struct Device { - mac_addr_t address; - std::pmr::string name; - uint32_t class_of_device; - int8_t signal_strength; -}; - -enum class Event { - kKnownDevicesChanged, - kConnectionStateChanged, - kPreferredDeviceChanged, -}; - -} // namespace bluetooth -} // namespace drivers diff --git a/src/drivers/include/display.hpp b/src/drivers/include/display.hpp deleted file mode 100644 index d2e18a5c..00000000 --- a/src/drivers/include/display.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include -#include -#include - -#include "driver/spi_master.h" -#include "lvgl/lvgl.h" -#include "result.hpp" -#include "tasks.hpp" - -#include "display_init.hpp" -#include "gpios.hpp" - -namespace drivers { - -/* - * LVGL display driver for ST77XX family displays. - */ -class Display { - public: - /* - * Creates the display driver, and resets and reinitialises the display - * over SPI. This never fails, since unfortunately these display don't give - * us back any kind of signal to tell us we're actually using them correctly. - */ - static auto Create(IGpios& expander, - const displays::InitialisationData& init_data) -> Display*; - - Display(IGpios& gpio, spi_device_handle_t handle); - ~Display(); - - auto SetDisplayOn(bool) -> void; - auto SetBrightness(uint_fast8_t) -> void; - - /* Driver callback invoked by LVGL when there is new data to display. */ - void OnLvglFlush(lv_disp_drv_t* disp_drv, - const lv_area_t* area, - lv_color_t* color_map); - - // Not copyable or movable. - Display(const Display&) = delete; - Display& operator=(const Display&) = delete; - - private: - IGpios& gpio_; - spi_device_handle_t handle_; - - bool first_flush_finished_; - bool display_on_; - uint_fast8_t brightness_; - - lv_disp_draw_buf_t buffers_; - lv_disp_drv_t driver_; - lv_disp_t* display_ = nullptr; - - enum TransactionType { - COMMAND = 0, - DATA = 1, - }; - - void SendInitialisationSequence(const uint8_t* data); - - void SendCommandWithData(uint8_t command, const uint8_t* data, size_t length); - void SendCmd(const uint8_t* data, size_t length); - void SendData(const uint8_t* data, size_t length); - - void SendTransaction(TransactionType type, - const uint8_t* data, - size_t length); - - auto SetDutyCycle(uint_fast8_t, bool) -> void; -}; - -} // namespace drivers diff --git a/src/drivers/include/display_init.hpp b/src/drivers/include/display_init.hpp deleted file mode 100644 index 9bf5b3f5..00000000 --- a/src/drivers/include/display_init.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include -#include - -namespace drivers { -namespace displays { - -extern const uint8_t kDelayBit; - -struct InitialisationData { - uint16_t width; - uint16_t height; - uint8_t num_sequences; - const uint8_t* sequences[4]; -}; - -extern const InitialisationData kST7735R; - -/* - * Valid command bytes that can be sent to ST77XX displays, as well as commands - * for more specific variants. - */ -enum StCommands { - ST77XX_NOP = 0x00, - ST77XX_SWRESET = 0x01, - ST77XX_RDDID = 0x04, - ST77XX_RDDST = 0x09, - - ST77XX_SLPIN = 0x10, - ST77XX_SLPOUT = 0x11, - ST77XX_PTLON = 0x12, - ST77XX_NORON = 0x13, - - ST77XX_INVOFF = 0x20, - ST77XX_INVON = 0x21, - ST77XX_DISPOFF = 0x28, - ST77XX_DISPON = 0x29, - ST77XX_CASET = 0x2A, - ST77XX_RASET = 0x2B, - ST77XX_RAMWR = 0x2C, - ST77XX_RAMRD = 0x2E, - - ST77XX_PTLAR = 0x30, - ST77XX_TEOFF = 0x34, - ST77XX_TEON = 0x35, - ST77XX_MADCTL = 0x36, - ST77XX_COLMOD = 0x3A, - - ST77XX_MADCTL_MY = 0x80, - ST77XX_MADCTL_MX = 0x40, - ST77XX_MADCTL_MV = 0x20, - ST77XX_MADCTL_ML = 0x10, - ST77XX_MADCTL_RGB = 0x00, - - ST77XX_RDID1 = 0xDA, - ST77XX_RDID2 = 0xDB, - ST77XX_RDID3 = 0xDC, - ST77XX_RDID4 = 0xDD, - - ST7735_MADCTL_BGR = 0x08, - ST7735_MADCTL_MH = 0x04, - - ST7735_FRMCTR1 = 0xB1, - ST7735_FRMCTR2 = 0xB2, - ST7735_FRMCTR3 = 0xB3, - ST7735_INVCTR = 0xB4, - ST7735_DISSET5 = 0xB6, - - ST7735_PWCTR1 = 0xC0, - ST7735_PWCTR2 = 0xC1, - ST7735_PWCTR3 = 0xC2, - ST7735_PWCTR4 = 0xC3, - ST7735_PWCTR5 = 0xC4, - ST7735_VMCTR1 = 0xC5, - - ST7735_PWCTR6 = 0xFC, - - ST7735_GMCTRP1 = 0xE0, - ST7735_GMCTRN1 = 0xE1, -}; - -} // namespace displays -} // namespace drivers diff --git a/src/drivers/include/drivers/a2dp_audio_output.hpp b/src/drivers/include/drivers/a2dp_audio_output.hpp new file mode 100644 index 00000000..010470c6 --- /dev/null +++ b/src/drivers/include/drivers/a2dp_audio_output.hpp @@ -0,0 +1,22 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include + +#include "audio_common.h" +#include "audio_element.h" +#include "audio_output.hpp" + +namespace drivers { + +class A2DPAudioOutput : IAudioOutput { + public: + virtual auto SetVolume(uint8_t volume) -> void; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/adc.hpp b/src/drivers/include/drivers/adc.hpp new file mode 100644 index 00000000..3e94a9ee --- /dev/null +++ b/src/drivers/include/drivers/adc.hpp @@ -0,0 +1,37 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include + +#include "esp_adc/adc_cali.h" +#include "esp_adc/adc_oneshot.h" +#include "esp_err.h" +#include "result.hpp" + +namespace drivers { + +/* + * Handles measuring the battery's current voltage. + */ +class AdcBattery { + public: + static auto Create() -> AdcBattery* { return new AdcBattery(); } + AdcBattery(); + ~AdcBattery(); + + /** + * Returns the current battery level in millivolts. + */ + auto Millivolts() -> uint32_t; + + private: + adc_oneshot_unit_handle_t adc_handle_; + adc_cali_handle_t adc_calibration_handle_; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/bluetooth.hpp b/src/drivers/include/drivers/bluetooth.hpp new file mode 100644 index 00000000..5960de7e --- /dev/null +++ b/src/drivers/include/drivers/bluetooth.hpp @@ -0,0 +1,218 @@ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "drivers/bluetooth_types.hpp" +#include "esp_a2dp_api.h" +#include "esp_avrc_api.h" +#include "esp_gap_bt_api.h" +#include "drivers/nvs.hpp" +#include "tasks.hpp" +#include "tinyfsm.hpp" +#include "tinyfsm/include/tinyfsm.hpp" + +namespace drivers { + +/* + * A handle used to interact with the bluetooth state machine. + */ +class Bluetooth { + public: + Bluetooth(NvsStorage& storage, tasks::WorkerPool&); + + auto Enable() -> bool; + auto Disable() -> void; + auto IsEnabled() -> bool; + + auto IsConnected() -> bool; + auto ConnectedDevice() -> std::optional; + + auto KnownDevices() -> std::vector; + + auto SetPreferredDevice(std::optional dev) -> void; + auto PreferredDevice() -> std::optional; + + auto SetSource(StreamBufferHandle_t) -> void; + auto SetVolumeFactor(float) -> void; + + auto SetEventHandler(std::function cb) -> void; +}; + +namespace bluetooth { + +namespace events { +struct Enable : public tinyfsm::Event {}; +struct Disable : public tinyfsm::Event {}; + +struct ConnectTimedOut : public tinyfsm::Event {}; +struct PreferredDeviceChanged : public tinyfsm::Event {}; +struct SourceChanged : public tinyfsm::Event {}; +struct DeviceDiscovered : public tinyfsm::Event { + const Device& device; +}; + +namespace internal { +struct Gap : public tinyfsm::Event { + esp_bt_gap_cb_event_t type; + esp_bt_gap_cb_param_t* param; +}; +struct A2dp : public tinyfsm::Event { + esp_a2d_cb_event_t type; + esp_a2d_cb_param_t* param; +}; +struct Avrc : public tinyfsm::Event { + esp_avrc_ct_cb_event_t type; + esp_avrc_ct_cb_param_t param; +}; +} // namespace internal +} // namespace events + +/* + * Utility for managing scanning, independent of the current connection state. + */ +class Scanner { + public: + Scanner(); + + auto ScanContinuously() -> void; + auto ScanOnce() -> void; + auto StopScanning() -> void; + auto StopScanningNow() -> void; + + auto HandleGapEvent(const events::internal::Gap&) -> void; + + private: + bool enabled_; + bool is_discovering_; + + auto HandleDeviceDiscovery(const esp_bt_gap_cb_param_t& param) -> void; +}; + +class BluetoothState : public tinyfsm::Fsm { + public: + static auto Init(NvsStorage& storage) -> void; + + static auto lock() -> std::lock_guard; + + static auto devices() -> std::vector; + + static auto preferred_device() -> std::optional; + static auto preferred_device(std::optional) -> void; + + static auto scanning() -> bool; + static auto discovery() -> bool; + static auto discovery(bool) -> void; + + static auto source() -> StreamBufferHandle_t; + static auto source(StreamBufferHandle_t) -> void; + + static auto event_handler(std::function) -> void; + + virtual ~BluetoothState(){}; + + virtual void entry() {} + virtual void exit() {} + + virtual void react(const events::Enable& ev){}; + virtual void react(const events::Disable& ev) = 0; + virtual void react(const events::ConnectTimedOut& ev){}; + virtual void react(const events::PreferredDeviceChanged& ev){}; + virtual void react(const events::SourceChanged& ev){}; + + virtual void react(const events::DeviceDiscovered&); + + virtual void react(const events::internal::Gap& ev) = 0; + virtual void react(const events::internal::A2dp& ev){}; + virtual void react(const events::internal::Avrc& ev){}; + + protected: + static NvsStorage* sStorage_; + static Scanner* sScanner_; + + static std::mutex sFsmMutex; + static std::map sDevices_; + static std::optional sPreferredDevice_; + + static std::optional sConnectingDevice_; + static int sConnectAttemptsRemaining_; + + static std::atomic sSource_; + static std::function sEventHandler_; + + auto connect(const bluetooth::MacAndName&) -> bool; +}; + +class Disabled : public BluetoothState { + public: + void entry() override; + + void react(const events::Enable& ev) override; + void react(const events::Disable& ev) override{}; + + void react(const events::internal::Gap& ev) override {} + void react(const events::internal::A2dp& ev) override {} + + using BluetoothState::react; +}; + +class Idle : public BluetoothState { + public: + void entry() override; + void exit() override; + + void react(const events::Disable& ev) override; + void react(const events::PreferredDeviceChanged& ev) override; + + void react(const events::internal::Gap& ev) override; + + using BluetoothState::react; +}; + +class Connecting : public BluetoothState { + public: + void entry() override; + void exit() override; + + void react(const events::PreferredDeviceChanged& ev) override; + + void react(const events::ConnectTimedOut& ev) override; + void react(const events::Disable& ev) override; + void react(const events::internal::Gap& ev) override; + void react(const events::internal::A2dp& ev) override; + + using BluetoothState::react; +}; + +class Connected : public BluetoothState { + public: + void entry() override; + void exit() override; + + void react(const events::PreferredDeviceChanged& ev) override; + void react(const events::SourceChanged& ev) override; + + void react(const events::Disable& ev) override; + void react(const events::internal::Gap& ev) override; + void react(const events::internal::A2dp& ev) override; + void react(const events::internal::Avrc& ev) override; + + using BluetoothState::react; + + private: + uint8_t transaction_num_; + mac_addr_t connected_to_; +}; + +} // namespace bluetooth + +} // namespace drivers diff --git a/src/drivers/include/drivers/bluetooth_types.hpp b/src/drivers/include/drivers/bluetooth_types.hpp new file mode 100644 index 00000000..7cfb236f --- /dev/null +++ b/src/drivers/include/drivers/bluetooth_types.hpp @@ -0,0 +1,35 @@ + +#pragma once + +#include +#include + +#include "memory_resource.hpp" + +namespace drivers { +namespace bluetooth { + +typedef std::array mac_addr_t; + +struct MacAndName { + mac_addr_t mac; + std::string name; + + bool operator==(const MacAndName&) const = default; +}; + +struct Device { + mac_addr_t address; + std::pmr::string name; + uint32_t class_of_device; + int8_t signal_strength; +}; + +enum class Event { + kKnownDevicesChanged, + kConnectionStateChanged, + kPreferredDeviceChanged, +}; + +} // namespace bluetooth +} // namespace drivers diff --git a/src/drivers/include/drivers/display.hpp b/src/drivers/include/drivers/display.hpp new file mode 100644 index 00000000..6dc78e01 --- /dev/null +++ b/src/drivers/include/drivers/display.hpp @@ -0,0 +1,81 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include +#include + +#include "driver/spi_master.h" +#include "lvgl/lvgl.h" +#include "result.hpp" +#include "tasks.hpp" + +#include "drivers/display_init.hpp" +#include "drivers/gpios.hpp" + +namespace drivers { + +/* + * LVGL display driver for ST77XX family displays. + */ +class Display { + public: + /* + * Creates the display driver, and resets and reinitialises the display + * over SPI. This never fails, since unfortunately these display don't give + * us back any kind of signal to tell us we're actually using them correctly. + */ + static auto Create(IGpios& expander, + const displays::InitialisationData& init_data) -> Display*; + + Display(IGpios& gpio, spi_device_handle_t handle); + ~Display(); + + auto SetDisplayOn(bool) -> void; + auto SetBrightness(uint_fast8_t) -> void; + + /* Driver callback invoked by LVGL when there is new data to display. */ + void OnLvglFlush(lv_disp_drv_t* disp_drv, + const lv_area_t* area, + lv_color_t* color_map); + + // Not copyable or movable. + Display(const Display&) = delete; + Display& operator=(const Display&) = delete; + + private: + IGpios& gpio_; + spi_device_handle_t handle_; + + bool first_flush_finished_; + bool display_on_; + uint_fast8_t brightness_; + + lv_disp_draw_buf_t buffers_; + lv_disp_drv_t driver_; + lv_disp_t* display_ = nullptr; + + enum TransactionType { + COMMAND = 0, + DATA = 1, + }; + + void SendInitialisationSequence(const uint8_t* data); + + void SendCommandWithData(uint8_t command, const uint8_t* data, size_t length); + void SendCmd(const uint8_t* data, size_t length); + void SendData(const uint8_t* data, size_t length); + + void SendTransaction(TransactionType type, + const uint8_t* data, + size_t length); + + auto SetDutyCycle(uint_fast8_t, bool) -> void; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/display_init.hpp b/src/drivers/include/drivers/display_init.hpp new file mode 100644 index 00000000..9bf5b3f5 --- /dev/null +++ b/src/drivers/include/drivers/display_init.hpp @@ -0,0 +1,90 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include + +namespace drivers { +namespace displays { + +extern const uint8_t kDelayBit; + +struct InitialisationData { + uint16_t width; + uint16_t height; + uint8_t num_sequences; + const uint8_t* sequences[4]; +}; + +extern const InitialisationData kST7735R; + +/* + * Valid command bytes that can be sent to ST77XX displays, as well as commands + * for more specific variants. + */ +enum StCommands { + ST77XX_NOP = 0x00, + ST77XX_SWRESET = 0x01, + ST77XX_RDDID = 0x04, + ST77XX_RDDST = 0x09, + + ST77XX_SLPIN = 0x10, + ST77XX_SLPOUT = 0x11, + ST77XX_PTLON = 0x12, + ST77XX_NORON = 0x13, + + ST77XX_INVOFF = 0x20, + ST77XX_INVON = 0x21, + ST77XX_DISPOFF = 0x28, + ST77XX_DISPON = 0x29, + ST77XX_CASET = 0x2A, + ST77XX_RASET = 0x2B, + ST77XX_RAMWR = 0x2C, + ST77XX_RAMRD = 0x2E, + + ST77XX_PTLAR = 0x30, + ST77XX_TEOFF = 0x34, + ST77XX_TEON = 0x35, + ST77XX_MADCTL = 0x36, + ST77XX_COLMOD = 0x3A, + + ST77XX_MADCTL_MY = 0x80, + ST77XX_MADCTL_MX = 0x40, + ST77XX_MADCTL_MV = 0x20, + ST77XX_MADCTL_ML = 0x10, + ST77XX_MADCTL_RGB = 0x00, + + ST77XX_RDID1 = 0xDA, + ST77XX_RDID2 = 0xDB, + ST77XX_RDID3 = 0xDC, + ST77XX_RDID4 = 0xDD, + + ST7735_MADCTL_BGR = 0x08, + ST7735_MADCTL_MH = 0x04, + + ST7735_FRMCTR1 = 0xB1, + ST7735_FRMCTR2 = 0xB2, + ST7735_FRMCTR3 = 0xB3, + ST7735_INVCTR = 0xB4, + ST7735_DISSET5 = 0xB6, + + ST7735_PWCTR1 = 0xC0, + ST7735_PWCTR2 = 0xC1, + ST7735_PWCTR3 = 0xC2, + ST7735_PWCTR4 = 0xC3, + ST7735_PWCTR5 = 0xC4, + ST7735_VMCTR1 = 0xC5, + + ST7735_PWCTR6 = 0xFC, + + ST7735_GMCTRP1 = 0xE0, + ST7735_GMCTRN1 = 0xE1, +}; + +} // namespace displays +} // namespace drivers diff --git a/src/drivers/include/drivers/fatfs_audio_input.hpp b/src/drivers/include/drivers/fatfs_audio_input.hpp new file mode 100644 index 00000000..705f6e7d --- /dev/null +++ b/src/drivers/include/drivers/fatfs_audio_input.hpp @@ -0,0 +1,45 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +namespace drivers { + +class FatfsAudioInput { + public: + FatfsAudioInput(std::shared_ptr storage); + ~FatfsAudioInput(); + + enum Status { + /* + * Successfully read data into the output buffer, and there is still + * data remaining in the file. + */ + OKAY, + + /* + * The ringbuffer was full. No data was read. + */ + RINGBUF_FULL, + + /* + * Some data may have been read into the output buffer, but the file is + * now empty. + */ + FILE_EMPTY, + }; + auto Process() -> Status; + + auto GetOutputBuffer() -> RingbufHandle_t; + + private: + std::shared_ptr storage_; + RingbufHandle_t output_; + + std::pmr::string path_; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/gpios.hpp b/src/drivers/include/drivers/gpios.hpp new file mode 100644 index 00000000..e27a3ade --- /dev/null +++ b/src/drivers/include/drivers/gpios.hpp @@ -0,0 +1,130 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "driver/i2c.h" +#include "esp_check.h" +#include "esp_err.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" + +namespace drivers { + +/** + * Wrapper for interfacing with the PCA8575 GPIO expander. Includes basic + * low-level pin setting methods, as well as higher level convenience functions + * for reading, writing, and atomically interacting with the SPI chip select + * pins. + * + * Each method of this class can be called safely from any thread, and all + * updates are guaranteed to be atomic. Any access to chip select related pins + * should be done whilst holding `cs_lock` (preferably via the helper methods). + */ +class IGpios { + public: + virtual ~IGpios() {} + + /* Maps each pin of the expander to its number in a `pack`ed uint16. */ + enum class Pin { + // Port A + kSdMuxSwitch = 0, + kSdMuxDisable = 1, + kKeyUp = 2, + kKeyDown = 3, + kKeyLock = 4, + kDisplayEnable = 5, + // 6 is unused + kSdPowerEnable = 7, + + // Port B + kPhoneDetect = 8, + kAmplifierEnable = 9, + kSdCardDetect = 10, + kAmplifierUnmuteLegacy = 11, + kAmplifierMute = 12, + // 13 through 15 are unused + }; + + /* Nicer value names for use with kSdMuxSwitch. */ + enum SdController { + SD_MUX_ESP = 0, + SD_MUX_SAMD = 1, + }; + + /* + * Sets a single specific pin to the given value. `true` corresponds to + * HIGH, and `false` corresponds to LOW. + * + * This function will block until the pin has changed level. + */ + virtual auto WriteSync(Pin, bool) -> bool = 0; + + /* + * Returns the most recently cached value of the given pin. + */ + virtual auto Get(Pin) const -> bool = 0; + + virtual auto IsLocked() const -> bool = 0; +}; + +class Gpios : public IGpios { + public: + static auto Create(bool invert_lock_switch) -> Gpios*; + ~Gpios(); + + /* + * Sets a single specific pin to the given value. `true` corresponds to + * HIGH, and `false` corresponds to LOW. + * + * Calls to this method will be buffered in memory until a call to `Write()` + * is made. + */ + auto WriteSync(Pin, bool) -> bool override; + + virtual auto WriteBuffered(Pin, bool) -> void; + + /** + * Sets the ports on the GPIO expander to the values currently represented + * in `ports`. + */ + auto Flush(void) -> bool; + + auto Get(Pin) const -> bool override; + + auto IsLocked() const -> bool override; + + /** + * Reads from the GPIO expander, populating `inputs` with the most recent + * values. + */ + auto Read(void) -> bool; + + // Not copyable or movable. There should usually only ever be once instance + // of this class, and that instance will likely have a static lifetime. + Gpios(const Gpios&) = delete; + Gpios& operator=(const Gpios&) = delete; + + private: + Gpios(bool invert_lock); + + std::atomic ports_; + std::atomic inputs_; + const bool invert_lock_switch_; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/haptics.hpp b/src/drivers/include/drivers/haptics.hpp new file mode 100644 index 00000000..940c3c6d --- /dev/null +++ b/src/drivers/include/drivers/haptics.hpp @@ -0,0 +1,331 @@ +/* + * Copyright 2023 jacqueline , robin + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace drivers { + +typedef std::monostate ErmMotor; +struct LraMotor { + // TODO: fill out with calibration data from https://www.ti.com/lit/ds/symlink/drv2605l.pdf + bool hi; +}; + +class Haptics { + public: + static auto Create(const std::variant& motor) + -> Haptics* { + return new Haptics(motor); + } + + Haptics(const std::variant& motor); + ~Haptics(); + + // Not copyable or movable. + Haptics(const Haptics&) = delete; + Haptics& operator=(const Haptics&) = delete; + + // See the datasheet for section references in the below comments: + // https://www.ti.com/lit/ds/symlink/drv2605l.pdf + + // §12.1.2 Waveform Library Effects List + enum class Effect { + kStop = 0, // Sentinel/terminator Effect for the Waveform Sequence Slots + kStrongClick_100Pct = 1, + kStrongClick_60Pct = 2, + kStrongClick_30Pct = 3, + kSharpClick_100Pct = 4, + kSharpClick_60Pct = 5, + kSharpClick_30Pct = 6, + kSoftBump_100Pct = 7, + kSoftBump_60Pct = 8, + kSoftBump_30Pct = 9, + kDoubleClick_100Pct = 10, + kDoubleClick_60Pct = 11, + kTripleClick_100Pct = 12, + kSoftFuzz_60Pct = 13, + kStrongBuzz_100Pct = 14, + k750msAlert_100Pct = 15, + k1000msAlert_100Pct = 16, + kStrongClick1_100Pct = 17, + kStrongClick2_80Pct = 18, + kStrongClick3_60Pct = 19, + kStrongClick4_30Pct = 20, + kMediumClick1_100Pct = 21, + kMediumClick2_80Pct = 22, + kMediumClick3_60Pct = 23, + kSharpTick1_100Pct = 24, + kSharpTick2_80Pct = 25, + kSharpTick3_60Pct = 26, + kShortDoubleClickStrong1_100Pct = 27, + kShortDoubleClickStrong2_80Pct = 28, + kShortDoubleClickStrong3_60Pct = 29, + kShortDoubleClickStrong4_30Pct = 30, + kShortDoubleClickMedium1_100Pct = 31, + kShortDoubleClickMedium2_80Pct = 32, + kShortDoubleClickMedium3_60Pct = 33, + kShortDoubleSharpTick1_100Pct = 34, + kShortDoubleSharpTick2_80Pct = 35, + kShortDoubleSharpTick3_60Pct = 36, + kLongDoubleSharpClickStrong1_100Pct = 37, + kLongDoubleSharpClickStrong2_80Pct = 38, + kLongDoubleSharpClickStrong3_60Pct = 39, + kLongDoubleSharpClickStrong4_30Pct = 40, + kLongDoubleSharpClickMedium1_100Pct = 41, + kLongDoubleSharpClickMedium2_80Pct = 42, + kLongDoubleSharpClickMedium3_60Pct = 43, + kLongDoubleSharpTick1_100Pct = 44, + kLongDoubleSharpTick2_80Pct = 45, + kLongDoubleSharpTick3_60Pct = 46, + kBuzz1_100Pct = 47, + kBuzz2_80Pct = 48, + kBuzz3_60Pct = 49, + kBuzz4_40Pct = 50, + kBuzz5_20Pct = 51, + kPulsingStrong1_100Pct = 52, + kPulsingStrong2_60Pct = 53, + kPulsingMedium1_100Pct = 54, + kPulsingMedium2_60Pct = 55, + kPulsingSharp1_100Pct = 56, + kPulsingSharp2_60Pct = 57, + kTransitionClick1_100Pct = 58, + kTransitionClick2_80Pct = 59, + kTransitionClick3_60Pct = 60, + kTransitionClick4_40Pct = 61, + kTransitionClick5_20Pct = 62, + kTransitionClick6_10Pct = 63, + kTransitionHum1_100Pct = 64, + kTransitionHum2_80Pct = 65, + kTransitionHum3_60Pct = 66, + kTransitionHum4_40Pct = 67, + kTransitionHum5_20Pct = 68, + kTransitionHum6_10Pct = 69, + kTransitionRampDownLongSmooth1_100to0Pct = 70, + kTransitionRampDownLongSmooth2_100to0Pct = 71, + kTransitionRampDownMediumSmooth1_100to0Pct = 72, + kTransitionRampDownMediumSmooth2_100to0Pct = 73, + kTransitionRampDownShortSmooth1_100to0Pct = 74, + kTransitionRampDownShortSmooth2_100to0Pct = 75, + kTransitionRampDownLongSharp1_100to0Pct = 76, + kTransitionRampDownLongSharp2_100to0Pct = 77, + kTransitionRampDownMediumSharp1_100to0Pct = 78, + kTransitionRampDownMediumSharp2_100to0Pct = 79, + kTransitionRampDownShortSharp1_100to0Pct = 80, + kTransitionRampDownShortSharp2_100to0Pct = 81, + kTransitionRampUpLongSmooth1_0to100Pct = 82, + kTransitionRampUpLongSmooth2_0to100Pct = 83, + kTransitionRampUpMediumSmooth1_0to100Pct = 84, + kTransitionRampUpMediumSmooth2_0to100Pct = 85, + kTransitionRampUpShortSmooth1_0to100Pct = 86, + kTransitionRampUpShortSmooth2_0to100Pct = 87, + kTransitionRampUpLongSharp1_0to100Pct = 88, + kTransitionRampUpLongSharp2_0to100Pct = 89, + kTransitionRampUpMediumSharp1_0to100Pct = 90, + kTransitionRampUpMediumSharp2_0to100Pct = 91, + kTransitionRampUpShortSharp1_0to100Pct = 92, + kTransitionRampUpShortSharp2_0to100Pct = 93, + kTransitionRampDownLongSmooth1_50to0Pct = 94, + kTransitionRampDownLongSmooth2_50to0Pct = 95, + kTransitionRampDownMediumSmooth1_50to0Pct = 96, + kTransitionRampDownMediumSmooth2_50to0Pct = 97, + kTransitionRampDownShortSmooth1_50to0Pct = 98, + kTransitionRampDownShortSmooth2_50to0Pct = 99, + kTransitionRampDownLongSharp1_50to0Pct = 100, + kTransitionRampDownLongSharp2_50to0Pct = 101, + kTransitionRampDownMediumSharp1_50to0Pct = 102, + kTransitionRampDownMediumSharp2_50to0Pct = 103, + kTransitionRampDownShortSharp1_50to0Pct = 104, + kTransitionRampDownShortSharp2_50to0Pct = 105, + kTransitionRampUpLongSmooth_10to50Pct = 106, + kTransitionRampUpLongSmooth_20to50Pct = 107, + kTransitionRampUpMediumSmooth_10to50Pct = 108, + kTransitionRampUpMediumSmooth_20to50Pct = 109, + kTransitionRampUpShortSmooth_10to50Pct = 110, + kTransitionRampUpShortSmooth_20to50Pct = 111, + kTransitionRampUpLongSharp_10to50Pct = 112, + kTransitionRampUpLongSharp_20to50Pct = 113, + kTransitionRampUpMediumSharp_10to50Pct = 114, + kTransitionRampUpMediumSharp_20to50Pct = 115, + kTransitionRampUpShortSharp_10to50Pct = 116, + kTransitionRampUpShortSharp_20to50Pct = 117, + kSmoothHum1NoKickOrBrakePulse_50Pct = 119, + kSmoothHum2NoKickOrBrakePulse_40Pct = 120, + kSmoothHum3NoKickOrBrakePulse_30Pct = 121, + kSmoothHum4NoKickOrBrakePulse_20Pct = 122, + kSmoothHum5NoKickOrBrakePulse_10Pct = 123, + + // We can't use this one; need to have the EN pin hooked up. + kDontUseThis_Longbuzzforprogrammaticstopping_100Pct = 118, + + kFirst = kStrongClick_100Pct, + kLast = kSmoothHum5NoKickOrBrakePulse_10Pct, + }; + + static constexpr Effect kStartupEffect = Effect::kLongDoubleSharpTick1_100Pct; + + // §8.3.5.2 Internal Memory Interface + // Pick the ERM Library matching the motor. + enum class Library : uint8_t { + A = 1, // 1.3V-3V, Rise: 40-60ms, Brake: 20-40ms + B = 2, // 3V, Rise: 40-60ms, Brake: 5-15ms + C = 3, // 3V, Rise: 60-80ms, Brake: 10-20ms + D = 4, // 3V, Rise: 100-140ms, Brake: 15-25ms + E = 5, // 3V, Rise: >140ms, Brake: >30ms + LRA = 6 + // 7 is 4.5V+ + }; + + static constexpr Library kDefaultErmLibrary = Library::C; + + auto PowerDown() -> void; + auto Reset() -> void; + + auto PlayWaveformEffect(Effect effect) -> void; + + // Play a range of Effects + auto TourEffects() -> void; + auto TourEffects(Effect from, Effect to) -> void; + auto TourEffects(Library lib) -> void; + auto TourEffects(Effect from, Effect to, Library lib) -> void; + + // Play a range of Effects to all the Libraries we support. + // TODO(robin): remove; I'm leaving this around for temporary testing + auto TourLibraries(Effect from, Effect to) -> void; + + private: + std::optional current_effect_; + std::mutex playing_effect_; + + // §8.4.2 Changing Modes of Operation + enum class Mode : uint8_t { + kInternalTrigger = 0, + kExternalTriggerEdge = 1, + kExternalTriggerLevel = 2, + kPwmAnalog = 3, + kAudioToVibe = 4, + kRealtimePlayback = 5, + kDiagnostics = 6, + kAutoCalibrate = 7, + }; + + struct ModeMask { + // §8.4.1.4 Operation With STANDBY Control + static constexpr uint8_t kStandby = 0b01000000; + // §8.4.1.5 Operation With DEV_RESET Control + static constexpr uint8_t kDevReset = 0b10000000; + }; + + struct ControlMask { + // FeedbackControl + static constexpr uint8_t kNErmLra = 0b10000000; + + // Control3 + static constexpr uint8_t kErmOpenLoop = 0b00100000; + static constexpr uint8_t kLraOpenLoop = 0b00000001; + }; + + // §8.6 Register Map + enum class Register { + kStatus = 0x00, + kMode = 0x01, + + kRealtimePlaybackInput = 0x02, + kWaveformLibrary = 0x03, // see Library enum + + kWaveformSequenceSlot1 = 0x04, + kWaveformSequenceSlot2 = 0x05, + kWaveformSequenceSlot3 = 0x06, + kWaveformSequenceSlot4 = 0x07, + kWaveformSequenceSlot5 = 0x08, + kWaveformSequenceSlot6 = 0x09, + kWaveformSequenceSlot7 = 0x0a, + kWaveformSequenceSlot8 = 0x0b, + + kGo = 0x0C, + + // §8.3.5.2.2 Library Parameterization + kOverdriveTimeOffset = 0x0D, + kSustainTimeOffsetPositive = 0x0E, + kSustainTimeOffsetNegative = 0x0F, + kBrakeTimeOffset = 0x10, + kAudioToVibeControl = 0x11, + + kAudioToVibeInputLevelMin = 0x12, + kAudioToVibeInputLevelMax = 0x13, + kAudioToVibeOutputLevelMin = 0x14, + kAudioToVibeOutputLevelMax = 0x15, + kRatedVoltage = 0x16, + kOverdriveClampVoltage = 0x17, + kAutoCalibrationCompensationResult = 0x18, + kAutoCalibrationBackEmfResult = 0x19, + + // A bunch of different options, not grouped + // in any particular sensible way + kFeedbackControl = 0x1A, + kControl1 = 0x1B, + kControl2 = 0x1C, + kControl3 = 0x1D, + kControl4 = 0x1E, + kControl5 = 0x1F, + + kSupplyVoltageMonitor = 0x21, // "VBAT" + kLraResonancePeriod = 0x22, + }; + + enum class RegisterDefaults : uint8_t { + kStatus = 0xE0, + kMode = 0x40, + kRealtimePlaybackInput = 0, + kWaveformLibrary = 0x01, + kWaveformSequenceSlot1 = 0x01, + kWaveformSequenceSlot2 = 0, + kWaveformSequenceSlot3 = 0, + kWaveformSequenceSlot4 = 0, + kWaveformSequenceSlot5 = 0, + kWaveformSequenceSlot6 = 0, + kWaveformSequenceSlot7 = 0, + kWaveformSequenceSlot8 = 0, + kGo = 0, + kOverdriveTimeOffset = 0, + kSustainTimeOffsetPositive = 0, + kSustainTimeOffsetNegative = 0, + kBrakeTimeOffset = 0, + kAudioToVibeControl = 0x05, + kAudioToVibeInputLevelMin = 0x19, + kAudioToVibeInputLevelMax = 0xFF, + kAudioToVibeOutputLevelMin = 0x19, + kAudioToVibeOutputLevelMax = 0xFF, + kRatedVoltage = 0x3E, + kOverdriveClampVoltage = 0x8C, + kAutoCalibrationCompensationResult = 0x0C, + kAutoCalibrationBackEmfResult = 0x6C, + kFeedbackControl = 0x36, + kControl1 = 0x93, + kControl2 = 0xF5, + kControl3 = 0xA0, + kControl4 = 0x20, + kControl5 = 0x80, + kSupplyVoltageMonitor = 0, + kLraResonancePeriod = 0, + }; + + auto PowerUp() -> void; + auto WriteRegister(Register reg, uint8_t val) -> void; + + auto SetWaveformEffect(Effect effect) -> void; + auto Go() -> void; + + auto EffectToLabel(Effect effect) -> std::string; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/i2c.hpp b/src/drivers/include/drivers/i2c.hpp new file mode 100644 index 00000000..0dc1e7c0 --- /dev/null +++ b/src/drivers/include/drivers/i2c.hpp @@ -0,0 +1,93 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include + +#include "driver/i2c.h" +#include "hal/i2c_types.h" + +namespace drivers { + +esp_err_t init_i2c(void); +esp_err_t deinit_i2c(void); + +/* + * Convenience wrapper for performing an I2C transaction with a reasonable + * preconfigured timeout, automatic management of a heap-based command buffer, + * and a terser API for enqueuing bytes. + * + * Any error codes from the underlying ESP IDF are treated as fatal, since they + * typically represent invalid arguments or OOMs. + */ +class I2CTransaction { + public: + static const uint8_t kI2CTimeout = pdMS_TO_TICKS(100); + + I2CTransaction(); + ~I2CTransaction(); + + /* + * Executes all enqueued commands, returning the result code. Possible error + * codes, per the ESP-IDF docs: + * + * ESP_OK Success + * ESP_ERR_INVALID_ARG Parameter error + * ESP_FAIL Sending command error, slave doesn’t ACK the transfer. + * ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode. + * ESP_ERR_TIMEOUT Operation timeout because the bus is busy. + */ + esp_err_t Execute(int num_retries = 0); + + /* + * Enqueues a start condition. May also be used for repeated start + * conditions. + */ + I2CTransaction& start(); + /* Enqueues a stop condition. */ + I2CTransaction& stop(); + + /* + * Enqueues writing the given 7 bit address, followed by one bit indicating + * whether this is a read or write request. + * + * This command will expect an ACK before continuing. + */ + I2CTransaction& write_addr(uint8_t addr, uint8_t op); + + /* + * Enqueues one or more bytes to be written. The transaction will wait for + * an ACK to be returned before writing the next byte. + */ + I2CTransaction& write_ack(uint8_t data); + template + I2CTransaction& write_ack(uint8_t data, More... more) { + write_ack(data); + write_ack(more...); + return *this; + } + + /* + * Enqueues a read of one byte into the given uint8. Responds with the given + * ACK/NACK type. + */ + I2CTransaction& read(uint8_t* dest, i2c_ack_type_t ack); + + /* Returns the underlying command buffer. */ + i2c_cmd_handle_t handle() { return handle_; } + + // Cannot be moved or copied, since doing so is probably an error. Pass a + // reference instead. + I2CTransaction(const I2CTransaction&) = delete; + I2CTransaction& operator=(const I2CTransaction&) = delete; + + private: + i2c_cmd_handle_t handle_; + uint8_t* buffer_; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/i2s_dac.hpp b/src/drivers/include/drivers/i2s_dac.hpp new file mode 100644 index 00000000..5e81f875 --- /dev/null +++ b/src/drivers/include/drivers/i2s_dac.hpp @@ -0,0 +1,91 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include "driver/i2s_std.h" +#include "driver/i2s_types.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/portmacro.h" +#include "freertos/stream_buffer.h" +#include "result.hpp" + +#include "drivers/gpios.hpp" +#include "sys/_stdint.h" + +namespace drivers { + +// DMA max buffer size for I2S is 4092. We normalise to 2-channel, 16 bit +// audio, which gives us a max of 4092 / 2 / 2 (16 bits) frames. This in turn +// means that at 48kHz, we have about 21ms of budget to fill each buffer. +// We base this off of the maximum DMA size in order to minimise the amount of +// work the CPU has to do to service the DMA callbacks. +constexpr size_t kI2SBufferLengthFrames = 1024; + +/** + * Interface for a DAC that receives PCM samples over I2S. + */ +class I2SDac { + public: + static auto create(IGpios& expander) -> std::optional; + + I2SDac(IGpios& gpio, i2s_chan_handle_t i2s_handle); + ~I2SDac(); + + auto Start() -> void; + auto Stop() -> void; + auto SetPaused(bool) -> void; + + enum Channels { + CHANNELS_MONO, + CHANNELS_STEREO, + }; + enum BitsPerSample { + BPS_16 = I2S_DATA_BIT_WIDTH_16BIT, + BPS_24 = I2S_DATA_BIT_WIDTH_24BIT, + BPS_32 = I2S_DATA_BIT_WIDTH_32BIT, + }; + enum SampleRate { + SAMPLE_RATE_8 = 8000, + SAMPLE_RATE_32 = 32000, + SAMPLE_RATE_44_1 = 44100, + SAMPLE_RATE_48 = 48000, + SAMPLE_RATE_88_2 = 88200, + SAMPLE_RATE_96 = 96000, + }; + + auto Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) -> void; + + auto WriteData(const std::span& data) -> void; + auto SetSource(StreamBufferHandle_t buffer) -> void; + + // Not copyable or movable. + I2SDac(const I2SDac&) = delete; + I2SDac& operator=(const I2SDac&) = delete; + + private: + auto set_channel(bool) -> void; + + IGpios& gpio_; + i2s_chan_handle_t i2s_handle_; + bool i2s_active_; + StreamBufferHandle_t buffer_; + std::mutex configure_mutex_; + + i2s_std_clk_config_t clock_config_; + i2s_std_slot_config_t slot_config_; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/nvs.hpp b/src/drivers/include/drivers/nvs.hpp new file mode 100644 index 00000000..83bb8097 --- /dev/null +++ b/src/drivers/include/drivers/nvs.hpp @@ -0,0 +1,156 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include +#include + +#include "esp_err.h" +#include "nvs.h" + +#include "drivers/bluetooth_types.hpp" +#include "lru_cache.hpp" + +namespace drivers { + +/* + * Wrapper for a single NVS setting, with its backing value cached in memory. + * NVS values that are just plain old data should generally use these for + * simpler implementation. + */ +template +class Setting { + public: + Setting(const char* name) : name_(name), val_(), dirty_(false) {} + + auto set(const std::optional&& v) -> void { + if (val_.has_value() != v.has_value() || *val_ != *v) { + val_ = v; + dirty_ = true; + } + } + auto get() -> std::optional& { return val_; } + + /* Reads the stored value from NVS and parses it into the correct type. */ + auto load(nvs_handle_t) -> std::optional; + /* Encodes the given value and writes it to NVS. */ + auto store(nvs_handle_t, T v) -> void; + + auto read(nvs_handle_t nvs) -> void { val_ = load(nvs); } + auto write(nvs_handle_t nvs) -> void { + if (!dirty_) { + return; + } + dirty_ = false; + if (val_) { + store(nvs, *val_); + } else { + nvs_erase_key(nvs, name_); + } + } + + private: + const char* name_; + std::optional val_; + bool dirty_; +}; + +class NvsStorage { + public: + static auto OpenSync() -> NvsStorage*; + + auto Read() -> void; + auto Write() -> bool; + + // Hardware Compatibility + auto LockPolarity() -> bool; + auto LockPolarity(bool) -> void; + + auto DisplaySize() + -> std::pair, std::optional>; + auto DisplaySize(std::pair, std::optional>) + -> void; + + auto HapticMotorIsErm() -> bool; + auto HapticMotorIsErm(bool) -> void; + // /Hardware Compatibility + + auto PreferredBluetoothDevice() -> std::optional; + auto PreferredBluetoothDevice(std::optional) -> void; + + auto BluetoothVolume(const bluetooth::mac_addr_t&) -> uint8_t; + auto BluetoothVolume(const bluetooth::mac_addr_t&, uint8_t) -> void; + + enum class Output : uint8_t { + kHeadphones = 0, + kBluetooth = 1, + }; + auto OutputMode() -> Output; + auto OutputMode(Output) -> void; + + auto ScreenBrightness() -> uint_fast8_t; + auto ScreenBrightness(uint_fast8_t) -> void; + + auto ScrollSensitivity() -> uint_fast8_t; + auto ScrollSensitivity(uint_fast8_t) -> void; + + auto AmpMaxVolume() -> uint16_t; + auto AmpMaxVolume(uint16_t) -> void; + + auto AmpCurrentVolume() -> uint16_t; + auto AmpCurrentVolume(uint16_t) -> void; + + auto AmpLeftBias() -> int_fast8_t; + auto AmpLeftBias(int_fast8_t) -> void; + + enum class InputModes : uint8_t { + kButtonsOnly = 0, + kButtonsWithWheel = 1, + kDirectionalWheel = 2, + kRotatingWheel = 3, + }; + + auto PrimaryInput() -> InputModes; + auto PrimaryInput(InputModes) -> void; + + auto DbAutoIndex() -> bool; + auto DbAutoIndex(bool) -> void; + + explicit NvsStorage(nvs_handle_t); + ~NvsStorage(); + + private: + auto DowngradeSchemaSync() -> bool; + auto SchemaVersionSync() -> uint8_t; + + std::mutex mutex_; + nvs_handle_t handle_; + + Setting lock_polarity_; + Setting display_cols_; + Setting display_rows_; + Setting haptic_motor_type_; + + Setting brightness_; + Setting sensitivity_; + Setting amp_max_vol_; + Setting amp_cur_vol_; + Setting amp_left_bias_; + Setting input_mode_; + Setting output_mode_; + Setting bt_preferred_; + Setting db_auto_index_; + + util::LruCache<10, bluetooth::mac_addr_t, uint8_t> bt_volumes_; + bool bt_volumes_dirty_; + + auto readBtVolumes() -> void; + auto writeBtVolumes() -> void; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/samd.hpp b/src/drivers/include/drivers/samd.hpp new file mode 100644 index 00000000..55ea513c --- /dev/null +++ b/src/drivers/include/drivers/samd.hpp @@ -0,0 +1,75 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +namespace drivers { + +class Samd { + public: + static auto Create() -> Samd* { return new Samd(); } + + Samd(); + ~Samd(); + + auto Version() -> std::string; + + enum class ChargeStatus { + // There is no battery plugged into the device. + kNoBattery, + // The battery is discharging, and the current voltage level is very low. + kBatteryCritical, + // The battery is discharging. + kDischarging, + // The battery is charging over a low-current USB connection + kChargingRegular, + // The battery is charging over a high-current USB connection + kChargingFast, + // The battery is full charged, and we are still plugged in. + kFullCharge, + }; + + auto GetChargeStatus() -> std::optional; + auto UpdateChargeStatus() -> void; + + enum class UsbStatus { + // There is no compatible usb host attached. + kDetached, + // There is a compatible usb host attached, but USB MSC is not currently + // in use by the SAMD. + kAttachedIdle, + // The SAMD is currently writing to the SD card via USB MSC. + kAttachedBusy, + }; + + auto GetUsbStatus() -> UsbStatus; + auto UpdateUsbStatus() -> void; + + auto ResetToFlashSamd() -> void; + auto PowerDown() -> void; + + auto UsbMassStorage(bool en) -> void; + auto UsbMassStorage() -> bool; + + // Not copyable or movable. There should usually only ever be once instance + // of this class, and that instance will likely have a static lifetime. + Samd(const Samd&) = delete; + Samd& operator=(const Samd&) = delete; + + private: + uint8_t version_; + std::optional charge_status_; + UsbStatus usb_status_; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/spi.hpp b/src/drivers/include/drivers/spi.hpp new file mode 100644 index 00000000..60638f71 --- /dev/null +++ b/src/drivers/include/drivers/spi.hpp @@ -0,0 +1,18 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include "esp_err.h" + +namespace drivers { + +esp_err_t init_spi(void); +esp_err_t deinit_spi(void); +std::lock_guard acquire_spi(void); + +} // namespace drivers diff --git a/src/drivers/include/drivers/spiffs.hpp b/src/drivers/include/drivers/spiffs.hpp new file mode 100644 index 00000000..04478590 --- /dev/null +++ b/src/drivers/include/drivers/spiffs.hpp @@ -0,0 +1,15 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include "esp_err.h" + +namespace drivers { + +esp_err_t spiffs_mount(); + +} // namespace drivers diff --git a/src/drivers/include/drivers/storage.hpp b/src/drivers/include/drivers/storage.hpp new file mode 100644 index 00000000..3aefff2d --- /dev/null +++ b/src/drivers/include/drivers/storage.hpp @@ -0,0 +1,71 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include + +#include "driver/sdmmc_types.h" +#include "driver/sdspi_host.h" +#include "esp_err.h" +#include "esp_vfs_fat.h" +#include "ff.h" +#include "result.hpp" + +#include "drivers/gpios.hpp" + +namespace drivers { + +extern const char* kStoragePath; + +enum class SdState { + kNotPresent, + kNotFormatted, + kNotMounted, + kMounted, +}; + +class SdStorage { + public: + enum Error { + FAILED_TO_INIT, + /** We couldn't interact with the SD card at all. Is it missing? */ + FAILED_TO_READ, + /** We couldn't mount the SD card. Is it formatted? */ + FAILED_TO_MOUNT, + }; + + static auto Create(IGpios& gpio) -> cpp::result; + + SdStorage(IGpios& gpio, + sdspi_dev_handle_t handle_, + std::unique_ptr host_, + std::unique_ptr card_, + FATFS* fs_); + ~SdStorage(); + + auto HandleTransaction(sdspi_dev_handle_t handle, sdmmc_command_t* cmdinfo) + -> esp_err_t; + + auto GetFs() -> FATFS*; + + // Not copyable or movable. + SdStorage(const SdStorage&) = delete; + SdStorage& operator=(const SdStorage&) = delete; + + private: + IGpios& gpio_; + + // SPI and SD driver info + sdspi_dev_handle_t handle_; + std::unique_ptr host_; + std::unique_ptr card_; + + // Filesystem info + FATFS* fs_ = nullptr; +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/touchwheel.hpp b/src/drivers/include/drivers/touchwheel.hpp new file mode 100644 index 00000000..60902087 --- /dev/null +++ b/src/drivers/include/drivers/touchwheel.hpp @@ -0,0 +1,68 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include + +#include "esp_err.h" +#include "result.hpp" + +#include "drivers/gpios.hpp" + +namespace drivers { + +struct TouchWheelData { + bool is_wheel_touched = false; + bool is_button_touched = false; + uint8_t wheel_position = -1; +}; + +class TouchWheel { + public: + static auto isAngleWithin(int16_t wheel_angle, + int16_t target_angle, + int threshold) -> bool; + + static auto Create() -> TouchWheel* { return new TouchWheel(); } + TouchWheel(); + ~TouchWheel(); + + // Not copyable or movable. + TouchWheel(const TouchWheel&) = delete; + TouchWheel& operator=(const TouchWheel&) = delete; + + auto Update() -> void; + auto GetTouchWheelData() const -> TouchWheelData; + + auto PowerDown() -> void; + + private: + TouchWheelData data_; + + enum Register { + FIRMWARE_VERSION = 1, + DETECTION_STATUS = 2, + KEY_STATUS_A = 3, + KEY_STATUS_B = 4, + SLIDER_POSITION = 5, + CALIBRATE = 6, + RESET = 7, + LOW_POWER = 8, + RECALIBRATION_DELAY = 12, + SLIDER_OPTIONS = 14, + CHARGE_TIME = 15, + DETECT_THRESHOLD_BASE = 16, + KEY_CONTROL_BASE = 28, + PULSE_SCALE_BASE = 40, + }; + + void WriteRegister(uint8_t reg, uint8_t val); + uint8_t ReadRegister(uint8_t reg); +}; + +} // namespace drivers diff --git a/src/drivers/include/drivers/wm8523.hpp b/src/drivers/include/drivers/wm8523.hpp new file mode 100644 index 00000000..a64f6bac --- /dev/null +++ b/src/drivers/include/drivers/wm8523.hpp @@ -0,0 +1,53 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ +#pragma once + +#include +#include +#include + +namespace drivers { +namespace wm8523 { + +extern const uint16_t kAbsoluteMaxVolume; + +extern const uint16_t kAbsoluteMinVolume; + +extern const uint16_t kMaxVolumeBeforeClipping; + +extern const uint16_t kLineLevelReferenceVolume; + +extern const uint16_t kDefaultVolume; +extern const uint16_t kDefaultMaxVolume; + +extern const uint16_t kZeroDbVolume; + +constexpr auto VolumeToDb(uint16_t vol) -> int_fast8_t { + return (vol - kLineLevelReferenceVolume) / 4; +} + +constexpr auto DbToVolume(int_fast8_t db) -> uint16_t { + return (db * 4) + kLineLevelReferenceVolume; +} + +enum class Register : uint8_t { + kReset = 0, + kRevision = 1, + kPsCtrl = 2, + kAifCtrl1 = 3, + kAifCtrl2 = 4, + kDacCtrl = 5, + kDacGainLeft = 6, + kDacGainRight = 7, + kZeroDetect = 8, +}; + +auto ReadRegister(Register reg) -> std::optional; +auto WriteRegister(Register reg, uint16_t data) -> bool; +auto WriteRegister(Register reg, uint8_t msb, uint8_t lsb) -> bool; + +} // namespace wm8523 +} // namespace drivers diff --git a/src/drivers/include/fatfs_audio_input.hpp b/src/drivers/include/fatfs_audio_input.hpp deleted file mode 100644 index 705f6e7d..00000000 --- a/src/drivers/include/fatfs_audio_input.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -namespace drivers { - -class FatfsAudioInput { - public: - FatfsAudioInput(std::shared_ptr storage); - ~FatfsAudioInput(); - - enum Status { - /* - * Successfully read data into the output buffer, and there is still - * data remaining in the file. - */ - OKAY, - - /* - * The ringbuffer was full. No data was read. - */ - RINGBUF_FULL, - - /* - * Some data may have been read into the output buffer, but the file is - * now empty. - */ - FILE_EMPTY, - }; - auto Process() -> Status; - - auto GetOutputBuffer() -> RingbufHandle_t; - - private: - std::shared_ptr storage_; - RingbufHandle_t output_; - - std::pmr::string path_; -}; - -} // namespace drivers diff --git a/src/drivers/include/gpios.hpp b/src/drivers/include/gpios.hpp deleted file mode 100644 index e27a3ade..00000000 --- a/src/drivers/include/gpios.hpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "driver/i2c.h" -#include "esp_check.h" -#include "esp_err.h" -#include "esp_log.h" -#include "freertos/FreeRTOS.h" - -namespace drivers { - -/** - * Wrapper for interfacing with the PCA8575 GPIO expander. Includes basic - * low-level pin setting methods, as well as higher level convenience functions - * for reading, writing, and atomically interacting with the SPI chip select - * pins. - * - * Each method of this class can be called safely from any thread, and all - * updates are guaranteed to be atomic. Any access to chip select related pins - * should be done whilst holding `cs_lock` (preferably via the helper methods). - */ -class IGpios { - public: - virtual ~IGpios() {} - - /* Maps each pin of the expander to its number in a `pack`ed uint16. */ - enum class Pin { - // Port A - kSdMuxSwitch = 0, - kSdMuxDisable = 1, - kKeyUp = 2, - kKeyDown = 3, - kKeyLock = 4, - kDisplayEnable = 5, - // 6 is unused - kSdPowerEnable = 7, - - // Port B - kPhoneDetect = 8, - kAmplifierEnable = 9, - kSdCardDetect = 10, - kAmplifierUnmuteLegacy = 11, - kAmplifierMute = 12, - // 13 through 15 are unused - }; - - /* Nicer value names for use with kSdMuxSwitch. */ - enum SdController { - SD_MUX_ESP = 0, - SD_MUX_SAMD = 1, - }; - - /* - * Sets a single specific pin to the given value. `true` corresponds to - * HIGH, and `false` corresponds to LOW. - * - * This function will block until the pin has changed level. - */ - virtual auto WriteSync(Pin, bool) -> bool = 0; - - /* - * Returns the most recently cached value of the given pin. - */ - virtual auto Get(Pin) const -> bool = 0; - - virtual auto IsLocked() const -> bool = 0; -}; - -class Gpios : public IGpios { - public: - static auto Create(bool invert_lock_switch) -> Gpios*; - ~Gpios(); - - /* - * Sets a single specific pin to the given value. `true` corresponds to - * HIGH, and `false` corresponds to LOW. - * - * Calls to this method will be buffered in memory until a call to `Write()` - * is made. - */ - auto WriteSync(Pin, bool) -> bool override; - - virtual auto WriteBuffered(Pin, bool) -> void; - - /** - * Sets the ports on the GPIO expander to the values currently represented - * in `ports`. - */ - auto Flush(void) -> bool; - - auto Get(Pin) const -> bool override; - - auto IsLocked() const -> bool override; - - /** - * Reads from the GPIO expander, populating `inputs` with the most recent - * values. - */ - auto Read(void) -> bool; - - // Not copyable or movable. There should usually only ever be once instance - // of this class, and that instance will likely have a static lifetime. - Gpios(const Gpios&) = delete; - Gpios& operator=(const Gpios&) = delete; - - private: - Gpios(bool invert_lock); - - std::atomic ports_; - std::atomic inputs_; - const bool invert_lock_switch_; -}; - -} // namespace drivers diff --git a/src/drivers/include/haptics.hpp b/src/drivers/include/haptics.hpp deleted file mode 100644 index 940c3c6d..00000000 --- a/src/drivers/include/haptics.hpp +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright 2023 jacqueline , robin - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace drivers { - -typedef std::monostate ErmMotor; -struct LraMotor { - // TODO: fill out with calibration data from https://www.ti.com/lit/ds/symlink/drv2605l.pdf - bool hi; -}; - -class Haptics { - public: - static auto Create(const std::variant& motor) - -> Haptics* { - return new Haptics(motor); - } - - Haptics(const std::variant& motor); - ~Haptics(); - - // Not copyable or movable. - Haptics(const Haptics&) = delete; - Haptics& operator=(const Haptics&) = delete; - - // See the datasheet for section references in the below comments: - // https://www.ti.com/lit/ds/symlink/drv2605l.pdf - - // §12.1.2 Waveform Library Effects List - enum class Effect { - kStop = 0, // Sentinel/terminator Effect for the Waveform Sequence Slots - kStrongClick_100Pct = 1, - kStrongClick_60Pct = 2, - kStrongClick_30Pct = 3, - kSharpClick_100Pct = 4, - kSharpClick_60Pct = 5, - kSharpClick_30Pct = 6, - kSoftBump_100Pct = 7, - kSoftBump_60Pct = 8, - kSoftBump_30Pct = 9, - kDoubleClick_100Pct = 10, - kDoubleClick_60Pct = 11, - kTripleClick_100Pct = 12, - kSoftFuzz_60Pct = 13, - kStrongBuzz_100Pct = 14, - k750msAlert_100Pct = 15, - k1000msAlert_100Pct = 16, - kStrongClick1_100Pct = 17, - kStrongClick2_80Pct = 18, - kStrongClick3_60Pct = 19, - kStrongClick4_30Pct = 20, - kMediumClick1_100Pct = 21, - kMediumClick2_80Pct = 22, - kMediumClick3_60Pct = 23, - kSharpTick1_100Pct = 24, - kSharpTick2_80Pct = 25, - kSharpTick3_60Pct = 26, - kShortDoubleClickStrong1_100Pct = 27, - kShortDoubleClickStrong2_80Pct = 28, - kShortDoubleClickStrong3_60Pct = 29, - kShortDoubleClickStrong4_30Pct = 30, - kShortDoubleClickMedium1_100Pct = 31, - kShortDoubleClickMedium2_80Pct = 32, - kShortDoubleClickMedium3_60Pct = 33, - kShortDoubleSharpTick1_100Pct = 34, - kShortDoubleSharpTick2_80Pct = 35, - kShortDoubleSharpTick3_60Pct = 36, - kLongDoubleSharpClickStrong1_100Pct = 37, - kLongDoubleSharpClickStrong2_80Pct = 38, - kLongDoubleSharpClickStrong3_60Pct = 39, - kLongDoubleSharpClickStrong4_30Pct = 40, - kLongDoubleSharpClickMedium1_100Pct = 41, - kLongDoubleSharpClickMedium2_80Pct = 42, - kLongDoubleSharpClickMedium3_60Pct = 43, - kLongDoubleSharpTick1_100Pct = 44, - kLongDoubleSharpTick2_80Pct = 45, - kLongDoubleSharpTick3_60Pct = 46, - kBuzz1_100Pct = 47, - kBuzz2_80Pct = 48, - kBuzz3_60Pct = 49, - kBuzz4_40Pct = 50, - kBuzz5_20Pct = 51, - kPulsingStrong1_100Pct = 52, - kPulsingStrong2_60Pct = 53, - kPulsingMedium1_100Pct = 54, - kPulsingMedium2_60Pct = 55, - kPulsingSharp1_100Pct = 56, - kPulsingSharp2_60Pct = 57, - kTransitionClick1_100Pct = 58, - kTransitionClick2_80Pct = 59, - kTransitionClick3_60Pct = 60, - kTransitionClick4_40Pct = 61, - kTransitionClick5_20Pct = 62, - kTransitionClick6_10Pct = 63, - kTransitionHum1_100Pct = 64, - kTransitionHum2_80Pct = 65, - kTransitionHum3_60Pct = 66, - kTransitionHum4_40Pct = 67, - kTransitionHum5_20Pct = 68, - kTransitionHum6_10Pct = 69, - kTransitionRampDownLongSmooth1_100to0Pct = 70, - kTransitionRampDownLongSmooth2_100to0Pct = 71, - kTransitionRampDownMediumSmooth1_100to0Pct = 72, - kTransitionRampDownMediumSmooth2_100to0Pct = 73, - kTransitionRampDownShortSmooth1_100to0Pct = 74, - kTransitionRampDownShortSmooth2_100to0Pct = 75, - kTransitionRampDownLongSharp1_100to0Pct = 76, - kTransitionRampDownLongSharp2_100to0Pct = 77, - kTransitionRampDownMediumSharp1_100to0Pct = 78, - kTransitionRampDownMediumSharp2_100to0Pct = 79, - kTransitionRampDownShortSharp1_100to0Pct = 80, - kTransitionRampDownShortSharp2_100to0Pct = 81, - kTransitionRampUpLongSmooth1_0to100Pct = 82, - kTransitionRampUpLongSmooth2_0to100Pct = 83, - kTransitionRampUpMediumSmooth1_0to100Pct = 84, - kTransitionRampUpMediumSmooth2_0to100Pct = 85, - kTransitionRampUpShortSmooth1_0to100Pct = 86, - kTransitionRampUpShortSmooth2_0to100Pct = 87, - kTransitionRampUpLongSharp1_0to100Pct = 88, - kTransitionRampUpLongSharp2_0to100Pct = 89, - kTransitionRampUpMediumSharp1_0to100Pct = 90, - kTransitionRampUpMediumSharp2_0to100Pct = 91, - kTransitionRampUpShortSharp1_0to100Pct = 92, - kTransitionRampUpShortSharp2_0to100Pct = 93, - kTransitionRampDownLongSmooth1_50to0Pct = 94, - kTransitionRampDownLongSmooth2_50to0Pct = 95, - kTransitionRampDownMediumSmooth1_50to0Pct = 96, - kTransitionRampDownMediumSmooth2_50to0Pct = 97, - kTransitionRampDownShortSmooth1_50to0Pct = 98, - kTransitionRampDownShortSmooth2_50to0Pct = 99, - kTransitionRampDownLongSharp1_50to0Pct = 100, - kTransitionRampDownLongSharp2_50to0Pct = 101, - kTransitionRampDownMediumSharp1_50to0Pct = 102, - kTransitionRampDownMediumSharp2_50to0Pct = 103, - kTransitionRampDownShortSharp1_50to0Pct = 104, - kTransitionRampDownShortSharp2_50to0Pct = 105, - kTransitionRampUpLongSmooth_10to50Pct = 106, - kTransitionRampUpLongSmooth_20to50Pct = 107, - kTransitionRampUpMediumSmooth_10to50Pct = 108, - kTransitionRampUpMediumSmooth_20to50Pct = 109, - kTransitionRampUpShortSmooth_10to50Pct = 110, - kTransitionRampUpShortSmooth_20to50Pct = 111, - kTransitionRampUpLongSharp_10to50Pct = 112, - kTransitionRampUpLongSharp_20to50Pct = 113, - kTransitionRampUpMediumSharp_10to50Pct = 114, - kTransitionRampUpMediumSharp_20to50Pct = 115, - kTransitionRampUpShortSharp_10to50Pct = 116, - kTransitionRampUpShortSharp_20to50Pct = 117, - kSmoothHum1NoKickOrBrakePulse_50Pct = 119, - kSmoothHum2NoKickOrBrakePulse_40Pct = 120, - kSmoothHum3NoKickOrBrakePulse_30Pct = 121, - kSmoothHum4NoKickOrBrakePulse_20Pct = 122, - kSmoothHum5NoKickOrBrakePulse_10Pct = 123, - - // We can't use this one; need to have the EN pin hooked up. - kDontUseThis_Longbuzzforprogrammaticstopping_100Pct = 118, - - kFirst = kStrongClick_100Pct, - kLast = kSmoothHum5NoKickOrBrakePulse_10Pct, - }; - - static constexpr Effect kStartupEffect = Effect::kLongDoubleSharpTick1_100Pct; - - // §8.3.5.2 Internal Memory Interface - // Pick the ERM Library matching the motor. - enum class Library : uint8_t { - A = 1, // 1.3V-3V, Rise: 40-60ms, Brake: 20-40ms - B = 2, // 3V, Rise: 40-60ms, Brake: 5-15ms - C = 3, // 3V, Rise: 60-80ms, Brake: 10-20ms - D = 4, // 3V, Rise: 100-140ms, Brake: 15-25ms - E = 5, // 3V, Rise: >140ms, Brake: >30ms - LRA = 6 - // 7 is 4.5V+ - }; - - static constexpr Library kDefaultErmLibrary = Library::C; - - auto PowerDown() -> void; - auto Reset() -> void; - - auto PlayWaveformEffect(Effect effect) -> void; - - // Play a range of Effects - auto TourEffects() -> void; - auto TourEffects(Effect from, Effect to) -> void; - auto TourEffects(Library lib) -> void; - auto TourEffects(Effect from, Effect to, Library lib) -> void; - - // Play a range of Effects to all the Libraries we support. - // TODO(robin): remove; I'm leaving this around for temporary testing - auto TourLibraries(Effect from, Effect to) -> void; - - private: - std::optional current_effect_; - std::mutex playing_effect_; - - // §8.4.2 Changing Modes of Operation - enum class Mode : uint8_t { - kInternalTrigger = 0, - kExternalTriggerEdge = 1, - kExternalTriggerLevel = 2, - kPwmAnalog = 3, - kAudioToVibe = 4, - kRealtimePlayback = 5, - kDiagnostics = 6, - kAutoCalibrate = 7, - }; - - struct ModeMask { - // §8.4.1.4 Operation With STANDBY Control - static constexpr uint8_t kStandby = 0b01000000; - // §8.4.1.5 Operation With DEV_RESET Control - static constexpr uint8_t kDevReset = 0b10000000; - }; - - struct ControlMask { - // FeedbackControl - static constexpr uint8_t kNErmLra = 0b10000000; - - // Control3 - static constexpr uint8_t kErmOpenLoop = 0b00100000; - static constexpr uint8_t kLraOpenLoop = 0b00000001; - }; - - // §8.6 Register Map - enum class Register { - kStatus = 0x00, - kMode = 0x01, - - kRealtimePlaybackInput = 0x02, - kWaveformLibrary = 0x03, // see Library enum - - kWaveformSequenceSlot1 = 0x04, - kWaveformSequenceSlot2 = 0x05, - kWaveformSequenceSlot3 = 0x06, - kWaveformSequenceSlot4 = 0x07, - kWaveformSequenceSlot5 = 0x08, - kWaveformSequenceSlot6 = 0x09, - kWaveformSequenceSlot7 = 0x0a, - kWaveformSequenceSlot8 = 0x0b, - - kGo = 0x0C, - - // §8.3.5.2.2 Library Parameterization - kOverdriveTimeOffset = 0x0D, - kSustainTimeOffsetPositive = 0x0E, - kSustainTimeOffsetNegative = 0x0F, - kBrakeTimeOffset = 0x10, - kAudioToVibeControl = 0x11, - - kAudioToVibeInputLevelMin = 0x12, - kAudioToVibeInputLevelMax = 0x13, - kAudioToVibeOutputLevelMin = 0x14, - kAudioToVibeOutputLevelMax = 0x15, - kRatedVoltage = 0x16, - kOverdriveClampVoltage = 0x17, - kAutoCalibrationCompensationResult = 0x18, - kAutoCalibrationBackEmfResult = 0x19, - - // A bunch of different options, not grouped - // in any particular sensible way - kFeedbackControl = 0x1A, - kControl1 = 0x1B, - kControl2 = 0x1C, - kControl3 = 0x1D, - kControl4 = 0x1E, - kControl5 = 0x1F, - - kSupplyVoltageMonitor = 0x21, // "VBAT" - kLraResonancePeriod = 0x22, - }; - - enum class RegisterDefaults : uint8_t { - kStatus = 0xE0, - kMode = 0x40, - kRealtimePlaybackInput = 0, - kWaveformLibrary = 0x01, - kWaveformSequenceSlot1 = 0x01, - kWaveformSequenceSlot2 = 0, - kWaveformSequenceSlot3 = 0, - kWaveformSequenceSlot4 = 0, - kWaveformSequenceSlot5 = 0, - kWaveformSequenceSlot6 = 0, - kWaveformSequenceSlot7 = 0, - kWaveformSequenceSlot8 = 0, - kGo = 0, - kOverdriveTimeOffset = 0, - kSustainTimeOffsetPositive = 0, - kSustainTimeOffsetNegative = 0, - kBrakeTimeOffset = 0, - kAudioToVibeControl = 0x05, - kAudioToVibeInputLevelMin = 0x19, - kAudioToVibeInputLevelMax = 0xFF, - kAudioToVibeOutputLevelMin = 0x19, - kAudioToVibeOutputLevelMax = 0xFF, - kRatedVoltage = 0x3E, - kOverdriveClampVoltage = 0x8C, - kAutoCalibrationCompensationResult = 0x0C, - kAutoCalibrationBackEmfResult = 0x6C, - kFeedbackControl = 0x36, - kControl1 = 0x93, - kControl2 = 0xF5, - kControl3 = 0xA0, - kControl4 = 0x20, - kControl5 = 0x80, - kSupplyVoltageMonitor = 0, - kLraResonancePeriod = 0, - }; - - auto PowerUp() -> void; - auto WriteRegister(Register reg, uint8_t val) -> void; - - auto SetWaveformEffect(Effect effect) -> void; - auto Go() -> void; - - auto EffectToLabel(Effect effect) -> std::string; -}; - -} // namespace drivers diff --git a/src/drivers/include/i2c.hpp b/src/drivers/include/i2c.hpp deleted file mode 100644 index 0dc1e7c0..00000000 --- a/src/drivers/include/i2c.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include - -#include "driver/i2c.h" -#include "hal/i2c_types.h" - -namespace drivers { - -esp_err_t init_i2c(void); -esp_err_t deinit_i2c(void); - -/* - * Convenience wrapper for performing an I2C transaction with a reasonable - * preconfigured timeout, automatic management of a heap-based command buffer, - * and a terser API for enqueuing bytes. - * - * Any error codes from the underlying ESP IDF are treated as fatal, since they - * typically represent invalid arguments or OOMs. - */ -class I2CTransaction { - public: - static const uint8_t kI2CTimeout = pdMS_TO_TICKS(100); - - I2CTransaction(); - ~I2CTransaction(); - - /* - * Executes all enqueued commands, returning the result code. Possible error - * codes, per the ESP-IDF docs: - * - * ESP_OK Success - * ESP_ERR_INVALID_ARG Parameter error - * ESP_FAIL Sending command error, slave doesn’t ACK the transfer. - * ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode. - * ESP_ERR_TIMEOUT Operation timeout because the bus is busy. - */ - esp_err_t Execute(int num_retries = 0); - - /* - * Enqueues a start condition. May also be used for repeated start - * conditions. - */ - I2CTransaction& start(); - /* Enqueues a stop condition. */ - I2CTransaction& stop(); - - /* - * Enqueues writing the given 7 bit address, followed by one bit indicating - * whether this is a read or write request. - * - * This command will expect an ACK before continuing. - */ - I2CTransaction& write_addr(uint8_t addr, uint8_t op); - - /* - * Enqueues one or more bytes to be written. The transaction will wait for - * an ACK to be returned before writing the next byte. - */ - I2CTransaction& write_ack(uint8_t data); - template - I2CTransaction& write_ack(uint8_t data, More... more) { - write_ack(data); - write_ack(more...); - return *this; - } - - /* - * Enqueues a read of one byte into the given uint8. Responds with the given - * ACK/NACK type. - */ - I2CTransaction& read(uint8_t* dest, i2c_ack_type_t ack); - - /* Returns the underlying command buffer. */ - i2c_cmd_handle_t handle() { return handle_; } - - // Cannot be moved or copied, since doing so is probably an error. Pass a - // reference instead. - I2CTransaction(const I2CTransaction&) = delete; - I2CTransaction& operator=(const I2CTransaction&) = delete; - - private: - i2c_cmd_handle_t handle_; - uint8_t* buffer_; -}; - -} // namespace drivers diff --git a/src/drivers/include/i2s_dac.hpp b/src/drivers/include/i2s_dac.hpp deleted file mode 100644 index 569f0a9a..00000000 --- a/src/drivers/include/i2s_dac.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include - -#include -#include -#include -#include -#include - -#include "driver/i2s_std.h" -#include "driver/i2s_types.h" -#include "esp_err.h" -#include "freertos/FreeRTOS.h" -#include "freertos/portmacro.h" -#include "freertos/stream_buffer.h" -#include "result.hpp" - -#include "gpios.hpp" -#include "sys/_stdint.h" - -namespace drivers { - -// DMA max buffer size for I2S is 4092. We normalise to 2-channel, 16 bit -// audio, which gives us a max of 4092 / 2 / 2 (16 bits) frames. This in turn -// means that at 48kHz, we have about 21ms of budget to fill each buffer. -// We base this off of the maximum DMA size in order to minimise the amount of -// work the CPU has to do to service the DMA callbacks. -constexpr size_t kI2SBufferLengthFrames = 1024; - -/** - * Interface for a DAC that receives PCM samples over I2S. - */ -class I2SDac { - public: - static auto create(IGpios& expander) -> std::optional; - - I2SDac(IGpios& gpio, i2s_chan_handle_t i2s_handle); - ~I2SDac(); - - auto Start() -> void; - auto Stop() -> void; - auto SetPaused(bool) -> void; - - enum Channels { - CHANNELS_MONO, - CHANNELS_STEREO, - }; - enum BitsPerSample { - BPS_16 = I2S_DATA_BIT_WIDTH_16BIT, - BPS_24 = I2S_DATA_BIT_WIDTH_24BIT, - BPS_32 = I2S_DATA_BIT_WIDTH_32BIT, - }; - enum SampleRate { - SAMPLE_RATE_8 = 8000, - SAMPLE_RATE_32 = 32000, - SAMPLE_RATE_44_1 = 44100, - SAMPLE_RATE_48 = 48000, - SAMPLE_RATE_88_2 = 88200, - SAMPLE_RATE_96 = 96000, - }; - - auto Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) -> void; - - auto WriteData(const std::span& data) -> void; - auto SetSource(StreamBufferHandle_t buffer) -> void; - - // Not copyable or movable. - I2SDac(const I2SDac&) = delete; - I2SDac& operator=(const I2SDac&) = delete; - - private: - auto set_channel(bool) -> void; - - IGpios& gpio_; - i2s_chan_handle_t i2s_handle_; - bool i2s_active_; - StreamBufferHandle_t buffer_; - std::mutex configure_mutex_; - - i2s_std_clk_config_t clock_config_; - i2s_std_slot_config_t slot_config_; -}; - -} // namespace drivers diff --git a/src/drivers/include/nvs.hpp b/src/drivers/include/nvs.hpp deleted file mode 100644 index ac1a1096..00000000 --- a/src/drivers/include/nvs.hpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include -#include -#include - -#include "esp_err.h" -#include "nvs.h" - -#include "bluetooth_types.hpp" -#include "lru_cache.hpp" - -namespace drivers { - -/* - * Wrapper for a single NVS setting, with its backing value cached in memory. - * NVS values that are just plain old data should generally use these for - * simpler implementation. - */ -template -class Setting { - public: - Setting(const char* name) : name_(name), val_(), dirty_(false) {} - - auto set(const std::optional&& v) -> void { - if (val_.has_value() != v.has_value() || *val_ != *v) { - val_ = v; - dirty_ = true; - } - } - auto get() -> std::optional& { return val_; } - - /* Reads the stored value from NVS and parses it into the correct type. */ - auto load(nvs_handle_t) -> std::optional; - /* Encodes the given value and writes it to NVS. */ - auto store(nvs_handle_t, T v) -> void; - - auto read(nvs_handle_t nvs) -> void { val_ = load(nvs); } - auto write(nvs_handle_t nvs) -> void { - if (!dirty_) { - return; - } - dirty_ = false; - if (val_) { - store(nvs, *val_); - } else { - nvs_erase_key(nvs, name_); - } - } - - private: - const char* name_; - std::optional val_; - bool dirty_; -}; - -class NvsStorage { - public: - static auto OpenSync() -> NvsStorage*; - - auto Read() -> void; - auto Write() -> bool; - - // Hardware Compatibility - auto LockPolarity() -> bool; - auto LockPolarity(bool) -> void; - - auto DisplaySize() - -> std::pair, std::optional>; - auto DisplaySize(std::pair, std::optional>) - -> void; - - auto HapticMotorIsErm() -> bool; - auto HapticMotorIsErm(bool) -> void; - // /Hardware Compatibility - - auto PreferredBluetoothDevice() -> std::optional; - auto PreferredBluetoothDevice(std::optional) -> void; - - auto BluetoothVolume(const bluetooth::mac_addr_t&) -> uint8_t; - auto BluetoothVolume(const bluetooth::mac_addr_t&, uint8_t) -> void; - - enum class Output : uint8_t { - kHeadphones = 0, - kBluetooth = 1, - }; - auto OutputMode() -> Output; - auto OutputMode(Output) -> void; - - auto ScreenBrightness() -> uint_fast8_t; - auto ScreenBrightness(uint_fast8_t) -> void; - - auto ScrollSensitivity() -> uint_fast8_t; - auto ScrollSensitivity(uint_fast8_t) -> void; - - auto AmpMaxVolume() -> uint16_t; - auto AmpMaxVolume(uint16_t) -> void; - - auto AmpCurrentVolume() -> uint16_t; - auto AmpCurrentVolume(uint16_t) -> void; - - auto AmpLeftBias() -> int_fast8_t; - auto AmpLeftBias(int_fast8_t) -> void; - - enum class InputModes : uint8_t { - kButtonsOnly = 0, - kButtonsWithWheel = 1, - kDirectionalWheel = 2, - kRotatingWheel = 3, - }; - - auto PrimaryInput() -> InputModes; - auto PrimaryInput(InputModes) -> void; - - auto DbAutoIndex() -> bool; - auto DbAutoIndex(bool) -> void; - - explicit NvsStorage(nvs_handle_t); - ~NvsStorage(); - - private: - auto DowngradeSchemaSync() -> bool; - auto SchemaVersionSync() -> uint8_t; - - std::mutex mutex_; - nvs_handle_t handle_; - - Setting lock_polarity_; - Setting display_cols_; - Setting display_rows_; - Setting haptic_motor_type_; - - Setting brightness_; - Setting sensitivity_; - Setting amp_max_vol_; - Setting amp_cur_vol_; - Setting amp_left_bias_; - Setting input_mode_; - Setting output_mode_; - Setting bt_preferred_; - Setting db_auto_index_; - - util::LruCache<10, bluetooth::mac_addr_t, uint8_t> bt_volumes_; - bool bt_volumes_dirty_; - - auto readBtVolumes() -> void; - auto writeBtVolumes() -> void; -}; - -} // namespace drivers diff --git a/src/drivers/include/samd.hpp b/src/drivers/include/samd.hpp deleted file mode 100644 index 55ea513c..00000000 --- a/src/drivers/include/samd.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" - -namespace drivers { - -class Samd { - public: - static auto Create() -> Samd* { return new Samd(); } - - Samd(); - ~Samd(); - - auto Version() -> std::string; - - enum class ChargeStatus { - // There is no battery plugged into the device. - kNoBattery, - // The battery is discharging, and the current voltage level is very low. - kBatteryCritical, - // The battery is discharging. - kDischarging, - // The battery is charging over a low-current USB connection - kChargingRegular, - // The battery is charging over a high-current USB connection - kChargingFast, - // The battery is full charged, and we are still plugged in. - kFullCharge, - }; - - auto GetChargeStatus() -> std::optional; - auto UpdateChargeStatus() -> void; - - enum class UsbStatus { - // There is no compatible usb host attached. - kDetached, - // There is a compatible usb host attached, but USB MSC is not currently - // in use by the SAMD. - kAttachedIdle, - // The SAMD is currently writing to the SD card via USB MSC. - kAttachedBusy, - }; - - auto GetUsbStatus() -> UsbStatus; - auto UpdateUsbStatus() -> void; - - auto ResetToFlashSamd() -> void; - auto PowerDown() -> void; - - auto UsbMassStorage(bool en) -> void; - auto UsbMassStorage() -> bool; - - // Not copyable or movable. There should usually only ever be once instance - // of this class, and that instance will likely have a static lifetime. - Samd(const Samd&) = delete; - Samd& operator=(const Samd&) = delete; - - private: - uint8_t version_; - std::optional charge_status_; - UsbStatus usb_status_; -}; - -} // namespace drivers diff --git a/src/drivers/include/spi.hpp b/src/drivers/include/spi.hpp deleted file mode 100644 index 60638f71..00000000 --- a/src/drivers/include/spi.hpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include -#include "esp_err.h" - -namespace drivers { - -esp_err_t init_spi(void); -esp_err_t deinit_spi(void); -std::lock_guard acquire_spi(void); - -} // namespace drivers diff --git a/src/drivers/include/spiffs.hpp b/src/drivers/include/spiffs.hpp deleted file mode 100644 index 04478590..00000000 --- a/src/drivers/include/spiffs.hpp +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include "esp_err.h" - -namespace drivers { - -esp_err_t spiffs_mount(); - -} // namespace drivers diff --git a/src/drivers/include/storage.hpp b/src/drivers/include/storage.hpp deleted file mode 100644 index 836bbbdc..00000000 --- a/src/drivers/include/storage.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include - -#include "driver/sdmmc_types.h" -#include "driver/sdspi_host.h" -#include "esp_err.h" -#include "esp_vfs_fat.h" -#include "ff.h" -#include "result.hpp" - -#include "gpios.hpp" - -namespace drivers { - -extern const char* kStoragePath; - -enum class SdState { - kNotPresent, - kNotFormatted, - kNotMounted, - kMounted, -}; - -class SdStorage { - public: - enum Error { - FAILED_TO_INIT, - /** We couldn't interact with the SD card at all. Is it missing? */ - FAILED_TO_READ, - /** We couldn't mount the SD card. Is it formatted? */ - FAILED_TO_MOUNT, - }; - - static auto Create(IGpios& gpio) -> cpp::result; - - SdStorage(IGpios& gpio, - sdspi_dev_handle_t handle_, - std::unique_ptr host_, - std::unique_ptr card_, - FATFS* fs_); - ~SdStorage(); - - auto HandleTransaction(sdspi_dev_handle_t handle, sdmmc_command_t* cmdinfo) - -> esp_err_t; - - auto GetFs() -> FATFS*; - - // Not copyable or movable. - SdStorage(const SdStorage&) = delete; - SdStorage& operator=(const SdStorage&) = delete; - - private: - IGpios& gpio_; - - // SPI and SD driver info - sdspi_dev_handle_t handle_; - std::unique_ptr host_; - std::unique_ptr card_; - - // Filesystem info - FATFS* fs_ = nullptr; -}; - -} // namespace drivers diff --git a/src/drivers/include/touchwheel.hpp b/src/drivers/include/touchwheel.hpp deleted file mode 100644 index 18ace2b4..00000000 --- a/src/drivers/include/touchwheel.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include -#include - -#include "esp_err.h" -#include "result.hpp" - -#include "gpios.hpp" - -namespace drivers { - -struct TouchWheelData { - bool is_wheel_touched = false; - bool is_button_touched = false; - uint8_t wheel_position = -1; -}; - -class TouchWheel { - public: - static auto isAngleWithin(int16_t wheel_angle, - int16_t target_angle, - int threshold) -> bool; - - static auto Create() -> TouchWheel* { return new TouchWheel(); } - TouchWheel(); - ~TouchWheel(); - - // Not copyable or movable. - TouchWheel(const TouchWheel&) = delete; - TouchWheel& operator=(const TouchWheel&) = delete; - - auto Update() -> void; - auto GetTouchWheelData() const -> TouchWheelData; - - auto PowerDown() -> void; - - private: - TouchWheelData data_; - - enum Register { - FIRMWARE_VERSION = 1, - DETECTION_STATUS = 2, - KEY_STATUS_A = 3, - KEY_STATUS_B = 4, - SLIDER_POSITION = 5, - CALIBRATE = 6, - RESET = 7, - LOW_POWER = 8, - RECALIBRATION_DELAY = 12, - SLIDER_OPTIONS = 14, - CHARGE_TIME = 15, - DETECT_THRESHOLD_BASE = 16, - KEY_CONTROL_BASE = 28, - PULSE_SCALE_BASE = 40, - }; - - void WriteRegister(uint8_t reg, uint8_t val); - uint8_t ReadRegister(uint8_t reg); -}; - -} // namespace drivers diff --git a/src/drivers/include/wm8523.hpp b/src/drivers/include/wm8523.hpp deleted file mode 100644 index a64f6bac..00000000 --- a/src/drivers/include/wm8523.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ -#pragma once - -#include -#include -#include - -namespace drivers { -namespace wm8523 { - -extern const uint16_t kAbsoluteMaxVolume; - -extern const uint16_t kAbsoluteMinVolume; - -extern const uint16_t kMaxVolumeBeforeClipping; - -extern const uint16_t kLineLevelReferenceVolume; - -extern const uint16_t kDefaultVolume; -extern const uint16_t kDefaultMaxVolume; - -extern const uint16_t kZeroDbVolume; - -constexpr auto VolumeToDb(uint16_t vol) -> int_fast8_t { - return (vol - kLineLevelReferenceVolume) / 4; -} - -constexpr auto DbToVolume(int_fast8_t db) -> uint16_t { - return (db * 4) + kLineLevelReferenceVolume; -} - -enum class Register : uint8_t { - kReset = 0, - kRevision = 1, - kPsCtrl = 2, - kAifCtrl1 = 3, - kAifCtrl2 = 4, - kDacCtrl = 5, - kDacGainLeft = 6, - kDacGainRight = 7, - kZeroDetect = 8, -}; - -auto ReadRegister(Register reg) -> std::optional; -auto WriteRegister(Register reg, uint16_t data) -> bool; -auto WriteRegister(Register reg, uint8_t msb, uint8_t lsb) -> bool; - -} // namespace wm8523 -} // namespace drivers -- cgit v1.2.3