diff --git a/lib/esp-adf b/lib/esp-adf new file mode 160000 index 00000000..9ffbb5a1 --- /dev/null +++ b/lib/esp-adf @@ -0,0 +1 @@ +Subproject commit 9ffbb5a1b8be06484e23e67202607e6b0b0d3a8e diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt index c4e4c172..bf8f0c4e 100644 --- a/src/drivers/CMakeLists.txt +++ b/src/drivers/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - SRCS "dac.cpp" "gpio_expander.cpp" "battery.cpp" "storage.cpp" "i2c.cpp" + SRCS "touchwheel.cpp" "dac.cpp" "gpio_expander.cpp" "battery.cpp" "storage.cpp" "i2c.cpp" "spi.cpp" "display.cpp" "display_init.cpp" INCLUDE_DIRS "include" REQUIRES "esp_adc" "fatfs" "result" "lvgl" "span") diff --git a/src/drivers/i2c.cpp b/src/drivers/i2c.cpp index 04a6d7d1..a66f54f0 100644 --- a/src/drivers/i2c.cpp +++ b/src/drivers/i2c.cpp @@ -36,6 +36,10 @@ esp_err_t init_i2c(void) { if (esp_err_t err = i2c_driver_install(kI2CPort, config.mode, 0, 0, 0)) { return err; } + if (esp_err_t err = i2c_set_timeout(kI2CPort, 400000)) { + return err; + } + // TODO: INT line @@ -57,8 +61,8 @@ I2CTransaction::~I2CTransaction() { free(buffer_); } -esp_err_t I2CTransaction::Execute() { - return i2c_master_cmd_begin(I2C_NUM_0, handle_, kI2CTimeout); +esp_err_t I2CTransaction::Execute(uint8_t port) { + return i2c_master_cmd_begin(port, handle_, kI2CTimeout); } I2CTransaction& I2CTransaction::start() { diff --git a/src/drivers/include/i2c.hpp b/src/drivers/include/i2c.hpp index dbdd8a11..811c9333 100644 --- a/src/drivers/include/i2c.hpp +++ b/src/drivers/include/i2c.hpp @@ -35,7 +35,7 @@ class I2CTransaction { * 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(); + esp_err_t Execute(uint8_t port = I2C_NUM_0); /* * Enqueues a start condition. May also be used for repeated start diff --git a/src/drivers/include/touchwheel.hpp b/src/drivers/include/touchwheel.hpp new file mode 100644 index 00000000..14215acd --- /dev/null +++ b/src/drivers/include/touchwheel.hpp @@ -0,0 +1,60 @@ +#pragma once + + +#include +#include + +#include "esp_err.h" +#include "result.hpp" + +#include "gpio_expander.hpp" + +namespace drivers { + +struct TouchWheelData { + bool is_touched = false; + uint8_t wheel_position = -1; +}; + +class TouchWheel { + public: + enum Error { + FAILED_TO_BOOT, + FAILED_TO_CONFIGURE, + }; + static auto create(GpioExpander* expander) + -> cpp::result, Error>; + + TouchWheel(GpioExpander* gpio); + ~TouchWheel(); + + // Not copyable or movable. + TouchWheel(const TouchWheel&) = delete; + TouchWheel& operator=(const TouchWheel&) = delete; + + auto Update() -> void; + auto GetTouchWheelData() const -> TouchWheelData; + + private: + GpioExpander* gpio_; + TouchWheelData data_; + + enum Register { + FIRMWARE_VERSION = 0x1, + DETECTION_STATUS = 0x2, + KEY_STATUS_A = 0x3, + KEY_STATUS_B = 0x4, + SLIDER_POSITION = 0x5, + CALIBRATE = 0x6, + RESET = 0x7, + LOW_POWER = 0x8, + SLIDER_OPTIONS = 0x14, + }; + + + void WriteRegister(uint8_t reg, uint8_t val); + void ReadRegister(uint8_t reg, uint8_t* data, uint8_t count); + +}; + +} // namespace drivers diff --git a/src/drivers/touchwheel.cpp b/src/drivers/touchwheel.cpp new file mode 100644 index 00000000..11a115fb --- /dev/null +++ b/src/drivers/touchwheel.cpp @@ -0,0 +1,92 @@ +#include "touchwheel.hpp" + +#include + +#include "assert.h" +#include "driver/i2c.h" +#include "esp_err.h" +#include "esp_log.h" +#include "hal/i2c_types.h" + +#include "i2c.hpp" + +namespace drivers { + +static const char* kTag = "TOUCHWHEEL"; +static const uint8_t kTouchWheelAddress = 0x1C; + +static const uint8_t kWriteMask = 0x80; +static const uint8_t kReadMask = 0xA0; + +double normalise(uint16_t min, uint16_t max, uint16_t value) { + if (value >= max) { + return 1.0; + } + if (value <= min) { + return 0.0; + } + uint16_t range = max - min; + return (double)(value - min) / range; +} + + +auto TouchWheel::create(GpioExpander* expander) + -> cpp::result, Error> { + std::unique_ptr wheel = std::make_unique(expander); + wheel->WriteRegister(Register::SLIDER_OPTIONS, 0xC0); + return wheel; +} + +TouchWheel::TouchWheel(GpioExpander* gpio) { + this->gpio_ = gpio; +}; + +TouchWheel::~TouchWheel(){ +}; + +void TouchWheel::WriteRegister(uint8_t reg, uint8_t val) { + // uint8_t maskedReg = reg | kWriteMask; + uint8_t maskedReg = reg; + I2CTransaction transaction; + transaction.start() + .write_addr(kTouchWheelAddress, I2C_MASTER_WRITE) + .write_ack(maskedReg, val) + .stop(); + ESP_ERROR_CHECK(transaction.Execute()); +} + +void TouchWheel::ReadRegister(uint8_t reg, uint8_t* data, uint8_t count) { + // uint8_t maskedReg = reg | kReadMask; + uint8_t maskedReg = reg; + + if (count <= 0) { + return; + } + + I2CTransaction transaction; + transaction.start() + .write_addr(kTouchWheelAddress, I2C_MASTER_WRITE) + .write_ack(maskedReg) + .stop() + .start() + .write_addr(kTouchWheelAddress, I2C_MASTER_READ) + .read(data, I2C_MASTER_NACK) + .stop(); + + // TODO: Handle errors here. + ESP_ERROR_CHECK(transaction.Execute()); +} + +void TouchWheel::Update() { + // Read data from device into member struct + uint8_t position; + this->ReadRegister(Register::SLIDER_POSITION, &position, 1); + data_.wheel_position = position; +} + +TouchWheelData TouchWheel::GetTouchWheelData() const { + return data_; +} + + +} // namespace drivers diff --git a/src/main/main.cpp b/src/main/main.cpp index 91e17451..bd0a06af 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -35,6 +35,7 @@ #include "i2c.hpp" #include "spi.hpp" #include "storage.hpp" +#include "touchwheel.hpp" static const char* TAG = "MAIN"; @@ -102,6 +103,7 @@ extern "C" void app_main(void) { ESP_LOGI(TAG, "Enable power rails for development"); expander->with([&](auto& gpio) { gpio.set_pin(drivers::GpioExpander::AUDIO_POWER_ENABLE, 1); + gpio.set_pin(drivers::GpioExpander::DISPLAY_LED, 0); gpio.set_pin(drivers::GpioExpander::USB_INTERFACE_POWER_ENABLE, 0); gpio.set_pin(drivers::GpioExpander::SD_CARD_POWER_ENABLE, 1); gpio.set_pin(drivers::GpioExpander::SD_MUX_SWITCH, @@ -121,6 +123,15 @@ extern "C" void app_main(void) { storage = std::move(storage_res.value()); } + ESP_LOGI(TAG, "Init touch wheel"); + auto touchwheel_res = drivers::TouchWheel::create(expander); + std::shared_ptr touchwheel; + if (touchwheel_res.has_error()) { + ESP_LOGE(TAG, "Failed!"); + } else { + touchwheel = std::move(touchwheel_res.value()); + } + LvglArgs* lvglArgs = (LvglArgs*)calloc(1, sizeof(LvglArgs)); lvglArgs->gpio_expander = expander; xTaskCreateStaticPinnedToCore(&lvgl_main, "LVGL", kLvglStackSize, @@ -146,6 +157,8 @@ extern "C" void app_main(void) { console.Launch(); while (1) { + touchwheel->Update(); + ESP_LOGI(TAG, "Touch wheel pos: %d", touchwheel->GetTouchWheelData().wheel_position); vTaskDelay(pdMS_TO_TICKS(100)); } }