Add some placeholder splash and menu screens

Includes a bunch of misc display fixes. Most significantly, our lvgl
tickers was busted.
custom
jacqueline 2 years ago
parent 3b371cfc54
commit 65833649f4
  1. 2
      src/events/CMakeLists.txt
  2. 17
      src/events/event_queue.cpp
  3. 23
      src/events/include/event_queue.hpp
  4. 2
      src/main/main.cpp
  5. 1
      src/system_fsm/include/system_fsm.hpp
  6. 4
      src/ui/CMakeLists.txt
  7. 18
      src/ui/include/ui_fsm.hpp
  8. 35
      src/ui/lvgl_task.cpp
  9. 13
      src/ui/ui_fsm.cpp

@ -5,5 +5,5 @@
idf_component_register( idf_component_register(
SRCS "event_queue.cpp" SRCS "event_queue.cpp"
INCLUDE_DIRS "include" INCLUDE_DIRS "include"
REQUIRES "tinyfsm") REQUIRES "tinyfsm" "ui")
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS})

@ -14,11 +14,22 @@ namespace events {
static const std::size_t kMaxPendingEvents = 16; static const std::size_t kMaxPendingEvents = 16;
EventQueue::EventQueue() 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; 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)(); (*item)();
delete item; delete item;
return true; return true;

@ -7,12 +7,15 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <type_traits>
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h" #include "freertos/portmacro.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "tinyfsm.hpp" #include "tinyfsm.hpp"
#include "ui_fsm.hpp"
namespace events { namespace events {
typedef std::function<void(void)> WorkItem; typedef std::function<void(void)> WorkItem;
@ -24,14 +27,23 @@ class EventQueue {
return instance; return instance;
} }
template <typename Event, typename... Machines> template <typename Event, typename Machine, typename... Machines>
auto Dispatch(const Event& ev) -> void { auto Dispatch(const Event& ev) -> void {
WorkItem* item = new WorkItem( WorkItem* item = new WorkItem(
[=]() { tinyfsm::FsmList<Machines...>::template dispatch<Event>(ev); }); [=]() { tinyfsm::FsmList<Machine>::template dispatch<Event>(ev); });
xQueueSend(handle_, &item, portMAX_DELAY); if (std::is_same<Machine, ui::UiState>()) {
xQueueSend(system_handle_, &item, portMAX_DELAY);
} else {
xQueueSend(ui_handle_, &item, portMAX_DELAY);
} }
Dispatch<Event, Machines...>(ev);
}
template <typename Event>
auto Dispatch(const Event& ev) -> void {}
auto Service(TickType_t max_wait_time) -> bool; auto ServiceSystem(TickType_t max_wait_time) -> bool;
auto ServiceUi(TickType_t max_wait_time) -> bool;
EventQueue(EventQueue const&) = delete; EventQueue(EventQueue const&) = delete;
void operator=(EventQueue const&) = delete; void operator=(EventQueue const&) = delete;
@ -39,7 +51,8 @@ class EventQueue {
private: private:
EventQueue(); EventQueue();
QueueHandle_t handle_; QueueHandle_t system_handle_;
QueueHandle_t ui_handle_;
}; };
template <typename Event, typename... Machines> template <typename Event, typename... Machines>

@ -19,6 +19,6 @@ extern "C" void app_main(void) {
auto& queue = events::EventQueue::GetInstance(); auto& queue = events::EventQueue::GetInstance();
while (1) { while (1) {
queue.Service(portMAX_DELAY); queue.ServiceSystem(portMAX_DELAY);
} }
} }

