diff --git a/Tactility/Include/Tactility/kernel/SystemEvents.h b/Tactility/Include/Tactility/kernel/SystemEvents.h index d186e4c2..36302a77 100644 --- a/Tactility/Include/Tactility/kernel/SystemEvents.h +++ b/Tactility/Include/Tactility/kernel/SystemEvents.h @@ -14,12 +14,14 @@ enum class SystemEvent { BootInitSpiEnd, BootInitUartBegin, BootInitUartEnd, - BootInitLvglBegin, - BootInitLvglEnd, BootSplash, /** Gained IP address */ NetworkConnected, NetworkDisconnected, + /** LVGL devices are initialized and usable */ + LvglStarted, + /** LVGL devices were removed and not usable anymore */ + LvglStopped, /** An important system time-related event, such as NTP update or time-zone change */ Time, }; diff --git a/Tactility/Include/Tactility/lvgl/Lvgl.h b/Tactility/Include/Tactility/lvgl/Lvgl.h index 24ac56c1..e9872f6a 100644 --- a/Tactility/Include/Tactility/lvgl/Lvgl.h +++ b/Tactility/Include/Tactility/lvgl/Lvgl.h @@ -1,9 +1,11 @@ #pragma once -#include +namespace tt::lvgl { -#include "./Colors.h" +bool isStarted(); -void startLvgl(); +void start(); -void stopLvgl(); \ No newline at end of file +void stop(); + +} diff --git a/Tactility/Include/Tactility/service/ServiceRegistry.h b/Tactility/Include/Tactility/service/ServiceRegistry.h index 2fef6f4f..6a6f03c9 100644 --- a/Tactility/Include/Tactility/service/ServiceRegistry.h +++ b/Tactility/Include/Tactility/service/ServiceRegistry.h @@ -30,11 +30,11 @@ bool startService(const std::string& id); bool stopService(const std::string& id); /** Get the state of a service. + * @warning If the service is not found, the returned result will be "Stopped" - even if the service id does not exist * @param[in] the service id as defined in its manifest - * @param[out] the variable to store the resulting state in - * @return true if the service was found and "state" was set + * @return the service state */ -bool getState(const std::string& id, State& state); +State getState(const std::string& id); /** Find a service manifest by its id. * @param[in] id the id as defined in the manifest diff --git a/Tactility/Private/Tactility/lvgl/Init_i.h b/Tactility/Private/Tactility/lvgl/LvglPrivate.h similarity index 100% rename from Tactility/Private/Tactility/lvgl/Init_i.h rename to Tactility/Private/Tactility/lvgl/LvglPrivate.h diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index 5cf7e9cf..5ee03dff 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -1,7 +1,7 @@ #include "Tactility/Tactility.h" #include "Tactility/app/ManifestRegistry.h" -#include "Tactility/lvgl/Init_i.h" +#include "Tactility/lvgl/LvglPrivate.h" #include "Tactility/service/ServiceManifest.h" #include diff --git a/Tactility/Source/kernel/SystemEvents.cpp b/Tactility/Source/kernel/SystemEvents.cpp index 95d222d2..55152a8e 100644 --- a/Tactility/Source/kernel/SystemEvents.cpp +++ b/Tactility/Source/kernel/SystemEvents.cpp @@ -38,16 +38,16 @@ static const char* getEventName(SystemEvent event) { return TT_STRINGIFY(BootInitUartBegin); case BootInitUartEnd: return TT_STRINGIFY(BootInitUartEnd); - case BootInitLvglBegin: - return TT_STRINGIFY(BootInitLvglBegin); - case BootInitLvglEnd: - return TT_STRINGIFY(BootInitLvglEnd); case BootSplash: return TT_STRINGIFY(BootSplash); case NetworkConnected: return TT_STRINGIFY(NetworkConnected); case NetworkDisconnected: return TT_STRINGIFY(NetworkDisconnected); + case LvglStarted: + return TT_STRINGIFY(LvglStarted); + case LvglStopped: + return TT_STRINGIFY(LvglStopped); case Time: return TT_STRINGIFY(Time); } diff --git a/Tactility/Source/lvgl/Init.cpp b/Tactility/Source/lvgl/Init.cpp deleted file mode 100644 index e98ed673..00000000 --- a/Tactility/Source/lvgl/Init.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "Tactility/app/display/DisplaySettings.h" -#include "Tactility/lvgl/Keyboard.h" - -#include "Tactility/hal/display/DisplayDevice.h" -#include "Tactility/hal/touch/TouchDevice.h" -#include -#include -#include - -#ifdef ESP_PLATFORM -#include "Tactility/lvgl/EspLvglPort.h" -#endif - -#include - -namespace tt::lvgl { - -#define TAG "lvgl_init" - -static std::shared_ptr initDisplay(const hal::Configuration& config) { - assert(config.createDisplay); - auto display = config.createDisplay(); - assert(display != nullptr); - - if (!display->start()) { - TT_LOG_E(TAG, "Display start failed"); - return nullptr; - } - - if (display->supportsBacklightDuty()) { - display->setBacklightDuty(0); - } - - if (display->supportsLvgl() && display->startLvgl()) { - auto lvgl_display = display->getLvglDisplay(); - assert(lvgl_display != nullptr); - lv_display_rotation_t rotation = app::display::getRotation(); - if (rotation != lv_display_get_rotation(lvgl_display)) { - lv_display_set_rotation(lvgl_display, rotation); - } - } - - return display; -} - -static bool initKeyboard(const std::shared_ptr& display, const std::shared_ptr& keyboard) { - TT_LOG_I(TAG, "Keyboard init"); - assert(display); - assert(keyboard); - if (keyboard->isAttached()) { - if (keyboard->start(display->getLvglDisplay())) { - lv_indev_t* keyboard_indev = keyboard->getLvglIndev(); - lv_indev_set_user_data(keyboard_indev, keyboard.get()); - hardware_keyboard_set_indev(keyboard_indev); - TT_LOG_I(TAG, "Keyboard started"); - return true; - } else { - TT_LOG_E(TAG, "Keyboard start failed"); - return false; - } - } else { - TT_LOG_E(TAG, "Keyboard attach failed"); - return false; - } -} - -void init(const hal::Configuration& config) { - TT_LOG_I(TAG, "Starting"); - - kernel::publishSystemEvent(kernel::SystemEvent::BootInitLvglBegin); - -#ifdef ESP_PLATFORM - if (config.lvglInit == hal::LvglInit::Default && !initEspLvglPort()) { - return; - } -#endif - - auto display = initDisplay(config); - if (display == nullptr) { - return; - } - hal::registerDevice(display); - - auto touch = display->getTouchDevice(); - if (touch != nullptr) { - hal::registerDevice(touch); - } - - if (config.createKeyboard) { - auto keyboard = config.createKeyboard(); - if (keyboard != nullptr) { - hal::registerDevice(keyboard); - initKeyboard(display, keyboard); - } - } - - TT_LOG_I(TAG, "Finished"); - - kernel::publishSystemEvent(kernel::SystemEvent::BootInitLvglEnd); -} - -} // namespace diff --git a/Tactility/Source/lvgl/Lvgl.cpp b/Tactility/Source/lvgl/Lvgl.cpp new file mode 100644 index 00000000..885d3528 --- /dev/null +++ b/Tactility/Source/lvgl/Lvgl.cpp @@ -0,0 +1,188 @@ +#include "Tactility/app/display/DisplaySettings.h" +#include "Tactility/lvgl/Keyboard.h" +#include "Tactility/lvgl/Lvgl.h" + +#include "Tactility/hal/display/DisplayDevice.h" +#include "Tactility/hal/touch/TouchDevice.h" +#include +#include +#include + +#ifdef ESP_PLATFORM +#include "Tactility/lvgl/EspLvglPort.h" +#endif + +#include +#include +#include +#include + +namespace tt::lvgl { + +#define TAG "Lvgl" + +static bool started = false; + +static std::shared_ptr createDisplay(const hal::Configuration& config) { + assert(config.createDisplay); + auto display = config.createDisplay(); + assert(display != nullptr); + + if (!display->start()) { + TT_LOG_E(TAG, "Display start failed"); + return nullptr; + } + + if (display->supportsBacklightDuty()) { + display->setBacklightDuty(0); + } + + return display; +} + +static bool startKeyboard(const std::shared_ptr& display, const std::shared_ptr& keyboard) { + TT_LOG_I(TAG, "Keyboard init"); + assert(display); + assert(keyboard); + if (keyboard->isAttached()) { + if (keyboard->start(display->getLvglDisplay())) { + lv_indev_t* keyboard_indev = keyboard->getLvglIndev(); + hardware_keyboard_set_indev(keyboard_indev); + TT_LOG_I(TAG, "Keyboard started"); + return true; + } else { + TT_LOG_E(TAG, "Keyboard start failed"); + return false; + } + } else { + TT_LOG_E(TAG, "Keyboard attach failed"); + return false; + } +} + +void init(const hal::Configuration& config) { + TT_LOG_I(TAG, "Init started"); + +#ifdef ESP_PLATFORM + if (config.lvglInit == hal::LvglInit::Default && !initEspLvglPort()) { + return; + } +#endif + + auto display = createDisplay(config); + if (display == nullptr) { + return; + } + hal::registerDevice(display); + + auto touch = display->getTouchDevice(); + if (touch != nullptr) { + hal::registerDevice(touch); + } + + auto configuration = hal::getConfiguration(); + if (configuration->createKeyboard) { + auto keyboard = configuration->createKeyboard(); + if (keyboard != nullptr) { + hal::registerDevice(keyboard); + } + } + + start(); + + TT_LOG_I(TAG, "Init finished"); +} + +bool isStarted() { + return started; +} + +void start() { + TT_LOG_I(TAG, "Start LVGL"); + + if (started) { + TT_LOG_W(TAG, "Can't start LVGL twice"); + return; + } + + // Start displays (their related touch devices start automatically within) + + auto displays = hal::findDevices(hal::Device::Type::Display); + for (auto display : displays) { + if (display->supportsLvgl() && display->startLvgl()) { + auto lvgl_display = display->getLvglDisplay(); + assert(lvgl_display != nullptr); + lv_display_rotation_t rotation = app::display::getRotation(); + if (rotation != lv_display_get_rotation(lvgl_display)) { + lv_display_set_rotation(lvgl_display, rotation); + } + } + } + + // Start keyboards + + auto keyboards = hal::findDevices(hal::Device::Type::Keyboard); + for (auto keyboard : keyboards) { + if (displays.size() > 0) { + // TODO: Consider implementing support for multiple displays + auto display = displays[0]; + startKeyboard(display, keyboard); + } + } + + // Restart services + + if (service::getState("Gui") == service::State::Stopped) { + service::startService("Gui"); + } else { + TT_LOG_E(TAG, "Gui service is not in Stopped state"); + } + + if (service::getState("Statusbar") == service::State::Stopped) { + service::startService("Statusbar"); + } else { + TT_LOG_E(TAG, "Statusbar service is not in Stopped state"); + } + + // Finalize + + kernel::publishSystemEvent(kernel::SystemEvent::LvglStarted); + + started = true; +} + +void stop() { + TT_LOG_I(TAG, "Stop LVGL"); + + if (!started) { + TT_LOG_W(TAG, "Can't stop LVGL: not started"); + return; + } + + // Stop services that highly depend on LVGL + + service::stopService("Statusbar"); + service::stopService("Gui"); + + // Stop keyboards + + auto keyboards = hal::findDevices(hal::Device::Type::Keyboard); + for (auto keyboard : keyboards) { + keyboard->stop(); + } + + // Stop displays (and their touch devices) + + auto displays = hal::findDevices(hal::Device::Type::Display); + for (auto display : displays) { + if (display->supportsLvgl() && display->getLvglDisplay() != nullptr && !display->stopLvgl()) { + TT_LOG_E("HelloWorld", "Failed to detach display from LVGL"); + } + } + + started = false; + + kernel::publishSystemEvent(kernel::SystemEvent::LvglStopped); +} + +} // namespace diff --git a/Tactility/Source/service/ServiceRegistry.cpp b/Tactility/Source/service/ServiceRegistry.cpp index a2885922..80a893ac 100644 --- a/Tactility/Source/service/ServiceRegistry.cpp +++ b/Tactility/Source/service/ServiceRegistry.cpp @@ -7,6 +7,7 @@ #include #include +#include namespace tt::service { @@ -98,7 +99,7 @@ bool stopService(const std::string& id) { TT_LOG_I(TAG, "Stopping %s", id.c_str()); auto service_instance = findServiceInstanceById(id); if (service_instance == nullptr) { - TT_LOG_W(TAG, "service not running: %s", id.c_str()); + TT_LOG_W(TAG, "Service not running: %s", id.c_str()); return false; } @@ -119,15 +120,12 @@ bool stopService(const std::string& id) { return true; } -bool getState(const std::string& id, State& state) { +State getState(const std::string& id) { auto service_instance = findServiceInstanceById(id); if (service_instance == nullptr) { - TT_LOG_W(TAG, "service not running: %s", id.c_str()); - return false; - } else { - state = service_instance->getState(); - return true; + return State::Stopped; } + return service_instance->getState(); } } // namespace diff --git a/Tactility/Source/service/gui/GuiService.cpp b/Tactility/Source/service/gui/GuiService.cpp index 35050427..1e886702 100644 --- a/Tactility/Source/service/gui/GuiService.cpp +++ b/Tactility/Source/service/gui/GuiService.cpp @@ -32,16 +32,11 @@ void GuiService::onLoaderMessage(const void* message, TT_UNUSED void* context) { } int32_t GuiService::guiMain() { - State service_state; while (true) { uint32_t flags = Thread::awaitFlags(GUI_THREAD_FLAG_ALL, EventFlag::WaitAny, (uint32_t)portMAX_DELAY); - // When service (state) not found -> exit - if (!getState(manifest.id, service_state)) { - break; - } - // When service not started or starting -> exit + State service_state = getState(manifest.id); if (service_state != State::Started && service_state != State::Starting) { break; }