Generalise the lvgl input driver in preparation for more input methods

custom
jacqueline 2 years ago
parent f2bad894cd
commit 7d5536e2ab
  1. 26
      src/system_fsm/booting.cpp
  2. 2
      src/ui/CMakeLists.txt
  3. 46
      src/ui/encoder_input.cpp
  4. 47
      src/ui/include/encoder_input.hpp
  5. 9
      src/ui/include/lvgl_task.hpp
  6. 4
      src/ui/include/ui_fsm.hpp
  7. 33
      src/ui/include/wheel_encoder.hpp
  8. 18
      src/ui/lvgl_task.cpp
  9. 13
      src/ui/ui_fsm.cpp
  10. 44
      src/ui/wheel_encoder.cpp

@ -4,39 +4,37 @@
* SPDX-License-Identifier: GPL-3.0-only
*/
#include "system_fsm.hpp"
#include <stdint.h>
#include "adc.hpp"
#include "assert.h"
#include "audio_fsm.hpp"
#include "battery.hpp"
#include "bluetooth.hpp"
#include "bluetooth_types.hpp"
#include "core/lv_obj.h"
#include "display_init.hpp"
#include "esp_err.h"
#include "esp_log.h"
#include "event_queue.hpp"
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
#include "freertos/projdefs.h"
#include "freertos/timers.h"
#include "adc.hpp"
#include "audio_fsm.hpp"
#include "battery.hpp"
#include "bluetooth.hpp"
#include "bluetooth_types.hpp"
#include "display_init.hpp"
#include "event_queue.hpp"
#include "gpios.hpp"
#include "lvgl/lvgl.h"
#include "i2c.hpp"
#include "nvs.hpp"
#include "relative_wheel.hpp"
#include "samd.hpp"
#include "service_locator.hpp"
#include "spi.hpp"
#include "system_events.hpp"
#include "system_fsm.hpp"
#include "tag_parser.hpp"
#include "touchwheel.hpp"
#include "track_queue.hpp"
#include "ui_fsm.hpp"
#include "i2c.hpp"
#include "touchwheel.hpp"
namespace system_fsm {
namespace states {

@ -4,7 +4,7 @@
idf_component_register(
SRCS "lvgl_task.cpp" "ui_fsm.cpp" "screen_splash.cpp" "screen_menu.cpp"
"wheel_encoder.cpp" "screen_track_browser.cpp" "screen_playing.cpp"
"encoder_input.cpp" "screen_track_browser.cpp" "screen_playing.cpp"
"themes.cpp" "widget_top_bar.cpp" "screen.cpp" "screen_onboarding.cpp"
"modal_progress.cpp" "modal.cpp" "modal_confirm.cpp" "screen_settings.cpp"
"event_binding.cpp"

@ -0,0 +1,46 @@
/*
* Copyright 2023 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#include "encoder_input.hpp"
#include <sys/_stdint.h>
#include <memory>
#include "core/lv_group.h"
#include "gpios.hpp"
#include "hal/lv_hal_indev.h"
#include "relative_wheel.hpp"
#include "touchwheel.hpp"
namespace ui {
static void encoder_read(lv_indev_drv_t* drv, lv_indev_data_t* data) {
EncoderInput* instance = reinterpret_cast<EncoderInput*>(drv->user_data);
instance->Read(data);
}
EncoderInput::EncoderInput(drivers::IGpios& gpios, drivers::TouchWheel& wheel)
: gpios_(gpios),
raw_wheel_(wheel),
relative_wheel_(std::make_unique<drivers::RelativeWheel>(wheel)) {
lv_indev_drv_init(&driver_);
driver_.type = LV_INDEV_TYPE_ENCODER;
driver_.read_cb = encoder_read;
driver_.user_data = this;
registration_ = lv_indev_drv_register(&driver_);
}
auto EncoderInput::Read(lv_indev_data_t* data) -> void {
raw_wheel_.Update();
relative_wheel_->Update();
data->enc_diff = relative_wheel_->ticks();
data->state = relative_wheel_->is_clicking() ? LV_INDEV_STATE_PRESSED
: LV_INDEV_STATE_RELEASED;
}
} // namespace ui

@ -0,0 +1,47 @@
/*
* Copyright 2023 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#pragma once
#include <memory>
#include "core/lv_group.h"
#include "gpios.hpp"
#include "hal/lv_hal_indev.h"
#include "relative_wheel.hpp"
#include "touchwheel.hpp"
namespace ui {
/*
* Main input device abstracting that handles turning lower-level input device
* drivers into events and LVGL inputs.
*
* As far as LVGL is concerned, this class represents an ordinary rotary
* encoder, supporting only left and right ticks, and clicking.
*/
class EncoderInput {
public:
EncoderInput(drivers::IGpios& gpios, drivers::TouchWheel& wheel);
auto Read(lv_indev_data_t* data) -> void;
auto registration() -> lv_indev_t* { return registration_; }
auto lock(bool l) -> void { is_locked_ = l; }
private:
lv_indev_drv_t driver_;
lv_indev_t* registration_;
drivers::IGpios& gpios_;
drivers::TouchWheel& raw_wheel_;
std::unique_ptr<drivers::RelativeWheel> relative_wheel_;
bool is_locked_;
};
} // namespace ui

@ -15,30 +15,27 @@
#include "freertos/timers.h"
#include "display.hpp"
#include "encoder_input.hpp"
#include "relative_wheel.hpp"
#include "screen.hpp"
#include "themes.hpp"
#include "touchwheel.hpp"
#include "wheel_encoder.hpp"
namespace ui {
class UiTask {
public:
static auto Start() -> UiTask*;
~UiTask();
// FIXME: Once we have more input devices, this function should accept a more
// generic interface.
auto SetInputDevice(std::shared_ptr<TouchWheelEncoder> dev) -> void;
auto input(std::shared_ptr<EncoderInput> input) -> void;
private:
UiTask();
auto Main() -> void;
std::shared_ptr<TouchWheelEncoder> input_device_;
std::shared_ptr<EncoderInput> input_;
std::shared_ptr<Screen> current_screen_;
};

@ -26,6 +26,7 @@
#include "tinyfsm.hpp"
#include "display.hpp"
#include "encoder_input.hpp"
#include "modal.hpp"
#include "screen.hpp"
#include "storage.hpp"
@ -34,7 +35,6 @@
#include "track.hpp"
#include "track_queue.hpp"
#include "ui_events.hpp"
#include "wheel_encoder.hpp"
namespace ui {
@ -87,7 +87,7 @@ class UiState : public tinyfsm::Fsm<UiState> {
static std::unique_ptr<UiTask> sTask;
static std::shared_ptr<system_fsm::ServiceLocator> sServices;
static std::unique_ptr<drivers::Display> sDisplay;
static std::shared_ptr<TouchWheelEncoder> sEncoder;
static std::shared_ptr<EncoderInput> sInput;
static std::stack<std::shared_ptr<Screen>> sScreens;
static std::shared_ptr<Screen> sCurrentScreen;

@ -1,33 +0,0 @@
/*
* Copyright 2023 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#pragma once
#include <memory>
#include "core/lv_group.h"
#include "hal/lv_hal_indev.h"
#include "relative_wheel.hpp"
namespace ui {
class TouchWheelEncoder {
public:
explicit TouchWheelEncoder(std::unique_ptr<drivers::RelativeWheel> wheel);
auto Read(lv_indev_data_t* data) -> void;
auto registration() -> lv_indev_t* { return registration_; }
private:
lv_indev_drv_t driver_;
lv_indev_t* registration_;
lv_key_t last_key_;
std::unique_ptr<drivers::RelativeWheel> wheel_;
};
} // namespace ui

@ -40,7 +40,6 @@
#include "tasks.hpp"
#include "touchwheel.hpp"
#include "ui_fsm.hpp"
#include "wheel_encoder.hpp"
#include "widgets/lv_label.h"
#include "display.hpp"
@ -67,15 +66,15 @@ auto UiTask::Main() -> void {
std::shared_ptr<Screen> screen = UiState::current_screen();
if (screen != current_screen_ && screen != nullptr) {
lv_scr_load(screen->root());
if (input_device_) {
lv_indev_set_group(input_device_->registration(), screen->group());
if (input_) {
lv_indev_set_group(input_->registration(), screen->group());
}
current_screen_ = screen;
}
if (input_device_ && current_screen_->group() != current_group) {
if (input_ && current_screen_->group() != current_group) {
current_group = current_screen_->group();
lv_indev_set_group(input_device_->registration(), current_group);
lv_indev_set_group(input_->registration(), current_group);
}
if (current_screen_) {
@ -87,11 +86,10 @@ auto UiTask::Main() -> void {
}
}
auto UiTask::SetInputDevice(std::shared_ptr<TouchWheelEncoder> dev) -> void {
input_device_ = std::move(dev);
if (current_screen_ && input_device_) {
lv_indev_set_group(input_device_->registration(), current_screen_->group());
}
auto UiTask::input(std::shared_ptr<EncoderInput> input) -> void {
assert(current_screen_);
input_ = input;
lv_indev_set_group(input_->registration(), current_screen_->group());
}
auto UiTask::Start() -> UiTask* {

@ -15,6 +15,7 @@
#include "audio_events.hpp"
#include "display.hpp"
#include "encoder_input.hpp"
#include "event_queue.hpp"
#include "gpios.hpp"
#include "lvgl_task.hpp"
@ -35,7 +36,6 @@
#include "touchwheel.hpp"
#include "track_queue.hpp"
#include "ui_events.hpp"
#include "wheel_encoder.hpp"
#include "widget_top_bar.hpp"
namespace ui {
@ -47,7 +47,7 @@ static const std::size_t kRecordsPerPage = 15;
std::unique_ptr<UiTask> UiState::sTask;
std::shared_ptr<system_fsm::ServiceLocator> UiState::sServices;
std::unique_ptr<drivers::Display> UiState::sDisplay;
std::shared_ptr<TouchWheelEncoder> UiState::sEncoder;
std::shared_ptr<EncoderInput> UiState::sInput;
std::stack<std::shared_ptr<Screen>> UiState::sScreens;
std::shared_ptr<Screen> UiState::sCurrentScreen;
@ -88,8 +88,7 @@ void UiState::PopScreen() {
void UiState::react(const system_fsm::KeyLockChanged& ev) {
sDisplay->SetDisplayOn(ev.falling);
sTask->SetInputDevice(ev.falling ? sEncoder
: std::shared_ptr<TouchWheelEncoder>());
sInput->lock(!ev.falling);
}
void UiState::react(const system_fsm::BatteryStateChanged& ev) {
@ -138,10 +137,8 @@ void Splash::react(const system_fsm::BootComplete& ev) {
auto touchwheel = sServices->touchwheel();
if (touchwheel) {
auto relative_wheel =
std::make_unique<drivers::RelativeWheel>(**touchwheel);
sEncoder = std::make_shared<TouchWheelEncoder>(std::move(relative_wheel));
sTask->SetInputDevice(sEncoder);
sInput = std::make_shared<EncoderInput>(sServices->gpios(), **touchwheel);
sTask->input(sInput);
} else {
ESP_LOGE(kTag, "no input devices initialised!");
}

@ -1,44 +0,0 @@
/*
* Copyright 2023 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#include "wheel_encoder.hpp"
#include <sys/_stdint.h>
#include "core/lv_group.h"
#include "hal/lv_hal_indev.h"
namespace ui {
void encoder_read(lv_indev_drv_t* drv, lv_indev_data_t* data) {
TouchWheelEncoder* instance =
reinterpret_cast<TouchWheelEncoder*>(drv->user_data);
instance->Read(data);
}
void encoder_feedback(lv_indev_drv_t* drv, uint8_t event_code) {
ESP_LOGI("Touchwheel Event", "Event code: %d", event_code);
}
TouchWheelEncoder::TouchWheelEncoder(
std::unique_ptr<drivers::RelativeWheel> wheel)
: last_key_(0), wheel_(std::move(wheel)) {
lv_indev_drv_init(&driver_);
driver_.type = LV_INDEV_TYPE_ENCODER;
driver_.read_cb = encoder_read;
// driver_.feedback_cb = encoder_feedback;
driver_.user_data = this;
registration_ = lv_indev_drv_register(&driver_);
}
auto TouchWheelEncoder::Read(lv_indev_data_t* data) -> void {
wheel_->Update();
data->enc_diff = wheel_->ticks();
data->state =
wheel_->is_clicking() ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
}
} // namespace ui
Loading…
Cancel
Save