@ -67,6 +67,7 @@ namespace states {
class Booting : public SystemState { class Booting : public SystemState {
private: private:
static console::AppConsole* sAppConsole; static console::AppConsole* sAppConsole;
public: public:
void entry() override; void entry() override;
void exit() override; void exit() override;

@ -3,7 +3,7 @@
# SPDX-License-Identifier: GPL-3.0-only # SPDX-License-Identifier: GPL-3.0-only
idf_component_register( 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" 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}) target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS})

@ -8,13 +8,14 @@
#include <memory> #include <memory>
#include "tinyfsm.hpp"
#include "database.hpp" #include "database.hpp"
#include "display.hpp" #include "display.hpp"
#include "screen.hpp"
#include "storage.hpp" #include "storage.hpp"
#include "tinyfsm.hpp"
#include "touchwheel.hpp"
#include "system_events.hpp" #include "system_events.hpp"
#include "touchwheel.hpp"
namespace ui { namespace ui {
@ -27,6 +28,10 @@ class UiState : public tinyfsm::Fsm<UiState> {
virtual ~UiState() {} virtual ~UiState() {}
static auto current_screen() -> std::shared_ptr<Screen> {
return sCurrentScreen;
}
virtual void entry() {} virtual void entry() {}
virtual void exit() {} virtual void exit() {}
@ -41,6 +46,8 @@ class UiState : public tinyfsm::Fsm<UiState> {
static std::weak_ptr<drivers::TouchWheel> sTouchWheel; static std::weak_ptr<drivers::TouchWheel> sTouchWheel;
static std::weak_ptr<drivers::Display> sDisplay; static std::weak_ptr<drivers::Display> sDisplay;
static std::weak_ptr<database::Database> sDatabase; static std::weak_ptr<database::Database> sDatabase;
static std::shared_ptr<Screen> sCurrentScreen;
}; };
namespace states { namespace states {
@ -53,11 +60,14 @@ class PreBoot : public UiState {
class Splash : public UiState { class Splash : public UiState {
public: public:
void entry() override;
void react(const system_fsm::BootComplete&) override; void react(const system_fsm::BootComplete&) override;
using UiState::react; using UiState::react;
}; };
class Interactive : public UiState {}; class Interactive : public UiState {
void entry() override;
};
class FatalError : public UiState {}; class FatalError : public UiState {};

@ -19,18 +19,21 @@
#include "core/lv_obj_pos.h" #include "core/lv_obj_pos.h"
#include "core/lv_obj_tree.h" #include "core/lv_obj_tree.h"
#include "esp_log.h" #include "esp_log.h"
#include "event_queue.hpp"
#include "font/lv_font.h" #include "font/lv_font.h"
#include "freertos/portmacro.h" #include "freertos/portmacro.h"
#include "freertos/projdefs.h" #include "freertos/projdefs.h"
#include "freertos/timers.h" #include "freertos/timers.h"
#include "hal/gpio_types.h" #include "hal/gpio_types.h"
#include "hal/spi_types.h" #include "hal/spi_types.h"
#include "lv_api_map.h"
#include "lvgl/lvgl.h" #include "lvgl/lvgl.h"
#include "misc/lv_color.h" #include "misc/lv_color.h"
#include "misc/lv_style.h" #include "misc/lv_style.h"
#include "misc/lv_timer.h" #include "misc/lv_timer.h"
#include "tasks.hpp" #include "tasks.hpp"
#include "touchwheel.hpp" #include "touchwheel.hpp"
#include "ui_fsm.hpp"
#include "widgets/lv_label.h" #include "widgets/lv_label.h"
#include "display.hpp" #include "display.hpp"
@ -40,33 +43,25 @@ namespace ui {
static const char* kTag = "lv_task"; static const char* kTag = "lv_task";
auto tick_hook(TimerHandle_t xTimer) -> void {
lv_tick_inc(1);
}
void LvglMain(std::weak_ptr<drivers::TouchWheel> weak_touch_wheel, void LvglMain(std::weak_ptr<drivers::TouchWheel> weak_touch_wheel,
std::weak_ptr<drivers::Display> weak_display) { std::weak_ptr<drivers::Display> weak_display) {
ESP_LOGI(kTag, "init lvgl"); ESP_LOGI(kTag, "init lvgl");
lv_init(); lv_init();
// LVGL has been initialised, so we can now start reporting ticks to it. std::shared_ptr<Screen> current_screen;
xTimerCreate("lv_tick", pdMS_TO_TICKS(1), pdTRUE, NULL, &tick_hook); auto& events = events::EventQueue::GetInstance();
while (1) {
lv_style_t style; while (events.ServiceUi(0)) {
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);
lv_obj_center(label); std::shared_ptr<Screen> screen = UiState::current_screen();
lv_scr_load(label); if (screen != current_screen && screen != nullptr) {
current_screen = screen;
// TODO(jacqueline): animate this sometimes
lv_scr_load(screen->root());
}
while (1) { lv_task_handler();
lv_timer_handler();
// 30 FPS // 30 FPS
// TODO(jacqueline): make this dynamic // TODO(jacqueline): make this dynamic
vTaskDelay(pdMS_TO_TICKS(33)); vTaskDelay(pdMS_TO_TICKS(33));

@ -7,6 +7,9 @@
#include "ui_fsm.hpp" #include "ui_fsm.hpp"
#include "display.hpp" #include "display.hpp"
#include "lvgl_task.hpp" #include "lvgl_task.hpp"
#include "screen.hpp"
#include "screen_menu.hpp"
#include "screen_splash.hpp"
#include "system_events.hpp" #include "system_events.hpp"
#include "touchwheel.hpp" #include "touchwheel.hpp"
@ -17,6 +20,8 @@ std::weak_ptr<drivers::TouchWheel> UiState::sTouchWheel;
std::weak_ptr<drivers::Display> UiState::sDisplay; std::weak_ptr<drivers::Display> UiState::sDisplay;
std::weak_ptr<database::Database> UiState::sDatabase; std::weak_ptr<database::Database> UiState::sDatabase;
std::shared_ptr<Screen> UiState::sCurrentScreen;
auto UiState::Init(drivers::GpioExpander* gpio_expander, auto UiState::Init(drivers::GpioExpander* gpio_expander,
std::weak_ptr<drivers::TouchWheel> touchwheel, std::weak_ptr<drivers::TouchWheel> touchwheel,
std::weak_ptr<drivers::Display> display, std::weak_ptr<drivers::Display> display,
@ -33,10 +38,18 @@ void PreBoot::react(const system_fsm::DisplayReady& ev) {
transit<Splash>([&]() { StartLvgl(sTouchWheel, sDisplay); }); transit<Splash>([&]() { StartLvgl(sTouchWheel, sDisplay); });
} }
void Splash::entry() {
sCurrentScreen.reset(new screens::Splash());
}
void Splash::react(const system_fsm::BootComplete& ev) { void Splash::react(const system_fsm::BootComplete& ev) {
transit<Interactive>(); transit<Interactive>();
} }
void Interactive::entry() {
// sCurrentScreen.reset(new screens::Menu());
}
} // namespace states } // namespace states
} // namespace ui } // namespace ui

Loading…
Cancel
Save