diff --git a/.github/workflows/build_windows_bin.yml b/.github/workflows/build_windows_bin.yml index 8ad2acefdb0..f76f782e439 100644 --- a/.github/workflows/build_windows_bin.yml +++ b/.github/workflows/build_windows_bin.yml @@ -49,6 +49,7 @@ jobs: mingw-w64-ucrt-x86_64-openssl mingw-w64-ucrt-x86_64-curl mingw-w64-ucrt-x86_64-libusb + mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja git diff --git a/platformio.ini b/platformio.ini index 040da932ccf..86a79dbd4e4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -128,7 +128,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/bcb327f058469282408eed93e27249d6447de9c0.zip + https://github.com/meshtastic/device-ui/archive/89df53208b85da7119d18f97dc810bf5ae72e2ab.zip ; Common libs for environmental measurements in telemetry module [environmental_base] diff --git a/src/graphics/tftSetup.cpp b/src/graphics/tftSetup.cpp index 95b721e67d4..c8b2f43a981 100644 --- a/src/graphics/tftSetup.cpp +++ b/src/graphics/tftSetup.cpp @@ -40,6 +40,15 @@ void tft_task_handler(void *param = nullptr) } } +#if defined(ARCH_PORTDUINO) +void tft_thread_entry(void) +{ + // SDL expects window/event/render work on a single thread. + deviceScreen->init(new PacketClient); + tft_task_handler(); +} +#endif + void tftSetup(void) { #ifndef ARCH_PORTDUINO @@ -49,32 +58,32 @@ void tftSetup(void) #else if (portduino_config.displayPanel != no_screen) { DisplayDriverConfig displayConfig; - static char *panels[] = {"NOSCREEN", "X11", "FB", "ST7789", "ST7735", "ST7735S", - "ST7796", "ILI9341", "ILI9342", "ILI9486", "ILI9488", "HX8357D"}; + static char *panels[] = {"NOSCREEN", "X11", "SDL", "FB", "ST7789", "ST7735", "ST7735S", + "ST7796", "ILI9341", "ILI9342", "ILI9486", "ILI9488", "HX8357D", "HUB75"}; static char *touch[] = {"NOTOUCH", "XPT2046", "STMPE610", "GT911", "FT5x06"}; -#if defined(USE_X11) - if (portduino_config.displayPanel == x11) { + if (portduino_config.displayPanel == sdl) { + if (portduino_config.displayWidth && portduino_config.displayHeight) + displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::SDL, (uint16_t)portduino_config.displayWidth, + (uint16_t)portduino_config.displayHeight, portduino_config.displayZoom); + else + displayConfig.device(DisplayDriverConfig::device_t::SDL); + } else if (portduino_config.displayPanel == x11) { if (portduino_config.displayWidth && portduino_config.displayHeight) displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::X11, (uint16_t)portduino_config.displayWidth, (uint16_t)portduino_config.displayHeight); else displayConfig.device(DisplayDriverConfig::device_t::X11); - } else -#elif defined(USE_FRAMEBUFFER) - if (portduino_config.displayPanel == fb) { - // Rotation from yaml Display.OffsetRotate: 1=90, 2=180, 3=270 deg - char rbuf[4]; - snprintf(rbuf, sizeof(rbuf), "%d", portduino_config.displayRotate ? (portduino_config.displayOffsetRotate & 3) : 0); - if (setenv("MESHTASTIC_FB_ROTATION", rbuf, 1) != 0) - LOG_ERROR("Failed to set MESHTASTIC_FB_ROTATION, framebuffer will use its default rotation"); - if (portduino_config.displayWidth && portduino_config.displayHeight) - displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::FB, (uint16_t)portduino_config.displayWidth, - (uint16_t)portduino_config.displayHeight); + } else if (portduino_config.displayPanel == fb) { + if (portduino_config.displayWidth && portduino_config.displayHeight) { + displayConfig.device(DisplayDriverConfig::device_t::FB) + .panel(DisplayDriverConfig::panel_config_t{.type = panels[portduino_config.displayPanel], + .panel_width = (uint16_t)portduino_config.displayWidth, + .panel_height = (uint16_t)portduino_config.displayHeight, + .offset_rotation = (uint8_t)portduino_config.displayOffsetRotate }); + } else displayConfig.device(DisplayDriverConfig::device_t::FB); - } else -#endif - { + } else { displayConfig.device(DisplayDriverConfig::device_t::CUSTOM_TFT) .panel(DisplayDriverConfig::panel_config_t{.type = panels[portduino_config.displayPanel], .panel_width = (uint16_t)portduino_config.displayWidth, @@ -128,7 +137,6 @@ void tftSetup(void) } deviceScreen = &DeviceScreen::create(&displayConfig); PacketAPI::create(PacketServer::init()); - deviceScreen->init(new PacketClient); } else { LOG_INFO("Running without TFT display!"); } @@ -140,7 +148,7 @@ void tftSetup(void) endSleepObserver.observe(¬ifyLightSleepEnd); xTaskCreatePinnedToCore(tft_task_handler, "tft", TFT_TASK_STACK_SIZE, NULL, 1, NULL, 0); #elif defined(ARCH_PORTDUINO) - std::thread *tft_task = new std::thread([] { tft_task_handler(); }); + std::thread *tft_task = new std::thread([] { tft_thread_entry(); }); #endif } } diff --git a/src/main.cpp b/src/main.cpp index c737a902f8e..ec0a568c0cd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1477,8 +1477,8 @@ void loop() rebootAtMsec = millis() + 25; } } -#if HAS_TFT - if (screen && portduino_config.displayPanel == x11 && +#if HAS_TFT && HAS_SCREEN + if (screen && (portduino_config.displayPanel == sdl) && config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { auto dispdev = screen->getDisplayDevice(); if (dispdev) diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index dd0f663f0f9..1ba0df1e1ce 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -1054,6 +1054,7 @@ bool loadConfig(const char *configPath) } portduino_config.displayHeight = yamlConfig["Display"]["Height"].as(0); portduino_config.displayWidth = yamlConfig["Display"]["Width"].as(0); + portduino_config.displayZoom = yamlConfig["Display"]["Zoom"].as(1.0); readGPIOFromYaml(yamlConfig["Display"]["DC"], portduino_config.displayDC, -1); readGPIOFromYaml(yamlConfig["Display"]["CS"], portduino_config.displayCS, -1); diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index a6797c29236..c7fbcd3eed3 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -34,7 +34,22 @@ inline const std::unordered_map configProducts = { {"RAK6421-13300-S1", "lora-RAK6421-13300-slot1.yaml"}, {"RAK6421-13300-S2", "lora-RAK6421-13300-slot2.yaml"}}; -enum screen_modules { no_screen, x11, fb, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9486, ili9488, hx8357d, hub75 }; +enum screen_modules { + no_screen, + x11, + sdl, + fb, + st7789, + st7735, + st7735s, + st7796, + ili9341, + ili9342, + ili9486, + ili9488, + hx8357d, + hub75 +}; enum touchscreen_modules { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 }; enum portduino_log_level { level_error, level_warn, level_info, level_debug, level_trace }; enum lora_module_enum { @@ -82,10 +97,10 @@ extern struct portduino_config_struct { {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}, {use_lr2021, "lr2021"}}; - std::map screen_names = {{x11, "X11"}, {fb, "FB"}, {st7789, "ST7789"}, - {st7735, "ST7735"}, {st7735s, "ST7735S"}, {st7796, "ST7796"}, - {ili9341, "ILI9341"}, {ili9342, "ILI9342"}, {ili9486, "ILI9486"}, - {ili9488, "ILI9488"}, {hx8357d, "HX8357D"}, {hub75, "HUB75"}}; + std::map screen_names = { + {x11, "X11"}, {sdl, "SDL"}, {fb, "FB"}, {st7789, "ST7789"}, {st7735, "ST7735"}, + {st7735s, "ST7735S"}, {st7796, "ST7796"}, {ili9341, "ILI9341"}, {ili9342, "ILI9342"}, {ili9486, "ILI9486"}, + {ili9488, "ILI9488"}, {hx8357d, "HX8357D"}, {hub75, "HUB75"}}; lora_module_enum lora_module; bool has_rfswitch_table = false; @@ -138,6 +153,7 @@ extern struct portduino_config_struct { screen_modules displayPanel = no_screen; int displayWidth = 0; int displayHeight = 0; + float displayZoom = 1.0; bool displayRGBOrder = false; bool displayBacklightInvert = false; bool displayRotate = false; @@ -439,6 +455,8 @@ extern struct portduino_config_struct { out << YAML::Key << "Width" << YAML::Value << displayWidth; if (displayHeight) out << YAML::Key << "Height" << YAML::Value << displayHeight; + if (displayZoom != 1.0) + out << YAML::Key << "Zoom" << YAML::Value << displayZoom; if (displayRGBOrder) out << YAML::Key << "RGBOrder" << YAML::Value << true; if (displayBacklightInvert) @@ -453,7 +471,6 @@ extern struct portduino_config_struct { out << YAML::Key << "OffsetY" << YAML::Value << displayOffsetY; out << YAML::Key << "OffsetRotate" << YAML::Value << displayOffsetRotate; - if (displayPanel == hub75) { out << YAML::Key << "HUB75" << YAML::Value << YAML::BeginMap; out << YAML::Key << "HardwareMapping" << YAML::Value << hub75_hardware_mapping; diff --git a/variants/native/portduino/platformio.ini b/variants/native/portduino/platformio.ini index 76d3fec8294..a89a9a38179 100644 --- a/variants/native/portduino/platformio.ini +++ b/variants/native/portduino/platformio.ini @@ -34,12 +34,14 @@ lib_deps = ${device-ui_base.lib_deps} build_flags = ${native_base.build_flags} -Os -lcurl -lX11 -linput -lxkbcommon -ffunction-sections -fdata-sections -Wl,--gc-sections -D RAM_SIZE=16384 - -D USE_X11=1 -D HAS_TFT=1 -D HAS_SCREEN=1 - -D LV_CACHE_DEF_SIZE=6291456 - -D LV_BUILD_TEST=0 + -D USE_X11=1 + -D USE_SDL=1 + -D LV_USE_EVDEV=1 -D LV_USE_LIBINPUT=1 +; -D LV_CACHE_DEF_SIZE=6291456 + -D LV_BUILD_TEST=0 -D LV_LVGL_H_INCLUDE_SIMPLE -D LV_CONF_INCLUDE_SIMPLE -D LV_COMP_CONF_INCLUDE_SIMPLE @@ -263,7 +265,7 @@ lib_ignore = ${env:native-macos.lib_ignore} ; firmware builds as gnu17/gnu++17 with GNU extensions throughout. ; ; Prerequisites (MSYS2, https://www.msys2.org/): -; pacman -S --needed mingw-w64-ucrt-x86_64-{gcc,pkgconf,yaml-cpp,libuv,jsoncpp,openssl,libusb} +; pacman -S --needed mingw-w64-ucrt-x86_64-{gcc,pkgconf,yaml-cpp,libuv,jsoncpp,openssl,libusb,SDL2} ; ; argp is not packaged for MSYS2's mingw environments (msys/libargp links the ; msys-2.0.dll emulation layer and can't be used for a native binary), yet @@ -307,7 +309,28 @@ build_flags = ${portduino_base.build_flags_common} ; screen renderer; EXCLUDE_SCREEN gates the `screen->...` hooks in the sensors. -DHAS_SCREEN=0 -DMESHTASTIC_EXCLUDE_SCREEN=1 - !pkg-config --cflags --libs openssl --silence-errors || : + ; MUI + -D RAM_SIZE=16384 + -D HAS_TFT=1 + -D USE_SDL=1 + -D LV_USE_LOG=0 + -D LV_USE_EVDEV=1 +; -D LV_CACHE_DEF_SIZE=6291456 + -D LV_BUILD_TEST=0 + -D LV_LVGL_H_INCLUDE_SIMPLE + -D LV_CONF_INCLUDE_SIMPLE + -D LV_COMP_CONF_INCLUDE_SIMPLE + -D USE_LOG_DEBUG + -D LOG_DEBUG_INC=\"DebugConfiguration.h\" + -D USE_PACKET_API + -D VIEW_320x240 + ; NOTE: PlatformIO invokes this env with a Windows shell, use `cmd /c exit 0` as a Windows-safe fallback. + ; pkg-config must be in user environment path, e.g. C:\msys64\ucrt64\bin + ; and the .pc files must be in PKG_CONFIG_PATH, e.g. C:\msys64\ucrt64\lib\pkgconfig + !pkg-config --cflags --libs openssl --silence-errors || cmd /c exit 0 + !pkg-config --cflags-only-I --libs --static sdl2 --silence-errors || cmd /c exit 0 + !pkg-config --cflags --libs --static libcurl --silence-errors || cmd /c exit 0 + -Wl,-subsystem,console build_unflags = -fPIC ; ignored on Windows, where all code is position-independent ; Static link, so meshtasticd.exe stands alone and can't be hijacked by a stray @@ -322,12 +345,14 @@ build_src_filter = ${native_base.build_src_filter} - - - -; LovyanGFX includes and is only needed by the TFT variants. The pine64 -; libch341 is the libusb backend that libpinedio_ch341dll.c replaces; keeping both + +lib_deps = + ${native_base.lib_deps} + ${device-ui_base.lib_deps} +; Pine libch341 is the libusb backend that libpinedio_ch341dll.c replaces; keeping both ; would duplicate every pinedio_* symbol. lib_ignore = ${portduino_base.lib_ignore} - LovyanGFX Pine libch341-spi Userspace library ; ---------------------------------------------------------------------------