diff options
Diffstat (limited to 'src/drivers/gpio_expander.cpp')
| -rw-r--r-- | src/drivers/gpio_expander.cpp | 101 |
1 files changed, 83 insertions, 18 deletions
diff --git a/src/drivers/gpio_expander.cpp b/src/drivers/gpio_expander.cpp index 87c5d038..5a9bb83e 100644 --- a/src/drivers/gpio_expander.cpp +++ b/src/drivers/gpio_expander.cpp @@ -5,35 +5,97 @@ */ #include "gpio_expander.hpp" +#include <stdint.h> #include <cstdint> +#include "driver/gpio.h" +#include "hal/gpio_types.h" #include "i2c.hpp" namespace drivers { -GpioExpander::GpioExpander() { - ports_ = pack(kPortADefault, kPortBDefault); - // Read and write initial values on initialisation so that we do not have a - // strange partially-initialised state. - // TODO: log or abort if these error; it's really bad! - Write(); - Read(); +static const uint8_t kPca8575Address = 0x20; + +// Port A: +// 0 - sd card mux switch +// 1 - sd card mux enable (active low) +// 2 - key up +// 3 - key down +// 4 - key lock +// 5 - display reset (active low) +// 6 - NC +// 7 - sd card power (active low) +// Default to SD card off, inputs high. +static const uint8_t kPortADefault = 0b10111110; + +// Port B: +// 0 - 3.5mm jack detect (active low) +// 1 - headphone amp power enable +// 2 - volume zero-cross detection +// 3 - volume direction +// 4 - volume left channel +// 5 - volume right channel +// 6 - NC +// 7 - NC +// Default input high, trs output low +static const uint8_t kPortBDefault = 0b00000011; + +/* + * Convenience mehod for packing the port a and b bytes into a single 16 bit + * value. + */ +constexpr uint16_t pack(uint8_t a, uint8_t b) { + return ((uint16_t)b) << 8 | a; } -GpioExpander::~GpioExpander() {} +/* + * Convenience mehod for unpacking the result of `pack` back into two single + * byte port datas. + */ +constexpr std::pair<uint8_t, uint8_t> unpack(uint16_t ba) { + return std::pair((uint8_t)ba, (uint8_t)(ba >> 8)); +} -void GpioExpander::with(std::function<void(GpioExpander&)> f) { - f(*this); - Write(); +void interrupt_isr(void* arg) { + GpioExpander* instance = reinterpret_cast<GpioExpander*>(arg); + auto listener = instance->listener().lock(); + if (listener) { + std::invoke(*listener); + } } -esp_err_t GpioExpander::Write() { - i2c_cmd_handle_t handle = i2c_cmd_link_create(); - if (handle == NULL) { - return ESP_ERR_NO_MEM; +auto GpioExpander::Create() -> GpioExpander* { + GpioExpander* instance = new GpioExpander(); + // Read and write initial values on initialisation so that we do not have a + // strange partially-initialised state. + if (!instance->Write() || !instance->Read()) { + return nullptr; } + return instance; +} + +GpioExpander::GpioExpander() + : ports_(pack(kPortADefault, kPortBDefault)), inputs_(0), listener_() { + gpio_config_t config{ + .pin_bit_mask = static_cast<uint64_t>(1) << GPIO_NUM_34, + .mode = GPIO_MODE_INPUT, + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_NEGEDGE, + }; + gpio_config(&config); + gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | + ESP_INTR_FLAG_IRAM); + gpio_isr_handler_add(GPIO_NUM_34, &interrupt_isr, this); +} + +GpioExpander::~GpioExpander() { + gpio_isr_handler_remove(GPIO_NUM_34); + gpio_uninstall_isr_service(); +} +bool GpioExpander::Write() { std::pair<uint8_t, uint8_t> ports_ab = unpack(ports()); I2CTransaction transaction; @@ -42,10 +104,10 @@ esp_err_t GpioExpander::Write() { .write_ack(ports_ab.first, ports_ab.second) .stop(); - return transaction.Execute(); + return transaction.Execute() == ESP_OK; } -esp_err_t GpioExpander::Read() { +bool GpioExpander::Read() { uint8_t input_a, input_b; I2CTransaction transaction; @@ -56,8 +118,11 @@ esp_err_t GpioExpander::Read() { .stop(); esp_err_t ret = transaction.Execute(); + if (ret != ESP_OK) { + return false; + } inputs_ = pack(input_a, input_b); - return ret; + return true; } void GpioExpander::set_pin(Pin pin, bool value) { |
