diff --git a/src/events/CMakeLists.txt b/src/events/CMakeLists.txt index f5bd471e..132c39c7 100644 --- a/src/events/CMakeLists.txt +++ b/src/events/CMakeLists.txt @@ -5,5 +5,5 @@ idf_component_register( SRCS "event_queue.cpp" INCLUDE_DIRS "include" - REQUIRES "tinyfsm") + REQUIRES "tinyfsm" "ui") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/events/event_queue.cpp b/src/events/event_queue.cpp index 06f747ab..c69b1e72 100644 --- a/src/events/event_queue.cpp +++ b/src/events/event_queue.cpp @@ -14,11 +14,22 @@ namespace events { static const std::size_t kMaxPendingEvents = 16; EventQueue::EventQueue() - : handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))) {} + : system_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))), + ui_handle_(xQueueCreate(kMaxPendingEvents, sizeof(WorkItem*))) {} -auto EventQueue::Service(TickType_t max_wait_time) -> bool { +auto EventQueue::ServiceSystem(TickType_t max_wait_time) -> bool { WorkItem* item; - if (xQueueReceive(handle_, &item, max_wait_time)) { + if (xQueueReceive(system_handle_, &item, max_wait_time)) { + (*item)(); + delete item; + return true; + } + return false; +} + +auto EventQueue::ServiceUi(TickType_t max_wait_time) -> bool { + WorkItem* item; + if (xQueueReceive(ui_handle_, &item, max_wait_time)) { (*item)(); delete item; return true; diff --git a/src/events/include/event_queue.hpp b/src/events/include/event_queue.hpp index f57af08e..45d766fd 100644 --- a/src/events/include/event_queue.hpp +++ b/src/events/include/event_queue.hpp @@ -7,12 +7,15 @@ #pragma once #include +#include #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" #include "freertos/queue.h" #include "tinyfsm.hpp" +#include "ui_fsm.hpp" + namespace events { typedef std::function WorkItem; @@ -24,14 +27,23 @@ class EventQueue { return instance; } - template + template auto Dispatch(const Event& ev) -> void { WorkItem* item = new WorkItem( - [=]() { tinyfsm::FsmList::template dispatch(ev); }); - xQueueSend(handle_, &item, portMAX_DELAY); + [=]() { tinyfsm::FsmList::template dispatch(ev); }); + if (std::is_same()) { + xQueueSend(system_handle_, &item, portMAX_DELAY); + } else { + xQueueSend(ui_handle_, &item, portMAX_DELAY); + } + Dispatch(ev); } - auto Service(TickType_t max_wait_time) -> bool; + template + auto Dispatch(const Event& ev) -> void {} + + auto ServiceSystem(TickType_t max_wait_time) -> bool; + auto ServiceUi(TickType_t max_wait_time) -> bool; EventQueue(EventQueue const&) = delete; void operator=(EventQueue const&) = delete; @@ -39,7 +51,8 @@ class EventQueue { private: EventQueue(); - QueueHandle_t handle_; + QueueHandle_t system_handle_; + QueueHandle_t ui_handle_; }; template diff --git a/src/main/main.cpp b/src/main/main.cpp index b8dd90c5..ac2f6ed8 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -19,6 +19,6 @@ extern "C" void app_main(void) { auto& queue = events::EventQueue::GetInstance(); while (1) { - queue.Service(portMAX_DELAY); + queue.ServiceSystem(portMAX_DELAY); } } diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp index 2abc277a..383bba81 100644 --- a/src/system_fsm/booting.cpp +++ b/src/system_fsm/booting.cpp @@ -26,7 +26,7 @@ namespace states { static const char kTag[] = "BOOT"; -console::AppConsole *Booting::sAppConsole; +console::AppConsole* Booting::sAppConsole; auto Booting::entry() -> void { ESP_LOGI(kTag, "beginning tangara boot"); diff --git a/src/system_fsm/include/system_fsm.hpp b/src/system_fsm/include/system_fsm.hpp index 9214b840..0153e403 100644 --- a/src/system_fsm/include/system_fsm.hpp +++ b/src/system_fsm/include/system_fsm.hpp @@ -65,8 +65,9 @@ namespace states { * looks good. */ class Booting : public SystemState { - private: - static console::AppConsole *sAppConsole; + private: + static console::AppConsole* sAppConsole; + public: void entry() override; void exit() override; diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 48961e00..9a41ae0d 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" + SRCS "lvgl_task.cpp" "ui_fsm.cpp" "screen_splash.cpp" "screen_menu.cpp" INCLUDE_DIRS "include" - REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database") + REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp index 4a51551b..2afcfa86 100644 --- a/src/ui/include/ui_fsm.hpp +++ b/src/ui/include/ui_fsm.hpp @@ -8,13 +8,14 @@ #include +#include "tinyfsm.hpp" + #include "database.hpp" #include "display.hpp" +#include "screen.hpp" #include "storage.hpp" -#include "tinyfsm.hpp" -#include "touchwheel.hpp" - #include "system_events.hpp" +#include "touchwheel.hpp" namespace ui { @@ -27,6 +28,10 @@ class UiState : public tinyfsm::Fsm { virtual ~UiState() {} + static auto current_screen() -> std::shared_ptr { + return sCurrentScreen; + } + virtual void entry() {} virtual void exit() {} @@ -41,6 +46,8 @@ class UiState : public tinyfsm::Fsm { static std::weak_ptr sTouchWheel; static std::weak_ptr sDisplay; static std::weak_ptr sDatabase; + + static std::shared_ptr sCurrentScreen; }; namespace states { @@ -53,11 +60,14 @@ class PreBoot : public UiState { class Splash : public UiState { public: + void entry() override; void react(const system_fsm::BootComplete&) override; using UiState::react; }; -class Interactive : public UiState {}; +class Interactive : public UiState { + void entry() override; +}; class FatalError : public UiState {}; diff --git a/src/ui/lvgl_task.cpp b/src/ui/lvgl_task.cpp index 55087f77..f2f7c67c 100644 --- a/src/ui/lvgl_task.cpp +++ b/src/ui/lvgl_task.cpp @@ -19,18 +19,21 @@ #include "core/lv_obj_pos.h" #include "core/lv_obj_tree.h" #include "esp_log.h" +#include "event_queue.hpp" #include "font/lv_font.h" #include "freertos/portmacro.h" #include "freertos/projdefs.h" #include "freertos/timers.h" #include "hal/gpio_types.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 "tasks.hpp" #include "touchwheel.hpp" +#include "ui_fsm.hpp" #include "widgets/lv_label.h" #include "display.hpp" @@ -40,33 +43,25 @@ namespace ui { static const char* kTag = "lv_task"; -auto tick_hook(TimerHandle_t xTimer) -> void { - lv_tick_inc(1); -} - void LvglMain(std::weak_ptr weak_touch_wheel, std::weak_ptr weak_display) { ESP_LOGI(kTag, "init lvgl"); lv_init(); - // LVGL has been initialised, so we can now start reporting ticks to it. - xTimerCreate("lv_tick", pdMS_TO_TICKS(1), pdTRUE, NULL, &tick_hook); - - lv_style_t style; - lv_style_init(&style); - lv_style_set_text_color(&style, LV_COLOR_MAKE(0xFF, 0, 0)); - // TODO: find a nice bitmap font for this display size and density. - // lv_style_set_text_font(&style, &lv_font_montserrat_24); - - auto label = lv_label_create(NULL); - lv_label_set_text(label, "COLOURS!!"); - lv_obj_add_style(label, &style, 0); + std::shared_ptr current_screen; + auto& events = events::EventQueue::GetInstance(); + while (1) { + while (events.ServiceUi(0)) { + } - lv_obj_center(label); - lv_scr_load(label); + std::shared_ptr screen = UiState::current_screen(); + if (screen != current_screen && screen != nullptr) { + current_screen = screen; + // TODO(jacqueline): animate this sometimes + lv_scr_load(screen->root()); + } - while (1) { - lv_timer_handler(); + lv_task_handler(); // 30 FPS // TODO(jacqueline): make this dynamic vTaskDelay(pdMS_TO_TICKS(33)); diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp index a9d130ed..b08722aa 100644 --- a/src/ui/ui_fsm.cpp +++ b/src/ui/ui_fsm.cpp @@ -7,6 +7,9 @@ #include "ui_fsm.hpp" #include "display.hpp" #include "lvgl_task.hpp" +#include "screen.hpp" +#include "screen_menu.hpp" +#include "screen_splash.hpp" #include "system_events.hpp" #include "touchwheel.hpp" @@ -17,6 +20,8 @@ std::weak_ptr UiState::sTouchWheel; std::weak_ptr UiState::sDisplay; std::weak_ptr UiState::sDatabase; +std::shared_ptr UiState::sCurrentScreen; + auto UiState::Init(drivers::GpioExpander* gpio_expander, std::weak_ptr touchwheel, std::weak_ptr display, @@ -33,10 +38,18 @@ void PreBoot::react(const system_fsm::DisplayReady& ev) { transit([&]() { StartLvgl(sTouchWheel, sDisplay); }); } +void Splash::entry() { + sCurrentScreen.reset(new screens::Splash()); +} + void Splash::react(const system_fsm::BootComplete& ev) { transit(); } +void Interactive::entry() { + // sCurrentScreen.reset(new screens::Menu()); +} + } // namespace states } // namespace ui