diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp index 7914a5c3..08a1c083 100644 --- a/src/system_fsm/booting.cpp +++ b/src/system_fsm/booting.cpp @@ -4,39 +4,37 @@ * SPDX-License-Identifier: GPL-3.0-only */ +#include "system_fsm.hpp" + #include -#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 { diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index e331d96f..5f2d64d7 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -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" diff --git a/src/ui/encoder_input.cpp b/src/ui/encoder_input.cpp new file mode 100644 index 00000000..62cb4c8b --- /dev/null +++ b/src/ui/encoder_input.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "encoder_input.hpp" + +#include +#include + +#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(drv->user_data); + instance->Read(data); +} + +EncoderInput::EncoderInput(drivers::IGpios& gpios, drivers::TouchWheel& wheel) + : gpios_(gpios), + raw_wheel_(wheel), + relative_wheel_(std::make_unique(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 diff --git a/src/ui/include/encoder_input.hpp b/src/ui/include/encoder_input.hpp new file mode 100644 index 00000000..9c114e80 --- /dev/null +++ b/src/ui/include/encoder_input.hpp @@ -0,0 +1,47 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include + +#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 relative_wheel_; + + bool is_locked_; +}; + +} // namespace ui diff --git a/src/ui/include/lvgl_task.hpp b/src/ui/include/lvgl_task.hpp index 4362249b..f212ab9d 100644 --- a/src/ui/include/lvgl_task.hpp +++ b/src/ui/include/lvgl_task.hpp @@ -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 dev) -> void; + auto input(std::shared_ptr input) -> void; private: UiTask(); auto Main() -> void; - std::shared_ptr input_device_; + std::shared_ptr input_; std::shared_ptr current_screen_; }; diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp index 24f0c270..4db8257d 100644 --- a/src/ui/include/ui_fsm.hpp +++ b/src/ui/include/ui_fsm.hpp @@ -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 { static std::unique_ptr sTask; static std::shared_ptr sServices; static std::unique_ptr sDisplay; - static std::shared_ptr sEncoder; + static std::shared_ptr sInput; static std::stack> sScreens; static std::shared_ptr sCurrentScreen; diff --git a/src/ui/include/wheel_encoder.hpp b/src/ui/include/wheel_encoder.hpp deleted file mode 100644 index fcac5edd..00000000 --- a/src/ui/include/wheel_encoder.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include - -#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 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 wheel_; -}; - -} // namespace ui diff --git a/src/ui/lvgl_task.cpp b/src/ui/lvgl_task.cpp index 74f68cf5..ff85a055 100644 --- a/src/ui/lvgl_task.cpp +++ b/src/ui/lvgl_task.cpp @@ -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 = 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 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 input) -> void { + assert(current_screen_); + input_ = input; + lv_indev_set_group(input_->registration(), current_screen_->group()); } auto UiTask::Start() -> UiTask* { diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp index f66e3e8a..bc976eab 100644 --- a/src/ui/ui_fsm.cpp +++ b/src/ui/ui_fsm.cpp @@ -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 UiState::sTask; std::shared_ptr UiState::sServices; std::unique_ptr UiState::sDisplay; -std::shared_ptr UiState::sEncoder; +std::shared_ptr UiState::sInput; std::stack> UiState::sScreens; std::shared_ptr 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()); + 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(**touchwheel); - sEncoder = std::make_shared(std::move(relative_wheel)); - sTask->SetInputDevice(sEncoder); + sInput = std::make_shared(sServices->gpios(), **touchwheel); + sTask->input(sInput); } else { ESP_LOGE(kTag, "no input devices initialised!"); } diff --git a/src/ui/wheel_encoder.cpp b/src/ui/wheel_encoder.cpp deleted file mode 100644 index 2f2e7f68..00000000 --- a/src/ui/wheel_encoder.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#include "wheel_encoder.hpp" -#include -#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(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 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