summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-06-01 15:28:32 +1000
committerjacqueline <me@jacqueline.id.au>2023-06-01 15:28:54 +1000
commit6fd588e970470b15936187980829916d0dbe77bb (patch)
tree1b1e73ef52bef2e41499ee5ceadc45efd408050b
parentdb2e29a72d9b934e7b58f1d20ac3768eae484ab5 (diff)
downloadtangara-fw-6fd588e970470b15936187980829916d0dbe77bb.tar.gz
Add touchwheel -> encoder adapter
-rw-r--r--src/app_console/app_console.cpp80
-rw-r--r--src/drivers/CMakeLists.txt2
-rw-r--r--src/drivers/display.cpp32
-rw-r--r--src/drivers/include/relative_wheel.hpp44
-rw-r--r--src/drivers/relative_wheel.cpp78
-rw-r--r--src/events/event_queue.cpp3
-rw-r--r--src/events/include/event_queue.hpp14
-rw-r--r--src/system_fsm/booting.cpp16
-rw-r--r--src/system_fsm/include/system_fsm.hpp2
-rw-r--r--src/system_fsm/system_fsm.cpp2
-rw-r--r--src/tasks/tasks.cpp2
-rw-r--r--src/ui/CMakeLists.txt2
-rw-r--r--src/ui/include/lvgl_task.hpp3
-rw-r--r--src/ui/include/screen.hpp28
-rw-r--r--src/ui/include/screen_menu.hpp29
-rw-r--r--src/ui/include/screen_splash.hpp30
-rw-r--r--src/ui/include/ui_fsm.hpp10
-rw-r--r--src/ui/include/ui_tick.hpp11
-rw-r--r--src/ui/include/wheel_encoder.hpp30
-rw-r--r--src/ui/lvgl_task.cpp16
-rw-r--r--src/ui/screen_menu.cpp52
-rw-r--r--src/ui/screen_splash.cpp38
-rw-r--r--src/ui/ui_fsm.cpp12
-rw-r--r--src/ui/wheel_encoder.cpp39
24 files changed, 463 insertions, 112 deletions
diff --git a/src/app_console/app_console.cpp b/src/app_console/app_console.cpp
index 23e8875e..39d6d8e0 100644
--- a/src/app_console/app_console.cpp
+++ b/src/app_console/app_console.cpp
@@ -14,9 +14,12 @@
#include <iostream>
#include <string>
+#include "audio_events.hpp"
+#include "audio_fsm.hpp"
#include "database.hpp"
#include "esp_console.h"
#include "esp_log.h"
+#include "event_queue.hpp"
namespace console {
@@ -66,7 +69,7 @@ void RegisterListDir() {
esp_console_cmd_register(&cmd);
}
-/*
+ //sInstance->playback_->Play(path + argv[1]);
int CmdPlayFile(int argc, char** argv) {
static const std::string usage = "usage: play [file]";
if (argc != 2) {
@@ -75,7 +78,9 @@ int CmdPlayFile(int argc, char** argv) {
}
std::string path = "/";
- sInstance->playback_->Play(path + argv[1]);
+
+ events::Dispatch<audio::PlayFile, audio::AudioState>(
+ audio::PlayFile{ .filename = path + argv[1] });
return 0;
}
@@ -89,77 +94,6 @@ void RegisterPlayFile() {
esp_console_cmd_register(&cmd);
}
-int CmdToggle(int argc, char** argv) {
- static const std::string usage = "usage: toggle";
- if (argc != 1) {
- std::cout << usage << std::endl;
- return 1;
- }
-
- // sInstance->playback_->Toggle();
-
- return 0;
-}
-
-void RegisterToggle() {
- esp_console_cmd_t cmd{.command = "toggle",
- .help = "Toggles between play and pause",
- .hint = NULL,
- .func = &CmdToggle,
- .argtable = NULL};
- esp_console_cmd_register(&cmd);
-}
-
-int CmdVolume(int argc, char** argv) {
- static const std::string usage = "usage: volume [0-255]";
- if (argc != 2) {
- std::cout << usage << std::endl;
- return 1;
- }
-
- long int raw_vol = strtol(argv[1], NULL, 10);
- if (raw_vol < 0 || raw_vol > 255) {
- std::cout << usage << std::endl;
- return 1;
- }
-
- // sInstance->playback_->SetVolume((uint8_t)raw_vol);
-
- return 0;
-}
-
-void RegisterVolume() {
- esp_console_cmd_t cmd{
- .command = "vol",
- .help = "Changes the volume (between 0 and 254. 255 is mute.)",
- .hint = NULL,
- .func = &CmdVolume,
- .argtable = NULL};
- esp_console_cmd_register(&cmd);
-}
-
-int CmdAudioStatus(int argc, char** argv) {
- static const std::string usage = "usage: audio";
- if (argc != 1) {
- std::cout << usage << std::endl;
- return 1;
- }
-
- sInstance->playback_->LogStatus();
-
- return 0;
-}
-
-void RegisterAudioStatus() {
- esp_console_cmd_t cmd{.command = "audio",
- .help = "logs the current status of the audio pipeline",
- .hint = NULL,
- .func = &CmdAudioStatus,
- .argtable = NULL};
- esp_console_cmd_register(&cmd);
-}
-*/
-
int CmdDbInit(int argc, char** argv) {
static const std::string usage = "usage: db_init";
if (argc != 1) {
diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt
index 43e67786..82acab3d 100644
--- a/src/drivers/CMakeLists.txt
+++ b/src/drivers/CMakeLists.txt
@@ -4,7 +4,7 @@
idf_component_register(
SRCS "touchwheel.cpp" "dac.cpp" "gpio_expander.cpp" "battery.cpp" "storage.cpp" "i2c.cpp"
- "spi.cpp" "display.cpp" "display_init.cpp" "samd.cpp"
+ "spi.cpp" "display.cpp" "display_init.cpp" "samd.cpp" "relative_wheel.cpp"
INCLUDE_DIRS "include"
REQUIRES "esp_adc" "fatfs" "result" "lvgl" "span" "tasks")
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS})
diff --git a/src/drivers/display.cpp b/src/drivers/display.cpp
index a503d0e9..0c9e56b3 100644
--- a/src/drivers/display.cpp
+++ b/src/drivers/display.cpp
@@ -12,6 +12,7 @@
#include "assert.h"
#include "driver/gpio.h"
+#include "driver/ledc.h"
#include "driver/spi_master.h"
#include "esp_attr.h"
#include "esp_err.h"
@@ -20,6 +21,7 @@
#include "freertos/portmacro.h"
#include "freertos/projdefs.h"
#include "hal/gpio_types.h"
+#include "hal/ledc_types.h"
#include "hal/lv_hal_disp.h"
#include "hal/spi_types.h"
#include "lvgl/lvgl.h"
@@ -95,16 +97,24 @@ auto Display::Create(GpioExpander* expander,
gpio_config(&dr_config);
gpio_set_level(kDisplayDr, 0);
- // TODO: use pwm for the backlight.
- gpio_config_t led_config{
- .pin_bit_mask = 1ULL << kDisplayLedEn,
- .mode = GPIO_MODE_OUTPUT,
- .pull_up_en = GPIO_PULLUP_ENABLE,
- .pull_down_en = GPIO_PULLDOWN_DISABLE,
- .intr_type = GPIO_INTR_DISABLE,
+ ledc_timer_config_t led_config {
+ .speed_mode = LEDC_LOW_SPEED_MODE,
+ .duty_resolution = LEDC_TIMER_13_BIT,
+ .timer_num = LEDC_TIMER_0,
+ .freq_hz = 5000,
+ .clk_cfg = LEDC_AUTO_CLK,
+ };
+ ledc_timer_config(&led_config);
+
+ ledc_channel_config_t led_channel {
+ .gpio_num = kDisplayLedEn,
+ .speed_mode = LEDC_LOW_SPEED_MODE,
+ .channel = LEDC_CHANNEL_0,
+ .timer_sel = LEDC_TIMER_0,
+ .duty = 4095,
+ .hpoint = 0
};
- gpio_config(&led_config);
- gpio_set_level(kDisplayLedEn, 1);
+ ledc_channel_config(&led_channel);
// Next, init the SPI device
spi_device_interface_config_t spi_cfg = {
@@ -250,7 +260,7 @@ void Display::OnLvglFlush(lv_disp_drv_t* disp_drv,
// area is stack-allocated, so it isn't safe to reference from the flush
// thread.
lv_area_t area_copy = *area;
- worker_task_->Dispatch<void>([=, this]() {
+ //worker_task_->Dispatch<void>([=, this]() {
// Ideally we want to complete a single flush as quickly as possible, so
// grab the bus for this entire transaction sequence.
spi_device_acquire_bus(handle_, portMAX_DELAY);
@@ -276,7 +286,7 @@ void Display::OnLvglFlush(lv_disp_drv_t* disp_drv,
spi_device_release_bus(handle_);
lv_disp_flush_ready(&driver_);
- });
+ //});
}
void RenderMain(void* raw_args) {
diff --git a/src/drivers/include/relative_wheel.hpp b/src/drivers/include/relative_wheel.hpp
new file mode 100644
index 00000000..3ff64b70
--- /dev/null
+++ b/src/drivers/include/relative_wheel.hpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <cstdint>
+#include <functional>
+
+#include "esp_err.h"
+#include "result.hpp"
+
+#include "gpio_expander.hpp"
+#include "touchwheel.hpp"
+
+namespace drivers {
+
+class RelativeWheel {
+ public:
+ static auto Create(TouchWheel *touch) -> RelativeWheel* { return new RelativeWheel(touch); }
+
+ explicit RelativeWheel(TouchWheel *touch);
+
+ // Not copyable or movable.
+ RelativeWheel(const RelativeWheel&) = delete;
+ RelativeWheel& operator=(const RelativeWheel&) = delete;
+
+ auto Update() -> void;
+
+ auto is_pressed() -> bool;
+ auto ticks() -> std::int_fast16_t;
+
+ private:
+ TouchWheel *touch_;
+ bool is_pressed_;
+ bool is_first_read_;
+ std::int_fast16_t ticks_;
+ uint8_t last_angle_;
+};
+
+} // namespace drivers
diff --git a/src/drivers/relative_wheel.cpp b/src/drivers/relative_wheel.cpp
new file mode 100644
index 00000000..f64d213d
--- /dev/null
+++ b/src/drivers/relative_wheel.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "relative_wheel.hpp"
+
+#include <stdint.h>
+#include <cstdint>
+
+#include "esp_log.h"
+
+namespace drivers {
+
+RelativeWheel::RelativeWheel(TouchWheel *touch)
+ :touch_(touch),
+ is_pressed_(false),
+ is_first_read_(true),
+ ticks_(0),
+ last_angle_(0) {}
+
+auto RelativeWheel::Update() -> void {
+ touch_->Update();
+ TouchWheelData d = touch_->GetTouchWheelData();
+ is_pressed_ = d.is_touched;
+
+ uint8_t new_angle = d.wheel_position;
+ if (is_first_read_) {
+ is_first_read_ = false;
+ last_angle_ = new_angle;
+ return;
+ }
+
+ // Work out the magnitude of travel.
+ uint8_t change_cw = last_angle_ - new_angle;
+ uint8_t change_ccw = new_angle - last_angle_;
+ int change = std::min(change_cw, change_ccw);
+
+ last_angle_ = new_angle;
+
+ // Round to eliminate noise.
+ if (change <= 2) {
+ ticks_ = 0;
+ return;
+ }
+
+ // Quantize into ticks.
+ change /= 4;
+
+ // Clamp to reliminate more noise.
+ if (change > 10) {
+ change = 0;
+ }
+
+ // Work out the direction of travel.
+ if (change_cw > change_ccw) {
+ change *= -1;
+ }
+
+ ticks_ = change;
+}
+
+auto RelativeWheel::is_pressed() -> bool {
+ return is_pressed_;
+}
+
+auto RelativeWheel::ticks() -> std::int_fast16_t {
+ int_fast16_t t = ticks_;
+ if (t != 0) {
+ ESP_LOGI("teeks", "ticks %d", t);
+ }
+ ticks_ = 0;
+ return t;
+}
+
+
+} // namespace drivers
diff --git a/src/events/event_queue.cpp b/src/events/event_queue.cpp
index c69b1e72..1b04cb90 100644
--- a/src/events/event_queue.cpp
+++ b/src/events/event_queue.cpp
@@ -15,7 +15,8 @@ static const std::size_t kMaxPendingEvents = 16;
EventQueue::EventQueue()
: system_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))),
- ui_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))) {}
+ ui_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))),
+ audio_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))) {}
auto EventQueue::ServiceSystem(TickType_t max_wait_time) -> bool {
WorkItem* item;
diff --git a/src/events/include/event_queue.hpp b/src/events/include/event_queue.hpp
index 45d766fd..eb8dd0a0 100644
--- a/src/events/include/event_queue.hpp
+++ b/src/events/include/event_queue.hpp
@@ -9,6 +9,7 @@
#include <functional>
#include <type_traits>
+#include "audio_fsm.hpp"
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
#include "freertos/queue.h"
@@ -20,6 +21,11 @@ namespace events {
typedef std::function<void(void)> WorkItem;
+/*
+ * Handles communication of events between the system's state machines. Each
+ * event will be dispatched separately to each FSM, on the correct task for
+ * that FSM.
+ */
class EventQueue {
public:
static EventQueue& GetInstance() {
@@ -32,9 +38,11 @@ class EventQueue {
WorkItem* item = new WorkItem(
[=]() { tinyfsm::FsmList<Machine>::template dispatch<Event>(ev); });
if (std::is_same<Machine, ui::UiState>()) {
- xQueueSend(system_handle_, &item, portMAX_DELAY);
- } else {
xQueueSend(ui_handle_, &item, portMAX_DELAY);
+ } else if (std::is_same<Machine, audio::AudioState>()) {
+ xQueueSend(audio_handle_, &item, portMAX_DELAY);
+ } else {
+ xQueueSend(system_handle_, &item, portMAX_DELAY);
}
Dispatch<Event, Machines...>(ev);
}
@@ -44,6 +52,7 @@ class EventQueue {
auto ServiceSystem(TickType_t max_wait_time) -> bool;
auto ServiceUi(TickType_t max_wait_time) -> bool;
+ auto ServiceAudio(TickType_t max_wait_time) -> bool;
EventQueue(EventQueue const&) = delete;
void operator=(EventQueue const&) = delete;
@@ -53,6 +62,7 @@ class EventQueue {
QueueHandle_t system_handle_;
QueueHandle_t ui_handle_;
+ QueueHandle_t audio_handle_;
};
template <typename Event, typename... Machines>
diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp
index 383bba81..b14da10c 100644
--- a/src/system_fsm/booting.cpp
+++ b/src/system_fsm/booting.cpp
@@ -13,6 +13,7 @@
#include "event_queue.hpp"
#include "gpio_expander.hpp"
#include "lvgl/lvgl.h"
+#include "relative_wheel.hpp"
#include "spi.hpp"
#include "system_events.hpp"
#include "system_fsm.hpp"
@@ -43,25 +44,28 @@ auto Booting::entry() -> void {
assert(sGpioExpander != nullptr);
// Start bringing up LVGL now, since we have all of its prerequisites.
- ESP_LOGI(kTag, "starting ui");
+ ESP_LOGI(kTag, "installing ui drivers");
lv_init();
sDisplay.reset(drivers::Display::Create(sGpioExpander.get(),
drivers::displays::kST7735R));
assert(sDisplay != nullptr);
+ sTouch.reset(drivers::TouchWheel::Create());
+ if (sTouch != nullptr) {
+ sRelativeTouch.reset(new drivers::RelativeWheel(sTouch.get()));
+ }
// The UI FSM now has everything it needs to start setting up. Do this now,
// so that we can properly show the user any errors that appear later.
- ui::UiState::Init(sGpioExpander.get(), sTouch, sDisplay, sDatabase);
+ ui::UiState::Init(sGpioExpander.get(), sRelativeTouch, sDisplay);
events::Dispatch<DisplayReady, ui::UiState>(DisplayReady());
// These drivers are required for normal operation, but aren't critical for
// booting. We will transition to the error state if these aren't present.
ESP_LOGI(kTag, "installing required drivers");
sSamd.reset(drivers::Samd::Create());
- sTouch.reset(drivers::TouchWheel::Create());
-
auto dac_res = drivers::AudioDac::create(sGpioExpander.get());
- if (dac_res.has_error() || !sSamd || !sTouch) {
+
+ if (dac_res.has_error() || !sSamd || !sRelativeTouch) {
events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>(
FatalError());
return;
@@ -70,7 +74,7 @@ auto Booting::entry() -> void {
// These drivers are initialised on boot, but are recoverable (if weird) if
// they fail.
- ESP_LOGI(kTag, "installing extra drivers");
+ ESP_LOGI(kTag, "installing optional drivers");
sBattery.reset(drivers::Battery::Create());
// All drivers are now loaded, so we can finish initing the other state
diff --git a/src/system_fsm/include/system_fsm.hpp b/src/system_fsm/include/system_fsm.hpp
index 0153e403..4413f64e 100644
--- a/src/system_fsm/include/system_fsm.hpp
+++ b/src/system_fsm/include/system_fsm.hpp
@@ -14,6 +14,7 @@
#include "database.hpp"
#include "display.hpp"
#include "gpio_expander.hpp"
+#include "relative_wheel.hpp"
#include "samd.hpp"
#include "storage.hpp"
#include "tinyfsm.hpp"
@@ -51,6 +52,7 @@ class SystemState : public tinyfsm::Fsm<SystemState> {
static std::shared_ptr<drivers::Samd> sSamd;
static std::shared_ptr<drivers::TouchWheel> sTouch;
+ static std::shared_ptr<drivers::RelativeWheel> sRelativeTouch;
static std::shared_ptr<drivers::Battery> sBattery;
static std::shared_ptr<drivers::SdStorage> sStorage;
static std::shared_ptr<drivers::Display> sDisplay;
diff --git a/src/system_fsm/system_fsm.cpp b/src/system_fsm/system_fsm.cpp
index 6956b87c..eb7cce52 100644
--- a/src/system_fsm/system_fsm.cpp
+++ b/src/system_fsm/system_fsm.cpp
@@ -5,6 +5,7 @@
*/
#include "system_fsm.hpp"
+#include "relative_wheel.hpp"
#include "system_events.hpp"
namespace system_fsm {
@@ -13,6 +14,7 @@ std::shared_ptr<drivers::GpioExpander> SystemState::sGpioExpander;
std::shared_ptr<drivers::Samd> SystemState::sSamd;
std::shared_ptr<drivers::TouchWheel> SystemState::sTouch;
+std::shared_ptr<drivers::RelativeWheel> SystemState::sRelativeTouch;
std::shared_ptr<drivers::Battery> SystemState::sBattery;
std::shared_ptr<drivers::SdStorage> SystemState::sStorage;
std::shared_ptr<drivers::Display> SystemState::sDisplay;
diff --git a/src/tasks/tasks.cpp b/src/tasks/tasks.cpp
index aa5c4aa7..b95d8e16 100644
--- a/src/tasks/tasks.cpp
+++ b/src/tasks/tasks.cpp
@@ -47,7 +47,7 @@ auto AllocateStack<Type::kAudio>() -> cpp::span<StackType_t> {
// PSRAM so we give it a bit of headroom for safety.
template <>
auto AllocateStack<Type::kUi>() -> cpp::span<StackType_t> {
- std::size_t size = 16 * 1024;
+ std::size_t size = 32 * 1024;
return {static_cast<StackType_t*>(heap_caps_malloc(size, MALLOC_CAP_DEFAULT)),
size};
}
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 9a41ae0d..bd0b76f0 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: GPL-3.0-only
idf_component_register(
- SRCS "lvgl_task.cpp" "ui_fsm.cpp" "screen_splash.cpp" "screen_menu.cpp"
+ SRCS "lvgl_task.cpp" "ui_fsm.cpp" "screen_splash.cpp" "screen_menu.cpp" "wheel_encoder.cpp"
INCLUDE_DIRS "include"
REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer")
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS})
diff --git a/src/ui/include/lvgl_task.hpp b/src/ui/include/lvgl_task.hpp
index 25e7dd14..8e387683 100644
--- a/src/ui/include/lvgl_task.hpp
+++ b/src/ui/include/lvgl_task.hpp
@@ -14,11 +14,12 @@
#include "freertos/task.h"
#include "display.hpp"
+#include "relative_wheel.hpp"
#include "touchwheel.hpp"
namespace ui {
-auto StartLvgl(std::weak_ptr<drivers::TouchWheel> touch_wheel,
+auto StartLvgl(std::weak_ptr<drivers::RelativeWheel> touch_wheel,
std::weak_ptr<drivers::Display> display) -> void;
} // namespace ui
diff --git a/src/ui/include/screen.hpp b/src/ui/include/screen.hpp
new file mode 100644
index 00000000..87a0d9b8
--- /dev/null
+++ b/src/ui/include/screen.hpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "core/lv_obj.h"
+#include "core/lv_obj_tree.h"
+#include "lvgl.h"
+
+namespace ui {
+
+class Screen {
+ public:
+ Screen() : root_(lv_obj_create(NULL)) {}
+ virtual ~Screen() { lv_obj_del(root_); }
+
+ auto root() -> lv_obj_t* { return root_; }
+
+ protected:
+ lv_obj_t* const root_;
+};
+
+} // namespace ui
diff --git a/src/ui/include/screen_menu.hpp b/src/ui/include/screen_menu.hpp
new file mode 100644
index 00000000..a0b07b9e
--- /dev/null
+++ b/src/ui/include/screen_menu.hpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "lvgl.h"
+
+#include "screen.hpp"
+
+namespace ui {
+namespace screens {
+
+class Menu : public Screen {
+ public:
+ Menu();
+ ~Menu();
+
+ private:
+ lv_obj_t* container_;
+ lv_obj_t* label_;
+};
+
+} // namespace screens
+} // namespace ui
diff --git a/src/ui/include/screen_splash.hpp b/src/ui/include/screen_splash.hpp
new file mode 100644
index 00000000..1ee7dd89
--- /dev/null
+++ b/src/ui/include/screen_splash.hpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "lvgl.h"
+
+#include "screen.hpp"
+
+namespace ui {
+namespace screens {
+
+class Splash : public Screen {
+ public:
+ Splash();
+ ~Splash();
+
+ private:
+ lv_obj_t* container_;
+ lv_obj_t* label_;
+ lv_obj_t* spinner_;
+};
+
+} // namespace screens
+} // namespace ui
diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp
index 2afcfa86..d4d23bb0 100644
--- a/src/ui/include/ui_fsm.hpp
+++ b/src/ui/include/ui_fsm.hpp
@@ -8,9 +8,9 @@
#include <memory>
+#include "relative_wheel.hpp"
#include "tinyfsm.hpp"
-#include "database.hpp"
#include "display.hpp"
#include "screen.hpp"
#include "storage.hpp"
@@ -22,9 +22,8 @@ namespace ui {
class UiState : public tinyfsm::Fsm<UiState> {
public:
static auto Init(drivers::GpioExpander* gpio_expander,
- std::weak_ptr<drivers::TouchWheel> touchwheel,
- std::weak_ptr<drivers::Display> display,
- std::weak_ptr<database::Database> database) -> void;
+ std::weak_ptr<drivers::RelativeWheel> touchwheel,
+ std::weak_ptr<drivers::Display> display) -> void;
virtual ~UiState() {}
@@ -43,9 +42,8 @@ class UiState : public tinyfsm::Fsm<UiState> {
protected:
static drivers::GpioExpander* sGpioExpander;
- static std::weak_ptr<drivers::TouchWheel> sTouchWheel;
+ static std::weak_ptr<drivers::RelativeWheel> sTouchWheel;
static std::weak_ptr<drivers::Display> sDisplay;
- static std::weak_ptr<database::Database> sDatabase;
static std::shared_ptr<Screen> sCurrentScreen;
};
diff --git a/src/ui/include/ui_tick.hpp b/src/ui/include/ui_tick.hpp
new file mode 100644
index 00000000..37f8a8bd
--- /dev/null
+++ b/src/ui/include/ui_tick.hpp
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include "esp_timer.h"
+
+#define LV_TICK_CUSTOM_SYS_TIME_EXPR (esp_timer_get_time() / 1000)
diff --git a/src/ui/include/wheel_encoder.hpp b/src/ui/include/wheel_encoder.hpp
new file mode 100644
index 00000000..0651ce0b
--- /dev/null
+++ b/src/ui/include/wheel_encoder.hpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "hal/lv_hal_indev.h"
+
+#include "relative_wheel.hpp"
+
+namespace ui {
+
+class TouchWheelEncoder {
+ public:
+ explicit TouchWheelEncoder(std::weak_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_;
+ std::weak_ptr<drivers::RelativeWheel> wheel_;
+};
+
+} // namespace ui
diff --git a/src/ui/lvgl_task.cpp b/src/ui/lvgl_task.cpp
index f2f7c67c..1ce7fd40 100644
--- a/src/ui/lvgl_task.cpp
+++ b/src/ui/lvgl_task.cpp
@@ -15,6 +15,8 @@
#include <memory>
#include "core/lv_disp.h"
+#include "core/lv_group.h"
+#include "core/lv_indev.h"
#include "core/lv_obj.h"
#include "core/lv_obj_pos.h"
#include "core/lv_obj_tree.h"
@@ -25,15 +27,18 @@
#include "freertos/projdefs.h"
#include "freertos/timers.h"
#include "hal/gpio_types.h"
+#include "hal/lv_hal_indev.h"
#include "hal/spi_types.h"
#include "lv_api_map.h"
#include "lvgl/lvgl.h"
#include "misc/lv_color.h"
#include "misc/lv_style.h"
#include "misc/lv_timer.h"
+#include "relative_wheel.hpp"
#include "tasks.hpp"
#include "touchwheel.hpp"
#include "ui_fsm.hpp"
+#include "wheel_encoder.hpp"
#include "widgets/lv_label.h"
#include "display.hpp"
@@ -43,11 +48,16 @@ namespace ui {
static const char* kTag = "lv_task";
-void LvglMain(std::weak_ptr<drivers::TouchWheel> weak_touch_wheel,
+void LvglMain(std::weak_ptr<drivers::RelativeWheel> weak_touch_wheel,
std::weak_ptr<drivers::Display> weak_display) {
ESP_LOGI(kTag, "init lvgl");
lv_init();
+ TouchWheelEncoder encoder(weak_touch_wheel);
+ lv_group_t *nav_group = lv_group_create();
+ lv_group_set_default(nav_group);
+ lv_indev_set_group(encoder.registration(), nav_group);
+
std::shared_ptr<Screen> current_screen;
auto& events = events::EventQueue::GetInstance();
while (1) {
@@ -65,10 +75,12 @@ void LvglMain(std::weak_ptr<drivers::TouchWheel> weak_touch_wheel,
// 30 FPS
// TODO(jacqueline): make this dynamic
vTaskDelay(pdMS_TO_TICKS(33));
+ lv_indev_data_t d;
+ encoder.Read(&d);
}
}
-auto StartLvgl(std::weak_ptr<drivers::TouchWheel> touch_wheel,
+auto StartLvgl(std::weak_ptr<drivers::RelativeWheel> touch_wheel,
std::weak_ptr<drivers::Display> display) -> void {
tasks::StartPersistent<tasks::Type::kUi>(
[=]() { LvglMain(touch_wheel, display); });
diff --git a/src/ui/screen_menu.cpp b/src/ui/screen_menu.cpp
new file mode 100644
index 00000000..da0a7d3c
--- /dev/null
+++ b/src/ui/screen_menu.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "screen_menu.hpp"
+
+#include "core/lv_group.h"
+#include "core/lv_obj_pos.h"
+#include "extra/widgets/menu/lv_menu.h"
+#include "extra/widgets/spinner/lv_spinner.h"
+#include "hal/lv_hal_disp.h"
+#include "misc/lv_area.h"
+#include "widgets/lv_label.h"
+
+namespace ui {
+namespace screens {
+
+Menu::Menu() {
+ lv_obj_t *menu = lv_menu_create(root_);
+ lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
+ lv_obj_center(menu);
+
+ lv_obj_t *main_page = lv_menu_page_create(menu, NULL);
+
+ lv_obj_t *container;
+ lv_obj_t *label;
+
+ container = lv_menu_cont_create(main_page);
+ label = lv_label_create(container);
+ lv_label_set_text(label, "I am an item");
+
+ container = lv_menu_cont_create(main_page);
+ label = lv_label_create(container);
+ lv_label_set_text(label, "I am also an item");
+
+ container = lv_menu_cont_create(main_page);
+ label = lv_label_create(container);
+ lv_label_set_text(label, "Item #3");
+
+ container = lv_menu_cont_create(main_page);
+ label = lv_label_create(container);
+ lv_label_set_text(label, "Yay!");
+
+ lv_menu_set_page(menu, main_page);
+}
+
+Menu::~Menu() {}
+
+} // namespace screens
+} // namespace ui
diff --git a/src/ui/screen_splash.cpp b/src/ui/screen_splash.cpp
new file mode 100644
index 00000000..2b2a7b1e
--- /dev/null
+++ b/src/ui/screen_splash.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "screen_splash.hpp"
+
+#include "core/lv_obj_pos.h"
+#include "extra/widgets/spinner/lv_spinner.h"
+#include "misc/lv_area.h"
+#include "widgets/lv_label.h"
+
+namespace ui {
+namespace screens {
+
+Splash::Splash() {
+ container_ = lv_obj_create(root_);
+ lv_obj_set_align(container_, LV_ALIGN_CENTER);
+ lv_obj_set_size(container_, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
+
+ label_ = lv_label_create(container_);
+ lv_label_set_text_static(label_, "TANGARA");
+ lv_obj_set_align(label_, LV_ALIGN_TOP_MID);
+
+ spinner_ = lv_spinner_create(container_, 1000, 60);
+ lv_obj_set_size(spinner_, 32, 32);
+ lv_obj_align_to(spinner_, label_, LV_ALIGN_OUT_BOTTOM_MID, 0, 8);
+}
+
+Splash::~Splash() {
+ lv_obj_del(spinner_);
+ lv_obj_del(label_);
+ lv_obj_del(container_);
+}
+
+} // namespace screens
+} // namespace ui
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index b08722aa..f12104e6 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -7,6 +7,7 @@
#include "ui_fsm.hpp"
#include "display.hpp"
#include "lvgl_task.hpp"
+#include "relative_wheel.hpp"
#include "screen.hpp"
#include "screen_menu.hpp"
#include "screen_splash.hpp"
@@ -16,20 +17,17 @@
namespace ui {
drivers::GpioExpander* UiState::sGpioExpander;
-std::weak_ptr<drivers::TouchWheel> UiState::sTouchWheel;
+std::weak_ptr<drivers::RelativeWheel> UiState::sTouchWheel;
std::weak_ptr<drivers::Display> UiState::sDisplay;
-std::weak_ptr<database::Database> UiState::sDatabase;
std::shared_ptr<Screen> UiState::sCurrentScreen;
auto UiState::Init(drivers::GpioExpander* gpio_expander,
- std::weak_ptr<drivers::TouchWheel> touchwheel,
- std::weak_ptr<drivers::Display> display,
- std::weak_ptr<database::Database> database) -> void {
+ std::weak_ptr<drivers::RelativeWheel> touchwheel,
+ std::weak_ptr<drivers::Display> display) -> void {
sGpioExpander = gpio_expander;
sTouchWheel = touchwheel;
sDisplay = display;
- sDatabase = database;
}
namespace states {
@@ -47,7 +45,7 @@ void Splash::react(const system_fsm::BootComplete& ev) {
}
void Interactive::entry() {
- // sCurrentScreen.reset(new screens::Menu());
+ //sCurrentScreen.reset(new screens::Menu());
}
} // namespace states
diff --git a/src/ui/wheel_encoder.cpp b/src/ui/wheel_encoder.cpp
new file mode 100644
index 00000000..0129434d
--- /dev/null
+++ b/src/ui/wheel_encoder.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "wheel_encoder.hpp"
+#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);
+}
+
+ TouchWheelEncoder::TouchWheelEncoder(std::weak_ptr<drivers::RelativeWheel> wheel) : wheel_(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 TouchWheelEncoder::Read(lv_indev_data_t *data) -> void {
+ auto lock = wheel_.lock();
+ if (lock == nullptr) {
+ data->state = LV_INDEV_STATE_RELEASED;
+ data->enc_diff = 0;
+ return;
+ }
+
+ lock->Update();
+ data->state = lock->is_pressed() ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
+ data->enc_diff = lock->ticks();
+}
+
+} // namespace ui