#include #include #include #include #include #include #include #include #include #include #include #ifdef ESP_PLATFORM #include #endif #include namespace tt::lvgl { constexpr auto* TAG = "Lvgl"; static bool started = false; // TODO: Move to hal init static void initDisplays(const hal::Configuration& config) { TT_LOG_I(TAG, "Init displays"); if (config.createDisplay != nullptr) { auto display = config.createDisplay(); if (display != nullptr) { hal::registerDevice(display); } } TT_LOG_I(TAG, "Start displays"); auto displays = hal::findDevices(hal::Device::Type::Display); for (auto& display : displays) { if (!display->start()) { TT_LOG_E(TAG, "Display start failed"); } if (display->supportsBacklightDuty()) { display->setBacklightDuty(0); } auto touch = display->getTouchDevice(); if (touch != nullptr) { hal::registerDevice(touch); touch->start(); } } } void init(const hal::Configuration& config) { TT_LOG_I(TAG, "Init started"); #ifdef ESP_PLATFORM if (config.lvglInit == hal::LvglInit::Default && !initEspLvglPort()) { return; } #endif initDisplays(config); 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; } auto lock = getSyncLock()->asScopedLock(); lock.lock(); // Start displays (their related touch devices start automatically within) TT_LOG_I(TAG, "Start displays"); auto displays = hal::findDevices(hal::Device::Type::Display); for (auto display : displays) { if (display->supportsLvgl()) { if (display->startLvgl()) { TT_LOG_I(TAG, "Started %s", display->getName().c_str()); auto lvgl_display = display->getLvglDisplay(); assert(lvgl_display != nullptr); auto settings = settings::display::loadOrGetDefault(); lv_display_rotation_t rotation = settings::display::toLvglDisplayRotation(settings.orientation); if (rotation != lv_display_get_rotation(lvgl_display)) { lv_display_set_rotation(lvgl_display, rotation); } } else { TT_LOG_E(TAG, "Start failed for %s", display->getName().c_str()); } } } // Start touch TT_LOG_I(TAG, "Start touch devices"); auto touch_devices = hal::findDevices(hal::Device::Type::Touch); for (auto touch_device : touch_devices) { if (displays.size() > 0) { // TODO: Consider implementing support for multiple displays auto display = displays[0]; // Start any touch devices that haven't been started yet if (touch_device->supportsLvgl() && touch_device->getLvglIndev() == nullptr) { if (touch_device->startLvgl(display->getLvglDisplay())) { TT_LOG_I(TAG, "Started %s", touch_device->getName().c_str()); } else { TT_LOG_E(TAG, "Start failed for %s", touch_device->getName().c_str()); } } } } // Start keyboards TT_LOG_I(TAG, "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]; if (keyboard->isAttached()) { if (keyboard->startLvgl(display->getLvglDisplay())) { lv_indev_t* keyboard_indev = keyboard->getLvglIndev(); hardware_keyboard_set_indev(keyboard_indev); TT_LOG_I(TAG, "Started %s", keyboard->getName().c_str()); } else { TT_LOG_E(TAG, "Start failed for %s", keyboard->getName().c_str()); } } } } // Start encoders TT_LOG_I(TAG, "Start encoders"); auto encoders = hal::findDevices(hal::Device::Type::Encoder); for (auto encoder : encoders) { if (displays.size() > 0) { // TODO: Consider implementing support for multiple displays auto display = displays[0]; if (encoder->startLvgl(display->getLvglDisplay())) { TT_LOG_I(TAG, "Started %s", encoder->getName().c_str()); } else { TT_LOG_E(TAG, "Start failed for %s", encoder->getName().c_str()); } } } // Restart services // We search for the manifest first, because during the initial start() during boot // the service won't be registered yet. if (service::findManifestById("Gui") != nullptr) { if (service::getState("Gui") == service::State::Stopped) { service::startService("Gui"); } else { TT_LOG_E(TAG, "Gui service is not in Stopped state"); } } // We search for the manifest first, because during the initial start() during boot // the service won't be registered yet. if (service::findManifestById("Statusbar") != nullptr) { 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, "Stopping LVGL"); if (!started) { TT_LOG_W(TAG, "Can't stop LVGL: not started"); return; } auto lock = getSyncLock()->asScopedLock(); lock.lock(); // Stop services that highly depend on LVGL service::stopService("Statusbar"); service::stopService("Gui"); // Stop keyboards TT_LOG_I(TAG, "Stopping keyboards"); auto keyboards = hal::findDevices(hal::Device::Type::Keyboard); for (auto keyboard : keyboards) { if (keyboard->getLvglIndev() != nullptr) { keyboard->stopLvgl(); } } // Stop touch TT_LOG_I(TAG, "Stopping touch"); // The display generally stops their own touch devices, but we'll clean up anything that didn't auto touch_devices = hal::findDevices(hal::Device::Type::Touch); for (auto touch_device : touch_devices) { if (touch_device->getLvglIndev() != nullptr) { touch_device->stopLvgl(); } } // Stop encoders TT_LOG_I(TAG, "Stopping encoders"); // The display generally stops their own touch devices, but we'll clean up anything that didn't auto encoder_devices = hal::findDevices(hal::Device::Type::Encoder); for (auto encoder_device : encoder_devices) { if (encoder_device->getLvglIndev() != nullptr) { encoder_device->stopLvgl(); } } // Stop displays (and their touch devices) TT_LOG_I(TAG, "Stopping displays"); 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); TT_LOG_I(TAG, "Stopped LVGL"); } } // namespace