From a7b558eb3381012a182c5ceed75a5bd9d1d29b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 6 Feb 2024 19:52:00 +0100 Subject: [PATCH 01/36] Rename SDL2 port to PC --- src/{main_sdl2.cpp => main_pc.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{main_sdl2.cpp => main_pc.cpp} (100%) diff --git a/src/main_sdl2.cpp b/src/main_pc.cpp similarity index 100% rename from src/main_sdl2.cpp rename to src/main_pc.cpp From 246f5e3ac270f1709f9beac2e49af6ab6f7ccfb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 6 Feb 2024 19:52:23 +0100 Subject: [PATCH 02/36] Only enable SDL2 driver with USE_MONITOR --- include/hasp_conf.h | 4 ++++ src/dev/win32/hasp_win32.cpp | 8 +++++++- src/dev/win32/hasp_win32.h | 2 +- src/drv/tft/tft_driver.h | 2 +- src/drv/tft/tft_driver_sdl2.cpp | 4 ++-- src/drv/tft/tft_driver_sdl2.h | 2 +- src/hasp_gui.cpp | 2 +- src/main_pc.cpp | 18 +++++++++++------- 8 files changed, 28 insertions(+), 14 deletions(-) diff --git a/include/hasp_conf.h b/include/hasp_conf.h index 448b66a35..ef832b691 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -371,7 +371,9 @@ static WiFiSpiClass WiFi; #include #include #include +#if USE_MONITOR #include +#endif #define snprintf_P snprintf #define memcpy_P memcpy @@ -380,7 +382,9 @@ static WiFiSpiClass WiFi; #define strcpy_P strcpy #define strstr_P strstr #define halRestartMcu() +#if USE_MONITOR #define millis SDL_GetTicks +#endif #define DEC 10 #define HEX 16 diff --git a/src/dev/win32/hasp_win32.cpp b/src/dev/win32/hasp_win32.cpp index 61fce87d7..f089307c6 100644 --- a/src/dev/win32/hasp_win32.cpp +++ b/src/dev/win32/hasp_win32.cpp @@ -11,7 +11,9 @@ #include "hasp_conf.h" #include "hasp_debug.h" +#if USE_MONITOR #include "display/monitor.h" +#endif namespace dev { @@ -48,8 +50,10 @@ const char* Win32Device::get_hostname() void Win32Device::set_hostname(const char* hostname) { _hostname = hostname; +#if USE_MONITOR monitor_title(hostname); // SDL_SetWindowTitle(monitor.window, hostname); +#endif } const char* Win32Device::get_core_version() { @@ -112,7 +116,9 @@ void Win32Device::update_backlight() { uint8_t level = _backlight_power ? _backlight_level : 0; if(_backlight_invert) level = 255 - level; +#if USE_MONITOR monitor_backlight(level); +#endif } size_t Win32Device::get_free_max_block() @@ -152,4 +158,4 @@ long Win32Device::get_uptime() dev::Win32Device haspDevice; -#endif // WINDOWS \ No newline at end of file +#endif // WINDOWS diff --git a/src/dev/win32/hasp_win32.h b/src/dev/win32/hasp_win32.h index 3c2edb231..0c64e1f9a 100644 --- a/src/dev/win32/hasp_win32.h +++ b/src/dev/win32/hasp_win32.h @@ -96,4 +96,4 @@ extern dev::Win32Device haspDevice; #endif // WINDOWS -#endif // HASP_DEVICE_WINDOWS_H \ No newline at end of file +#endif // HASP_DEVICE_WINDOWS_H diff --git a/src/drv/tft/tft_driver.h b/src/drv/tft/tft_driver.h index 913be18f7..0c0d58144 100644 --- a/src/drv/tft/tft_driver.h +++ b/src/drv/tft/tft_driver.h @@ -77,7 +77,7 @@ class BaseTft { #elif defined(STM32F7) #warning Building for STM32F7xx Tfts #include "tft_driver_tftespi.h" -#elif defined(WINDOWS) || defined(POSIX) +#elif USE_MONITOR && (defined(WINDOWS) || defined(POSIX)) // #warning Building for SDL2 #include "tft_driver_sdl2.h" #else diff --git a/src/drv/tft/tft_driver_sdl2.cpp b/src/drv/tft/tft_driver_sdl2.cpp index a2b442331..98461f5b8 100644 --- a/src/drv/tft/tft_driver_sdl2.cpp +++ b/src/drv/tft/tft_driver_sdl2.cpp @@ -1,7 +1,7 @@ /* MIT License - Copyright (c) 2019-2022 Francis Van Roie For full license information read the LICENSE file in the project folder */ -#if defined(WINDOWS) || defined(POSIX) +#if USE_MONITOR && (defined(WINDOWS) || defined(POSIX)) #include "hasplib.h" #include "lvgl.h" @@ -115,4 +115,4 @@ const char* TftSdl::get_tft_model() dev::TftSdl haspTft; -#endif // WINDOWS || POSIX \ No newline at end of file +#endif // WINDOWS || POSIX diff --git a/src/drv/tft/tft_driver_sdl2.h b/src/drv/tft/tft_driver_sdl2.h index 85b32ee04..d0aaa1142 100644 --- a/src/drv/tft/tft_driver_sdl2.h +++ b/src/drv/tft/tft_driver_sdl2.h @@ -6,7 +6,7 @@ #include "tft_driver.h" -#if defined(WINDOWS) || defined(POSIX) +#if USE_MONITOR && (defined(WINDOWS) || defined(POSIX)) // #warning Building H driver TFT SDL2 #include "lvgl.h" diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index b69a1ee53..5fc3eb743 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -309,7 +309,7 @@ void guiSetup() static lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; -#if defined(WINDOWS) || defined(POSIX) +#if USE_MONITOR && (defined(WINDOWS) || defined(POSIX)) indev_drv.read_cb = mouse_read; #else indev_drv.read_cb = gui_touch_read; diff --git a/src/main_pc.cpp b/src/main_pc.cpp index d2942333d..4a32377df 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -25,7 +25,9 @@ #include "hasplib.h" // #include "app_hal.h" +#if USE_MONITOR #include "display/monitor.h" +#endif #include "hasp_debug.h" #include "hasp_gui.h" @@ -258,12 +260,14 @@ int main(int argc, char* argv[]) } #endif - SDL_Init(0); // Needs to be initialized for GetPerfPath char buf[4096]; // never know how much is needed std::cout << "CWD: " << cwd(buf, sizeof buf) << std::endl; +#if USE_MONITOR + SDL_Init(0); // Needs to be initialized for GetPerfPath cd(SDL_GetPrefPath("hasp", "hasp")); - std::cout << "CWD changed to: " << cwd(buf, sizeof buf) << std::endl; SDL_Quit(); // We'll properly init later +#endif + std::cout << "CWD changed to: " << cwd(buf, sizeof buf) << std::endl; // Change to preferences dir std::cout << "\nCommand-line arguments:\n"; @@ -376,11 +380,11 @@ int main(int argc, char* argv[]) LOG_TRACE(TAG_MAIN, "main loop completed"); #if defined(WINDOWS) - WriteConsole(std_out, "bye\n\n", 3, NULL, NULL); - std::cout << std::endl << std::flush; - fflush(stdout); - FreeConsole(); - exit(0); + WriteConsole(std_out, "bye\n\n", 3, NULL, NULL); + std::cout << std::endl << std::flush; + fflush(stdout); + FreeConsole(); + exit(0); #endif return 0; From a2d97204f80ccf8f901af726f456c28792c4d1f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 6 Feb 2024 19:52:39 +0100 Subject: [PATCH 03/36] Fix storage root path with LV_USE_FS_IF --- include/lv_conf_v7.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/lv_conf_v7.h b/include/lv_conf_v7.h index 0b094c3f0..14ec75fa9 100644 --- a/include/lv_conf_v7.h +++ b/include/lv_conf_v7.h @@ -227,7 +227,9 @@ typedef void* lv_fs_drv_user_data_t; //# define LV_FS_IF_SPIFFS '\0' // no internal esp Flash #endif #endif /*LV_USE_FS_IF*/ +#if !(defined(WINDOWS) || defined(POSIX)) #define LV_FS_PC_PATH "/littlefs" +#endif #endif From 9b3bbcc1079e53cd6e34f8761e510fcdade2c521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 6 Feb 2024 19:52:57 +0100 Subject: [PATCH 04/36] Fix PC building with MQTT disabled --- src/main_pc.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main_pc.cpp b/src/main_pc.cpp index 4a32377df..ff155bcbd 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -152,7 +152,9 @@ void setup() void loop() { haspLoop(); +#if HASP_USE_MQTT mqttLoop(); +#endif // debugLoop(); // Console haspDevice.loop(); @@ -190,7 +192,7 @@ void loop() haspDevice.loop_5s(); gpioEvery5Seconds(); -#if defined(HASP_USE_MQTT) +#if HASP_USE_MQTT mqttEvery5Seconds(true); #endif @@ -363,7 +365,9 @@ int main(int argc, char* argv[]) serializeJson(settings, buffer, sizeof(buffer)); std::cout << buffer << std::endl << std::flush; fflush(stdout); +#if HASP_USE_MQTT mqttSetConfig(settings["mqtt"]); +#endif // printf("%s %d\n", __FILE__, __LINE__); // fflush(stdout); From 76b9be4d9795c54743760f36a2476d483b2d075f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 6 Feb 2024 19:53:58 +0100 Subject: [PATCH 05/36] Add Win32Drv GDI port --- include/hasp_conf.h | 2 + include/lv_drv_conf.h | 6 +- src/dev/win32/hasp_win32.cpp | 10 +- src/dev/win32/hasp_win32.h | 2 + src/drv/tft/tft_driver.h | 3 + src/drv/tft/tft_driver_win32drv.cpp | 109 +++++++++++++++++++ src/drv/tft/tft_driver_win32drv.h | 44 ++++++++ src/main_pc.cpp | 20 +++- user_setups/win32/windows_gdi_64bits.ini | 131 +++++++++++++++++++++++ 9 files changed, 321 insertions(+), 6 deletions(-) create mode 100644 src/drv/tft/tft_driver_win32drv.cpp create mode 100644 src/drv/tft/tft_driver_win32drv.h create mode 100644 user_setups/win32/windows_gdi_64bits.ini diff --git a/include/hasp_conf.h b/include/hasp_conf.h index ef832b691..a5619c467 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -384,6 +384,8 @@ static WiFiSpiClass WiFi; #define halRestartMcu() #if USE_MONITOR #define millis SDL_GetTicks +#elif USE_WIN32DRV +#define millis Win32Millis #endif #define DEC 10 diff --git a/include/lv_drv_conf.h b/include/lv_drv_conf.h index cb5bd6031..3afc0d92b 100644 --- a/include/lv_drv_conf.h +++ b/include/lv_drv_conf.h @@ -125,7 +125,11 @@ #define USE_WINDOWS 0 #endif -#if USE_WINDOWS +#ifndef USE_WIN32DRV +#define USE_WINDOWS 0 +#endif + +#if USE_WINDOWS || USE_WIN32DRV #define WINDOW_HOR_RES 480 #define WINDOW_VER_RES 320 #endif diff --git a/src/dev/win32/hasp_win32.cpp b/src/dev/win32/hasp_win32.cpp index f089307c6..460518047 100644 --- a/src/dev/win32/hasp_win32.cpp +++ b/src/dev/win32/hasp_win32.cpp @@ -13,6 +13,8 @@ #if USE_MONITOR #include "display/monitor.h" +#elif USE_WIN32DRV +#include "win32drv/win32drv.h" #endif namespace dev { @@ -52,7 +54,8 @@ void Win32Device::set_hostname(const char* hostname) _hostname = hostname; #if USE_MONITOR monitor_title(hostname); - // SDL_SetWindowTitle(monitor.window, hostname); +#elif USE_WIN32DRV + lv_win32_set_title(hostname); #endif } const char* Win32Device::get_core_version() @@ -156,6 +159,11 @@ long Win32Device::get_uptime() } // namespace dev +long Win32Millis() +{ + return GetTickCount64(); +} + dev::Win32Device haspDevice; #endif // WINDOWS diff --git a/src/dev/win32/hasp_win32.h b/src/dev/win32/hasp_win32.h index 0c64e1f9a..5e59ea738 100644 --- a/src/dev/win32/hasp_win32.h +++ b/src/dev/win32/hasp_win32.h @@ -91,6 +91,8 @@ class Win32Device : public BaseDevice { } // namespace dev +extern long Win32Millis(); + using dev::Win32Device; extern dev::Win32Device haspDevice; diff --git a/src/drv/tft/tft_driver.h b/src/drv/tft/tft_driver.h index 0c0d58144..18eaa7564 100644 --- a/src/drv/tft/tft_driver.h +++ b/src/drv/tft/tft_driver.h @@ -80,6 +80,9 @@ class BaseTft { #elif USE_MONITOR && (defined(WINDOWS) || defined(POSIX)) // #warning Building for SDL2 #include "tft_driver_sdl2.h" +#elif USE_WIN32DRV && (defined(WINDOWS) || defined(POSIX)) +// #warning Building for Win32Drv +#include "tft_driver_win32drv.h" #else // #warning Building for Generic Tfts using dev::BaseTft; diff --git a/src/drv/tft/tft_driver_win32drv.cpp b/src/drv/tft/tft_driver_win32drv.cpp new file mode 100644 index 000000000..709ed0543 --- /dev/null +++ b/src/drv/tft/tft_driver_win32drv.cpp @@ -0,0 +1,109 @@ +/* MIT License - Copyright (c) 2019-2022 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if USE_WIN32DRV && (defined(WINDOWS) || defined(POSIX)) + +#include "hasplib.h" +#include "lvgl.h" + +#include "win32drv/win32drv.h" + +#include "drv/tft/tft_driver.h" +#include "tft_driver_win32drv.h" + +#include "dev/device.h" +#include "hasp_debug.h" + +#ifdef HASP_CUSTOMIZE_BOOTLOGO +#include "custom/bootlogo.h" // Sketch tab header for xbm images +#else +#include "custom/bootlogo_template.h" // Sketch tab header for xbm images +#endif + +namespace dev { + +/** + * A task to measure the elapsed time for LittlevGL + * @param data unused + * @return never return + */ +static DWORD tick_thread(void* data) +{ + (void)data; + + while(1) { + Sleep(5); /*Sleep for 5 millisecond*/ + lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/ + } + + return 0; +} + +int32_t TftWin32Drv::width() +{ + return _width; +} +int32_t TftWin32Drv::height() +{ + return _height; +} + +void TftWin32Drv::init(int32_t w, int h) +{ + _width = w; + _height = h; + + /* Add a display + * Use the 'win32drv' driver which creates window on PC's monitor to simulate a display + * The following input devices are handled: mouse, keyboard, mousewheel */ + lv_win32_init(0, SW_SHOWNORMAL, w, h, 0); + lv_win32_set_title(haspDevice.get_hostname()); + + /* Tick init. + * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed + * Create a Windows thread to do this*/ + CreateThread(NULL, 0, tick_thread, NULL, 0, NULL); +} +void TftWin32Drv::show_info() +{ + splashscreen(); + + unsigned long version = GetVersion(); + unsigned long major = LOBYTE(LOWORD(version)); + unsigned long minor = HIBYTE(LOWORD(version)); + unsigned long build = 0; + if(version < 0x80000000) build = HIWORD(version); + LOG_VERBOSE(TAG_TFT, F("Driver : Win32Drv")); + LOG_VERBOSE(TAG_TFT, F("Windows Version: %d.%d.%d"), major, minor, build); +} + +void TftWin32Drv::splashscreen() +{ + uint8_t fg[] = logoFgColor; + uint8_t bg[] = logoBgColor; + lv_color_t fgColor = lv_color_make(fg[0], fg[1], fg[2]); + lv_color_t bgColor = lv_color_make(bg[0], bg[1], bg[2]); + lv_win32_splashscreen(logoImage, logoWidth, logoHeight, lv_color_to32(fgColor), lv_color_to32(bgColor)); +} +void TftWin32Drv::set_rotation(uint8_t rotation) +{} +void TftWin32Drv::set_invert(bool invert) +{} +void TftWin32Drv::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) +{ + lv_disp_flush_ready(disp); +} +bool TftWin32Drv::is_driver_pin(uint8_t pin) +{ + return false; +} +const char* TftWin32Drv::get_tft_model() +{ + return "Win32Drv"; +} + +} // namespace dev + +dev::TftWin32Drv haspTft; + +#endif // WINDOWS || POSIX diff --git a/src/drv/tft/tft_driver_win32drv.h b/src/drv/tft/tft_driver_win32drv.h new file mode 100644 index 000000000..89dd4223f --- /dev/null +++ b/src/drv/tft/tft_driver_win32drv.h @@ -0,0 +1,44 @@ +/* MIT License - Copyright (c) 2019-2022 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_WIN32DRV_DRIVER_H +#define HASP_WIN32DRV_DRIVER_H + +#include "tft_driver.h" + +#if USE_WIN32DRV && (defined(WINDOWS) || defined(POSIX)) +// #warning Building H driver WIN32DRV + +#include "lvgl.h" + +namespace dev { + +class TftWin32Drv : BaseTft { + public: + void init(int w, int h); + void show_info(); + void splashscreen(); + + void set_rotation(uint8_t rotation); + void set_invert(bool invert); + + void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); + bool is_driver_pin(uint8_t pin); + + const char* get_tft_model(); + + int32_t width(); + int32_t height(); + + private: + int32_t _width, _height; +}; + +} // namespace dev + +using dev::TftWin32Drv; +extern dev::TftWin32Drv haspTft; + +#endif // defined(WINDOWS) || defined(POSIX) + +#endif // HASP_SDL2_DRIVER_H diff --git a/src/main_pc.cpp b/src/main_pc.cpp index ff155bcbd..322fb24bc 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include // MSDN recommends against using getcwd & chdir names #define cwd _getcwd #define cd _chdir @@ -35,7 +37,6 @@ #include "dev/device.h" bool isConnected; -bool isRunning = 1; uint8_t mainLoopCounter = 0; unsigned long mainLastLoopTime = 0; @@ -268,6 +269,12 @@ int main(int argc, char* argv[]) SDL_Init(0); // Needs to be initialized for GetPerfPath cd(SDL_GetPrefPath("hasp", "hasp")); SDL_Quit(); // We'll properly init later +#elif USE_WIN32DRV + if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, buf))) { + PathAppendA(buf, "hasp"); + PathAppendA(buf, "hasp"); + cd(buf); + } #endif std::cout << "CWD changed to: " << cwd(buf, sizeof buf) << std::endl; @@ -377,11 +384,16 @@ int main(int argc, char* argv[]) setup(); - LOG_TRACE(TAG_MAIN, "loop started"); - while(isRunning) { +#if USE_MONITOR + while(1) { loop(); } - LOG_TRACE(TAG_MAIN, "main loop completed"); +#elif USE_WIN32DRV + extern bool lv_win32_quit_signal; + while(!lv_win32_quit_signal) { + loop(); + } +#endif #if defined(WINDOWS) WriteConsole(std_out, "bye\n\n", 3, NULL, NULL); diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini new file mode 100644 index 000000000..38d8b4c3a --- /dev/null +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -0,0 +1,131 @@ +[env:windows_gdi_64bits] +platform = native@^1.1.4 +extra_scripts = + tools/sdl2_build_extra.py + tools/windows_build_extra.py +build_flags = + ${env.build_flags} + -D HASP_MODEL="Windows App" + + ; ----- Monitor + -D TFT_WIDTH=240 + -D TFT_HEIGHT=320 + ; SDL drivers options + ;-D LV_LVGL_H_INCLUDE_SIMPLE + ;-D LV_DRV_NO_CONF + -D USE_WIN32DRV + ; ----- ArduinoJson + -D ARDUINOJSON_DECODE_UNICODE=1 + -D HASP_NUM_PAGES=12 + -D HASP_USE_SPIFFS=0 + -D HASP_USE_LITTLEFS=0 + -D HASP_USE_EEPROM=0 + -D HASP_USE_GPIO=1 + -D HASP_USE_CONFIG=0 ; Standalone application, as library + -D HASP_USE_DEBUG=1 + -D HASP_USE_PNGDECODE=1 + -D HASP_USE_BMPDECODE=1 + -D HASP_USE_GIFDECODE=0 + -D HASP_USE_JPGDECODE=0 + -D HASP_USE_MQTT=1 + -D HASP_USE_SYSLOG=0 + -D MQTT_MAX_PACKET_SIZE=2048 + -D HASP_ATTRIBUTE_FAST_MEM= + -D IRAM_ATTR= ; No IRAM_ATTR available + -D PROGMEM= ; No PROGMEM available + + ; -- FreeType build options ------------------------ + -D LV_USE_FT_CACHE_MANAGER=1 ; crashes without cache + -D LVGL_FREETYPE_MAX_FACES=64 ; max number of FreeType faces in cache + -D LVGL_FREETYPE_MAX_SIZES=4 ; max number of sizes in cache + -D LVGL_FREETYPE_MAX_BYTES=16384 ; max bytes in cache + -D LVGL_FREETYPE_MAX_BYTES_PSRAM=65536 ; max bytes in cache when using PSRAM + + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO + ;-D LV_LOG_PRINTF=1 + ; Add recursive dirs for hal headers search + -D _WIN64 + -D WINDOWS ; We add this ourselves for code branching in hasp + -D WIN32_LEAN_AND_MEAN ; exclude a bunch of Windows header files from windows.h + -D PAHO_MQTT_STATIC + -DPAHO_WITH_SSL=TRUE + -DPAHO_BUILD_DOCUMENTATION=FALSE + -DPAHO_BUILD_SAMPLES=FALSE + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_VERBOSE_MAKEFILE=TRUE + ;-D NO_PERSISTENCE + -I.pio/libdeps/windows_gdi_64bits/paho/src + -I.pio/libdeps/windows_gdi_64bits/ArduinoJson/src + -I lib/lv_fs_if + -I lib/lv_datetime + -mconsole + ; ----- Statically linked libraries -------------------- + -l"ws2_32" ;windsock2 + -lrpcrt4 + -lcrypt32 + -lmingw32 + -mwindows + -lm + -ldinput8 + ;-ldxguid + ;-ldxerr8 + ;-luser32 + ;-lgdi32 + -lwinmm + -limm32 + -lole32 + -loleaut32 + ;-lshell32 + -lversion + ;-luuid + -lsetupapi + -lshlwapi + ;-lhid + +lib_deps = + ${env.lib_deps} + ;lv_drivers@~7.9.0 + ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip + https://github.com/eclipse/paho.mqtt.c.git + bblanchon/ArduinoJson@^6.21.4 ; Json(l) parser + https://github.com/fvanroie/lv_drivers + +lib_ignore = + paho + AXP192 + ArduinoLog + lv_lib_qrcode + ETHSPI + +build_src_filter = + +<*> + -<*.h> + +<../hal/sdl2> + +<../.pio/libdeps/windows_gdi_64bits/paho/src/*.c> + +<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTClient.c> + -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTAsync.c> + -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTVersion.c> + -<../.pio/libdeps/windows_gdi_64bits/paho/src/SSLSocket.c> + + + - + - + - + - + - + + + - + + + - + + + + + - + - + - + + + + + + + - + + + +<../.pio/libdeps/windows_gdi_64bits/ArduinoJson/src/ArduinoJson.h> + + From b738c22c679d05f4ba882761014c4e3ec7f4f7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 6 Feb 2024 19:59:28 +0100 Subject: [PATCH 06/36] Disable app_hal.c if not using SDL2 --- hal/sdl2/app_hal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hal/sdl2/app_hal.c b/hal/sdl2/app_hal.c index fd062ada4..c7524836a 100644 --- a/hal/sdl2/app_hal.c +++ b/hal/sdl2/app_hal.c @@ -1,3 +1,4 @@ +#if USE_MONITOR #include #define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/ #include @@ -53,3 +54,4 @@ void hal_loop(void) // lv_task_handler(); // } } +#endif From 96bfbf397baeeda39697bfce6c6774b5a1f51b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 7 Feb 2024 11:11:15 +0100 Subject: [PATCH 07/36] Add HASP_TARGET_ARDUINO and HASP_TARGET_PC macros --- include/hasp_conf.h | 81 +++++++++++--------- include/hasp_macro.h | 6 +- include/lv_conf_v7.h | 2 +- lib/lv_lib_zifont/lv_zifont.cpp | 2 +- src/dev/device.h | 2 +- src/drv/tft/tft_driver.h | 4 +- src/drv/tft/tft_driver_sdl2.cpp | 2 +- src/drv/tft/tft_driver_sdl2.h | 4 +- src/drv/tft/tft_driver_win32drv.cpp | 2 +- src/drv/tft/tft_driver_win32drv.h | 6 +- src/hasp/hasp.cpp | 2 +- src/hasp/hasp_dispatch.cpp | 6 +- src/hasp/hasp_font.cpp | 2 +- src/hasp/hasp_object.cpp | 2 +- src/hasp_debug.cpp | 4 +- src/hasp_debug.h | 2 +- src/hasp_gui.cpp | 6 +- src/main_arduino.cpp | 2 +- src/main_pc.cpp | 2 +- src/mqtt/hasp_mqtt_ha.cpp | 4 +- user_setups/darwin_sdl/darwin_sdl_64bits.ini | 3 +- user_setups/esp32/_esp32.ini | 1 + user_setups/esp8266/_esp8266.ini | 1 + user_setups/linux_sdl/linux_sdl_64bits.ini | 1 + user_setups/stm32f4xx/_stm32f4.ini | 3 +- user_setups/stm32f7xx/_stm32f7.ini | 1 + user_setups/win32/windows_gdi_64bits.ini | 1 + user_setups/win32/windows_sdl_64bits.ini | 1 + 28 files changed, 86 insertions(+), 69 deletions(-) diff --git a/include/hasp_conf.h b/include/hasp_conf.h index a5619c467..59ef00c1d 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -33,6 +33,11 @@ #define HASP_USE_APP 1 +/* Validate that build target was specified */ +#if HASP_TARGET_ARDUINO + HASP_TARGET_PC != 1 +#error "Build target invalid! Set *one* of: HASP_TARGET_ARDUINO, HASP_TARGET_PC" +#endif + #ifndef HASP_USE_DEBUG #define HASP_USE_DEBUG 1 #endif @@ -190,6 +195,41 @@ #define HASP_OBJECT_NOTATION "p%ub%u" +#ifndef HASP_ATTRIBUTE_FAST_MEM +#define HASP_ATTRIBUTE_FAST_MEM +#endif + +#ifndef IRAM_ATTR +#define IRAM_ATTR +#endif + +#ifndef FPSTR +#define FPSTR(pstr_pointer) (reinterpret_cast(pstr_pointer)) +#endif + +#ifndef PGM_P +#define PGM_P const char* +#endif + +/* Workarounds for PC build */ +#if HASP_TARGET_PC +#ifndef __FlashStringHelper +#define __FlashStringHelper char +#endif + +#ifndef F +#define F(x) (x) +#endif + +#ifndef PSTR +#define PSTR(x) x +#endif + +#ifndef PROGMEM +#define PROGMEM +#endif +#endif + /* Includes */ #ifdef WINDOWS #include "winsock2.h" @@ -281,7 +321,7 @@ static WiFiSpiClass WiFi; #if HASP_USE_MQTT > 0 #include "mqtt/hasp_mqtt.h" -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC #define HASP_USE_PAHO #else #define HASP_USE_ESP_MQTT @@ -326,51 +366,20 @@ static WiFiSpiClass WiFi; #include "sys/svc/hasp_slave.h" #endif -#ifndef HASP_ATTRIBUTE_FAST_MEM -#define HASP_ATTRIBUTE_FAST_MEM -#endif - -#ifndef IRAM_ATTR -#define IRAM_ATTR -#endif - -#ifndef FPSTR -#define FPSTR(pstr_pointer) (reinterpret_cast(pstr_pointer)) -#endif - -#ifndef PGM_P -#define PGM_P const char* -#endif - -#if defined(WINDOWS) || defined(POSIX) -#ifndef __FlashStringHelper -#define __FlashStringHelper char -#endif - -#ifndef F -#define F(x) (x) -#endif - -#ifndef PSTR -#define PSTR(x) x -#endif - -#ifndef PROGMEM -#define PROGMEM -#endif -#endif - #if defined(WINDOWS) #include #define delay Sleep #endif + #if defined(POSIX) #define delay SDL_Delay #endif -#if defined(WINDOWS) || defined(POSIX) + +#if HASP_TARGET_PC #include #include #include + #if USE_MONITOR #include #endif diff --git a/include/hasp_macro.h b/include/hasp_macro.h index f1f937b92..7dc1f82bf 100644 --- a/include/hasp_macro.h +++ b/include/hasp_macro.h @@ -12,15 +12,15 @@ #include "user_config_override.h" #endif -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC #define HASP_RANDOM(x) rand() % x -#elif defined(ARDUINO) +#elif HASP_TARGET_ARDUINO #define HASP_RANDOM(x) random(x) #else #define HASP_RANDOM(x) random() % x #endif -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC #define LOG_OUTPUT(x, ...) printf(__VA_ARGS__) #else diff --git a/include/lv_conf_v7.h b/include/lv_conf_v7.h index 14ec75fa9..e2adf67ea 100644 --- a/include/lv_conf_v7.h +++ b/include/lv_conf_v7.h @@ -227,7 +227,7 @@ typedef void* lv_fs_drv_user_data_t; //# define LV_FS_IF_SPIFFS '\0' // no internal esp Flash #endif #endif /*LV_USE_FS_IF*/ -#if !(defined(WINDOWS) || defined(POSIX)) +#if HASP_TARGET_ARDUINO #define LV_FS_PC_PATH "/littlefs" #endif diff --git a/lib/lv_lib_zifont/lv_zifont.cpp b/lib/lv_lib_zifont/lv_zifont.cpp index 43f7e3405..3db556277 100644 --- a/lib/lv_lib_zifont/lv_zifont.cpp +++ b/lib/lv_lib_zifont/lv_zifont.cpp @@ -5,7 +5,7 @@ * INCLUDES *********************/ -#if !(defined(WINDOWS) || defined(POSIX) || defined(STM32F7xx)) +#if !(HASP_TARGET_PC || defined(STM32F7xx)) #include #include diff --git a/src/dev/device.h b/src/dev/device.h index 32ad1dc7c..75039f340 100644 --- a/src/dev/device.h +++ b/src/dev/device.h @@ -8,7 +8,7 @@ #include "Arduino.h" #endif -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC #include #endif #if defined(POSIX) diff --git a/src/drv/tft/tft_driver.h b/src/drv/tft/tft_driver.h index 18eaa7564..914597a8e 100644 --- a/src/drv/tft/tft_driver.h +++ b/src/drv/tft/tft_driver.h @@ -77,10 +77,10 @@ class BaseTft { #elif defined(STM32F7) #warning Building for STM32F7xx Tfts #include "tft_driver_tftespi.h" -#elif USE_MONITOR && (defined(WINDOWS) || defined(POSIX)) +#elif USE_MONITOR && HASP_TARGET_PC // #warning Building for SDL2 #include "tft_driver_sdl2.h" -#elif USE_WIN32DRV && (defined(WINDOWS) || defined(POSIX)) +#elif USE_WIN32DRV && HASP_TARGET_PC // #warning Building for Win32Drv #include "tft_driver_win32drv.h" #else diff --git a/src/drv/tft/tft_driver_sdl2.cpp b/src/drv/tft/tft_driver_sdl2.cpp index 98461f5b8..82ca964d2 100644 --- a/src/drv/tft/tft_driver_sdl2.cpp +++ b/src/drv/tft/tft_driver_sdl2.cpp @@ -1,7 +1,7 @@ /* MIT License - Copyright (c) 2019-2022 Francis Van Roie For full license information read the LICENSE file in the project folder */ -#if USE_MONITOR && (defined(WINDOWS) || defined(POSIX)) +#if USE_MONITOR && HASP_TARGET_PC #include "hasplib.h" #include "lvgl.h" diff --git a/src/drv/tft/tft_driver_sdl2.h b/src/drv/tft/tft_driver_sdl2.h index d0aaa1142..32ce9e6df 100644 --- a/src/drv/tft/tft_driver_sdl2.h +++ b/src/drv/tft/tft_driver_sdl2.h @@ -6,7 +6,7 @@ #include "tft_driver.h" -#if USE_MONITOR && (defined(WINDOWS) || defined(POSIX)) +#if USE_MONITOR && HASP_TARGET_PC // #warning Building H driver TFT SDL2 #include "lvgl.h" @@ -40,6 +40,6 @@ class TftSdl : BaseTft { using dev::TftSdl; extern dev::TftSdl haspTft; -#endif // defined(WINDOWS) || defined(POSIX) +#endif // HASP_TARGET_PC #endif // HASP_SDL2_DRIVER_H diff --git a/src/drv/tft/tft_driver_win32drv.cpp b/src/drv/tft/tft_driver_win32drv.cpp index 709ed0543..911cae2e9 100644 --- a/src/drv/tft/tft_driver_win32drv.cpp +++ b/src/drv/tft/tft_driver_win32drv.cpp @@ -1,7 +1,7 @@ /* MIT License - Copyright (c) 2019-2022 Francis Van Roie For full license information read the LICENSE file in the project folder */ -#if USE_WIN32DRV && (defined(WINDOWS) || defined(POSIX)) +#if USE_WIN32DRV && HASP_TARGET_PC #include "hasplib.h" #include "lvgl.h" diff --git a/src/drv/tft/tft_driver_win32drv.h b/src/drv/tft/tft_driver_win32drv.h index 89dd4223f..eefcd4eb0 100644 --- a/src/drv/tft/tft_driver_win32drv.h +++ b/src/drv/tft/tft_driver_win32drv.h @@ -6,7 +6,7 @@ #include "tft_driver.h" -#if USE_WIN32DRV && (defined(WINDOWS) || defined(POSIX)) +#if USE_WIN32DRV && HASP_TARGET_PC // #warning Building H driver WIN32DRV #include "lvgl.h" @@ -39,6 +39,6 @@ class TftWin32Drv : BaseTft { using dev::TftWin32Drv; extern dev::TftWin32Drv haspTft; -#endif // defined(WINDOWS) || defined(POSIX) +#endif // HASP_TARGET_PC -#endif // HASP_SDL2_DRIVER_H +#endif // HASP_WIN32DRV_DRIVER_H diff --git a/src/hasp/hasp.cpp b/src/hasp/hasp.cpp index e2e49f0fc..353885706 100644 --- a/src/hasp/hasp.cpp +++ b/src/hasp/hasp.cpp @@ -11,7 +11,7 @@ #include "ArduinoLog.h" #endif -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC #include #include #include diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index f478fa621..80c699abf 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -16,7 +16,7 @@ #include "../hasp_debug.h" #include "hasp_gui.h" // for screenshot -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC #include #include #include @@ -1113,7 +1113,7 @@ void dispatch_reboot(bool saveConfig) LOG_VERBOSE(TAG_MSGR, F("-------------------------------------")); LOG_TRACE(TAG_MSGR, F(D_DISPATCH_REBOOT)); -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC fflush(stdout); #else Serial.flush(); @@ -1217,7 +1217,7 @@ void dispatch_send_discovery(const char*, const char*, uint8_t source) #if HASP_USE_HTTP > 0 network_get_ipaddress(buffer, sizeof(buffer)); doc[F("uri")] = String(F("http://")) + String(buffer); -#elif defined(WINDOWS) || defined(POSIX) +#elif HASP_TARGET_PC doc[F("uri")] = "http://google.pt"; #endif diff --git a/src/hasp/hasp_font.cpp b/src/hasp/hasp_font.cpp index 98a20c463..d86a4f14f 100644 --- a/src/hasp/hasp_font.cpp +++ b/src/hasp/hasp_font.cpp @@ -68,7 +68,7 @@ void font_setup() } else { LOG_ERROR(TAG_FONT, F("FreeType " D_SERVICE_START_FAILED)); } -#elif defined(WINDOWS) || defined(POSIX) +#elif HASP_TARGET_PC #else #endif diff --git a/src/hasp/hasp_object.cpp b/src/hasp/hasp_object.cpp index 08fd170e5..f7e436cfc 100644 --- a/src/hasp/hasp_object.cpp +++ b/src/hasp/hasp_object.cpp @@ -179,7 +179,7 @@ int hasp_parse_json_attributes(lv_obj_t* obj, const JsonObject& doc) { int i = 0; -#if defined(WINDOWS) || defined(POSIX) || defined(ESP32) +#if HASP_TARGET_PC || defined(ESP32) std::string v; v.reserve(64); diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp index 672c0ba20..fa2f54061 100644 --- a/src/hasp_debug.cpp +++ b/src/hasp_debug.cpp @@ -99,7 +99,7 @@ static inline void debug_flush() HASP_SERIAL.flush(); #endif -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC fflush(stdout); #endif } @@ -116,7 +116,7 @@ void debugEverySecond() void debugStart(void) { -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC debug_newline(); debugPrintHaspHeader(NULL); debug_newline(); diff --git a/src/hasp_debug.h b/src/hasp_debug.h index 425a7d973..c025ff99d 100644 --- a/src/hasp_debug.h +++ b/src/hasp_debug.h @@ -17,7 +17,7 @@ #include "lang/lang.h" -#if(!defined(WINDOWS)) && (!defined(POSIX)) +#if HASP_TARGET_ARDUINO /* ===== Default Event Processors ===== */ void debugSetup(JsonObject settings); diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 5fc3eb743..68a51d1c5 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -309,7 +309,7 @@ void guiSetup() static lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; -#if USE_MONITOR && (defined(WINDOWS) || defined(POSIX)) +#if USE_MONITOR && HASP_TARGET_PC indev_drv.read_cb = mouse_read; #else indev_drv.read_cb = gui_touch_read; @@ -345,7 +345,7 @@ void guiSetup() gui_hide_pointer(false); lv_indev_set_cursor(mouse_indev, cursor); /*Connect the image object to the driver*/ -#if !(defined(WINDOWS) || defined(POSIX)) +#if HASP_TARGET_ARDUINO // drv_touch_init(gui_settings.rotation); // Touch driver haspTouch.init(tft_width, tft_height); haspTouch.set_calibration(gui_settings.cal_data); @@ -386,7 +386,7 @@ IRAM_ATTR void guiLoop(void) // tick.update(); #endif -#if !(defined(WINDOWS) || defined(POSIX)) +#if HASP_TARGET_ARDUINO // haspTouch.loop(); #endif } diff --git a/src/main_arduino.cpp b/src/main_arduino.cpp index 8fc378b20..b383531c9 100644 --- a/src/main_arduino.cpp +++ b/src/main_arduino.cpp @@ -1,7 +1,7 @@ /* MIT License - Copyright (c) 2019-2024 Francis Van Roie For full license information read the LICENSE file in the project folder */ -#if !(defined(WINDOWS) || defined(POSIX)) +#if HASP_TARGET_ARDUINO /* #ifdef CORE_DEBUG_LEVEL diff --git a/src/main_pc.cpp b/src/main_pc.cpp index 322fb24bc..c49887714 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -1,7 +1,7 @@ /* MIT License - Copyright (c) 2019-2022 Francis Van Roie For full license information read the LICENSE file in the project folder */ -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC #if defined(WINDOWS) diff --git a/src/mqtt/hasp_mqtt_ha.cpp b/src/mqtt/hasp_mqtt_ha.cpp index bf6edb1c0..f7040e07d 100644 --- a/src/mqtt/hasp_mqtt_ha.cpp +++ b/src/mqtt/hasp_mqtt_ha.cpp @@ -16,7 +16,7 @@ #define RETAINED true -#if defined(WINDOWS) || defined(POSIX) +#if HASP_TARGET_PC extern std::string mqttNodeTopic; extern std::string mqttGroupTopic; #else @@ -35,7 +35,7 @@ const char FP_MQTT_HA_NAME[] PROGMEM = "name"; const char FP_MQTT_HA_MODEL[] PROGMEM = "mdl"; const char FP_MQTT_HA_MANUFACTURER[] PROGMEM = "mf"; -#if !(defined(WINDOWS) || defined(POSIX)) +#if HASP_TARGET_ARDUINO #include "hal/hasp_hal.h" diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin_sdl/darwin_sdl_64bits.ini index a1e640626..1cae860ee 100644 --- a/user_setups/darwin_sdl/darwin_sdl_64bits.ini +++ b/user_setups/darwin_sdl/darwin_sdl_64bits.ini @@ -6,7 +6,8 @@ extra_scripts = tools/linux_build_extra.py build_flags = ${env.build_flags} - -D HASP_MODEL="MacOS X App" + -D HASP_MODEL="MacOS X App" + -D HASP_TARGET_PC=1 ; ----- Monitor -D TFT_WIDTH=240 diff --git a/user_setups/esp32/_esp32.ini b/user_setups/esp32/_esp32.ini index a7440eae2..1a12c95d0 100644 --- a/user_setups/esp32/_esp32.ini +++ b/user_setups/esp32/_esp32.ini @@ -35,6 +35,7 @@ files = build_flags = ${env.build_flags} + -D HASP_TARGET_ARDUINO=1 -D HTTP_UPLOAD_BUFLEN=1024 ; lower http upload buffer -D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages -D HASP_CONSOLE_BUFFER=256 ; maximum length of a console/telnet command diff --git a/user_setups/esp8266/_esp8266.ini b/user_setups/esp8266/_esp8266.ini index ad231166d..e9ffe2120 100644 --- a/user_setups/esp8266/_esp8266.ini +++ b/user_setups/esp8266/_esp8266.ini @@ -12,6 +12,7 @@ board_build.f_cpu = 160000000L ; set frequency to 160MHz monitor_filters = esp8266_exception_decoder build_flags= + -D HASP_TARGET_ARDUINO=1 -D HTTP_UPLOAD_BUFLEN=512 ; lower http upload buffer -D MQTT_MAX_PACKET_SIZE=1024 ; longer PubSubClient messages -D HASP_CONSOLE_BUFFER=160 ; maximum length of a console/telnet command diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux_sdl/linux_sdl_64bits.ini index e68c716b1..dbe7f24c2 100644 --- a/user_setups/linux_sdl/linux_sdl_64bits.ini +++ b/user_setups/linux_sdl/linux_sdl_64bits.ini @@ -6,6 +6,7 @@ extra_scripts = build_flags = ${env.build_flags} -D HASP_MODEL="Linux App" + -D HASP_TARGET_PC=1 ; ----- Monitor -D TFT_WIDTH=240 diff --git a/user_setups/stm32f4xx/_stm32f4.ini b/user_setups/stm32f4xx/_stm32f4.ini index 20a755d32..7ec27e016 100644 --- a/user_setups/stm32f4xx/_stm32f4.ini +++ b/user_setups/stm32f4xx/_stm32f4.ini @@ -3,6 +3,7 @@ framework = arduino platform = ststm32 build_flags= + -D HASP_TARGET_ARDUINO=1 -I include/stm32f4 -D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages -D HASP_CONSOLE_BUFFER=220 ; maximum length of a console/telnet command @@ -21,4 +22,4 @@ build_flags= lib_deps = stm32duino/STM32duino LwIP @ ^2.1.2 - ;https://github.com/stm32duino/LwIP.git \ No newline at end of file + ;https://github.com/stm32duino/LwIP.git diff --git a/user_setups/stm32f7xx/_stm32f7.ini b/user_setups/stm32f7xx/_stm32f7.ini index 192119d5b..17fa84a67 100644 --- a/user_setups/stm32f7xx/_stm32f7.ini +++ b/user_setups/stm32f7xx/_stm32f7.ini @@ -3,6 +3,7 @@ framework = arduino platform = ststm32 build_flags= + -D HASP_TARGET_ARDUINO=1 ; -I include/stm32f4 -D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages -D HASP_CONSOLE_BUFFER=220 ; maximum length of a console/telnet command diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index 38d8b4c3a..87a24f4e0 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -6,6 +6,7 @@ extra_scripts = build_flags = ${env.build_flags} -D HASP_MODEL="Windows App" + -D HASP_TARGET_PC=1 ; ----- Monitor -D TFT_WIDTH=240 diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini index babadf777..e7b7b0821 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -6,6 +6,7 @@ extra_scripts = build_flags = ${env.build_flags} -D HASP_MODEL="Windows App" + -D HASP_TARGET_PC=1 ; ----- Monitor -D TFT_WIDTH=240 From 0e87f52c1fcdf938efd23c9b77ab87e7e6d7cbca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 7 Feb 2024 14:24:11 +0100 Subject: [PATCH 08/36] Support config file on PC build --- include/hasp_conf.h | 7 +- src/hasp/hasp_dispatch.cpp | 6 +- src/hasp_config.cpp | 86 +++++++++++++++++++----- src/hasp_config.h | 8 ++- src/hasp_debug.cpp | 19 +++++- src/hasp_gui.cpp | 14 ---- src/main_pc.cpp | 10 +-- src/mqtt/hasp_mqtt_paho_single.cpp | 28 ++++++++ user_setups/win32/windows_gdi_64bits.ini | 2 +- user_setups/win32/windows_sdl_64bits.ini | 2 +- 10 files changed, 138 insertions(+), 44 deletions(-) diff --git a/include/hasp_conf.h b/include/hasp_conf.h index 59ef00c1d..723b070de 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -214,7 +214,12 @@ /* Workarounds for PC build */ #if HASP_TARGET_PC #ifndef __FlashStringHelper -#define __FlashStringHelper char +typedef char __FlashStringHelper; +#endif + +#if defined(__cplusplus) && !defined(String) +#include +using String = std::string; #endif #ifndef F diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 80c699abf..db7ffdf40 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -460,10 +460,12 @@ void dispatch_config(const char* topic, const char* payload, uint8_t source) } if(strcasecmp_P(topic, PSTR("debug")) == 0) { +#if HASP_TARGET_ARDUINO if(update) debugSetConfig(settings); else debugGetConfig(settings); +#endif } else if(strcasecmp_P(topic, PSTR("gui")) == 0) { @@ -734,7 +736,7 @@ void dispatch_parse_jsonl(std::istream& stream, uint8_t& saved_page_id) void dispatch_parse_jsonl(const char*, const char* payload, uint8_t source) { if(source != TAG_MQTT) saved_jsonl_page = haspPages.get(); -#if HASP_USE_CONFIG > 0 +#if HASP_USE_CONFIG > 0 && HASP_TARGET_ARDUINO CharStream stream((char*)payload); // stream.setTimeout(10); dispatch_parse_jsonl(stream, saved_jsonl_page); @@ -1510,7 +1512,7 @@ void dispatchSetup() dispatch_add_command(PSTR("unzip"), filesystemUnzip); #endif #endif -#if HASP_USE_CONFIG > 0 +#if HASP_USE_CONFIG > 0 && HASP_TARGET_ARDUINO dispatch_add_command(PSTR("setupap"), oobeFakeSetup); #endif /* WARNING: remember to expand the commands array when adding new commands */ diff --git a/src/hasp_config.cpp b/src/hasp_config.cpp index d3e55b1ef..559c3f0a9 100644 --- a/src/hasp_config.cpp +++ b/src/hasp_config.cpp @@ -8,7 +8,9 @@ #include "hasp_config.h" #include "hasp_debug.h" #include "hasp_gui.h" +#if HASP_TARGET_ARDUINO #include "hal/hasp_hal.h" +#endif // #include "hasp_ota.h" included in conf // #include "hasp_filesystem.h" included in conf @@ -21,7 +23,9 @@ #include "EEPROM.h" #endif +#if HASP_USE_EEPROM > 0 #include "StreamUtils.h" // For EEPromStream +#endif extern uint16_t dispatchTelePeriod; extern uint32_t dispatchLastMillis; @@ -29,6 +33,7 @@ extern uint32_t dispatchLastMillis; extern gui_conf_t gui_settings; extern dispatch_conf_t dispatch_settings; +#if HASP_TARGET_ARDUINO void confDebugSet(const __FlashStringHelper* fstr_name) { /*char buffer[128]; @@ -36,6 +41,7 @@ void confDebugSet(const __FlashStringHelper* fstr_name) debugPrintln(buffer);*/ LOG_VERBOSE(TAG_CONF, F(D_BULLET "%S set"), fstr_name); } +#endif void confDebugSet(const char* fstr_name) { /*char buffer[128]; @@ -44,6 +50,7 @@ void confDebugSet(const char* fstr_name) LOG_VERBOSE(TAG_CONF, F(D_BULLET "%s set"), fstr_name); } +#if HASP_TARGET_ARDUINO bool configSet(bool& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name) { if(!setting.isNull()) { @@ -130,6 +137,7 @@ bool configSet(char *value, size_t size, const JsonVariant& setting, const __Fla } return false; } +#endif bool configSet(bool& value, const JsonVariant& setting, const char* fstr_name) { @@ -207,7 +215,9 @@ bool configSet(lv_color_t& value, const JsonVariant& setting, const char* fstr_n void configSetupDebug(JsonDocument& settings) { +#if HASP_TARGET_ARDUINO debugSetup(settings[FPSTR(FP_DEBUG)]); +#endif debugStart(); // Debug started, now we can use it; HASP header sent } @@ -239,9 +249,9 @@ void configMaskPasswords(JsonDocument& settings) DeserializationError configParseFile(String& configFile, JsonDocument& settings) { + DeserializationError result = DeserializationError::InvalidInput; #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 File file = HASP_FS.open(configFile, "r"); - DeserializationError result; if(file) { // size_t size = file.size(); @@ -254,30 +264,51 @@ DeserializationError configParseFile(String& configFile, JsonDocument& settings) return result; } return DeserializationError::InvalidInput; +#elif HASP_TARGET_PC + lv_fs_if_init(); + lv_fs_file_t f; + lv_fs_res_t res; + lv_fs_open(&f, "L:/config.json", LV_FS_MODE_RD); + if(res == LV_FS_RES_OK) { + uint32_t size = 0, read = 0; + if(lv_fs_size(&f, &size) == LV_FS_RES_OK && size != 0) { + char* buf = (char*)malloc(size + 1); + if(lv_fs_read(&f, buf, size, &read) == LV_FS_RES_OK && read == size) { + result = deserializeJson(settings, buf); + } + } + lv_fs_close(&f); + return result; + } + LOG_ERROR(TAG_HASP, F("Opening config.json from FS failed %d"), res); + return result; #else - return DeserializationError::InvalidInput; + return result; #endif } DeserializationError configRead(JsonDocument& settings, bool setupdebug) { - String configFile((char*)0); + String configFile; configFile.reserve(32); configFile = String(FPSTR(FP_HASP_CONFIG_FILE)); DeserializationError error; -#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 + if(setupdebug) configSetupDebug(settings); // Now we can use log + +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 || HASP_TARGET_PC error = configParseFile(configFile, settings); if(!error) { String output, wifiPass, mqttPass, httpPass, wgPrivKey; /* Load Debug params */ if(setupdebug) { - configSetupDebug(settings); // Now we can use log LOG_INFO(TAG_CONF, F("SPI flash FS mounted")); +#if HASP_TARGET_ARDUINO filesystemInfo(); filesystemList(); +#endif } LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), configFile.c_str()); @@ -304,9 +335,6 @@ DeserializationError configRead(JsonDocument& settings, bool setupdebug) #endif - // File does not exist or error reading file - if(setupdebug) configSetupDebug(settings); // Now we can use log - #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 LOG_ERROR(TAG_CONF, F(D_FILE_LOAD_FAILED), configFile.c_str()); #endif @@ -360,11 +388,11 @@ void configBackupToEeprom() */ void configWrite() { - String configFile((char*)0); + String configFile; configFile.reserve(32); configFile = String(FPSTR(FP_HASP_CONFIG_FILE)); - String settingsChanged((char*)0); + String settingsChanged; settingsChanged.reserve(128); settingsChanged = F(D_CONFIG_CHANGED); @@ -462,6 +490,7 @@ void configWrite() } #endif +#if HASP_TARGET_ARDUINO module = FPSTR(FP_DEBUG); if(settings[module].as().isNull()) settings.createNestedObject(module); changed = debugGetConfig(settings[module]); @@ -470,6 +499,7 @@ void configWrite() configOutput(settings[module], TAG_DEBG); writefile = true; } +#endif if(settings[FPSTR(FP_GUI)].as().isNull()) settings.createNestedObject(FPSTR(FP_GUI)); changed = guiGetConfig(settings[FPSTR(FP_GUI)]); @@ -561,9 +591,10 @@ void configSetup() configRead(settings, true); } - // #if HASP_USE_SPIFFS > 0 +#if HASP_TARGET_ARDUINO LOG_INFO(TAG_DEBG, F("Loading debug settings")); debugSetConfig(settings[FPSTR(FP_DEBUG)]); +#endif LOG_INFO(TAG_GPIO, F("Loading GUI settings")); guiSetConfig(settings[FPSTR(FP_GUI)]); LOG_INFO(TAG_HASP, F("Loading HASP settings")); @@ -615,15 +646,15 @@ void configLoop(void) void configOutput(const JsonObject& settings, uint8_t tag) { - String output((char*)0); + String output; output.reserve(128); serializeJson(settings, output); - String passmask((char*)0); + String passmask; passmask.reserve(128); passmask = F("\"pass\":\"" D_PASSWORD_MASK "\""); - String password((char*)0); + String password; password.reserve(128); String pass = F("pass"); @@ -631,28 +662,48 @@ void configOutput(const JsonObject& settings, uint8_t tag) password = F("\"pass\":\""); password += settings[pass].as(); password += F("\""); +#if HASP_TARGET_ARDUINO output.replace(password, passmask); +#elif HASP_TARGET_PC + size_t pos = 0; + if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask); +#endif } if(!settings[FPSTR(FP_WIFI)][pass].isNull()) { password = F("\"pass\":\""); password += settings[FPSTR(FP_WIFI)][pass].as(); password += F("\""); +#if HASP_TARGET_ARDUINO output.replace(password, passmask); +#elif HASP_TARGET_PC + size_t pos = 0; + if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask); +#endif } if(!settings[FPSTR(FP_MQTT)][pass].isNull()) { password = F("\"pass\":\""); password += settings[FPSTR(FP_MQTT)][pass].as(); password += F("\""); +#if HASP_TARGET_ARDUINO output.replace(password, passmask); +#elif HASP_TARGET_PC + size_t pos = 0; + if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask); +#endif } if(!settings[FPSTR(FP_HTTP)][pass].isNull()) { password = F("\"pass\":\""); password += settings[FPSTR(FP_HTTP)][pass].as(); password += F("\""); +#if HASP_TARGET_ARDUINO output.replace(password, passmask); +#elif HASP_TARGET_PC + size_t pos = 0; + if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask); +#endif } if(!settings[FPSTR(FP_WG)][FPSTR(FP_CONFIG_PRIVATE_KEY)].isNull()) { @@ -660,7 +711,12 @@ void configOutput(const JsonObject& settings, uint8_t tag) password += settings[FPSTR(FP_WG)][FPSTR(FP_CONFIG_PRIVATE_KEY)].as(); password += F("\""); passmask = F("\"privkey\":\"" D_PASSWORD_MASK "\""); +#if HASP_TARGET_ARDUINO output.replace(password, passmask); +#elif HASP_TARGET_PC + size_t pos = 0; + if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask); +#endif } LOG_VERBOSE(tag, output.c_str()); @@ -688,4 +744,4 @@ bool configClearEeprom() #endif } -#endif // HAS_USE_CONFIG \ No newline at end of file +#endif // HAS_USE_CONFIG diff --git a/src/hasp_config.h b/src/hasp_config.h index 8a667ed61..04160d30d 100644 --- a/src/hasp_config.h +++ b/src/hasp_config.h @@ -25,13 +25,15 @@ void configOutput(const JsonObject& settings, uint8_t tag); bool configClearEeprom(void); /* ===== Getter and Setter Functions ===== */ +#if HASP_TARGET_ARDUINO bool configSet(bool& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name); bool configSet(int8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name); bool configSet(uint8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name); bool configSet(uint16_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name); bool configSet(int32_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name); bool configSet(lv_color_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name); -bool configSet(char *value, size_t size, const JsonVariant& setting, const __FlashStringHelper* fstr_name); +bool configSet(char* value, size_t size, const JsonVariant& setting, const __FlashStringHelper* fstr_name); +#endif bool configSet(bool& value, const JsonVariant& setting, const char* fstr_name); bool configSet(int8_t& value, const JsonVariant& setting, const char* fstr_name); bool configSet(uint8_t& value, const JsonVariant& setting, const char* fstr_name); @@ -41,8 +43,10 @@ bool configSet(lv_color_t& value, const JsonVariant& setting, const char* fstr_n void configMaskPasswords(JsonDocument& settings); /* ===== Read/Write Configuration ===== */ +#if HASP_TARGET_ARDUINO void configSetConfig(JsonObject& settings); void configGetConfig(JsonDocument& settings); +#endif /* json keys used in the configfile */ const char FP_CONFIG_STARTPAGE[] PROGMEM = "startpage"; @@ -107,4 +111,4 @@ const char FP_OTA[] PROGMEM = "ota"; #endif -#endif // HASP_USE_CONFIG \ No newline at end of file +#endif // HASP_USE_CONFIG diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp index fa2f54061..421606cc4 100644 --- a/src/hasp_debug.cpp +++ b/src/hasp_debug.cpp @@ -8,12 +8,12 @@ #include "hasp_debug.h" #include "hasp_macro.h" -#if(!defined(WINDOWS)) && (!defined(POSIX)) +#if HASP_TARGET_ARDUINO #define debug_print(io, ...) io->printf(__VA_ARGS__) #define debug_newline(io) io->println() -#else +#elif HASP_TARGET_PC #include #include #include @@ -21,6 +21,17 @@ #define debug_print(io, ...) fprintf(stdout, __VA_ARGS__) #define debug_newline(io) fprintf(stdout, "\n") +#if defined(WINDOWS) +#include +#include +#define cwd _getcwd +#endif + +#if defined(POSIX) +#include +#define cwd getcwd +#endif + #endif bool debugAnsiCodes = false; @@ -121,6 +132,8 @@ void debugStart(void) debugPrintHaspHeader(NULL); debug_newline(); + char curdir[PATH_MAX]; + LOG_INFO(TAG_DEBG, F("Configuration directory: %s"), cwd(curdir, sizeof(curdir))); LOG_INFO(TAG_DEBG, F("Environment: " PIOENV)); LOG_INFO(TAG_DEBG, F("Console started")); @@ -445,4 +458,4 @@ void debugPrintPrefix(uint8_t tag, int level, Print* _logOutput) #else debug_print(_logOutput, PSTR(" %s: "), buffer); #endif -} \ No newline at end of file +} diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 68a51d1c5..d39195e81 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -207,21 +207,7 @@ static inline void gui_init_images() static inline void gui_init_filesystems() { #if LV_USE_FS_IF != 0 - //_lv_fs_init(); // lvgl File System -- not needed, it done in lv_init() when LV_USE_FILESYSTEM is set LOG_VERBOSE(TAG_LVGL, F("Filesystem : " D_SETTING_ENABLED)); - lv_fs_if_init(); // auxiliary file system drivers - // filesystem_list_path("L:/"); - - lv_fs_file_t f; - lv_fs_res_t res; - res = lv_fs_open(&f, "L:/config.json", LV_FS_MODE_RD); - if(res == LV_FS_RES_OK) { - LOG_VERBOSE(TAG_HASP, F("TEST Opening config.json OK")); - lv_fs_close(&f); - } else { - LOG_ERROR(TAG_HASP, F("TEST Opening config.json from FS failed %d"), res); - } - #else LOG_VERBOSE(TAG_LVGL, F("Filesystem : " D_SETTING_DISABLED)); #endif diff --git a/src/main_pc.cpp b/src/main_pc.cpp index c49887714..6b2d0c83b 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -112,15 +112,15 @@ void InitializeConsoleOutput() void setup() { - // Load Settings - - // Init debug log - // debug_init(); - // Initialize lvgl environment lv_init(); lv_log_register_print_cb(debugLvglLogEvent); + // Read & Apply User Configuration +#if HASP_USE_CONFIG > 0 + configSetup(); +#endif + haspDevice.init(); // hardware setup haspDevice.show_info(); // debug info // hal_setup(); diff --git a/src/mqtt/hasp_mqtt_paho_single.cpp b/src/mqtt/hasp_mqtt_paho_single.cpp index 17804f894..323b82fd3 100644 --- a/src/mqtt/hasp_mqtt_paho_single.cpp +++ b/src/mqtt/hasp_mqtt_paho_single.cpp @@ -8,12 +8,14 @@ #if HASP_USE_MQTT > 0 #ifdef HASP_USE_PAHO +#if !HASP_USE_CONFIG const char FP_CONFIG_HOST[] PROGMEM = "host"; const char FP_CONFIG_PORT[] PROGMEM = "port"; const char FP_CONFIG_NAME[] PROGMEM = "name"; const char FP_CONFIG_USER[] PROGMEM = "user"; const char FP_CONFIG_PASS[] PROGMEM = "pass"; const char FP_CONFIG_GROUP[] PROGMEM = "group"; +#endif /******************************************************************************* * Copyright (c) 2012, 2020 IBM Corp. @@ -411,6 +413,32 @@ void mqtt_get_info(JsonDocument& doc) info[F(D_INFO_FAILED)] = mqttFailedCount; } +bool mqttGetConfig(const JsonObject& settings) +{ + bool changed = false; + + if(strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)].as().c_str()) != 0) changed = true; + settings[FPSTR(FP_CONFIG_NAME)] = haspDevice.get_hostname(); + + if(mqttGroupName != settings[FPSTR(FP_CONFIG_GROUP)].as()) changed = true; + settings[FPSTR(FP_CONFIG_GROUP)] = mqttGroupName; + + if(mqttServer != settings[FPSTR(FP_CONFIG_HOST)].as()) changed = true; + settings[FPSTR(FP_CONFIG_HOST)] = mqttServer; + + if(mqttPort != settings[FPSTR(FP_CONFIG_PORT)].as()) changed = true; + settings[FPSTR(FP_CONFIG_PORT)] = mqttPort; + + if(mqttUsername != settings[FPSTR(FP_CONFIG_USER)].as()) changed = true; + settings[FPSTR(FP_CONFIG_USER)] = mqttUsername; + + if(mqttPassword != settings[FPSTR(FP_CONFIG_PASS)].as()) changed = true; + settings[FPSTR(FP_CONFIG_PASS)] = mqttPassword; + + if(changed) configOutput(settings, TAG_MQTT); + return changed; +} + /** Set MQTT Configuration. * * Read the settings from json and sets the application variables. diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index 87a24f4e0..4330c02a9 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -22,7 +22,7 @@ build_flags = -D HASP_USE_LITTLEFS=0 -D HASP_USE_EEPROM=0 -D HASP_USE_GPIO=1 - -D HASP_USE_CONFIG=0 ; Standalone application, as library + -D HASP_USE_CONFIG=1 ; Standalone application, as library -D HASP_USE_DEBUG=1 -D HASP_USE_PNGDECODE=1 -D HASP_USE_BMPDECODE=1 diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini index e7b7b0821..30de808f9 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -26,7 +26,7 @@ build_flags = -D HASP_USE_LITTLEFS=0 -D HASP_USE_EEPROM=0 -D HASP_USE_GPIO=1 - -D HASP_USE_CONFIG=0 ; Standalone application, as library + -D HASP_USE_CONFIG=1 ; Standalone application, as library -D HASP_USE_DEBUG=1 -D HASP_USE_PNGDECODE=1 -D HASP_USE_BMPDECODE=1 From cb1d860635ce329246b5a0faff8a6261739da68f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 7 Feb 2024 16:33:52 +0100 Subject: [PATCH 09/36] Cleanup PC entrypoint, remove MQTT CLI options --- src/dev/win32/hasp_win32.cpp | 1 + src/dev/win32/hasp_win32.h | 2 +- src/drv/tft/tft_driver_win32drv.cpp | 8 +- src/main_pc.cpp | 209 +++++++---------------- user_setups/win32/windows_gdi_64bits.ini | 4 +- user_setups/win32/windows_sdl_64bits.ini | 3 +- 6 files changed, 63 insertions(+), 164 deletions(-) diff --git a/src/dev/win32/hasp_win32.cpp b/src/dev/win32/hasp_win32.cpp index 460518047..213b8801f 100644 --- a/src/dev/win32/hasp_win32.cpp +++ b/src/dev/win32/hasp_win32.cpp @@ -43,6 +43,7 @@ void Win32Device::show_info() LOG_VERBOSE(0, F("Processor : %s"), vendor); LOG_VERBOSE(0, F("CPU freq. : %i MHz"), get_cpu_frequency()); + LOG_VERBOSE(0, F("OS Version : %s"), get_core_version()); } const char* Win32Device::get_hostname() diff --git a/src/dev/win32/hasp_win32.h b/src/dev/win32/hasp_win32.h index 5e59ea738..e4b11746d 100644 --- a/src/dev/win32/hasp_win32.h +++ b/src/dev/win32/hasp_win32.h @@ -43,7 +43,7 @@ class Win32Device : public BaseDevice { if(dwVersion < 0x80000000) dwBuild = (DWORD)(HIWORD(dwVersion)); char version[128]; - snprintf(version, sizeof(version), "Windows %d.%d-%d", dwMajorVersion, dwMinorVersion, dwBuild); + snprintf(version, sizeof(version), "Windows %d.%d.%d", dwMajorVersion, dwMinorVersion, dwBuild); _core_version = version; // _backlight_pin = -1; diff --git a/src/drv/tft/tft_driver_win32drv.cpp b/src/drv/tft/tft_driver_win32drv.cpp index 911cae2e9..38babbb91 100644 --- a/src/drv/tft/tft_driver_win32drv.cpp +++ b/src/drv/tft/tft_driver_win32drv.cpp @@ -68,13 +68,7 @@ void TftWin32Drv::show_info() { splashscreen(); - unsigned long version = GetVersion(); - unsigned long major = LOBYTE(LOWORD(version)); - unsigned long minor = HIBYTE(LOWORD(version)); - unsigned long build = 0; - if(version < 0x80000000) build = HIWORD(version); - LOG_VERBOSE(TAG_TFT, F("Driver : Win32Drv")); - LOG_VERBOSE(TAG_TFT, F("Windows Version: %d.%d.%d"), major, minor, build); + LOG_VERBOSE(TAG_TFT, F("Driver : Win32Drv")); } void TftWin32Drv::splashscreen() diff --git a/src/main_pc.cpp b/src/main_pc.cpp index 6b2d0c83b..5430b1305 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -121,23 +121,19 @@ void setup() configSetup(); #endif - haspDevice.init(); // hardware setup - haspDevice.show_info(); // debug info + haspDevice.init(); // hardware setup // hal_setup(); guiSetup(); - LOG_DEBUG(TAG_MAIN, "%s %d", __FILE__, __LINE__); dispatchSetup(); // for hasp and oobe haspSetup(); #if HASP_USE_MQTT > 0 - LOG_DEBUG(TAG_MAIN, "%s %d", __FILE__, __LINE__); mqttSetup(); // Hasp must be running mqttStart(); #endif #if HASP_USE_GPIO > 0 - LOG_DEBUG(TAG_MAIN, "%s %d", __FILE__, __LINE__); gpioSetup(); #endif @@ -146,7 +142,6 @@ void setup() #endif mainLastLoopTime = millis(); // - 1000; // reset loop counter - LOG_DEBUG(TAG_MAIN, "%s %d", __FILE__, __LINE__); // delay(250); } @@ -191,7 +186,9 @@ void loop() if(mainLoopCounter == 0 || mainLoopCounter == 5) { haspDevice.loop_5s(); +#if HASP_USE_GPIO > 0 gpioEvery5Seconds(); +#endif #if HASP_USE_MQTT mqttEvery5Seconds(true); @@ -215,175 +212,86 @@ void loop() void usage(const char* progName, const char* version) { - std::cout << "\n\n" - << progName << " " << version << " [options]" << std::endl - << std::endl - << "Options:" << std::endl - << " -? | --help Print this help" << std::endl - << " -w | --width Width of the window" << std::endl - << " -h | --height Height of the window" << std::endl - << " --mqttname MQTT device name topic (default: computer hostname)" << std::endl - << " --mqtthost MQTT broker hostname or IP address" << std::endl - << " --mqttport MQTT broker port (default: 1883)" << std::endl - << " --mqttuser MQTT username" << std::endl - << " --mqttpass MQTT password" << std::endl - << " --mqttgroup MQTT groupname (default: plates)" << std::endl - << std::endl - // << " -t | --topic Base topic of the mqtt messages (default: hasp)" << std::endl - // << std::endl - // << " -f | --fullscreen Open the application fullscreen" << std::endl - // << " -v | --verbose Verbosity level" << std::endl - << std::endl; + std::cout + << "\n" + << progName << " " << version << " [options]" << std::endl + << std::endl + << "Options:" << std::endl + << " -h | --help Print this help" << std::endl + << " -W | --width Width of the window" << std::endl + << " -H | --height Height of the window" << std::endl + << " -C | --config Configuration directory (default: '~/.local/share/hasp' or 'AppData\\hasp\\hasp')" + << std::endl + << std::endl; fflush(stdout); -#if defined(WINDOWS) - static const char s[] = "\n"; - DWORD slen = lstrlen(s); - WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), s, slen, &slen, NULL); -#endif } int main(int argc, char* argv[]) { - bool showhelp = false; - int count; + bool showhelp = false; + bool console = true; + char config[PATH_MAX] = {'\0'}; #if defined(WINDOWS) InitializeConsoleOutput(); SetConsoleCP(65001); // 65001 = UTF-8 - static const char s[] = "tränenüberströmt™\n"; - DWORD slen = lstrlen(s); - WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), s, slen, &slen, NULL); - - HANDLE std_out = GetStdHandle(STD_OUTPUT_HANDLE); - if(std_out == INVALID_HANDLE_VALUE) { - return 66; - } - if(!WriteConsole(std_out, "Hello World!\n", 13, NULL, NULL)) { - return 67; - } -#endif - - char buf[4096]; // never know how much is needed - std::cout << "CWD: " << cwd(buf, sizeof buf) << std::endl; -#if USE_MONITOR - SDL_Init(0); // Needs to be initialized for GetPerfPath - cd(SDL_GetPrefPath("hasp", "hasp")); - SDL_Quit(); // We'll properly init later -#elif USE_WIN32DRV - if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, buf))) { - PathAppendA(buf, "hasp"); - PathAppendA(buf, "hasp"); - cd(buf); - } #endif - std::cout << "CWD changed to: " << cwd(buf, sizeof buf) << std::endl; - - // Change to preferences dir - std::cout << "\nCommand-line arguments:\n"; - for(count = 0; count < argc; count++) - std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush; - - StaticJsonDocument<1024> settings; - for(count = 0; count < argc; count++) { - if(argv[count][0] == '-') { - - if(strncmp(argv[count], "--help", 6) == 0 || strncmp(argv[count], "-?", 2) == 0) { - showhelp = true; - } - - if(strncmp(argv[count], "--width", 7) == 0 || strncmp(argv[count], "-w", 2) == 0) { - int w = atoi(argv[count + 1]); + for(int arg = 1; arg < argc; arg++) { + if(strncmp(argv[arg], "--help", 6) == 0 || strncmp(argv[arg], "-h", 2) == 0) { + showhelp = true; + } else if(strncmp(argv[arg], "--width", 7) == 0 || strncmp(argv[arg], "-W", 2) == 0) { + if(arg + 1 < argc) { + int w = atoi(argv[arg + 1]); if(w > 0) tft_width = w; + arg++; + } else { + std::cout << "Missing width value" << std::endl; + showhelp = true; } - - if(strncmp(argv[count], "--height", 8) == 0 || strncmp(argv[count], "-h", 2) == 0) { - int h = atoi(argv[count + 1]); + } else if(strncmp(argv[arg], "--height", 8) == 0 || strncmp(argv[arg], "-H", 2) == 0) { + if(arg + 1 < argc) { + int h = atoi(argv[arg + 1]); if(h > 0) tft_height = h; + arg++; + } else { + std::cout << "Missing height value" << std::endl; + showhelp = true; } - - if(strncmp(argv[count], "--mqttname", 10) == 0 || strncmp(argv[count], "-n", 2) == 0) { - std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush; - fflush(stdout); - if(count + 1 < argc) { - haspDevice.set_hostname(argv[count + 1]); - settings["mqtt"]["name"] = argv[count + 1]; - } else { - showhelp = true; - } - } - - if(strncmp(argv[count], "--mqtthost", 10) == 0) { - std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush; - fflush(stdout); - if(count + 1 < argc) { - settings["mqtt"]["host"] = argv[count + 1]; - } else { - showhelp = true; - } - } - - if(strncmp(argv[count], "--mqttport", 10) == 0) { - std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush; - fflush(stdout); - if(count + 1 < argc) { - settings["mqtt"]["port"] = atoi(argv[count + 1]); - } else { - showhelp = true; - } - } - - if(strncmp(argv[count], "--mqttuser", 10) == 0) { - std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush; - fflush(stdout); - if(count + 1 < argc) { - settings["mqtt"]["user"] = argv[count + 1]; - } else { - showhelp = true; - } - } - - if(strncmp(argv[count], "--mqttpass", 10) == 0) { - std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush; - fflush(stdout); - if(count + 1 < argc) { - settings["mqtt"]["pass"] = argv[count + 1]; - } else { - showhelp = true; - } + } else if(strncmp(argv[arg], "--config", 8) == 0 || strncmp(argv[arg], "-C", 2) == 0) { + if(arg + 1 < argc) { + strcpy(config, argv[arg + 1]); + arg++; + } else { + std::cout << "Missing config directory" << std::endl; + showhelp = true; } + } else { + std::cout << "Unrecognized command line parameter: " << argv[arg] << std::endl; + showhelp = true; } } if(showhelp) { usage("openHASP", haspDevice.get_version()); - -#if defined(WINDOWS) - WriteConsole(std_out, "bye\n\n", 3, NULL, NULL); - std::cout << std::endl << std::flush; - fflush(stdout); - FreeConsole(); - exit(0); -#endif - return 0; + goto end; } - char buffer[2048]; - serializeJson(settings, buffer, sizeof(buffer)); - std::cout << buffer << std::endl << std::flush; - fflush(stdout); -#if HASP_USE_MQTT - mqttSetConfig(settings["mqtt"]); + if(config[0] == '\0') { +#if USE_MONITOR + SDL_Init(0); // Needs to be initialized for GetPerfPath + strcpy(config, SDL_GetPrefPath("hasp", "hasp")); + SDL_Quit(); // We'll properly init later +#elif USE_WIN32DRV + if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, config))) { + PathAppendA(config, "hasp"); + PathAppendA(config, "hasp"); + } #endif - // printf("%s %d\n", __FILE__, __LINE__); - // fflush(stdout); - - debugPrintHaspHeader(stdout); - LOG_INFO(TAG_MAIN, "resolution %d x %d", tft_width, tft_height); - LOG_INFO(TAG_MAIN, "pre setup"); + } + cd(config); setup(); - #if USE_MONITOR while(1) { loop(); @@ -395,14 +303,13 @@ int main(int argc, char* argv[]) } #endif +end: #if defined(WINDOWS) - WriteConsole(std_out, "bye\n\n", 3, NULL, NULL); std::cout << std::endl << std::flush; fflush(stdout); FreeConsole(); exit(0); #endif - return 0; } diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index 4330c02a9..0344d2fcf 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -1,7 +1,6 @@ [env:windows_gdi_64bits] platform = native@^1.1.4 extra_scripts = - tools/sdl2_build_extra.py tools/windows_build_extra.py build_flags = ${env.build_flags} @@ -65,13 +64,12 @@ build_flags = -lrpcrt4 -lcrypt32 -lmingw32 - -mwindows -lm -ldinput8 ;-ldxguid ;-ldxerr8 ;-luser32 - ;-lgdi32 + -lgdi32 -lwinmm -limm32 -lole32 diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini index 30de808f9..0caacccac 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -72,13 +72,12 @@ build_flags = -lmingw32 -lSDL2main -lSDL2 - -mwindows -lm -ldinput8 ;-ldxguid ;-ldxerr8 ;-luser32 - ;-lgdi32 + -lgdi32 -lwinmm -limm32 -lole32 From d0e383e398043d60e26b5469d35419c935441a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 7 Feb 2024 17:19:35 +0100 Subject: [PATCH 10/36] Merge setup() and loop() of PC and Arduino --- include/hasp_conf.h | 2 +- src/{main_arduino.cpp => main.cpp} | 24 ++-- src/main_pc.cpp | 118 +------------------ user_setups/darwin_sdl/darwin_sdl_64bits.ini | 4 +- user_setups/linux_sdl/linux_sdl_64bits.ini | 4 +- user_setups/win32/windows_gdi_64bits.ini | 4 +- user_setups/win32/windows_sdl_64bits.ini | 4 +- 7 files changed, 27 insertions(+), 133 deletions(-) rename src/{main_arduino.cpp => main.cpp} (94%) diff --git a/include/hasp_conf.h b/include/hasp_conf.h index 723b070de..dece01d19 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -123,7 +123,7 @@ #endif #ifndef HASP_USE_CONSOLE -#define HASP_USE_CONSOLE 1 +#define HASP_USE_CONSOLE HASP_TARGET_ARDUINO #endif /* Filesystem */ diff --git a/src/main_arduino.cpp b/src/main.cpp similarity index 94% rename from src/main_arduino.cpp rename to src/main.cpp index b383531c9..68a51af38 100644 --- a/src/main_arduino.cpp +++ b/src/main.cpp @@ -1,8 +1,6 @@ /* MIT License - Copyright (c) 2019-2024 Francis Van Roie For full license information read the LICENSE file in the project folder */ -#if HASP_TARGET_ARDUINO - /* #ifdef CORE_DEBUG_LEVEL #undef CORE_DEBUG_LEVEL @@ -28,9 +26,9 @@ #include "hasp_gui.h" #endif -bool isConnected; -uint8_t mainLoopCounter = 0; -unsigned long mainLastLoopTime = 0; +static bool isConnected; +static uint8_t mainLoopCounter = 0; +static unsigned long mainLastLoopTime = 0; #ifdef HASP_USE_STAT_COUNTER uint16_t statLoopCounter = 0; // measures the average looptime @@ -40,11 +38,18 @@ void setup() { // hal_setup(); +#if HASP_TARGET_ARDUINO esp_log_level_set("*", ESP_LOG_NONE); // set all components to ERROR level // esp_log_level_set("wifi", ESP_LOG_NONE); // enable WARN logs from WiFi stack // esp_log_level_set("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client // esp_log_level_set("esp_crt_bundle", ESP_LOG_VERBOSE); // enable WARN logs from WiFi stack // esp_log_level_set("esp_tls", ESP_LOG_VERBOSE); // enable WARN logs from WiFi stack +#elif HASP_TARGET_PC + // Initialize lvgl environment + lv_init(); + lv_log_register_print_cb(debugLvglLogEvent); +#endif + haspDevice.init(); /**************************** @@ -149,7 +154,7 @@ void setup() gui_setup_lvgl_task(); #endif // HASP_USE_LVGL_TASK - mainLastLoopTime = -1000; // reset loop counter + mainLastLoopTime = 0; // reset loop counter } IRAM_ATTR void loop() @@ -195,7 +200,7 @@ IRAM_ATTR void loop() /* Timer Loop */ if(millis() - mainLastLoopTime >= 1000) { - mainLastLoopTime += 1000; + mainLastLoopTime = millis(); /* Runs Every Second */ haspEverySecond(); // sleep timer & statusupdate @@ -237,10 +242,9 @@ IRAM_ATTR void loop() case 4: #if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0 isConnected = networkEvery5Seconds(); // Check connection - +#endif #if HASP_USE_MQTT > 0 mqttEvery5Seconds(isConnected); -#endif #endif break; @@ -270,5 +274,3 @@ IRAM_ATTR void loop() delay(2); // ms #endif } - -#endif diff --git a/src/main_pc.cpp b/src/main_pc.cpp index 5430b1305..2b4f73627 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -26,28 +26,20 @@ #include "hasplib.h" -// #include "app_hal.h" #if USE_MONITOR #include "display/monitor.h" #endif #include "hasp_debug.h" -#include "hasp_gui.h" - -#include "dev/device.h" - -bool isConnected; - -uint8_t mainLoopCounter = 0; -unsigned long mainLastLoopTime = 0; - -#ifdef HASP_USE_STAT_COUNTER -uint16_t statLoopCounter = 0; // measures the average looptime -#endif +// hasp_gui.cpp extern uint16_t tft_width; extern uint16_t tft_height; +// main.cpp +extern void setup(); +extern void loop(); + #if defined(WINDOWS) // https://gist.github.com/kingseva/a918ec66079a9475f19642ec31276a21 void BindStdHandlesToConsole() @@ -110,106 +102,6 @@ void InitializeConsoleOutput() } #endif -void setup() -{ - // Initialize lvgl environment - lv_init(); - lv_log_register_print_cb(debugLvglLogEvent); - - // Read & Apply User Configuration -#if HASP_USE_CONFIG > 0 - configSetup(); -#endif - - haspDevice.init(); // hardware setup - // hal_setup(); - guiSetup(); - - dispatchSetup(); // for hasp and oobe - haspSetup(); - -#if HASP_USE_MQTT > 0 - mqttSetup(); // Hasp must be running - mqttStart(); -#endif - -#if HASP_USE_GPIO > 0 - gpioSetup(); -#endif - -#if defined(HASP_USE_CUSTOM) - custom_setup(); -#endif - - mainLastLoopTime = millis(); // - 1000; // reset loop counter - // delay(250); -} - -void loop() -{ - haspLoop(); -#if HASP_USE_MQTT - mqttLoop(); -#endif - - // debugLoop(); // Console - haspDevice.loop(); - guiLoop(); - -#if HASP_USE_GPIO > 0 - gpioLoop(); -#endif - -#if defined(HASP_USE_CUSTOM) - custom_loop(); -#endif - -#ifdef HASP_USE_STAT_COUNTER - statLoopCounter++; // measures the average looptime -#endif - - /* Timer Loop */ - if(millis() - mainLastLoopTime >= 1000) { - /* Runs Every Second */ - haspEverySecond(); // sleep timer - dispatchEverySecond(); // sleep timer - -#if HASP_USE_ARDUINOOTA > 0 - otaEverySecond(); // progressbar -#endif - -#if defined(HASP_USE_CUSTOM) - custom_every_second(); -#endif - - /* Runs Every 5 Seconds */ - if(mainLoopCounter == 0 || mainLoopCounter == 5) { - - haspDevice.loop_5s(); -#if HASP_USE_GPIO > 0 - gpioEvery5Seconds(); -#endif - -#if HASP_USE_MQTT - mqttEvery5Seconds(true); -#endif - -#if defined(HASP_USE_CUSTOM) - custom_every_5seconds(); -#endif - } - - /* Reset loop counter every 10 seconds */ - if(mainLoopCounter >= 9) { - mainLoopCounter = 0; - } else { - mainLoopCounter++; - } - mainLastLoopTime += 1000; - } - // delay(6); -} - void usage(const char* progName, const char* version) { std::cout diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin_sdl/darwin_sdl_64bits.ini index 1cae860ee..1003bc6fa 100644 --- a/user_setups/darwin_sdl/darwin_sdl_64bits.ini +++ b/user_setups/darwin_sdl/darwin_sdl_64bits.ini @@ -26,8 +26,8 @@ build_flags = -D HASP_USE_SPIFFS=0 -D HASP_USE_LITTLEFS=0 -D HASP_USE_EEPROM=0 - -D HASP_USE_GPIO=1 - -D HASP_USE_CONFIG=0 ; Standalone application, as library + -D HASP_USE_GPIO=0 + -D HASP_USE_CONFIG=1 -D HASP_USE_DEBUG=1 -D HASP_USE_PNGDECODE=1 -D HASP_USE_BMPDECODE=1 diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux_sdl/linux_sdl_64bits.ini index dbe7f24c2..c1e8d8dcb 100644 --- a/user_setups/linux_sdl/linux_sdl_64bits.ini +++ b/user_setups/linux_sdl/linux_sdl_64bits.ini @@ -26,8 +26,8 @@ build_flags = -D HASP_USE_LITTLEFS=0 -D LV_USE_FS_IF=1 -D HASP_USE_EEPROM=0 - -D HASP_USE_GPIO=1 - -D HASP_USE_CONFIG=0 ; Standalone application, as library + -D HASP_USE_GPIO=0 + -D HASP_USE_CONFIG=1 -D HASP_USE_DEBUG=1 -D HASP_USE_PNGDECODE=1 -D HASP_USE_BMPDECODE=1 diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index 0344d2fcf..e3a86401b 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -20,8 +20,8 @@ build_flags = -D HASP_USE_SPIFFS=0 -D HASP_USE_LITTLEFS=0 -D HASP_USE_EEPROM=0 - -D HASP_USE_GPIO=1 - -D HASP_USE_CONFIG=1 ; Standalone application, as library + -D HASP_USE_GPIO=0 + -D HASP_USE_CONFIG=1 -D HASP_USE_DEBUG=1 -D HASP_USE_PNGDECODE=1 -D HASP_USE_BMPDECODE=1 diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini index 0caacccac..a4a131e2f 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -25,8 +25,8 @@ build_flags = -D HASP_USE_SPIFFS=0 -D HASP_USE_LITTLEFS=0 -D HASP_USE_EEPROM=0 - -D HASP_USE_GPIO=1 - -D HASP_USE_CONFIG=1 ; Standalone application, as library + -D HASP_USE_GPIO=0 + -D HASP_USE_CONFIG=1 -D HASP_USE_DEBUG=1 -D HASP_USE_PNGDECODE=1 -D HASP_USE_BMPDECODE=1 From a884fbf705e035eb00c3a76f5b4820176642dc62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 7 Feb 2024 19:30:17 +0100 Subject: [PATCH 11/36] Implement LVGL task for Windows GDI --- src/dev/device.h | 3 ++ src/drv/tft/tft_driver_sdl2.cpp | 4 ++ src/drv/tft/tft_driver_win32drv.cpp | 60 +++++++++++++++++++++--- src/hasp_gui.cpp | 21 +++++++-- src/hasp_gui.h | 7 ++- src/main_pc.cpp | 3 +- user_setups/win32/windows_gdi_64bits.ini | 1 + 7 files changed, 84 insertions(+), 15 deletions(-) diff --git a/src/dev/device.h b/src/dev/device.h index 75039f340..a17ef6dd3 100644 --- a/src/dev/device.h +++ b/src/dev/device.h @@ -30,6 +30,9 @@ class BaseDevice { public: bool has_battery = false; bool has_backligth_control = true; +#if HASP_TARGET_PC + bool pc_is_running = true; +#endif virtual void reboot() {} diff --git a/src/drv/tft/tft_driver_sdl2.cpp b/src/drv/tft/tft_driver_sdl2.cpp index 82ca964d2..c6c946513 100644 --- a/src/drv/tft/tft_driver_sdl2.cpp +++ b/src/drv/tft/tft_driver_sdl2.cpp @@ -75,6 +75,10 @@ void TftSdl::init(int32_t w, int h) * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed * Create an SDL thread to do this*/ SDL_CreateThread(tick_thread, "tick", NULL); + +#if HASP_USE_LVGL_TASK +#error "SDL2 LVGL task is not implemented" +#endif } void TftSdl::show_info() { diff --git a/src/drv/tft/tft_driver_win32drv.cpp b/src/drv/tft/tft_driver_win32drv.cpp index 38babbb91..25a857476 100644 --- a/src/drv/tft/tft_driver_win32drv.cpp +++ b/src/drv/tft/tft_driver_win32drv.cpp @@ -13,6 +13,7 @@ #include "dev/device.h" #include "hasp_debug.h" +#include "hasp_gui.h" #ifdef HASP_CUSTOMIZE_BOOTLOGO #include "custom/bootlogo.h" // Sketch tab header for xbm images @@ -48,21 +49,66 @@ int32_t TftWin32Drv::height() return _height; } -void TftWin32Drv::init(int32_t w, int h) +static void win32_message_loop(lv_task_t* param) { - _width = w; - _height = h; + MSG Message; +#if HASP_USE_LVGL_TASK + while(haspDevice.pc_is_running && GetMessageW(&Message, NULL, 0, 0)) { + TranslateMessage(&Message); + DispatchMessageW(&Message); + } + // apparently GetMessageW doesn't deliver WM_QUIT + haspDevice.pc_is_running = false; +#else + BOOL Result = PeekMessageW(&Message, NULL, 0, 0, TRUE); + if(Result != 0 && Result != -1) { + TranslateMessage(&Message); + DispatchMessageW(&Message); + if(Message.message == WM_QUIT) haspDevice.pc_is_running = false; + } +#endif +} +static DWORD gui_entrypoint(HANDLE semaphore) +{ /* Add a display * Use the 'win32drv' driver which creates window on PC's monitor to simulate a display * The following input devices are handled: mouse, keyboard, mousewheel */ - lv_win32_init(0, SW_SHOWNORMAL, w, h, 0); + lv_win32_init(0, SW_SHOWNORMAL, haspTft.width(), haspTft.height(), 0); lv_win32_set_title(haspDevice.get_hostname()); - /* Tick init. - * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed - * Create a Windows thread to do this*/ +#if HASP_USE_LVGL_TASK + // let the init() function continue + ReleaseSemaphore(semaphore, 1, NULL); + // run the LVGL task as a thread + HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)gui_task, NULL, 0, NULL); + // run a blocking message loop on this thread + win32_message_loop(NULL); + // wait for the LVGL task now + WaitForSingleObject(thread, 4000); +#else + // create a LVGL tick thread CreateThread(NULL, 0, tick_thread, NULL, 0, NULL); + // create a LVGL task for the message loop + lv_task_create(win32_message_loop, 5, LV_TASK_PRIO_HIGHEST, NULL); +#endif + return 0; +} + +void TftWin32Drv::init(int32_t w, int h) +{ + _width = w; + _height = h; + +#if HASP_USE_LVGL_TASK + // run a thread for creating the window and running the message loop + HANDLE semaphore = CreateSemaphore(NULL, 0, 1, NULL); + HANDLE thread = CreateThread(NULL, 0, gui_entrypoint, semaphore, 0, NULL); + WaitForSingleObject(semaphore, INFINITE); +#else + // do not use the gui_task(), just init the GUI and return + gui_entrypoint(NULL); +#endif } void TftWin32Drv::show_info() { diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index d39195e81..af4c83881 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -382,23 +382,34 @@ void guiEverySecond(void) // nothing } -#if defined(ESP32) && defined(HASP_USE_ESP_MQTT) - #if HASP_USE_LVGL_TASK == 1 -static void gui_task(void* args) +void gui_task(void* args) { LOG_TRACE(TAG_GUI, "Start to run LVGL"); - while(1) { + while(haspDevice.pc_is_running) { + // no idea what MQTT has to do with LVGL - the #if is copied from the code below +#if defined(ESP32) && defined(HASP_USE_ESP_MQTT) /* Try to take the semaphore, call lvgl related function on success */ - // if(pdTRUE == xSemaphoreTake(xGuiSemaphore, pdMS_TO_TICKS(10))) { if(pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) { lv_task_handler(); xSemaphoreGive(xGuiSemaphore); vTaskDelay(pdMS_TO_TICKS(5)); } +#else + // optimize lv_task_handler() by actually using the returned delay value + auto time_start = millis(); + uint32_t sleep_time = lv_task_handler(); + delay(sleep_time); + auto time_end = millis(); + lv_tick_inc(time_end - time_start); +#endif } } +#endif // HASP_USE_LVGL_TASK + +#if defined(ESP32) && defined(HASP_USE_ESP_MQTT) +#if HASP_USE_LVGL_TASK == 1 esp_err_t gui_setup_lvgl_task() { #if CONFIG_FREERTOS_UNICORE == 0 diff --git a/src/hasp_gui.h b/src/hasp_gui.h index a95e877a0..8b5b12afd 100644 --- a/src/hasp_gui.h +++ b/src/hasp_gui.h @@ -60,6 +60,11 @@ uint32_t guiScreenshotEtag(); void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); void gui_antiburn_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); +/* ===== Main LVGL Task ===== */ +#if HASP_USE_LVGL_TASK == 1 +void gui_task(void* args); +#endif + /* ===== Locks ===== */ #ifdef ESP32 IRAM_ATTR bool gui_acquire(TickType_t timeout); @@ -73,4 +78,4 @@ bool guiGetConfig(const JsonObject& settings); bool guiSetConfig(const JsonObject& settings); #endif // HASP_USE_CONFIG -#endif // HASP_GUI_H \ No newline at end of file +#endif // HASP_GUI_H diff --git a/src/main_pc.cpp b/src/main_pc.cpp index 2b4f73627..cb6f7c03c 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -189,8 +189,7 @@ int main(int argc, char* argv[]) loop(); } #elif USE_WIN32DRV - extern bool lv_win32_quit_signal; - while(!lv_win32_quit_signal) { + while(haspDevice.pc_is_running) { loop(); } #endif diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index e3a86401b..039c40045 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -29,6 +29,7 @@ build_flags = -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 -D HASP_USE_SYSLOG=0 + -D HASP_USE_LVGL_TASK=1 -D MQTT_MAX_PACKET_SIZE=2048 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available From e922042a3deaf3559a3a604af7907e5d0acbbb23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 7 Feb 2024 23:12:23 +0100 Subject: [PATCH 12/36] Fix disk access path separator on Linux --- src/dev/posix/hasp_posix.cpp | 10 +++++----- src/hasp/hasp_dispatch.cpp | 8 ++++++-- src/hasp/hasp_page.cpp | 4 ++++ src/hasp_debug.cpp | 1 + src/main_pc.cpp | 26 +++++++++++++++----------- 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp index a70ff4e25..af392e62e 100644 --- a/src/dev/posix/hasp_posix.cpp +++ b/src/dev/posix/hasp_posix.cpp @@ -62,11 +62,11 @@ void PosixDevice::show_info() if(uname(&uts) < 0) { LOG_ERROR(0, "uname() error"); } else { - LOG_VERBOSE(0, "Sysname: %s", uts.sysname); - LOG_VERBOSE(0, "Nodename: %s", uts.nodename); - LOG_VERBOSE(0, "Release: %s", uts.release); - LOG_VERBOSE(0, "Version: %s", uts.version); - LOG_VERBOSE(0, "Machine: %s", uts.machine); + LOG_VERBOSE(0, "Sysname : %s", uts.sysname); + LOG_VERBOSE(0, "Nodename : %s", uts.nodename); + LOG_VERBOSE(0, "Release : %s", uts.release); + LOG_VERBOSE(0, "Version : %s", uts.version); + LOG_VERBOSE(0, "Machine : %s", uts.machine); } LOG_VERBOSE(0, "Processor : %s", "unknown"); diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index db7ffdf40..1124a76d4 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -800,7 +800,11 @@ void dispatch_run_script(const char*, const char* payload, uint8_t source) path[0] = '.'; path[1] = '\0'; strcat(path, filename); +#if defined(WINDOWS) path[1] = '\\'; +#elif defined(POSIX) + path[1] = '/'; +#endif LOG_TRACE(TAG_HASP, F("Loading %s from disk..."), path); std::ifstream f(path); // taking file as inputstream @@ -1323,8 +1327,8 @@ void dispatch_current_state(uint8_t source) bool dispatch_factory_reset() { bool formatted = true; - bool erased = true; - bool cleared = true; + bool erased = true; + bool cleared = true; #if ESP32 erased = nvs_clear_user_config(); diff --git a/src/hasp/hasp_page.cpp b/src/hasp/hasp_page.cpp index bb970e577..50b803439 100644 --- a/src/hasp/hasp_page.cpp +++ b/src/hasp/hasp_page.cpp @@ -244,7 +244,11 @@ void Page::load_jsonl(const char* pagesfile) path[0] = '.'; path[1] = '\0'; strcat(path, pagesfile); +#if defined(WINDOWS) path[1] = '\\'; +#elif defined(POSIX) + path[1] = '/'; +#endif LOG_TRACE(TAG_HASP, F("Loading %s from disk..."), path); std::ifstream f(path); // taking file as inputstream diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp index 421606cc4..2adfd826a 100644 --- a/src/hasp_debug.cpp +++ b/src/hasp_debug.cpp @@ -29,6 +29,7 @@ #if defined(POSIX) #include +#include #define cwd getcwd #endif diff --git a/src/main_pc.cpp b/src/main_pc.cpp index cb6f7c03c..50690677c 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -17,6 +17,7 @@ #if defined(POSIX) #include #include +#include #define cwd getcwd #define cd chdir #endif @@ -104,17 +105,20 @@ void InitializeConsoleOutput() void usage(const char* progName, const char* version) { - std::cout - << "\n" - << progName << " " << version << " [options]" << std::endl - << std::endl - << "Options:" << std::endl - << " -h | --help Print this help" << std::endl - << " -W | --width Width of the window" << std::endl - << " -H | --height Height of the window" << std::endl - << " -C | --config Configuration directory (default: '~/.local/share/hasp' or 'AppData\\hasp\\hasp')" - << std::endl - << std::endl; + std::cout << "\n" + << progName << " " << version << " [options]" << std::endl + << std::endl + << "Options:" << std::endl + << " -h | --help Print this help" << std::endl + << " -W | --width Width of the window" << std::endl + << " -H | --height Height of the window" << std::endl + << " -C | --config Configuration directory" << std::endl +#if defined(WINDOWS) + << " (default: 'AppData\\hasp\\hasp')" << std::endl +#elif defined(POSIX) + << " (default: '~/.local/share/hasp/hasp')" << std::endl +#endif + << std::endl; fflush(stdout); } From ac5fe4a4249452d210621ab246ba676875659baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 8 Feb 2024 16:37:14 +0100 Subject: [PATCH 13/36] Add POSIX fbdev port --- include/hasp_conf.h | 8 +- src/dev/posix/hasp_posix.cpp | 44 ++++--- src/dev/posix/hasp_posix.h | 3 + src/dev/win32/hasp_win32.cpp | 48 ++++++-- src/dev/win32/hasp_win32.h | 35 +----- src/drv/tft/tft_driver.h | 3 + src/drv/tft/tft_driver_posix_fbdev.cpp | 117 +++++++++++++++++++ src/drv/tft/tft_driver_posix_fbdev.h | 44 +++++++ src/drv/tft/tft_driver_win32drv.cpp | 2 +- src/main_pc.cpp | 14 +-- user_setups/darwin_sdl/darwin_sdl_64bits.ini | 1 - user_setups/linux_sdl/linux_fbdev_64bits.ini | 98 ++++++++++++++++ user_setups/linux_sdl/linux_sdl_64bits.ini | 1 - user_setups/win32/windows_gdi_64bits.ini | 1 - user_setups/win32/windows_sdl_64bits.ini | 1 - 15 files changed, 352 insertions(+), 68 deletions(-) create mode 100644 src/drv/tft/tft_driver_posix_fbdev.cpp create mode 100644 src/drv/tft/tft_driver_posix_fbdev.h create mode 100644 user_setups/linux_sdl/linux_fbdev_64bits.ini diff --git a/include/hasp_conf.h b/include/hasp_conf.h index dece01d19..dc6eca523 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -377,7 +377,11 @@ static WiFiSpiClass WiFi; #endif #if defined(POSIX) +#ifdef USE_MONITOR #define delay SDL_Delay +#else +#define delay msleep +#endif #endif #if HASP_TARGET_PC @@ -398,8 +402,10 @@ static WiFiSpiClass WiFi; #define halRestartMcu() #if USE_MONITOR #define millis SDL_GetTicks -#elif USE_WIN32DRV +#elif defined(WINDOWS) #define millis Win32Millis +#elif defined(POSIX) +#define millis PosixMillis #endif #define DEC 10 diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp index af392e62e..ef4fc10bd 100644 --- a/src/dev/posix/hasp_posix.cpp +++ b/src/dev/posix/hasp_posix.cpp @@ -19,7 +19,13 @@ #include "hasp_conf.h" #include "hasp_debug.h" +#ifdef USE_MONITOR #include "display/monitor.h" +#elif USE_FBDEV +#include "display/fbdev.h" +#endif + +#include // extern monitor_t monitor; @@ -35,12 +41,6 @@ PosixDevice::PosixDevice() _core_version = "unknown"; _chip_model = "unknown"; } else { - // LOG_VERBOSE(0,"Sysname: %s", uts.sysname); - // LOG_VERBOSE(0,"Nodename: %s", uts.nodename); - // LOG_VERBOSE(0,"Release: %s", uts.release); - // LOG_VERBOSE(0,"Version: %s", uts.version); - // LOG_VERBOSE(0,"Machine: %s", uts.machine); - char version[256]; snprintf(version, sizeof(version), "%s %s", uts.sysname, uts.release); _core_version = version; @@ -69,8 +69,9 @@ void PosixDevice::show_info() LOG_VERBOSE(0, "Machine : %s", uts.machine); } - LOG_VERBOSE(0, "Processor : %s", "unknown"); - LOG_VERBOSE(0, "CPU freq. : %i MHz", 0); + LOG_VERBOSE(0, "Processor : %s", get_chip_model()); + LOG_VERBOSE(0, "CPU freq. : %i MHz", get_cpu_frequency()); + LOG_VERBOSE(0, "OS Version : %s", get_core_version()); } const char* PosixDevice::get_hostname() @@ -81,8 +82,11 @@ const char* PosixDevice::get_hostname() void PosixDevice::set_hostname(const char* hostname) { _hostname = hostname; +#if USE_MONITOR monitor_title(hostname); - // SDL_SetWindowTitle(monitor.window, hostname); +#elif USE_FBDEV + // fbdev doesn't really have a title bar +#endif } const char* PosixDevice::get_core_version() @@ -146,13 +150,11 @@ void PosixDevice::update_backlight() { uint8_t level = _backlight_power ? _backlight_level : 0; if(_backlight_invert) level = 255 - level; +#if USE_MONITOR monitor_backlight(level); - // SDL_SetTextureColorMod(monitor.texture, level, level, level); - // window_update(&monitor); - // monitor.sdl_refr_qry = true; - // monitor_sdl_refr(NULL); - // const lv_area_t area = {1,1,0,0}; - // monitor_flush(NULL,&area,NULL); +#elif USE_FBDEV + // set display backlight, if possible +#endif } size_t PosixDevice::get_free_max_block() @@ -221,6 +223,18 @@ long PosixDevice::get_uptime() } // namespace dev +long PosixMillis() +{ + struct timespec spec; + clock_gettime(CLOCK_REALTIME, &spec); + return (spec.tv_sec) * 1000 + (spec.tv_nsec) / 1e6; +} + +void msleep(unsigned long millis) +{ + usleep(millis * 1000); +} + dev::PosixDevice haspDevice; #endif // POSIX diff --git a/src/dev/posix/hasp_posix.h b/src/dev/posix/hasp_posix.h index 9dc8ad9f9..73a8a49cf 100644 --- a/src/dev/posix/hasp_posix.h +++ b/src/dev/posix/hasp_posix.h @@ -71,6 +71,9 @@ class PosixDevice : public BaseDevice { } // namespace dev +extern long PosixMillis(); +extern void msleep(unsigned long millis); + using dev::PosixDevice; extern dev::PosixDevice haspDevice; diff --git a/src/dev/win32/hasp_win32.cpp b/src/dev/win32/hasp_win32.cpp index 213b8801f..6f7576de9 100644 --- a/src/dev/win32/hasp_win32.cpp +++ b/src/dev/win32/hasp_win32.cpp @@ -25,11 +25,33 @@ static inline void native_cpuid(unsigned int* eax, unsigned int* ebx, unsigned i asm volatile("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "0"(*eax), "2"(*ecx) : "memory"); } -void Win32Device::reboot() -{} +Win32Device::Win32Device() +{ + char buffer[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD length = sizeof(buffer); + + if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameNetBIOS, buffer, &length)) { + _hostname = buffer; + } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameDnsHostname, buffer, &length)) { + _hostname = buffer; + } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsHostname, buffer, &length)) { + _hostname = buffer; + } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsDomain, buffer, &length)) { + _hostname = buffer; + } else { + _hostname = "localhost"; + } -void Win32Device::show_info() -{ + // Get the Windows version. + DWORD dwBuild = 0; + DWORD dwVersion = GetVersion(); + DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); + if(dwVersion < 0x80000000) dwBuild = (DWORD)(HIWORD(dwVersion)); + + char version[128]; + snprintf(version, sizeof(version), "Windows %d.%d.%d", dwMajorVersion, dwMinorVersion, dwBuild); + _core_version = version; unsigned int eax, ebx, ecx, edx; eax = 0; @@ -39,9 +61,21 @@ void Win32Device::show_info() memcpy(vendor, &ebx, 4); memcpy(vendor + 4, &edx, 4); memcpy(vendor + 8, &ecx, 4); - vendor[12] = '\0'; + vendor[12] = '\0'; + _chip_model = vendor; - LOG_VERBOSE(0, F("Processor : %s"), vendor); + // _backlight_pin = -1; + _backlight_power = 1; + _backlight_invert = 0; + _backlight_level = 255; +} + +void Win32Device::reboot() +{} + +void Win32Device::show_info() +{ + LOG_VERBOSE(0, F("Processor : %s"), get_chip_model()); LOG_VERBOSE(0, F("CPU freq. : %i MHz"), get_cpu_frequency()); LOG_VERBOSE(0, F("OS Version : %s"), get_core_version()); } @@ -66,7 +100,7 @@ const char* Win32Device::get_core_version() const char* Win32Device::get_chip_model() { - return "SDL2"; + return _chip_model.c_str(); } const char* Win32Device::get_hardware_id() diff --git a/src/dev/win32/hasp_win32.h b/src/dev/win32/hasp_win32.h index e4b11746d..1a25106de 100644 --- a/src/dev/win32/hasp_win32.h +++ b/src/dev/win32/hasp_win32.h @@ -18,39 +18,7 @@ namespace dev { class Win32Device : public BaseDevice { public: - Win32Device() - { - char buffer[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD length = sizeof(buffer); - - if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameNetBIOS, buffer, &length)) { - _hostname = buffer; - } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameDnsHostname, buffer, &length)) { - _hostname = buffer; - } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsHostname, buffer, &length)) { - _hostname = buffer; - } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsDomain, buffer, &length)) { - _hostname = buffer; - } else { - _hostname = "localhost"; - } - - // Get the Windows version. - DWORD dwBuild = 0; - DWORD dwVersion = GetVersion(); - DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); - DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); - if(dwVersion < 0x80000000) dwBuild = (DWORD)(HIWORD(dwVersion)); - - char version[128]; - snprintf(version, sizeof(version), "Windows %d.%d.%d", dwMajorVersion, dwMinorVersion, dwBuild); - _core_version = version; - - // _backlight_pin = -1; - _backlight_power = 1; - _backlight_invert = 0; - _backlight_level = 255; - } + Win32Device(); void reboot() override; void show_info() override; @@ -80,6 +48,7 @@ class Win32Device : public BaseDevice { private: std::string _hostname; std::string _core_version; + std::string _chip_model; uint8_t _backlight_pin; uint8_t _backlight_level; diff --git a/src/drv/tft/tft_driver.h b/src/drv/tft/tft_driver.h index 914597a8e..4a9dff48a 100644 --- a/src/drv/tft/tft_driver.h +++ b/src/drv/tft/tft_driver.h @@ -83,6 +83,9 @@ class BaseTft { #elif USE_WIN32DRV && HASP_TARGET_PC // #warning Building for Win32Drv #include "tft_driver_win32drv.h" +#elif USE_FBDEV && HASP_TARGET_PC +// #warning Building for POSIX fbdev +#include "tft_driver_posix_fbdev.h" #else // #warning Building for Generic Tfts using dev::BaseTft; diff --git a/src/drv/tft/tft_driver_posix_fbdev.cpp b/src/drv/tft/tft_driver_posix_fbdev.cpp new file mode 100644 index 000000000..ba584b011 --- /dev/null +++ b/src/drv/tft/tft_driver_posix_fbdev.cpp @@ -0,0 +1,117 @@ +/* MIT License - Copyright (c) 2019-2022 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#if USE_FBDEV && HASP_TARGET_PC + +#include "hasplib.h" +#include "lvgl.h" + +#include "display/fbdev.h" + +#include "drv/tft/tft_driver.h" +#include "tft_driver_posix_fbdev.h" + +#include "dev/device.h" +#include "hasp_debug.h" +#include "hasp_gui.h" + +#ifdef HASP_CUSTOMIZE_BOOTLOGO +#include "custom/bootlogo.h" // Sketch tab header for xbm images +#else +#include "custom/bootlogo_template.h" // Sketch tab header for xbm images +#endif + +#include + +namespace dev { + +/** + * A task to measure the elapsed time for LittlevGL + * @param data unused + * @return never return + */ +static void* tick_thread(void* data) +{ + (void)data; + + while(1) { + usleep(5000); /*Sleep for 5 millisecond*/ + lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/ + } + + return 0; +} + +int32_t TftFbdevDrv::width() +{ + return _width; +} +int32_t TftFbdevDrv::height() +{ + return _height; +} + +static void* gui_entrypoint(void* arg) +{ +#if HASP_USE_LVGL_TASK +#error "fbdev LVGL task is not implemented" +#else + // create a LVGL tick thread + pthread_t thread; + pthread_create(&thread, 0, tick_thread, NULL); +#endif + return 0; +} + +void TftFbdevDrv::init(int32_t w, int h) +{ + /* Add a display + * Use the 'fbdev' driver which uses POSIX framebuffer device as a display + * The following input devices are handled: mouse, keyboard, mousewheel */ + fbdev_init(); + fbdev_get_sizes((uint32_t*)&_width, (uint32_t*)&_height); + +#if HASP_USE_LVGL_TASK +#error "fbdev LVGL task is not implemented" +#else + // do not use the gui_task(), just init the GUI and return + gui_entrypoint(NULL); +#endif +} +void TftFbdevDrv::show_info() +{ + splashscreen(); + + LOG_VERBOSE(TAG_TFT, F("Driver : %s"), get_tft_model()); +} + +void TftFbdevDrv::splashscreen() +{ + uint8_t fg[] = logoFgColor; + uint8_t bg[] = logoBgColor; + lv_color_t fgColor = lv_color_make(fg[0], fg[1], fg[2]); + lv_color_t bgColor = lv_color_make(bg[0], bg[1], bg[2]); + // TODO show splashscreen +} +void TftFbdevDrv::set_rotation(uint8_t rotation) +{} +void TftFbdevDrv::set_invert(bool invert) +{} +void TftFbdevDrv::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) +{ + fbdev_flush(disp, area, color_p); +} +bool TftFbdevDrv::is_driver_pin(uint8_t pin) +{ + return false; +} +const char* TftFbdevDrv::get_tft_model() +{ + return "POSIX fbdev"; +} + +} // namespace dev + +dev::TftFbdevDrv haspTft; + +#endif // WINDOWS || POSIX diff --git a/src/drv/tft/tft_driver_posix_fbdev.h b/src/drv/tft/tft_driver_posix_fbdev.h new file mode 100644 index 000000000..5856f892d --- /dev/null +++ b/src/drv/tft/tft_driver_posix_fbdev.h @@ -0,0 +1,44 @@ +/* MIT License - Copyright (c) 2019-2022 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_FBDEV_DRIVER_H +#define HASP_FBDEV_DRIVER_H + +#include "tft_driver.h" + +#if USE_FBDEV && HASP_TARGET_PC +// #warning Building H driver FBDEV + +#include "lvgl.h" + +namespace dev { + +class TftFbdevDrv : BaseTft { + public: + void init(int w, int h); + void show_info(); + void splashscreen(); + + void set_rotation(uint8_t rotation); + void set_invert(bool invert); + + void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); + bool is_driver_pin(uint8_t pin); + + const char* get_tft_model(); + + int32_t width(); + int32_t height(); + + private: + int32_t _width, _height; +}; + +} // namespace dev + +using dev::TftFbdevDrv; +extern dev::TftFbdevDrv haspTft; + +#endif // HASP_TARGET_PC + +#endif // HASP_FBDEV_DRIVER_H diff --git a/src/drv/tft/tft_driver_win32drv.cpp b/src/drv/tft/tft_driver_win32drv.cpp index 25a857476..9e32cb59a 100644 --- a/src/drv/tft/tft_driver_win32drv.cpp +++ b/src/drv/tft/tft_driver_win32drv.cpp @@ -114,7 +114,7 @@ void TftWin32Drv::show_info() { splashscreen(); - LOG_VERBOSE(TAG_TFT, F("Driver : Win32Drv")); + LOG_VERBOSE(TAG_TFT, F("Driver : %s"), get_tft_model()); } void TftWin32Drv::splashscreen() diff --git a/src/main_pc.cpp b/src/main_pc.cpp index 50690677c..c6190c7af 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #define cwd getcwd #define cd chdir #endif @@ -178,25 +180,23 @@ int main(int argc, char* argv[]) SDL_Init(0); // Needs to be initialized for GetPerfPath strcpy(config, SDL_GetPrefPath("hasp", "hasp")); SDL_Quit(); // We'll properly init later -#elif USE_WIN32DRV +#elif defined(WINDOWS) if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, config))) { PathAppendA(config, "hasp"); PathAppendA(config, "hasp"); } +#elif defined(POSIX) + struct passwd* pw = getpwuid(getuid()); + strcpy(config, pw->pw_dir); + strcat(config, "/.local/share/hasp/hasp"); #endif } cd(config); setup(); -#if USE_MONITOR - while(1) { - loop(); - } -#elif USE_WIN32DRV while(haspDevice.pc_is_running) { loop(); } -#endif end: #if defined(WINDOWS) diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin_sdl/darwin_sdl_64bits.ini index 1003bc6fa..4a1962c05 100644 --- a/user_setups/darwin_sdl/darwin_sdl_64bits.ini +++ b/user_setups/darwin_sdl/darwin_sdl_64bits.ini @@ -85,7 +85,6 @@ lib_ignore = build_src_filter = +<*> -<*.h> - +<../hal/sdl2> +<../.pio/libdeps/darwin_sdl_64bits/paho/src/*.c> +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTClient.c> +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTClient.h> diff --git a/user_setups/linux_sdl/linux_fbdev_64bits.ini b/user_setups/linux_sdl/linux_fbdev_64bits.ini new file mode 100644 index 000000000..624d3de60 --- /dev/null +++ b/user_setups/linux_sdl/linux_fbdev_64bits.ini @@ -0,0 +1,98 @@ +[env:linux_fbdev_64bits] +platform = native@^1.1.4 +extra_scripts = + tools/linux_build_extra.py +build_flags = + ${env.build_flags} + -D HASP_MODEL="Linux App" + -D HASP_TARGET_PC=1 + + ; ----- Monitor + -D TFT_WIDTH=240 + -D TFT_HEIGHT=320 + ; SDL drivers options + ;-D LV_LVGL_H_INCLUDE_SIMPLE + ;-D LV_DRV_NO_CONF + -D USE_FBDEV + ; ----- ArduinoJson + -D ARDUINOJSON_DECODE_UNICODE=1 + -D HASP_NUM_PAGES=12 + -D HASP_USE_SPIFFS=0 + -D HASP_USE_LITTLEFS=0 + -D LV_USE_FS_IF=1 + -D HASP_USE_EEPROM=0 + -D HASP_USE_GPIO=0 + -D HASP_USE_CONFIG=1 + -D HASP_USE_DEBUG=1 + -D HASP_USE_PNGDECODE=1 + -D HASP_USE_BMPDECODE=1 + -D HASP_USE_GIFDECODE=0 + -D HASP_USE_JPGDECODE=0 + -D HASP_USE_MQTT=1 + -D MQTT_MAX_PACKET_SIZE=2048 + -D HASP_ATTRIBUTE_FAST_MEM= + -D IRAM_ATTR= ; No IRAM_ATTR available + -D PROGMEM= ; No PROGMEM available + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO + ;-D LV_LOG_PRINTF=1 + ; Add recursive dirs for hal headers search + -D POSIX + -D PAHO_MQTT_STATIC + -DPAHO_WITH_SSL=TRUE + -DPAHO_BUILD_DOCUMENTATION=FALSE + -DPAHO_BUILD_SAMPLES=FALSE + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_VERBOSE_MAKEFILE=TRUE + ;-D NO_PERSISTENCE + -I.pio/libdeps/linux_fbdev_64bits/paho/src + -I.pio/libdeps/linux_fbdev_64bits/ArduinoJson/src + + ; ----- Statically linked libraries -------------------- + -lm + -lpthread + +lib_deps = + ${env.lib_deps} + ;lv_drivers@~7.9.0 + ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip + https://github.com/eclipse/paho.mqtt.c.git + bblanchon/ArduinoJson@^6.21.4 ; Json(l) parser + https://github.com/fvanroie/lv_drivers + +lib_ignore = + paho + AXP192 + ArduinoLog + lv_lib_qrcode + ETHSPI + +build_src_filter = + +<*> + -<*.h> + +<../.pio/libdeps/linux_fbdev_64bits/paho/src/*.c> + +<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTClient.c> + -<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTAsync.c> + -<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTVersion.c> + -<../.pio/libdeps/linux_fbdev_64bits/paho/src/SSLSocket.c> + + + - + - + - + - + - + + + - + + + - + + + + + - + - + - + + + + + + + - + + + +<../.pio/libdeps/linux_fbdev_64bits/ArduinoJson/src/ArduinoJson.h> diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux_sdl/linux_sdl_64bits.ini index c1e8d8dcb..432c98149 100644 --- a/user_setups/linux_sdl/linux_sdl_64bits.ini +++ b/user_setups/linux_sdl/linux_sdl_64bits.ini @@ -76,7 +76,6 @@ lib_ignore = build_src_filter = +<*> -<*.h> - +<../hal/sdl2> +<../.pio/libdeps/linux_sdl_64bits/paho/src/*.c> +<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTClient.c> -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsync.c> diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index 039c40045..d2657df56 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -100,7 +100,6 @@ lib_ignore = build_src_filter = +<*> -<*.h> - +<../hal/sdl2> +<../.pio/libdeps/windows_gdi_64bits/paho/src/*.c> +<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTClient.c> -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTAsync.c> diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini index a4a131e2f..3c6957bbd 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -106,7 +106,6 @@ lib_ignore = build_src_filter = +<*> -<*.h> - +<../hal/sdl2> +<../.pio/libdeps/windows_sdl_64bits/paho/src/*.c> +<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTClient.c> -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTAsync.c> From fdc5f9170a2065ca59137e6081508e4c5a56442e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 8 Feb 2024 18:57:08 +0100 Subject: [PATCH 14/36] Support evdev on Linux --- src/drv/tft/tft_driver_posix_fbdev.cpp | 16 +++++++++++++++- src/hasp_gui.cpp | 6 ++++++ user_setups/linux_sdl/linux_fbdev_64bits.ini | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/drv/tft/tft_driver_posix_fbdev.cpp b/src/drv/tft/tft_driver_posix_fbdev.cpp index ba584b011..e76b71906 100644 --- a/src/drv/tft/tft_driver_posix_fbdev.cpp +++ b/src/drv/tft/tft_driver_posix_fbdev.cpp @@ -11,6 +11,10 @@ #include "drv/tft/tft_driver.h" #include "tft_driver_posix_fbdev.h" +#if USE_EVDEV || USE_BSD_EVDEV +#include "indev/evdev.h" +#endif + #include "dev/device.h" #include "hasp_debug.h" #include "hasp_gui.h" @@ -23,6 +27,9 @@ #include +extern uint16_t tft_width; +extern uint16_t tft_height; + namespace dev { /** @@ -71,6 +78,13 @@ void TftFbdevDrv::init(int32_t w, int h) fbdev_init(); fbdev_get_sizes((uint32_t*)&_width, (uint32_t*)&_height); + tft_width = _width; + tft_height = _height; + +#if USE_EVDEV || USE_BSD_EVDEV + evdev_register("/dev/input/event2", LV_INDEV_TYPE_POINTER, NULL); +#endif + #if HASP_USE_LVGL_TASK #error "fbdev LVGL task is not implemented" #else @@ -99,7 +113,7 @@ void TftFbdevDrv::set_invert(bool invert) {} void TftFbdevDrv::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) { - fbdev_flush(disp, area, color_p); + lv_disp_flush_ready(disp); } bool TftFbdevDrv::is_driver_pin(uint8_t pin) { diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index af4c83881..ac181b830 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -291,6 +291,10 @@ void guiSetup() #endif disp_drv.monitor_cb = gui_monitor_cb; + // register a touchscreen/mouse driver - only on real hardware and SDL2 + // Win32 and POSIX handles input drivers in tft_driver +#if TOUCH_DRIVER != -1 || USE_MONITOR + /* Initialize the touch pad */ static lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); @@ -331,6 +335,8 @@ void guiSetup() gui_hide_pointer(false); lv_indev_set_cursor(mouse_indev, cursor); /*Connect the image object to the driver*/ +#endif // TOUCH_DRIVER != -1 || USE_MONITOR + #if HASP_TARGET_ARDUINO // drv_touch_init(gui_settings.rotation); // Touch driver haspTouch.init(tft_width, tft_height); diff --git a/user_setups/linux_sdl/linux_fbdev_64bits.ini b/user_setups/linux_sdl/linux_fbdev_64bits.ini index 624d3de60..d1982e574 100644 --- a/user_setups/linux_sdl/linux_fbdev_64bits.ini +++ b/user_setups/linux_sdl/linux_fbdev_64bits.ini @@ -14,6 +14,7 @@ build_flags = ;-D LV_LVGL_H_INCLUDE_SIMPLE ;-D LV_DRV_NO_CONF -D USE_FBDEV + -D USE_EVDEV ; ----- ArduinoJson -D ARDUINOJSON_DECODE_UNICODE=1 -D HASP_NUM_PAGES=12 From 9693ef361aedb306a0a73a28788ea23220f1ccb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 8 Feb 2024 19:44:12 +0100 Subject: [PATCH 15/36] Scan for input devices on Linux, show splashscreen --- src/drv/tft/tft_driver_posix_fbdev.cpp | 79 +++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/src/drv/tft/tft_driver_posix_fbdev.cpp b/src/drv/tft/tft_driver_posix_fbdev.cpp index e76b71906..bde0450ec 100644 --- a/src/drv/tft/tft_driver_posix_fbdev.cpp +++ b/src/drv/tft/tft_driver_posix_fbdev.cpp @@ -26,6 +26,14 @@ #endif #include +#include +#include + +#if USE_BSD_EVDEV +#include +#else +#include +#endif extern uint16_t tft_width; extern uint16_t tft_height; @@ -82,7 +90,74 @@ void TftFbdevDrv::init(int32_t w, int h) tft_height = _height; #if USE_EVDEV || USE_BSD_EVDEV - evdev_register("/dev/input/event2", LV_INDEV_TYPE_POINTER, NULL); + DIR* dir = opendir("/dev/input"); + if(dir == NULL) { + perror("/dev/input opendir failed"); + } else { + // iterate through /dev/input devices + struct dirent* dirent; + unsigned char ev_type[EV_MAX / 8 + 1]; + while((dirent = readdir(dir)) != NULL) { + // make sure it's a block device matching /dev/input/event* + if(strncmp(dirent->d_name, "event", 5) != 0 || strlen(dirent->d_name) <= 5) continue; + if(dirent->d_type != DT_CHR) continue; + // get full path + char dev_path[64]; + strcpy(dev_path, "/dev/input/"); + strcat(dev_path, dirent->d_name); +#if USE_BSD_EVDEV + // open the device + int fd = open(dev_path, O_RDONLY | O_NOCTTY); +#else + int fd = open(dev_path, O_RDONLY | O_NOCTTY | O_NDELAY); +#endif + if(fd == -1) { + perror("input open failed"); + continue; + } + // read supported event types + memset(ev_type, 0, sizeof(ev_type)); + if(ioctl(fd, EVIOCGBIT(0, sizeof(ev_type)), ev_type) < 0) { + perror("ioctl failed"); + close(fd); + continue; + } + // read device name + char dev_name[256]; + if(ioctl(fd, EVIOCGNAME(sizeof(dev_name)), dev_name) < 0) { + perror("ioctl failed"); + close(fd); + continue; + } + // check which types are supported; judge LVGL device type + lv_indev_type_t dev_type; + if(ev_type[EV_ABS / 8] & (1 << (EV_ABS % 8))) { + dev_type = LV_INDEV_TYPE_POINTER; + } else if(ev_type[EV_REL / 8] & (1 << (EV_REL % 8))) { + dev_type = LV_INDEV_TYPE_POINTER; + } else if(ev_type[EV_KEY / 8] & (1 << (EV_KEY % 8))) { + dev_type = LV_INDEV_TYPE_KEYPAD; + } else { + close(fd); + continue; + } + // register the device + switch(dev_type) { + case LV_INDEV_TYPE_POINTER: + LOG_VERBOSE(TAG_TFT, F("Pointer : %s (%s)"), dev_path, dev_name); + break; + case LV_INDEV_TYPE_KEYPAD: + LOG_VERBOSE(TAG_TFT, F("Keypad : %s (%s)"), dev_path, dev_name); + break; + default: + LOG_VERBOSE(TAG_TFT, F("Input : %s (%s)"), dev_path, dev_name); + break; + } + evdev_register(dev_path, dev_type, NULL); + close(fd); + } + closedir(dir); + } #endif #if HASP_USE_LVGL_TASK @@ -105,7 +180,7 @@ void TftFbdevDrv::splashscreen() uint8_t bg[] = logoBgColor; lv_color_t fgColor = lv_color_make(fg[0], fg[1], fg[2]); lv_color_t bgColor = lv_color_make(bg[0], bg[1], bg[2]); - // TODO show splashscreen + fbdev_splashscreen(logoImage, logoWidth, logoHeight, fgColor, bgColor); } void TftFbdevDrv::set_rotation(uint8_t rotation) {} From ed6b17cfd722da324963ac9f1f6aad66e9c44898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 8 Feb 2024 22:01:53 +0100 Subject: [PATCH 16/36] Print evdev input device resolution, enable cursor on fbdev --- src/drv/tft/tft_driver_posix_fbdev.cpp | 34 +++++++++++++++++++------- src/hasp_gui.cpp | 16 ++++++++---- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/drv/tft/tft_driver_posix_fbdev.cpp b/src/drv/tft/tft_driver_posix_fbdev.cpp index bde0450ec..79706c49e 100644 --- a/src/drv/tft/tft_driver_posix_fbdev.cpp +++ b/src/drv/tft/tft_driver_posix_fbdev.cpp @@ -86,6 +86,9 @@ void TftFbdevDrv::init(int32_t w, int h) fbdev_init(); fbdev_get_sizes((uint32_t*)&_width, (uint32_t*)&_height); + // show the splashscreen early + splashscreen(); + tft_width = _width; tft_height = _height; @@ -131,12 +134,16 @@ void TftFbdevDrv::init(int32_t w, int h) } // check which types are supported; judge LVGL device type lv_indev_type_t dev_type; - if(ev_type[EV_ABS / 8] & (1 << (EV_ABS % 8))) { - dev_type = LV_INDEV_TYPE_POINTER; - } else if(ev_type[EV_REL / 8] & (1 << (EV_REL % 8))) { - dev_type = LV_INDEV_TYPE_POINTER; + const char* dev_type_name; + if(ev_type[EV_REL / 8] & (1 << (EV_REL % 8))) { + dev_type = LV_INDEV_TYPE_POINTER; + dev_type_name = "EV_REL"; + } else if(ev_type[EV_ABS / 8] & (1 << (EV_ABS % 8))) { + dev_type = LV_INDEV_TYPE_POINTER; + dev_type_name = "EV_ABS"; } else if(ev_type[EV_KEY / 8] & (1 << (EV_KEY % 8))) { - dev_type = LV_INDEV_TYPE_KEYPAD; + dev_type = LV_INDEV_TYPE_KEYPAD; + dev_type_name = "EV_KEY"; } else { close(fd); continue; @@ -144,17 +151,26 @@ void TftFbdevDrv::init(int32_t w, int h) // register the device switch(dev_type) { case LV_INDEV_TYPE_POINTER: - LOG_VERBOSE(TAG_TFT, F("Pointer : %s (%s)"), dev_path, dev_name); + LOG_VERBOSE(TAG_TFT, F("Pointer : %s %s (%s)"), dev_path, dev_type_name, dev_name); break; case LV_INDEV_TYPE_KEYPAD: - LOG_VERBOSE(TAG_TFT, F("Keypad : %s (%s)"), dev_path, dev_name); + LOG_VERBOSE(TAG_TFT, F("Keypad : %s %s (%s)"), dev_path, dev_type_name, dev_name); break; default: - LOG_VERBOSE(TAG_TFT, F("Input : %s (%s)"), dev_path, dev_name); + LOG_VERBOSE(TAG_TFT, F("Input : %s %s (%s)"), dev_path, dev_type_name, dev_name); break; } - evdev_register(dev_path, dev_type, NULL); close(fd); + // print verbose resolution info + lv_indev_t* indev; + if(!evdev_register(dev_path, dev_type, &indev) || indev == NULL) { + printf("Failed to register evdev\n"); + continue; + } + evdev_data_t* user_data = (evdev_data_t*)indev->driver.user_data; + LOG_VERBOSE(TAG_TFT, F("Resolution : X=%d (%d..%d), Y=%d (%d..%d)"), user_data->x_max, + user_data->x_absinfo.minimum, user_data->x_absinfo.maximum, user_data->y_max, + user_data->y_absinfo.minimum, user_data->y_absinfo.maximum); } closedir(dir); } diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index ac181b830..9fd55c9bf 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -294,7 +294,6 @@ void guiSetup() // register a touchscreen/mouse driver - only on real hardware and SDL2 // Win32 and POSIX handles input drivers in tft_driver #if TOUCH_DRIVER != -1 || USE_MONITOR - /* Initialize the touch pad */ static lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); @@ -306,6 +305,13 @@ void guiSetup() #endif lv_indev_t* mouse_indev = lv_indev_drv_register(&indev_drv); mouse_indev->driver.type = LV_INDEV_TYPE_POINTER; +#else + // find the first registered input device to add a cursor to + lv_indev_t* mouse_indev = NULL; + while((mouse_indev = lv_indev_get_next(mouse_indev))) { + if(mouse_indev->driver.type == LV_INDEV_TYPE_POINTER) break; + } +#endif /*Set a cursor for the mouse*/ LOG_TRACE(TAG_GUI, F("Initialize Cursor")); @@ -326,16 +332,16 @@ void guiSetup() cursor = lv_img_create(mouse_layer, NULL); /*Create an image object for the cursor */ lv_img_set_src(cursor, &mouse_cursor_icon); /*Set the image source*/ #else - cursor = lv_obj_create(mouse_layer, NULL); // show cursor object on every page + cursor = lv_obj_create(mouse_layer, NULL); // show cursor object on every page lv_obj_set_size(cursor, 9, 9); lv_obj_set_style_local_radius(cursor, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_obj_set_style_local_bg_color(cursor, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); lv_obj_set_style_local_bg_opa(cursor, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER); #endif gui_hide_pointer(false); - lv_indev_set_cursor(mouse_indev, cursor); /*Connect the image object to the driver*/ - -#endif // TOUCH_DRIVER != -1 || USE_MONITOR + if(mouse_indev != NULL) { + lv_indev_set_cursor(mouse_indev, cursor); /*Connect the image object to the driver*/ + } #if HASP_TARGET_ARDUINO // drv_touch_init(gui_settings.rotation); // Touch driver From f36dd66a0577e9f70d5ac3ad8a325f5771a9ae5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 8 Feb 2024 22:05:57 +0100 Subject: [PATCH 17/36] Fix memory corruption with memcpy(), support musl libc --- src/hasp/hasp_dispatch.cpp | 2 +- src/hasp/hasp_event.cpp | 22 +++++++++++++--------- src/hasp/hasp_parser.cpp | 22 +++++++++++----------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 1124a76d4..0b58089fd 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -1360,7 +1360,7 @@ void dispatch_idle_state(uint8_t state) { char topic[8]; char buffer[8]; - memcpy_P(topic, PSTR("idle"), 8); + memcpy_P(topic, PSTR("idle"), 5); hasp_get_sleep_payload(state, buffer); dispatch_state_subtopic(topic, buffer); } diff --git a/src/hasp/hasp_event.cpp b/src/hasp/hasp_event.cpp index 433bc7ea7..fd5eeaeef 100644 --- a/src/hasp/hasp_event.cpp +++ b/src/hasp/hasp_event.cpp @@ -176,9 +176,9 @@ void event_timer_clock(lv_task_t* task) timeval curTime; int rslt = gettimeofday(&curTime, NULL); (void)rslt; // unused - time_t seconds = curTime.tv_sec; - useconds_t tv_msec = curTime.tv_usec / 1000; - tm* timeinfo = localtime(&seconds); + time_t seconds = curTime.tv_sec; + auto tv_msec = curTime.tv_usec / 1000; + tm* timeinfo = localtime(&seconds); lv_task_set_period(task, data->interval - tv_msec); char buffer[128] = {0}; @@ -835,7 +835,7 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) if(!translate_event(obj, event, hasp_event_id) || event == LV_EVENT_VALUE_CHANGED) return; /* Get the new value */ - lv_color_t color = lv_cpicker_get_color(obj); + lv_color_t color = lv_cpicker_get_color(obj); lv_cpicker_color_mode_t mode = lv_cpicker_get_color_mode(obj); if(hasp_event_id == HASP_EVENT_CHANGED && last_color_sent.full == color.full) return; // same value as before @@ -853,12 +853,16 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) if(const char* tag = my_obj_get_tag(obj)) snprintf_P(data, sizeof(data), - PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"h\":%d,\"s\":%d,\"v\":%d,\"tag\":%s}"), - eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, hsv.s, hsv.v, tag); + PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"h\":%d,\"s\":%" + "d,\"v\":%d,\"tag\":%s}"), + eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, + hsv.s, hsv.v, tag); else snprintf_P(data, sizeof(data), - PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"h\":%d,\"s\":%d,\"v\":%d}"), eventname, - c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, hsv.s, hsv.v); + PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"h\":%d,\"s\":%" + "d,\"v\":%d}"), + eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, + hsv.s, hsv.v); } event_send_object_data(obj, data); @@ -907,4 +911,4 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event) // event_update_group(obj->user_data.groupid, obj, val, min, max); } -#endif \ No newline at end of file +#endif diff --git a/src/hasp/hasp_parser.cpp b/src/hasp/hasp_parser.cpp index 0b85e4152..8660060cd 100644 --- a/src/hasp/hasp_parser.cpp +++ b/src/hasp/hasp_parser.cpp @@ -136,34 +136,34 @@ void Parser::get_event_name(uint8_t eventid, char* buffer, size_t size) { switch(eventid) { case HASP_EVENT_ON: - memcpy_P(buffer, PSTR("on"), size); + memcpy_P(buffer, PSTR("on"), 3); break; case HASP_EVENT_OFF: - memcpy_P(buffer, PSTR("off"), size); + memcpy_P(buffer, PSTR("off"), 4); break; case HASP_EVENT_UP: - memcpy_P(buffer, PSTR("up"), size); + memcpy_P(buffer, PSTR("up"), 3); break; case HASP_EVENT_DOWN: - memcpy_P(buffer, PSTR("down"), size); + memcpy_P(buffer, PSTR("down"), 5); break; case HASP_EVENT_RELEASE: - memcpy_P(buffer, PSTR("release"), size); + memcpy_P(buffer, PSTR("release"), 8); break; case HASP_EVENT_LONG: - memcpy_P(buffer, PSTR("long"), size); + memcpy_P(buffer, PSTR("long"), 5); break; case HASP_EVENT_HOLD: - memcpy_P(buffer, PSTR("hold"), size); + memcpy_P(buffer, PSTR("hold"), 5); break; case HASP_EVENT_LOST: - memcpy_P(buffer, PSTR("lost"), size); + memcpy_P(buffer, PSTR("lost"), 5); break; case HASP_EVENT_CHANGED: - memcpy_P(buffer, PSTR("changed"), size); + memcpy_P(buffer, PSTR("changed"), 8); break; default: - memcpy_P(buffer, PSTR("unknown"), size); + memcpy_P(buffer, PSTR("unknown"), 8); } } @@ -238,4 +238,4 @@ long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } -#endif \ No newline at end of file +#endif From a7d900ed7b04debe907c868a07d2d4f4bb229ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 8 Feb 2024 22:44:39 +0100 Subject: [PATCH 18/36] Support brightness control on Linux fbdev --- src/dev/posix/hasp_posix.cpp | 27 ++++++++++++++++++++++++++- src/dev/posix/hasp_posix.h | 4 ++++ src/main_pc.cpp | 23 +++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp index ef4fc10bd..3b0c7566f 100644 --- a/src/dev/posix/hasp_posix.cpp +++ b/src/dev/posix/hasp_posix.cpp @@ -25,6 +25,7 @@ #include "display/fbdev.h" #endif +#include #include // extern monitor_t monitor; @@ -153,7 +154,31 @@ void PosixDevice::update_backlight() #if USE_MONITOR monitor_backlight(level); #elif USE_FBDEV - // set display backlight, if possible + // set display backlight, if possible + if(backlight_device != "") { + if(backlight_max == 0) { + std::ifstream f; + f.open("/sys/class/backlight/" + backlight_device + "/max_brightness"); + if(!f.fail()) { + f >> backlight_max; + f.close(); + } else { + perror("Max brightness read failed"); + } + } + + int brightness = map(level, 0, 255, 0, backlight_max); + LOG_VERBOSE(0, "Setting brightness to %d/255 (%d)", level, brightness); + + std::ofstream f; + f.open("/sys/class/backlight/" + backlight_device + "/brightness"); + if(!f.fail()) { + f << brightness; + f.close(); + } else { + perror("Brightness write failed"); + } + } #endif } diff --git a/src/dev/posix/hasp_posix.h b/src/dev/posix/hasp_posix.h index 73a8a49cf..4ec64458e 100644 --- a/src/dev/posix/hasp_posix.h +++ b/src/dev/posix/hasp_posix.h @@ -56,6 +56,10 @@ class PosixDevice : public BaseDevice { bool is_system_pin(uint8_t pin) override; + public: + std::string backlight_device; + int backlight_max = 0; + private: std::string _hostname; std::string _core_version; diff --git a/src/main_pc.cpp b/src/main_pc.cpp index c6190c7af..ad851d1ba 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -119,6 +119,10 @@ void usage(const char* progName, const char* version) << " (default: 'AppData\\hasp\\hasp')" << std::endl #elif defined(POSIX) << " (default: '~/.local/share/hasp/hasp')" << std::endl +#endif +#if USE_FBDEV && defined(POSIX) + << " -b | --backlight Backlight device name (in /sys/class/backlight/)" << std::endl + << " -B | --bl-max Backlight brightness limit (default: max_brightness)" << std::endl #endif << std::endl; fflush(stdout); @@ -138,6 +142,25 @@ int main(int argc, char* argv[]) for(int arg = 1; arg < argc; arg++) { if(strncmp(argv[arg], "--help", 6) == 0 || strncmp(argv[arg], "-h", 2) == 0) { showhelp = true; +#if USE_FBDEV && defined(POSIX) + } else if(strncmp(argv[arg], "--backlight", 11) == 0 || strncmp(argv[arg], "-b", 2) == 0) { + if(arg + 1 < argc) { + haspDevice.backlight_device = argv[arg + 1]; + arg++; + } else { + std::cout << "Missing device name" << std::endl; + showhelp = true; + } + } else if(strncmp(argv[arg], "--bl-max", 9) == 0 || strncmp(argv[arg], "-B", 2) == 0) { + if(arg + 1 < argc) { + int bl_max = atoi(argv[arg + 1]); + if(bl_max > 0) haspDevice.backlight_max = bl_max; + arg++; + } else { + std::cout << "Missing backlight level" << std::endl; + showhelp = true; + } +#endif } else if(strncmp(argv[arg], "--width", 7) == 0 || strncmp(argv[arg], "-W", 2) == 0) { if(arg + 1 < argc) { int w = atoi(argv[arg + 1]); From a0c8fd49d410c02dbd153bf52863c046cb58d54d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 9 Feb 2024 20:45:53 +0100 Subject: [PATCH 19/36] Fix millis() overflow on 32-bit Linux --- src/dev/posix/hasp_posix.cpp | 11 +++++++++-- src/dev/posix/hasp_posix.h | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp index 3b0c7566f..e19e3c2e5 100644 --- a/src/dev/posix/hasp_posix.cpp +++ b/src/dev/posix/hasp_posix.cpp @@ -248,11 +248,18 @@ long PosixDevice::get_uptime() } // namespace dev -long PosixMillis() +static time_t tv_sec_start = 0; + +unsigned long PosixMillis() { struct timespec spec; clock_gettime(CLOCK_REALTIME, &spec); - return (spec.tv_sec) * 1000 + (spec.tv_nsec) / 1e6; + if (tv_sec_start == 0) { + tv_sec_start = spec.tv_sec; + } + unsigned long msec1 = (spec.tv_sec - tv_sec_start) * 1000; + unsigned long msec2 = spec.tv_nsec / 1e6; + return msec1 + msec2; } void msleep(unsigned long millis) diff --git a/src/dev/posix/hasp_posix.h b/src/dev/posix/hasp_posix.h index 4ec64458e..7e7d62756 100644 --- a/src/dev/posix/hasp_posix.h +++ b/src/dev/posix/hasp_posix.h @@ -75,7 +75,7 @@ class PosixDevice : public BaseDevice { } // namespace dev -extern long PosixMillis(); +extern unsigned long PosixMillis(); extern void msleep(unsigned long millis); using dev::PosixDevice; From 4c20d6a4b973938855fc3f4240a8dffe0e31f735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 9 Feb 2024 22:35:01 +0100 Subject: [PATCH 20/36] Allow choosing fbdev and evdev names, load POSIX settings from config --- src/dev/posix/hasp_posix.cpp | 31 ++++++++++++++++++++++++-- src/dev/posix/hasp_posix.h | 2 ++ src/drv/tft/tft_driver_posix_fbdev.cpp | 7 +++++- src/drv/tft/tft_driver_posix_fbdev.h | 6 +++++ src/hasp_config.cpp | 6 +++++ src/main_pc.cpp | 31 +++++--------------------- 6 files changed, 55 insertions(+), 28 deletions(-) diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp index e19e3c2e5..8d864cf7b 100644 --- a/src/dev/posix/hasp_posix.cpp +++ b/src/dev/posix/hasp_posix.cpp @@ -23,6 +23,7 @@ #include "display/monitor.h" #elif USE_FBDEV #include "display/fbdev.h" +#include "drv/tft/tft_driver.h" #endif #include @@ -54,6 +55,32 @@ PosixDevice::PosixDevice() _backlight_level = 255; } +void PosixDevice::set_config(const JsonObject& settings) +{ + configOutput(settings, 0); +#if USE_FBDEV + if(settings["fbdev"].is()) { + haspTft.fbdev_path = "/dev/" + settings["fbdev"].as(); + } +#if USE_EVDEV + if(settings["evdev"].is()) { + haspTft.evdev_names.push_back(settings["evdev"].as()); + } + if(settings["evdevs"].is()) { + for(auto v : settings["evdevs"].as()) { + haspTft.evdev_names.push_back(v.as()); + } + } +#endif + if(settings["bldev"].is()) { + haspDevice.backlight_device = settings["bldev"].as(); + } + if(settings["blmax"].is()) { + haspDevice.backlight_max = settings["blmax"]; + } +#endif +} + void PosixDevice::reboot() {} void PosixDevice::show_info() @@ -254,8 +281,8 @@ unsigned long PosixMillis() { struct timespec spec; clock_gettime(CLOCK_REALTIME, &spec); - if (tv_sec_start == 0) { - tv_sec_start = spec.tv_sec; + if(tv_sec_start == 0) { + tv_sec_start = spec.tv_sec; } unsigned long msec1 = (spec.tv_sec - tv_sec_start) * 1000; unsigned long msec2 = spec.tv_nsec / 1e6; diff --git a/src/dev/posix/hasp_posix.h b/src/dev/posix/hasp_posix.h index 7e7d62756..439d4c12c 100644 --- a/src/dev/posix/hasp_posix.h +++ b/src/dev/posix/hasp_posix.h @@ -31,6 +31,8 @@ class PosixDevice : public BaseDevice { public: PosixDevice(); + void set_config(const JsonObject& settings); + void reboot() override; void show_info() override; diff --git a/src/drv/tft/tft_driver_posix_fbdev.cpp b/src/drv/tft/tft_driver_posix_fbdev.cpp index 79706c49e..955903f88 100644 --- a/src/drv/tft/tft_driver_posix_fbdev.cpp +++ b/src/drv/tft/tft_driver_posix_fbdev.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #if USE_BSD_EVDEV #include @@ -83,7 +84,7 @@ void TftFbdevDrv::init(int32_t w, int h) /* Add a display * Use the 'fbdev' driver which uses POSIX framebuffer device as a display * The following input devices are handled: mouse, keyboard, mousewheel */ - fbdev_init(); + fbdev_init(fbdev_path.empty() ? NULL : fbdev_path.c_str()); fbdev_get_sizes((uint32_t*)&_width, (uint32_t*)&_height); // show the splashscreen early @@ -104,6 +105,10 @@ void TftFbdevDrv::init(int32_t w, int h) // make sure it's a block device matching /dev/input/event* if(strncmp(dirent->d_name, "event", 5) != 0 || strlen(dirent->d_name) <= 5) continue; if(dirent->d_type != DT_CHR) continue; + // skip device if not specified on command line + if(!evdev_names.empty() && + std::find(evdev_names.begin(), evdev_names.end(), std::string(dirent->d_name)) == evdev_names.end()) + continue; // get full path char dev_path[64]; strcpy(dev_path, "/dev/input/"); diff --git a/src/drv/tft/tft_driver_posix_fbdev.h b/src/drv/tft/tft_driver_posix_fbdev.h index 5856f892d..643126bf5 100644 --- a/src/drv/tft/tft_driver_posix_fbdev.h +++ b/src/drv/tft/tft_driver_posix_fbdev.h @@ -11,6 +11,8 @@ #include "lvgl.h" +#include + namespace dev { class TftFbdevDrv : BaseTft { @@ -30,6 +32,10 @@ class TftFbdevDrv : BaseTft { int32_t width(); int32_t height(); + public: + std::string fbdev_path; + std::vector evdev_names; + private: int32_t _width, _height; }; diff --git a/src/hasp_config.cpp b/src/hasp_config.cpp index 559c3f0a9..4bdb7c805 100644 --- a/src/hasp_config.cpp +++ b/src/hasp_config.cpp @@ -636,6 +636,12 @@ void configSetup() gpioSetConfig(settings[FPSTR(FP_GPIO)]); #endif + // target-specific config +#if defined(POSIX) + LOG_INFO(TAG_CONF, F("Loading POSIX-specific settings")); + haspDevice.set_config(settings[F("posix")]); +#endif + LOG_INFO(TAG_CONF, F(D_CONFIG_LOADED)); } // #endif diff --git a/src/main_pc.cpp b/src/main_pc.cpp index ad851d1ba..63d3d2bb5 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -112,17 +112,15 @@ void usage(const char* progName, const char* version) << std::endl << "Options:" << std::endl << " -h | --help Print this help" << std::endl +#if !USE_FBDEV << " -W | --width Width of the window" << std::endl << " -H | --height Height of the window" << std::endl - << " -C | --config Configuration directory" << std::endl +#endif + << " -c | --config Configuration/storage directory" << std::endl #if defined(WINDOWS) << " (default: 'AppData\\hasp\\hasp')" << std::endl #elif defined(POSIX) << " (default: '~/.local/share/hasp/hasp')" << std::endl -#endif -#if USE_FBDEV && defined(POSIX) - << " -b | --backlight Backlight device name (in /sys/class/backlight/)" << std::endl - << " -B | --bl-max Backlight brightness limit (default: max_brightness)" << std::endl #endif << std::endl; fflush(stdout); @@ -142,25 +140,7 @@ int main(int argc, char* argv[]) for(int arg = 1; arg < argc; arg++) { if(strncmp(argv[arg], "--help", 6) == 0 || strncmp(argv[arg], "-h", 2) == 0) { showhelp = true; -#if USE_FBDEV && defined(POSIX) - } else if(strncmp(argv[arg], "--backlight", 11) == 0 || strncmp(argv[arg], "-b", 2) == 0) { - if(arg + 1 < argc) { - haspDevice.backlight_device = argv[arg + 1]; - arg++; - } else { - std::cout << "Missing device name" << std::endl; - showhelp = true; - } - } else if(strncmp(argv[arg], "--bl-max", 9) == 0 || strncmp(argv[arg], "-B", 2) == 0) { - if(arg + 1 < argc) { - int bl_max = atoi(argv[arg + 1]); - if(bl_max > 0) haspDevice.backlight_max = bl_max; - arg++; - } else { - std::cout << "Missing backlight level" << std::endl; - showhelp = true; - } -#endif +#if !USE_FBDEV } else if(strncmp(argv[arg], "--width", 7) == 0 || strncmp(argv[arg], "-W", 2) == 0) { if(arg + 1 < argc) { int w = atoi(argv[arg + 1]); @@ -179,7 +159,8 @@ int main(int argc, char* argv[]) std::cout << "Missing height value" << std::endl; showhelp = true; } - } else if(strncmp(argv[arg], "--config", 8) == 0 || strncmp(argv[arg], "-C", 2) == 0) { +#endif + } else if(strncmp(argv[arg], "--config", 8) == 0 || strncmp(argv[arg], "-c", 2) == 0) { if(arg + 1 < argc) { strcpy(config, argv[arg + 1]); arg++; From 6bfe89cac0bdca23b7594b7ac613d6730a97f7c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 9 Feb 2024 22:55:11 +0100 Subject: [PATCH 21/36] Implement LVGL task for POSIX fbdev --- src/drv/tft/tft_driver_posix_fbdev.cpp | 16 ++++++---------- user_setups/linux_sdl/linux_fbdev_64bits.ini | 1 + 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/drv/tft/tft_driver_posix_fbdev.cpp b/src/drv/tft/tft_driver_posix_fbdev.cpp index 955903f88..c596f8521 100644 --- a/src/drv/tft/tft_driver_posix_fbdev.cpp +++ b/src/drv/tft/tft_driver_posix_fbdev.cpp @@ -70,12 +70,13 @@ int32_t TftFbdevDrv::height() static void* gui_entrypoint(void* arg) { #if HASP_USE_LVGL_TASK -#error "fbdev LVGL task is not implemented" -#else - // create a LVGL tick thread - pthread_t thread; - pthread_create(&thread, 0, tick_thread, NULL); + // create an LVGL GUI task thread + pthread_t gui_pthread; + pthread_create(&gui_pthread, 0, (void* (*)(void*))gui_task, NULL); #endif + // create an LVGL tick thread + pthread_t tick_pthread; + pthread_create(&tick_pthread, 0, tick_thread, NULL); return 0; } @@ -181,12 +182,7 @@ void TftFbdevDrv::init(int32_t w, int h) } #endif -#if HASP_USE_LVGL_TASK -#error "fbdev LVGL task is not implemented" -#else - // do not use the gui_task(), just init the GUI and return gui_entrypoint(NULL); -#endif } void TftFbdevDrv::show_info() { diff --git a/user_setups/linux_sdl/linux_fbdev_64bits.ini b/user_setups/linux_sdl/linux_fbdev_64bits.ini index d1982e574..4904cf69a 100644 --- a/user_setups/linux_sdl/linux_fbdev_64bits.ini +++ b/user_setups/linux_sdl/linux_fbdev_64bits.ini @@ -30,6 +30,7 @@ build_flags = -D HASP_USE_GIFDECODE=0 -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 + -D HASP_USE_LVGL_TASK=1 -D MQTT_MAX_PACKET_SIZE=2048 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available From de0aeab4357994f4f8444c3eb6b24b263e5bbc11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 9 Feb 2024 23:47:18 +0100 Subject: [PATCH 22/36] Hide active tty cursor on POSIX fbdev --- src/drv/tft/tft_driver_posix_fbdev.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/drv/tft/tft_driver_posix_fbdev.cpp b/src/drv/tft/tft_driver_posix_fbdev.cpp index c596f8521..2961b7289 100644 --- a/src/drv/tft/tft_driver_posix_fbdev.cpp +++ b/src/drv/tft/tft_driver_posix_fbdev.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #if USE_BSD_EVDEV #include @@ -82,6 +83,23 @@ static void* gui_entrypoint(void* arg) void TftFbdevDrv::init(int32_t w, int h) { + // check active tty + std::ifstream f; + f.open("/sys/class/tty/tty0/active"); + std::string tty; + f >> tty; + tty = "/dev/" + tty; + f.close(); + + // try to hide the cursor + int tty_fd = open(tty.c_str(), O_WRONLY); + if(tty_fd == -1) { + perror("Couldn't open tty"); + } else { + write(tty_fd, "\033[?25l", 6); + } + close(tty_fd); + /* Add a display * Use the 'fbdev' driver which uses POSIX framebuffer device as a display * The following input devices are handled: mouse, keyboard, mousewheel */ From 2738bff96a7a0c86a73f93d668c885ce0394ebe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 10 Feb 2024 12:11:37 +0100 Subject: [PATCH 23/36] Allow changing LVGL refresh and animation period --- src/hasp_config.h | 1 + src/hasp_gui.cpp | 35 +++++++++++++++++++++++++++++++++++ src/hasp_gui.h | 1 + 3 files changed, 37 insertions(+) diff --git a/src/hasp_config.h b/src/hasp_config.h index 04160d30d..ca5429ae7 100644 --- a/src/hasp_config.h +++ b/src/hasp_config.h @@ -90,6 +90,7 @@ const char FP_GUI_BACKLIGHTINVERT[] PROGMEM = "bcklinv"; const char FP_GUI_POINTER[] PROGMEM = "cursor"; const char FP_GUI_LONG_TIME[] PROGMEM = "long"; const char FP_GUI_REPEAT_TIME[] PROGMEM = "repeat"; +const char FP_GUI_FPS[] PROGMEM = "fps"; const char FP_DEBUG_TELEPERIOD[] PROGMEM = "tele"; const char FP_DEBUG_ANSI[] PROGMEM = "ansi"; const char FP_GPIO_CONFIG[] PROGMEM = "config"; diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 9fd55c9bf..5c39f5900 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -57,6 +57,8 @@ uint32_t screenshotEtag = 0; void (*drv_display_flush_cb)(struct _disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p); static lv_disp_buf_t disp_buf; +static bool gui_initialized = false; +static uint32_t anim_fps_deferred = 0; static inline void gui_init_lvgl() { @@ -100,6 +102,27 @@ void gui_hide_pointer(bool hidden) if(cursor) lv_obj_set_hidden(cursor, hidden || !gui_settings.show_pointer); } +bool gui_set_fps(uint32_t fps) +{ + if(!gui_initialized) { + LOG_ERROR(TAG_GUI, F("GUI not initialized, deferring FPS setting")); + anim_fps_deferred = fps; + return false; + } + + bool changed = false; + uint32_t period = 1000 / fps; + // find animation task by its period + lv_task_t* task = NULL; + while(task = lv_task_get_next(task)) { + if(!(task->period == LV_DISP_DEF_REFR_PERIOD)) continue; + changed |= (task->period != period); + LOG_INFO(TAG_GUI, F("Changing animation period: %u -> %u (%u FPS)"), task->period, period, fps); + task->period = period; + } + return changed; +} + IRAM_ATTR void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) { haspTft.flush_pixels(disp, area, color_p); @@ -373,6 +396,13 @@ void guiSetup() } #endif // ESP32 && HASP_USE_ESP_MQTT + // apply deferred FPS setting + gui_initialized = true; + if(anim_fps_deferred != 0) { + gui_set_fps(anim_fps_deferred); + anim_fps_deferred = 0; + } + LOG_INFO(TAG_LVGL, F(D_SERVICE_STARTED)); } @@ -612,6 +642,11 @@ bool guiSetConfig(const JsonObject& settings) changed |= status; } + if(!settings[FPSTR(FP_GUI_FPS)].isNull()) { + uint32_t fps = settings[FPSTR(FP_GUI_FPS)].as(); + changed |= gui_set_fps(fps); + } + return changed; } #endif // HASP_USE_CONFIG diff --git a/src/hasp_gui.h b/src/hasp_gui.h index 8b5b12afd..adb5ddb64 100644 --- a/src/hasp_gui.h +++ b/src/hasp_gui.h @@ -48,6 +48,7 @@ void guiEverySecond(void); void guiStart(void); void guiStop(void); void gui_hide_pointer(bool hidden); +bool gui_set_fps(uint32_t fps); /* ===== Special Event Processors ===== */ void guiCalibrate(void); From 4fff3d79c5696d7ce7ac7ea4b0aed1647cb9d988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 10 Feb 2024 15:05:01 +0100 Subject: [PATCH 24/36] Enable command console on PC build --- include/hasp_conf.h | 2 +- src/hasp_debug.cpp | 4 +- src/sys/svc/hasp_console.cpp | 41 ++++++++++++++++++-- src/sys/svc/hasp_console.h | 4 +- src/sys/svc/hasp_http.cpp | 4 +- src/sys/svc/hasp_http_async.cpp | 4 +- user_setups/darwin_sdl/darwin_sdl_64bits.ini | 1 + user_setups/linux_sdl/linux_fbdev_64bits.ini | 1 + user_setups/linux_sdl/linux_sdl_64bits.ini | 1 + user_setups/win32/windows_gdi_64bits.ini | 1 + user_setups/win32/windows_sdl_64bits.ini | 1 + 11 files changed, 53 insertions(+), 11 deletions(-) diff --git a/include/hasp_conf.h b/include/hasp_conf.h index dc6eca523..f458102b9 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -123,7 +123,7 @@ #endif #ifndef HASP_USE_CONSOLE -#define HASP_USE_CONSOLE HASP_TARGET_ARDUINO +#define HASP_USE_CONSOLE 1 #endif /* Filesystem */ diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp index 2adfd826a..ca648c60d 100644 --- a/src/hasp_debug.cpp +++ b/src/hasp_debug.cpp @@ -139,13 +139,11 @@ void debugStart(void) LOG_INFO(TAG_DEBG, F("Console started")); debug_flush(); -#else +#endif #if HASP_USE_CONSOLE > 0 consoleSetup(); #endif - -#endif } void debugStop() diff --git a/src/sys/svc/hasp_console.cpp b/src/sys/svc/hasp_console.cpp index 66312569c..17612d2d9 100644 --- a/src/sys/svc/hasp_console.cpp +++ b/src/sys/svc/hasp_console.cpp @@ -5,8 +5,10 @@ #if HASP_USE_CONSOLE > 0 +#if HASP_TARGET_ARDUINO #include "ConsoleInput.h" #include +#endif #include "hasp_debug.h" #include "hasp_console.h" @@ -17,15 +19,18 @@ extern hasp_http_config_t http_config; #endif +#if HASP_TARGET_ARDUINO // Create a new Stream that buffers all writes to serialClient HardwareSerial* bufferedSerialClient = (HardwareSerial*)&HASP_SERIAL; +ConsoleInput* console; +#endif uint8_t consoleLoginState = CONSOLE_UNAUTHENTICATED; uint16_t serialPort = 0; uint8_t consoleEnabled = true; // Enable serial debug output uint8_t consoleLoginAttempt = 0; // Initial attempt -ConsoleInput* console; +#if HASP_TARGET_ARDUINO void console_update_prompt() { if(console) console->update(__LINE__); @@ -101,9 +106,21 @@ static void console_process_line(const char* input) } } } +#elif HASP_TARGET_PC +static bool console_running = true; +static int console_thread(void* arg) +{ + while(console_running) { + std::string input; + std::getline(std::cin, input); + dispatch_text_line(input.c_str(), TAG_CONS); + } +} +#endif void consoleStart() { +#if HASP_TARGET_ARDUINO LOG_TRACE(TAG_MSGR, F(D_SERVICE_STARTING)); console = new ConsoleInput(bufferedSerialClient, HASP_CONSOLE_BUFFER); if(console) { @@ -126,16 +143,32 @@ void consoleStart() console_logoff(); LOG_ERROR(TAG_CONS, F(D_SERVICE_START_FAILED)); } +#elif HASP_TARGET_PC + LOG_TRACE(TAG_MSGR, F(D_SERVICE_STARTING)); +#if defined(WINDOWS) + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)console_thread, NULL, 0, NULL); +#elif defined(POSIX) + pthread_t thread; + pthread_create(&thread, NULL, (void* (*)(void*))console_thread, NULL); +#endif +#endif } void consoleStop() { +#if HASP_TARGET_ARDUINO console_logoff(); Log.unregisterOutput(0); // serialClient HASP_SERIAL.end(); - delete console; console = NULL; +#elif HASP_TARGET_PC +#if defined(WINDOWS) + +#elif defined(POSIX) + +#endif +#endif } void consoleSetup() @@ -147,6 +180,7 @@ void consoleSetup() IRAM_ATTR void consoleLoop() { +#if HASP_TARGET_ARDUINO if(!console) return; bool update = false; @@ -175,6 +209,7 @@ IRAM_ATTR void consoleLoop() } } if(update) console_update_prompt(); +#endif } #if HASP_USE_CONFIG > 0 @@ -201,4 +236,4 @@ bool consoleSetConfig(const JsonObject& settings) } #endif // HASP_USE_CONFIG -#endif \ No newline at end of file +#endif diff --git a/src/sys/svc/hasp_console.h b/src/sys/svc/hasp_console.h index 10c17b696..188345085 100644 --- a/src/sys/svc/hasp_console.h +++ b/src/sys/svc/hasp_console.h @@ -4,10 +4,10 @@ #ifndef HASP_CONSOLE_H #define HASP_CONSOLE_H -#if HASP_USE_CONSOLE > 0 - #include "hasplib.h" +#if HASP_USE_CONSOLE > 0 + /* ===== Default Event Processors ===== */ void consoleSetup(); IRAM_ATTR void consoleLoop(void); diff --git a/src/sys/svc/hasp_http.cpp b/src/sys/svc/hasp_http.cpp index e37373091..6debc383e 100644 --- a/src/sys/svc/hasp_http.cpp +++ b/src/sys/svc/hasp_http.cpp @@ -2,6 +2,9 @@ For full license information read the LICENSE file in the project folder */ #include "hasplib.h" + +#if HASP_USE_HTTP > 0 + #include "ArduinoLog.h" #define HTTP_LEGACY @@ -21,7 +24,6 @@ #include "hasp_gui.h" #include "hasp_debug.h" -#if HASP_USE_HTTP > 0 #include "sys/net/hasp_network.h" #include "sys/net/hasp_time.h" diff --git a/src/sys/svc/hasp_http_async.cpp b/src/sys/svc/hasp_http_async.cpp index 2c8ec7073..683d2f506 100644 --- a/src/sys/svc/hasp_http_async.cpp +++ b/src/sys/svc/hasp_http_async.cpp @@ -3,6 +3,9 @@ //#include "webServer.h" #include "hasplib.h" + +#if HASP_USE_HTTP_ASYNC > 0 + #include "ArduinoLog.h" #if defined(ARDUINO_ARCH_ESP32) @@ -16,7 +19,6 @@ #include "hasp_gui.h" #include "hasp_debug.h" -#if HASP_USE_HTTP_ASYNC > 0 #include "sys/net/hasp_network.h" /* clang-format off */ diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin_sdl/darwin_sdl_64bits.ini index 4a1962c05..7f6b2dca7 100644 --- a/user_setups/darwin_sdl/darwin_sdl_64bits.ini +++ b/user_setups/darwin_sdl/darwin_sdl_64bits.ini @@ -99,6 +99,7 @@ build_src_filter = - - + + + - + - diff --git a/user_setups/linux_sdl/linux_fbdev_64bits.ini b/user_setups/linux_sdl/linux_fbdev_64bits.ini index 4904cf69a..6517de417 100644 --- a/user_setups/linux_sdl/linux_fbdev_64bits.ini +++ b/user_setups/linux_sdl/linux_fbdev_64bits.ini @@ -84,6 +84,7 @@ build_src_filter = - - + + + - + - diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux_sdl/linux_sdl_64bits.ini index 432c98149..099760038 100644 --- a/user_setups/linux_sdl/linux_sdl_64bits.ini +++ b/user_setups/linux_sdl/linux_sdl_64bits.ini @@ -89,6 +89,7 @@ build_src_filter = - - + + + - + - diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index d2657df56..901d2f365 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -113,6 +113,7 @@ build_src_filter = - - + + + - + - diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini index 3c6957bbd..a9327f8a9 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -119,6 +119,7 @@ build_src_filter = - - + + + - + - From 603d38ae3c25844cb40aebe30e6bfec696462ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 10 Feb 2024 16:22:29 +0100 Subject: [PATCH 25/36] Support executing shell commands on PC build --- src/dev/posix/hasp_posix.cpp | 6 +++++ src/dev/posix/hasp_posix.h | 2 ++ src/dev/win32/hasp_win32.cpp | 5 ++++ src/dev/win32/hasp_win32.h | 2 ++ src/hasp/hasp_dispatch.cpp | 45 ++++++++++++++++++++++++++++++++++++ src/sys/svc/hasp_console.cpp | 11 +++------ 6 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp index 8d864cf7b..db6aa5848 100644 --- a/src/dev/posix/hasp_posix.cpp +++ b/src/dev/posix/hasp_posix.cpp @@ -246,6 +246,12 @@ bool PosixDevice::is_system_pin(uint8_t pin) return false; } +void Win32Device::run_thread(void (*func)(void*), void* arg) +{ + pthread_t thread; + pthread_create(&thread, NULL, (void* (*)(void*))func, arg); +} + #ifndef TARGET_OS_MAC long PosixDevice::get_uptime() { diff --git a/src/dev/posix/hasp_posix.h b/src/dev/posix/hasp_posix.h index 439d4c12c..70f626955 100644 --- a/src/dev/posix/hasp_posix.h +++ b/src/dev/posix/hasp_posix.h @@ -58,6 +58,8 @@ class PosixDevice : public BaseDevice { bool is_system_pin(uint8_t pin) override; + void run_thread(void (*func)(void*), void* arg); + public: std::string backlight_device; int backlight_max = 0; diff --git a/src/dev/win32/hasp_win32.cpp b/src/dev/win32/hasp_win32.cpp index 6f7576de9..591ccb756 100644 --- a/src/dev/win32/hasp_win32.cpp +++ b/src/dev/win32/hasp_win32.cpp @@ -187,6 +187,11 @@ bool Win32Device::is_system_pin(uint8_t pin) return false; } +void Win32Device::run_thread(void (*func)(void*), void* arg) +{ + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, arg, 0, NULL); +} + long Win32Device::get_uptime() { return GetTickCount64() / 1000; diff --git a/src/dev/win32/hasp_win32.h b/src/dev/win32/hasp_win32.h index 1a25106de..09f567732 100644 --- a/src/dev/win32/hasp_win32.h +++ b/src/dev/win32/hasp_win32.h @@ -45,6 +45,8 @@ class Win32Device : public BaseDevice { bool is_system_pin(uint8_t pin) override; + void run_thread(void (*func)(void*), void* arg); + private: std::string _hostname; std::string _core_version; diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 0b58089fd..42cc1750b 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -822,6 +822,48 @@ void dispatch_run_script(const char*, const char* payload, uint8_t source) #endif } +#if HASP_TARGET_PC +static void shell_command_thread(char* cmdline) +{ + // run the command + FILE* pipe = popen(cmdline, "r"); + // free the string duplicated previously + free(cmdline); + if(!pipe) { + LOG_ERROR(TAG_MSGR, F("Couldn't execute system command")); + return; + } + // read each line, up to 1023 chars long + char command[1024]; + while(fgets(command, sizeof(command), pipe) != NULL) { + // strip newline character + char* temp = command; + while(*temp) { + if(*temp == '\r' || *temp == '\n') { + *temp = '\0'; + break; + } + temp++; + } + // run the command + LOG_INFO(TAG_MSGR, F("Running '%s'"), command); + dispatch_text_line(command, TAG_MSGR); + } + // close the pipe, check return code + int status_code = pclose(pipe); + if(status_code) { + LOG_ERROR(TAG_MSGR, F("Process exited with non-zero return code %d"), status_code); + } +} + +void dispatch_shell_execute(const char*, const char* payload, uint8_t source) +{ + // must duplicate the string for thread's own usage + char* command = strdup(payload); + haspDevice.run_thread((void (*)(void*))shell_command_thread, (void*)command); +} +#endif + void dispatch_current_page() { char topic[8]; @@ -1495,6 +1537,9 @@ void dispatchSetup() dispatch_add_command(PSTR("sensors"), dispatch_send_sensordata); dispatch_add_command(PSTR("theme"), dispatch_theme); dispatch_add_command(PSTR("run"), dispatch_run_script); +#if HASP_TARGET_PC + dispatch_add_command(PSTR("shell"), dispatch_shell_execute); +#endif dispatch_add_command(PSTR("service"), dispatch_service); dispatch_add_command(PSTR("antiburn"), dispatch_antiburn); dispatch_add_command(PSTR("calibrate"), dispatch_calibrate); diff --git a/src/sys/svc/hasp_console.cpp b/src/sys/svc/hasp_console.cpp index 17612d2d9..04ab243fa 100644 --- a/src/sys/svc/hasp_console.cpp +++ b/src/sys/svc/hasp_console.cpp @@ -108,7 +108,7 @@ static void console_process_line(const char* input) } #elif HASP_TARGET_PC static bool console_running = true; -static int console_thread(void* arg) +static void console_thread(void* arg) { while(console_running) { std::string input; @@ -145,12 +145,7 @@ void consoleStart() } #elif HASP_TARGET_PC LOG_TRACE(TAG_MSGR, F(D_SERVICE_STARTING)); -#if defined(WINDOWS) - CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)console_thread, NULL, 0, NULL); -#elif defined(POSIX) - pthread_t thread; - pthread_create(&thread, NULL, (void* (*)(void*))console_thread, NULL); -#endif + haspDevice.run_thread(console_thread, NULL); #endif } @@ -202,7 +197,7 @@ IRAM_ATTR void consoleLoop() case 0: case -1: break; - + default: { update = true; } From 3cb5eb2d580cf8291eaccd84fdec8362f1785bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 10 Feb 2024 18:04:18 +0100 Subject: [PATCH 26/36] Support event data substitution in action commands --- include/hasp_conf.h | 4 + src/hasp/hasp_dispatch.cpp | 30 +++++-- src/hasp/hasp_dispatch.h | 3 +- src/hasp/hasp_event.cpp | 89 ++++++++++++-------- user_setups/darwin_sdl/darwin_sdl_64bits.ini | 3 +- user_setups/linux_sdl/linux_fbdev_64bits.ini | 3 +- user_setups/linux_sdl/linux_sdl_64bits.ini | 3 +- user_setups/win32/windows_gdi_64bits.ini | 3 +- user_setups/win32/windows_sdl_64bits.ini | 3 +- 9 files changed, 95 insertions(+), 46 deletions(-) diff --git a/include/hasp_conf.h b/include/hasp_conf.h index f458102b9..9f4b60ffb 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -177,6 +177,10 @@ #define HASP_NUM_GPIO_CONFIG 8 #endif +#ifndef HASP_USE_EVENT_DATA_SUBST +#define HASP_USE_EVENT_DATA_SUBST 0 +#endif + // #ifndef HASP_USE_CUSTOM // #define HASP_USE_CUSTOM 0 // #endif diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 42cc1750b..1fb19b013 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -610,11 +610,17 @@ void dispatch_screenshot(const char*, const char* filename, uint8_t source) } bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source) +{ + JsonObject dummy; + return dispatch_json_variant_with_data(json, savedPage, source, dummy); +} + +bool dispatch_json_variant_with_data(JsonVariant& json, uint8_t& savedPage, uint8_t source, JsonObject& data) { if(json.is()) { // handle json as an array of commands LOG_DEBUG(TAG_MSGR, "Json ARRAY"); for(JsonVariant command : json.as()) { - dispatch_json_variant(command, savedPage, source); + dispatch_json_variant_with_data(command, savedPage, source, data); } } else if(json.is()) { // handle json as a jsonl @@ -622,13 +628,23 @@ bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source hasp_new_object(json.as(), savedPage); } else if(json.is()) { // handle json as a single command - LOG_DEBUG(TAG_MSGR, "Json text = %s", json.as().c_str()); - dispatch_simple_text_command(json.as().c_str(), source); - - } else if(json.is()) { // handle json as a single command - LOG_DEBUG(TAG_MSGR, "Json text = %s", json.as()); - dispatch_simple_text_command(json.as(), source); + std::string command = json.as(); + +#if HASP_USE_EVENT_DATA_SUBST + if(command.find('%') != std::string::npos) { + // '%' found in command, run variable substitution + for(JsonPair kv : data) { + std::string find = "%" + std::string(kv.key().c_str()) + "%"; + std::string replace = kv.value().as(); + size_t pos = command.find(find); + if(pos == std::string::npos) continue; + command.replace(pos, find.length(), replace); + } + } +#endif + LOG_DEBUG(TAG_MSGR, "Json text = %s", command.c_str()); + dispatch_simple_text_command(command.c_str(), source); } else if(json.isNull()) { // event handler not found // nothing to do diff --git a/src/hasp/hasp_dispatch.h b/src/hasp/hasp_dispatch.h index 245da30c2..53a5804a1 100644 --- a/src/hasp/hasp_dispatch.h +++ b/src/hasp/hasp_dispatch.h @@ -55,6 +55,7 @@ void dispatch_parse_jsonl(Stream& stream, uint8_t& saved_page_id); void dispatch_parse_jsonl(std::istream& stream, uint8_t& saved_page_id); #endif bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source); +bool dispatch_json_variant_with_data(JsonVariant& json, uint8_t& savedPage, uint8_t source, JsonObject& data); void dispatch_clear_page(const char* page); void dispatch_json_error(uint8_t tag, DeserializationError& jsonError); @@ -101,4 +102,4 @@ struct haspCommand_t void (*func)(const char*, const char*, uint8_t); }; -#endif \ No newline at end of file +#endif diff --git a/src/hasp/hasp_event.cpp b/src/hasp/hasp_event.cpp index fd5eeaeef..9a5cc2bff 100644 --- a/src/hasp/hasp_event.cpp +++ b/src/hasp/hasp_event.cpp @@ -42,23 +42,47 @@ void event_reset_last_value_sent() last_value_sent = INT16_MIN; } -void script_event_handler(const char* eventname, const char* json) +static bool script_event_handler(const char* eventname, const char* action, const char* data) { + if(action == NULL) { + LOG_DEBUG(TAG_EVENT, F("Skipping event: name=%s, data=%s"), eventname, data); + return false; + } StaticJsonDocument<256> doc; StaticJsonDocument<64> filter; filter[eventname] = true; - DeserializationError jsonError = deserializeJson(doc, json, DeserializationOption::Filter(filter)); + DeserializationError jsonError = deserializeJson(doc, action, DeserializationOption::Filter(filter)); if(!jsonError) { - JsonVariant json = doc[eventname].as(); + JsonVariant json = doc[eventname].as(); + if(json.isNull()) { + LOG_DEBUG(TAG_EVENT, F("Skipping event: name=%s, data=%s"), eventname, data); + return true; + } else { + LOG_DEBUG(TAG_EVENT, F("Handling event: name=%s, data=%s"), eventname, data); + } + + JsonObject dataJson; +#if HASP_USE_EVENT_DATA_SUBST + if(data != NULL) { + StaticJsonDocument<256> jsonDoc; + if(deserializeJson(jsonDoc, data) != DeserializationError::Ok) { + LOG_ERROR(TAG_EVENT, F("Deserialization failed")); + } else { + dataJson = jsonDoc.as(); + } + } +#endif + uint8_t savedPage = haspPages.get(); - if(!dispatch_json_variant(json, savedPage, TAG_EVENT)) { + if(!dispatch_json_variant_with_data(json, savedPage, TAG_EVENT, dataJson)) { LOG_WARNING(TAG_EVENT, F(D_DISPATCH_COMMAND_NOT_FOUND), eventname); } } else { dispatch_json_error(TAG_EVENT, jsonError); } + return true; } /** @@ -254,11 +278,16 @@ static bool translate_event(lv_obj_t* obj, lv_event_t event, uint8_t& eventid) // ##################### Value Senders ######################################################## -static void event_send_object_data(lv_obj_t* obj, const char* data) +static void event_send_object_data(lv_obj_t* obj, const char* eventname, const char* data) { uint8_t pageid; uint8_t objid; + // handle object "action", abort sending if handled + if(script_event_handler(eventname, my_obj_get_action(obj), data)) { + return; + } + if(hasp_find_id_from_obj(obj, &pageid, &objid)) { if(!data) return; object_dispatch_state(pageid, objid, data); @@ -271,23 +300,23 @@ static void event_send_object_data(lv_obj_t* obj, const char* data) static void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val) { char data[512]; + char eventname[8]; { - char eventname[8]; Parser::get_event_name(eventid, eventname, sizeof(eventname)); if(const char* tag = my_obj_get_tag(obj)) snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"tag\":%s}"), eventname, val, tag); else snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d}"), eventname, val); } - event_send_object_data(obj, data); + event_send_object_data(obj, eventname, data); } // Send out events with a val and text attribute static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16_t val, const char* text) { char data[512]; + char eventname[8]; { - char eventname[8]; Parser::get_event_name(eventid, eventname, sizeof(eventname)); if(const char* tag = my_obj_get_tag(obj)) @@ -296,7 +325,7 @@ static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16 else snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":\"%s\"}"), eventname, val, text); } - event_send_object_data(obj, data); + event_send_object_data(obj, eventname, data); } // ##################### Event Handlers ######################################################## @@ -402,16 +431,16 @@ void swipe_event_handler(lv_obj_t* obj, lv_event_t event) lv_gesture_dir_t dir = lv_indev_get_gesture_dir(lv_indev_get_act()); switch(dir) { case LV_GESTURE_DIR_LEFT: - script_event_handler("left", swipe); + script_event_handler("left", swipe, NULL); break; case LV_GESTURE_DIR_RIGHT: - script_event_handler("right", swipe); + script_event_handler("right", swipe, NULL); break; case LV_GESTURE_DIR_BOTTOM: - script_event_handler("down", swipe); + script_event_handler("down", swipe, NULL); break; default: - script_event_handler("up", swipe); + script_event_handler("up", swipe, NULL); } } } @@ -432,8 +461,8 @@ void textarea_event_handler(lv_obj_t* obj, lv_event_t event) if(!translate_event(obj, event, hasp_event_id)) return; char data[1024]; + char eventname[8]; { - char eventname[8]; Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); if(const char* tag = my_obj_get_tag(obj)) @@ -444,7 +473,7 @@ void textarea_event_handler(lv_obj_t* obj, lv_event_t event) lv_textarea_get_text(obj)); } - event_send_object_data(obj, data); + event_send_object_data(obj, eventname, data); } else if(event == LV_EVENT_FOCUSED) { lv_textarea_set_cursor_hidden(obj, false); } else if(event == LV_EVENT_DEFOCUSED) { @@ -518,23 +547,17 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event) if(last_value_sent == HASP_EVENT_LOST) return; - if(const char* action = my_obj_get_action(obj)) { - char eventname[8]; + char data[512]; + char eventname[8]; + { Parser::get_event_name(last_value_sent, eventname, sizeof(eventname)); - script_event_handler(eventname, action); - } else { - char data[512]; - { - char eventname[8]; - Parser::get_event_name(last_value_sent, eventname, sizeof(eventname)); - if(const char* tag = my_obj_get_tag(obj)) - snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"tag\":%s}"), eventname, tag); - else - snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname); - } - event_send_object_data(obj, data); + if(const char* tag = my_obj_get_tag(obj)) + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"tag\":%s}"), eventname, tag); + else + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname); } + event_send_object_data(obj, eventname, data); // Update group objects and gpios on release if(last_value_sent != LV_EVENT_LONG_PRESSED && last_value_sent != LV_EVENT_LONG_PRESSED_REPEAT) { @@ -841,8 +864,8 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) if(hasp_event_id == HASP_EVENT_CHANGED && last_color_sent.full == color.full) return; // same value as before char data[512]; + char eventname[8]; { - char eventname[8]; Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); lv_color32_t c32; @@ -864,7 +887,7 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, hsv.s, hsv.v); } - event_send_object_data(obj, data); + event_send_object_data(obj, eventname, data); // event_update_group(obj->user_data.groupid, obj, val, min, max); } @@ -891,8 +914,8 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event) return; // same object and value as before char data[512]; + char eventname[8]; { - char eventname[8]; Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); last_value_sent = val; @@ -907,7 +930,7 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event) PSTR("{\"event\":\"%s\",\"val\":\"%d\",\"text\":\"%04d-%02d-%02dT00:00:00Z\"}"), eventname, date->day, date->year, date->month, date->day); } - event_send_object_data(obj, data); + event_send_object_data(obj, eventname, data); // event_update_group(obj->user_data.groupid, obj, val, min, max); } diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin_sdl/darwin_sdl_64bits.ini index 7f6b2dca7..55e0288ca 100644 --- a/user_setups/darwin_sdl/darwin_sdl_64bits.ini +++ b/user_setups/darwin_sdl/darwin_sdl_64bits.ini @@ -34,7 +34,8 @@ build_flags = -D HASP_USE_GIFDECODE=0 -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 - -D MQTT_MAX_PACKET_SIZE=2048 + -D HASP_USE_EVENT_DATA_SUBST=1 + -D MQTT_MAX_PACKET_SIZE=32768 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available diff --git a/user_setups/linux_sdl/linux_fbdev_64bits.ini b/user_setups/linux_sdl/linux_fbdev_64bits.ini index 6517de417..a709efb7e 100644 --- a/user_setups/linux_sdl/linux_fbdev_64bits.ini +++ b/user_setups/linux_sdl/linux_fbdev_64bits.ini @@ -31,7 +31,8 @@ build_flags = -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 -D HASP_USE_LVGL_TASK=1 - -D MQTT_MAX_PACKET_SIZE=2048 + -D HASP_USE_EVENT_DATA_SUBST=1 + -D MQTT_MAX_PACKET_SIZE=32768 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux_sdl/linux_sdl_64bits.ini index 099760038..fc3287ccc 100644 --- a/user_setups/linux_sdl/linux_sdl_64bits.ini +++ b/user_setups/linux_sdl/linux_sdl_64bits.ini @@ -34,7 +34,8 @@ build_flags = -D HASP_USE_GIFDECODE=0 -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 - -D MQTT_MAX_PACKET_SIZE=2048 + -D HASP_USE_EVENT_DATA_SUBST=1 + -D MQTT_MAX_PACKET_SIZE=32768 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index 901d2f365..23062b6f6 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -30,7 +30,8 @@ build_flags = -D HASP_USE_MQTT=1 -D HASP_USE_SYSLOG=0 -D HASP_USE_LVGL_TASK=1 - -D MQTT_MAX_PACKET_SIZE=2048 + -D HASP_USE_EVENT_DATA_SUBST=1 + -D MQTT_MAX_PACKET_SIZE=32768 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini index a9327f8a9..bd4338b11 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -34,7 +34,8 @@ build_flags = -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 -D HASP_USE_SYSLOG=0 - -D MQTT_MAX_PACKET_SIZE=2048 + -D HASP_USE_EVENT_DATA_SUBST=1 + -D MQTT_MAX_PACKET_SIZE=32768 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available From 3fcae65fadb3f2cf1671c0d3a091ffb4cec85109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 10 Feb 2024 18:20:54 +0100 Subject: [PATCH 27/36] Allow suppressing console output on PC build --- src/dev/posix/hasp_posix.cpp | 2 +- src/main_pc.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp index db6aa5848..e5f1b1735 100644 --- a/src/dev/posix/hasp_posix.cpp +++ b/src/dev/posix/hasp_posix.cpp @@ -246,7 +246,7 @@ bool PosixDevice::is_system_pin(uint8_t pin) return false; } -void Win32Device::run_thread(void (*func)(void*), void* arg) +void PosixDevice::run_thread(void (*func)(void*), void* arg) { pthread_t thread; pthread_create(&thread, NULL, (void* (*)(void*))func, arg); diff --git a/src/main_pc.cpp b/src/main_pc.cpp index 63d3d2bb5..40431d75e 100644 --- a/src/main_pc.cpp +++ b/src/main_pc.cpp @@ -17,6 +17,7 @@ #if defined(POSIX) #include #include +#include #include #include #include @@ -112,6 +113,7 @@ void usage(const char* progName, const char* version) << std::endl << "Options:" << std::endl << " -h | --help Print this help" << std::endl + << " -q | --quiet Suppress console output (can improve performance)" << std::endl #if !USE_FBDEV << " -W | --width Width of the window" << std::endl << " -H | --height Height of the window" << std::endl @@ -140,6 +142,15 @@ int main(int argc, char* argv[]) for(int arg = 1; arg < argc; arg++) { if(strncmp(argv[arg], "--help", 6) == 0 || strncmp(argv[arg], "-h", 2) == 0) { showhelp = true; + } else if(strncmp(argv[arg], "--quiet", 7) == 0 || strncmp(argv[arg], "-q", 2) == 0) { +#if defined(WINDOWS) + FreeConsole(); +#endif +#if defined(POSIX) + int nullfd = open("/dev/null", O_WRONLY); + dup2(nullfd, 1); + close(nullfd); +#endif #if !USE_FBDEV } else if(strncmp(argv[arg], "--width", 7) == 0 || strncmp(argv[arg], "-W", 2) == 0) { if(arg + 1 < argc) { From 32c21b9c5235acb61f9112f3b2dd0ff2a491e5b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 10 Feb 2024 20:30:12 +0100 Subject: [PATCH 28/36] Implement command scheduling --- src/hasp/hasp_dispatch.cpp | 87 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 1fb19b013..b5795d160 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -37,6 +37,8 @@ #endif #endif +#include + dispatch_conf_t dispatch_setings = {.teleperiod = 300}; uint16_t dispatchSecondsToNextTeleperiod = 0; @@ -48,6 +50,8 @@ haspCommand_t commands[28]; moodlight_t moodlight = {.brightness = 255}; uint8_t saved_jsonl_page = 0; +static std::map scheduled_tasks; + /* Sends the payload out on the state/subtopic */ void dispatch_state_subtopic(const char* subtopic, const char* payload) @@ -1414,6 +1418,88 @@ void dispatch_sleep(const char*, const char*, uint8_t source) hasp_set_wakeup_touch(false); } +static void dispatch_schedule_runner(lv_task_t* task) +{ + dispatch_text_line((const char*)task->user_data, TAG_MSGR); +} + +void dispatch_schedule(const char*, const char* payload, uint8_t source) +{ + // duplicate the string for modification + char* argline = strdup(payload); + // split argline into argv by whitespace; limit to 4 parts + char* argv[4]; + int argn = 0; + argv[argn++] = argline; + while(*argline) { + if(*argline == ' ') { + *argline = '\0'; + argv[argn++] = argline + 1; + } + argline++; + if(argn == 4) break; + } + + const char* action = argv[0]; + uint32_t id = atoi(argv[1]); + + if(strcasecmp(action, "set") == 0) { + if(argn != 4) { + LOG_ERROR(TAG_MSGR, F("Usage: schedule set ")); + goto end; + } + uint32_t period = atoi(argv[2]); + const char* command = strdup(argv[3]); + + if(scheduled_tasks.find(id) != scheduled_tasks.end()) { + // update an existing task + lv_task_t* task = scheduled_tasks[id]; + free(task->user_data); + task->period = period; + task->user_data = (void*)command; + } else { + // create a new task + lv_task_t* task = lv_task_create(dispatch_schedule_runner, period, LV_TASK_PRIO_MID, (void*)command); + scheduled_tasks[id] = task; + } + + LOG_INFO(TAG_MSGR, F("Scheduled command ID %u, every %u ms: %s"), id, period, command); + + goto end; + } + + if(argn != 2) { + LOG_ERROR(TAG_MSGR, F("Usage: schedule ")); + goto end; + } + if(scheduled_tasks.find(id) == scheduled_tasks.end()) { + LOG_ERROR(TAG_MSGR, F("Task by ID %u does not exist"), id); + goto end; + } + + { + lv_task_t* task = scheduled_tasks[id]; + if(strcasecmp(action, "del") == 0) { + free(task->user_data); + lv_task_del(task); + scheduled_tasks.erase(id); + goto end; + } + if(strcasecmp(action, "start") == 0) { + lv_task_set_prio(task, LV_TASK_PRIO_MID); + goto end; + } + if(strcasecmp(action, "stop") == 0) { + lv_task_set_prio(task, LV_TASK_PRIO_OFF); + goto end; + } + } + +end: + // release the duplicated argline + free(argv[0]); +} + void dispatch_idle_state(uint8_t state) { char topic[8]; @@ -1547,6 +1633,7 @@ void dispatchSetup() dispatch_add_command(PSTR("moodlight"), dispatch_moodlight); dispatch_add_command(PSTR("idle"), dispatch_idle); dispatch_add_command(PSTR("sleep"), dispatch_sleep); + dispatch_add_command(PSTR("schedule"), dispatch_schedule); dispatch_add_command(PSTR("statusupdate"), dispatch_statusupdate); dispatch_add_command(PSTR("clearpage"), dispatch_clear_page); dispatch_add_command(PSTR("clearfont"), dispatch_clear_font); From d0d2bc19409dee40d9598ecb0210aaa9ac8488b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 10 Feb 2024 23:43:28 +0100 Subject: [PATCH 29/36] Enable Paho Async MQTT client on PC build --- include/hasp_conf.h | 4 + src/mqtt/hasp_mqtt_paho_async.cpp | 548 ++++++++++++------- src/mqtt/hasp_mqtt_paho_single.cpp | 2 +- user_setups/darwin_sdl/darwin_sdl_64bits.ini | 13 +- user_setups/linux_sdl/linux_fbdev_64bits.ini | 12 +- user_setups/linux_sdl/linux_sdl_64bits.ini | 12 +- user_setups/win32/windows_gdi_64bits.ini | 12 +- user_setups/win32/windows_sdl_64bits.ini | 12 +- 8 files changed, 380 insertions(+), 235 deletions(-) diff --git a/include/hasp_conf.h b/include/hasp_conf.h index 9f4b60ffb..e36b8925c 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -70,6 +70,10 @@ #define HASP_USE_MQTT (HASP_HAS_NETWORK) #endif +#ifndef HASP_USE_MQTT_ASYNC +#define HASP_USE_MQTT_ASYNC (HASP_TARGET_PC) +#endif + #ifndef HASP_USE_WIREGUARD #define HASP_USE_WIREGUARD (HASP_HAS_NETWORK) #endif diff --git a/src/mqtt/hasp_mqtt_paho_async.cpp b/src/mqtt/hasp_mqtt_paho_async.cpp index b56783fa0..5485fe9e6 100644 --- a/src/mqtt/hasp_mqtt_paho_async.cpp +++ b/src/mqtt/hasp_mqtt_paho_async.cpp @@ -10,6 +10,15 @@ #if HASP_USE_MQTT_ASYNC > 0 #ifdef HASP_USE_PAHO +#if !HASP_USE_CONFIG +const char FP_CONFIG_HOST[] PROGMEM = "host"; +const char FP_CONFIG_PORT[] PROGMEM = "port"; +const char FP_CONFIG_NAME[] PROGMEM = "name"; +const char FP_CONFIG_USER[] PROGMEM = "user"; +const char FP_CONFIG_PASS[] PROGMEM = "pass"; +const char FP_CONFIG_GROUP[] PROGMEM = "group"; +#endif + /******************************************************************************* * Copyright (c) 2012, 2020 IBM Corp. * @@ -38,7 +47,7 @@ #include "hasp_mqtt.h" // functions to implement here #include "hasp/hasp_dispatch.h" // for dispatch_topic_payload -#include "hasp_debug.h" // for logging +#include "hasp_debug.h" // for logging #if !defined(_WIN32) #include @@ -50,78 +59,122 @@ #include #endif -#define ADDRESS "10.4.0.5:1883" -#define CLIENTID "ExampleClientSub" -#define TOPIC "hasp/plate35/" +// #define ADDRESS "10.4.0.5:1883" +// #define CLIENTID "ExampleClientSub" +// #define TOPIC "hasp/plate35/" #define QOS 1 #define TIMEOUT 10000L -const char* mqttNodeTopic = TOPIC; -const char* mqttGroupTopic = TOPIC; -// char mqttNodeTopic[24]; -// char mqttGroupTopic[24]; +std::string mqttNodeTopic; +std::string mqttGroupTopic; +std::string mqttLwtTopic; bool mqttEnabled = false; bool mqttHAautodiscover = true; +uint32_t mqttPublishCount; +uint32_t mqttReceiveCount; +uint32_t mqttFailedCount; std::recursive_mutex dispatch_mtx; std::recursive_mutex publish_mtx; -char mqttServer[MAX_HOSTNAME_LENGTH] = MQTT_HOSTNAME; -char mqttUser[MAX_USERNAME_LENGTH] = MQTT_USERNAME; -char mqttPassword[MAX_PASSWORD_LENGTH] = MQTT_PASSWORD; -// char mqttNodeName[16] = MQTT_NODENAME; -char mqttGroupName[16] = MQTT_GROUPNAME; -uint16_t mqttPort = MQTT_PORT; +std::string mqttServer = MQTT_HOSTNAME; +std::string mqttUsername = MQTT_USERNAME; +std::string mqttPassword = MQTT_PASSWORD; +std::string mqttGroupName = MQTT_GROUPNAME; +uint16_t mqttPort = MQTT_PORT; MQTTAsync mqtt_client; -int disc_finished = 0; -int subscribed = 0; -int connected = 0; +static bool mqttConnecting = false; +static bool mqttConnected = false; -static bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain = false); +int mqttPublish(const char* topic, const char* payload, size_t len, bool retain = false); /* ===== Paho event callbacks ===== */ -void connlost(void* context, char* cause) +static void onConnectFailure(void* context, MQTTAsync_failureData* response) { - printf("\nConnection lost\n"); - if(cause) printf(" cause: %s\n", cause); + mqttConnecting = false; + mqttConnected = false; + LOG_ERROR(TAG_MQTT, "Connection failed, return code %d (%s)", response->code, response->message); +} - printf("Reconnecting\n"); - mqttStart(); +static void onDisconnect(void* context, MQTTAsync_successData* response) +{ + mqttConnecting = false; + mqttConnected = false; +} + +static void onDisconnectFailure(void* context, MQTTAsync_failureData* response) +{ + mqttConnecting = false; + mqttConnected = false; + LOG_ERROR(TAG_MQTT, "Disconnection failed, return code %d (%s)", response->code, response->message); +} + +static void onSendFailure(void* context, MQTTAsync_failureData* response) +{ + LOG_ERROR(TAG_MQTT, "Send failed, return code %d (%s)", response->code, response->message); +} + +static void onSubscribeFailure(void* context, MQTTAsync_failureData* response) +{ + LOG_ERROR(TAG_MQTT, "Subscribe failed, return code %d (%s)", response->code, response->message); +} + +static void connlost(void* context, char* cause) +{ + LOG_WARNING(TAG_MQTT, F(D_MQTT_DISCONNECTED ": %s"), cause); + mqttConnecting = false; + mqttConnected = false; } // Receive incoming messages static void mqtt_message_cb(char* topic, char* payload, size_t length) { // Handle incoming commands from MQTT if(length + 1 >= MQTT_MAX_PACKET_SIZE) { + mqttFailedCount++; LOG_ERROR(TAG_MQTT_RCV, F(D_MQTT_PAYLOAD_TOO_LONG), (uint32_t)length); return; } else { + mqttReceiveCount++; payload[length] = '\0'; } LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char*)payload); - if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic + if(topic == strstr(topic, mqttNodeTopic.c_str())) { // startsWith mqttNodeTopic // Node topic - topic += strlen(mqttNodeTopic); // shorten topic + topic += mqttNodeTopic.length(); // shorten topic - } else if(topic == strstr(topic, mqttGroupTopic)) { // startsWith mqttGroupTopic + } else if(topic == strstr(topic, mqttGroupTopic.c_str())) { // startsWith mqttGroupTopic // Group topic - topic += strlen(mqttGroupTopic); // shorten topic + topic += mqttGroupTopic.length(); // shorten topic + dispatch_mtx.lock(); + dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT); + dispatch_mtx.unlock(); + return; + +#ifdef HASP_USE_BROADCAST + } else if(topic == strstr_P(topic, PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST + "/"))) { // /" MQTT_TOPIC_BROADCAST "/ discovery topic + + // /" MQTT_TOPIC_BROADCAST "/ topic + topic += strlen(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/"); // shorten topic dispatch_mtx.lock(); - dispatch_topic_payload(topic, (const char*)payload); + dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT); dispatch_mtx.unlock(); return; +#endif #ifdef HASP_USE_HA } else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic if(mqttHAautodiscover && !strcasecmp_P((char*)payload, PSTR("online"))) { - dispatch_current_state(); + dispatch_mtx.lock(); + dispatch_current_state(TAG_MQTT); + dispatch_mtx.unlock(); mqtt_ha_register_auto_discovery(); } return; @@ -138,11 +191,8 @@ static void mqtt_message_cb(char* topic, char* payload, size_t length) if(!strcasecmp_P((char*)payload, PSTR("offline"))) { { char msg[8]; - char tmp_topic[strlen(mqttNodeTopic) + 8]; - snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_LWT), mqttNodeTopic); snprintf_P(msg, sizeof(msg), PSTR("online")); - - mqttPublish(tmp_topic, msg, true); + mqttPublish(mqttLwtTopic.c_str(), msg, strlen(msg), true); } } else { @@ -150,175 +200,147 @@ static void mqtt_message_cb(char* topic, char* payload, size_t length) } } else { dispatch_mtx.lock(); - dispatch_topic_payload(topic, (const char*)payload); + dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT); dispatch_mtx.unlock(); } } -int msgarrvd(void* context, char* topicName, int topicLen, MQTTAsync_message* message) +static int mqtt_message_arrived(void* context, char* topicName, int topicLen, MQTTAsync_message* message) { - // printf("MQT RCV >> "); - // printf("%s => %.*s (%d)\n", topicName, message->payloadlen, (char *)message->payload, message->payloadlen); - char msg[message->payloadlen + 1]; memcpy(msg, (char*)message->payload, message->payloadlen); msg[message->payloadlen] = '\0'; - mqtt_message_cb(topicName, (char*)message->payload, message->payloadlen); + mqtt_message_cb(topicName, msg, message->payloadlen); MQTTAsync_freeMessage(&message); MQTTAsync_free(topicName); - return 1; -} - -void onDisconnectFailure(void* context, MQTTAsync_failureData* response) -{ - printf("Disconnect failed, rc %d\n", response->code); - disc_finished = 1; -} - -void onDisconnect(void* context, MQTTAsync_successData* response) -{ - printf("Successful disconnection\n"); - disc_finished = 1; - connected = 0; -} - -void onSubscribe(void* context, MQTTAsync_successData* response) -{ - printf("Subscribe succeeded %d\n", response->token); - subscribed = 1; + return 1; // the message was received properly } -void onSubscribeFailure(void* context, MQTTAsync_failureData* response) -{ - printf("Subscribe failed, rc %d\n", response->code); -} - -void onConnectFailure(void* context, MQTTAsync_failureData* response) -{ - connected = 0; - printf("Connect failed, rc %d\n", response->code); -} - -void mqtt_subscribe(void* context, const char* topic) +static void mqtt_subscribe(void* context, const char* topic) { MQTTAsync client = (MQTTAsync)context; MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; int rc; - printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n", topic, CLIENTID, QOS); - opts.onSuccess = onSubscribe; opts.onFailure = onSubscribeFailure; opts.context = client; if((rc = MQTTAsync_subscribe(client, topic, QOS, &opts)) != MQTTASYNC_SUCCESS) { - printf("Failed to start subscribe, return code %d\n", rc); + LOG_WARNING(TAG_MQTT, D_BULLET D_MQTT_NOT_SUBSCRIBED, topic); // error code rc + } else { + LOG_VERBOSE(TAG_MQTT, D_BULLET D_MQTT_SUBSCRIBED, topic); } } -void onConnect(void* context, MQTTAsync_successData* response) -{ - MQTTAsync client = (MQTTAsync)context; - connected = 1; - - printf("Successful connection\n"); - - mqtt_subscribe(context, TOPIC MQTT_TOPIC_COMMAND "/#"); - mqtt_subscribe(context, TOPIC MQTT_TOPIC_COMMAND); - mqtt_subscribe(context, TOPIC "light"); - mqtt_subscribe(context, TOPIC "dim"); - - mqttPublish(TOPIC MQTT_TOPIC_LWT, "online", false); - - mqtt_send_object_state(0, 0, "connected"); - std::cout << std::endl; -} +/* ===== Local HASP MQTT functions ===== */ -void onSendFailure(void* context, MQTTAsync_failureData* response) +int mqttPublish(const char* topic, const char* payload, size_t len, bool retain) { - MQTTAsync client = (MQTTAsync)context; - MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer; - int rc; + if(!mqttEnabled) return MQTT_ERR_DISABLED; - printf("Message send failed token %d error code %d\n", response->token, response->code); - opts.onSuccess = onDisconnect; - opts.onFailure = onDisconnectFailure; - opts.context = client; - if((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS) { - printf("Failed to start disconnect, return code %d\n", rc); - // exit(EXIT_FAILURE); + if(!mqttIsConnected()) { + mqttFailedCount++; + return MQTT_ERR_NO_CONN; } -} -void onSend(void* context, MQTTAsync_successData* response) -{ - MQTTAsync client = (MQTTAsync)context; - MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer; - int rc; + MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; + MQTTAsync_message pubmsg = MQTTAsync_message_initializer; - // printf("Message with token value %d delivery confirmed\n", response->token); + opts.onFailure = onSendFailure; + opts.context = mqtt_client; + pubmsg.payload = (char*)payload; + pubmsg.payloadlen = (int)strlen(payload); + pubmsg.qos = QOS; + pubmsg.retained = 0; - // opts.onSuccess = onDisconnect; - // opts.onFailure = onDisconnectFailure; - // opts.context = client; - // if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS) - // { - // printf("Failed to start disconnect, return code %d\n", rc); - // exit(EXIT_FAILURE); - // } -} - -/* ===== Local HASP MQTT functions ===== */ + dispatch_mtx.lock(); + int rc = MQTTAsync_sendMessage(mqtt_client, topic, &pubmsg, &opts); -static bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain) -{ - if(mqttIsConnected()) { - MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; - MQTTAsync_message pubmsg = MQTTAsync_message_initializer; - int rc; - - opts.onSuccess = onSend; - opts.onFailure = onSendFailure; - opts.context = mqtt_client; - pubmsg.payload = (char*)payload; - pubmsg.payloadlen = (int)strlen(payload); - pubmsg.qos = QOS; - pubmsg.retained = 0; - dispatch_mtx.lock(); - if((rc = MQTTAsync_sendMessage(mqtt_client, topic, &pubmsg, &opts)) != MQTTASYNC_SUCCESS) { - dispatch_mtx.unlock(); - LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), topic, payload); - } else { - dispatch_mtx.unlock(); - LOG_TRACE(TAG_MQTT_PUB, F("%s => %s"), topic, payload); - return true; - } + if(rc != MQTTASYNC_SUCCESS) { + dispatch_mtx.unlock(); + mqttFailedCount++; + LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " '%s' => %s"), topic, payload); + return MQTT_ERR_PUB_FAIL; } else { - LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED)); + dispatch_mtx.unlock(); + mqttPublishCount++; + // LOG_TRACE(TAG_MQTT_PUB, F("'%s' => %s OK"), topic, payload); + return MQTT_ERR_OK; } - return false; } /* ===== Public HASP MQTT functions ===== */ bool mqttIsConnected() { - return connected == 1; + return mqttConnected; // MQTTAsync_isConnected(mqtt_client); // <- deadlocking on Linux } -void mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload) +int mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload) { - char tmp_topic[strlen(mqttNodeTopic) + 20]; - printf(("%s" MQTT_TOPIC_STATE "/%s\n"), mqttNodeTopic, subtopic); - snprintf_P(tmp_topic, sizeof(tmp_topic), ("%s" MQTT_TOPIC_STATE "/%s"), mqttNodeTopic, subtopic); - mqttPublish(tmp_topic, payload, false); + char tmp_topic[mqttNodeTopic.length() + 20]; + snprintf_P(tmp_topic, sizeof(tmp_topic), ("%s" MQTT_TOPIC_STATE "/%s"), mqttNodeTopic.c_str(), subtopic); + return mqttPublish(tmp_topic, payload, strlen(payload), false); } -void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload) +int mqtt_send_discovery(const char* payload, size_t len) { - char tmp_topic[strlen(mqttNodeTopic) + 20]; - snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/p%ub%u"), mqttNodeTopic, pageid, btnid); - mqttPublish(tmp_topic, payload, false); + char tmp_topic[128]; + snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR(MQTT_PREFIX "/" MQTT_TOPIC_DISCOVERY "/%s"), + haspDevice.get_hardware_id()); + return mqttPublish(tmp_topic, payload, len, false); +} + +// int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload) +// { +// char tmp_topic[mqttNodeTopic.length() + 20]; +// snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/p%ub%u"), mqttNodeTopic.c_str(), pageid, +// btnid); +// return mqttPublish(tmp_topic, payload, strlen(payload), false); +// } + +static void onConnect(void* context, MQTTAsync_successData* response) +{ + mqttConnecting = false; + mqttConnected = true; + MQTTAsync client = (MQTTAsync)context; + std::string topic; + + LOG_VERBOSE(TAG_MQTT, D_MQTT_CONNECTED, mqttServer.c_str(), haspDevice.get_hostname()); + + topic = mqttGroupTopic + MQTT_TOPIC_COMMAND "/#"; + mqtt_subscribe(mqtt_client, topic.c_str()); + + topic = mqttNodeTopic + MQTT_TOPIC_COMMAND "/#"; + mqtt_subscribe(mqtt_client, topic.c_str()); + + topic = mqttGroupTopic + "config/#"; + mqtt_subscribe(mqtt_client, topic.c_str()); + + topic = mqttNodeTopic + "config/#"; + mqtt_subscribe(mqtt_client, topic.c_str()); + +#if defined(HASP_USE_CUSTOM) + topic = mqttGroupTopic + MQTT_TOPIC_CUSTOM "/#"; + mqtt_subscribe(mqtt_client, topic.c_str()); + + topic = mqttNodeTopic + MQTT_TOPIC_CUSTOM "/#"; + mqtt_subscribe(mqtt_client, topic.c_str()); +#endif + +#ifdef HASP_USE_BROADCAST + topic = MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/" MQTT_TOPIC_COMMAND "/#"; + mqtt_subscribe(mqtt_client, topic.c_str()); +#endif + + /* Home Assistant auto-configuration */ +#ifdef HASP_USE_HA + topic = "homeassistant/status"; + mqtt_subscribe(mqtt_client, topic.c_str()); +#endif + + mqttPublish(mqttLwtTopic.c_str(), "online", 6, true); } void mqttStart() @@ -328,47 +350,51 @@ void mqttStart() int rc; int ch; - if((rc = MQTTAsync_create(&mqtt_client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL)) != - MQTTASYNC_SUCCESS) { - printf("Failed to create client, return code %d\n", rc); + if((rc = MQTTAsync_create(&mqtt_client, mqttServer.c_str(), haspDevice.get_hostname(), MQTTCLIENT_PERSISTENCE_NONE, + NULL)) != MQTTASYNC_SUCCESS) { + LOG_ERROR(TAG_MQTT, "Failed to create client, return code %d", rc); rc = EXIT_FAILURE; return; } - if((rc = MQTTAsync_setCallbacks(mqtt_client, mqtt_client, connlost, msgarrvd, NULL)) != MQTTASYNC_SUCCESS) { - printf("Failed to set callbacks, return code %d\n", rc); + if((rc = MQTTAsync_setCallbacks(mqtt_client, mqtt_client, connlost, mqtt_message_arrived, NULL)) != + MQTTASYNC_SUCCESS) { + LOG_ERROR(TAG_MQTT, "Failed to set callbacks, return code %d", rc); rc = EXIT_FAILURE; return; } - conn_opts.will = &will_opts; - conn_opts.will->message = "offline"; - conn_opts.will->qos = 1; - conn_opts.will->retained = 0; - conn_opts.will->topicName = "hasp/plate35/LWT"; - - conn_opts.keepAliveInterval = 20; - conn_opts.cleansession = 1; - conn_opts.onSuccess = onConnect; - conn_opts.onFailure = onConnectFailure; - conn_opts.context = mqtt_client; - - if((rc = MQTTAsync_connect(mqtt_client, &conn_opts)) != MQTTASYNC_SUCCESS) { - printf("Failed to start connect, return code %d\n", rc); - rc = EXIT_FAILURE; - // goto destroy_exit; + mqttEnabled = mqttServer.length() > 0 && mqttPort > 0; + + if(mqttEnabled) { + conn_opts.will = &will_opts; + conn_opts.will->message = "offline"; + conn_opts.will->qos = 1; + conn_opts.will->retained = 1; + conn_opts.will->topicName = mqttLwtTopic.c_str(); + + conn_opts.keepAliveInterval = 20; + conn_opts.cleansession = 1; + conn_opts.connectTimeout = 2; // seconds + conn_opts.retryInterval = 15; // 0 = no retry + conn_opts.onSuccess = onConnect; + conn_opts.onFailure = onConnectFailure; + conn_opts.context = mqtt_client; + + conn_opts.username = mqttUsername.c_str(); + conn_opts.password = mqttPassword.c_str(); + + mqttConnecting = true; + if((rc = MQTTAsync_connect(mqtt_client, &conn_opts)) != MQTTASYNC_SUCCESS) { + mqttConnecting = false; + LOG_ERROR(TAG_MQTT, "Failed to connect, return code %d", rc); + rc = EXIT_FAILURE; + // goto destroy_exit; + } } else { + rc = EXIT_FAILURE; + LOG_WARNING(TAG_MQTT, "Mqtt server not configured"); } - - // while (!subscribed && !finished) - // #if defined(_WIN32) - // Sleep(100); - // #else - // usleep(10000L); - // #endif - - // if (finished) - // goto exit; } void mqttStop() @@ -378,30 +404,146 @@ void mqttStop() disc_opts.onSuccess = onDisconnect; disc_opts.onFailure = onDisconnectFailure; if((rc = MQTTAsync_disconnect(mqtt_client, &disc_opts)) != MQTTASYNC_SUCCESS) { - printf("Failed to start disconnect, return code %d\n", rc); + LOG_ERROR(TAG_MQTT, "Failed to disconnect, return code %d", rc); rc = EXIT_FAILURE; - // goto destroy_exit; } - // while (!disc_finished) - // { - // #if defined(_WIN32) - // Sleep(100); - // #else - // usleep(10000L); - // #endif - // } - - // destroy_exit: - // MQTTAsync_destroy(&client); - // exit: - // return rc; } -void mqttSetup(){}; +void mqttSetup() +{ + mqttNodeTopic = MQTT_PREFIX; + mqttNodeTopic += "/"; + mqttNodeTopic += haspDevice.get_hostname(); + mqttNodeTopic += "/"; + + mqttGroupTopic = MQTT_PREFIX; + mqttGroupTopic += "/"; + mqttGroupTopic += mqttGroupName; + mqttGroupTopic += "/"; + + mqttLwtTopic = mqttNodeTopic; + mqttLwtTopic += MQTT_TOPIC_LWT; +} IRAM_ATTR void mqttLoop(){}; -void mqttEvery5Seconds(bool wifiIsConnected){}; +void mqttEvery5Seconds(bool wifiIsConnected) +{ + if(!mqttIsConnected() && !mqttConnecting && mqttServer.length() > 0 && mqttPort > 0) { + LOG_WARNING(TAG_MQTT, F(D_MQTT_RECONNECTING)); + mqttStart(); + } +}; + +void mqtt_get_info(JsonDocument& doc) +{ + char mqttClientId[64]; + + JsonObject info = doc.createNestedObject(F("MQTT")); + info[F(D_INFO_SERVER)] = mqttServer; + info[F(D_INFO_USERNAME)] = mqttUsername; + info[F(D_INFO_CLIENTID)] = haspDevice.get_hostname(); + info[F(D_INFO_STATUS)] = mqttIsConnected() ? F(D_SERVICE_CONNECTED) : F(D_SERVICE_DISCONNECTED); + info[F(D_INFO_RECEIVED)] = mqttReceiveCount; + info[F(D_INFO_PUBLISHED)] = mqttPublishCount; + info[F(D_INFO_FAILED)] = mqttFailedCount; +} + +bool mqttGetConfig(const JsonObject& settings) +{ + bool changed = false; + + if(strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)].as().c_str()) != 0) changed = true; + settings[FPSTR(FP_CONFIG_NAME)] = haspDevice.get_hostname(); + + if(mqttGroupName != settings[FPSTR(FP_CONFIG_GROUP)].as()) changed = true; + settings[FPSTR(FP_CONFIG_GROUP)] = mqttGroupName; + + if(mqttServer != settings[FPSTR(FP_CONFIG_HOST)].as()) changed = true; + settings[FPSTR(FP_CONFIG_HOST)] = mqttServer; + + if(mqttPort != settings[FPSTR(FP_CONFIG_PORT)].as()) changed = true; + settings[FPSTR(FP_CONFIG_PORT)] = mqttPort; + + if(mqttUsername != settings[FPSTR(FP_CONFIG_USER)].as()) changed = true; + settings[FPSTR(FP_CONFIG_USER)] = mqttUsername; + + if(mqttPassword != settings[FPSTR(FP_CONFIG_PASS)].as()) changed = true; + settings[FPSTR(FP_CONFIG_PASS)] = mqttPassword; + + if(changed) configOutput(settings, TAG_MQTT); + return changed; +} + +/** Set MQTT Configuration. + * + * Read the settings from json and sets the application variables. + * + * @note: data pixel should be formatted to uint32_t RGBA. Imagemagick requirements. + * + * @param[in] settings JsonObject with the config settings. + **/ +bool mqttSetConfig(const JsonObject& settings) +{ + // configOutput(settings, TAG_MQTT); + bool changed = false; + + if(!settings[FPSTR(FP_CONFIG_PORT)].isNull()) { + // changed |= configSet(mqttPort, settings[FPSTR(FP_CONFIG_PORT)], F("mqttPort")); + changed |= mqttPort != settings[FPSTR(FP_CONFIG_PORT)]; + mqttPort = settings[FPSTR(FP_CONFIG_PORT)]; + } + + if(!settings[FPSTR(FP_CONFIG_NAME)].isNull()) { + LOG_VERBOSE(TAG_MQTT, "%s => %s", FP_CONFIG_NAME, settings[FPSTR(FP_CONFIG_NAME)].as()); + changed |= strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)]) != 0; + // strncpy(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)], sizeof(mqttNodeName)); + haspDevice.set_hostname(settings[FPSTR(FP_CONFIG_NAME)].as()); + } + // Prefill node name + // if(strlen(haspDevice.get_hostname()) == 0) { + // char mqttNodeName[64]; + // std::string mac = halGetMacAddress(3, ""); + // mac.toLowerCase(); + // snprintf_P(mqttNodeName, sizeof(mqttNodeName), PSTR(D_MQTT_DEFAULT_NAME), mac.c_str()); + // haspDevice.set_hostname(mqttNodeName); + // changed = true; + // } + + if(!settings[FPSTR(FP_CONFIG_GROUP)].isNull()) { + changed |= mqttGroupName != settings[FPSTR(FP_CONFIG_GROUP)]; + mqttGroupName = settings[FPSTR(FP_CONFIG_GROUP)].as(); + } + + if(mqttGroupName.length() == 0) { + mqttGroupName = "plates"; + changed = true; + } + + if(!settings[FPSTR(FP_CONFIG_HOST)].isNull()) { + LOG_VERBOSE(TAG_MQTT, "%s => %s", FP_CONFIG_HOST, settings[FPSTR(FP_CONFIG_HOST)].as()); + changed |= mqttServer != settings[FPSTR(FP_CONFIG_HOST)]; + mqttServer = settings[FPSTR(FP_CONFIG_HOST)].as(); + } + + if(!settings[FPSTR(FP_CONFIG_USER)].isNull()) { + changed |= mqttUsername != settings[FPSTR(FP_CONFIG_USER)]; + mqttUsername = settings[FPSTR(FP_CONFIG_USER)].as(); + } + + if(!settings[FPSTR(FP_CONFIG_PASS)].isNull() && + settings[FPSTR(FP_CONFIG_PASS)].as() != D_PASSWORD_MASK) { + changed |= mqttPassword != settings[FPSTR(FP_CONFIG_PASS)]; + mqttPassword = settings[FPSTR(FP_CONFIG_PASS)].as(); + } + + mqttNodeTopic = MQTT_PREFIX; + mqttNodeTopic += haspDevice.get_hostname(); + mqttGroupTopic = MQTT_PREFIX; + mqttGroupTopic += mqttGroupName; + + return changed; +} #endif // HASP_USE_PAHO #endif // USE_MQTT diff --git a/src/mqtt/hasp_mqtt_paho_single.cpp b/src/mqtt/hasp_mqtt_paho_single.cpp index 323b82fd3..653a884fe 100644 --- a/src/mqtt/hasp_mqtt_paho_single.cpp +++ b/src/mqtt/hasp_mqtt_paho_single.cpp @@ -5,7 +5,7 @@ #include "hasplib.h" -#if HASP_USE_MQTT > 0 +#if HASP_USE_MQTT > 0 && !HASP_USE_MQTT_ASYNC #ifdef HASP_USE_PAHO #if !HASP_USE_CONFIG diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin_sdl/darwin_sdl_64bits.ini index 55e0288ca..d9c2f28eb 100644 --- a/user_setups/darwin_sdl/darwin_sdl_64bits.ini +++ b/user_setups/darwin_sdl/darwin_sdl_64bits.ini @@ -87,15 +87,14 @@ build_src_filter = +<*> -<*.h> +<../.pio/libdeps/darwin_sdl_64bits/paho/src/*.c> - +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTClient.c> - +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTClient.h> - -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsync.c> - -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTClient.c> + +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsync.c> + +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsyncUtils.c> -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTVersion.c> -<../.pio/libdeps/darwin_sdl_64bits/paho/src/SSLSocket.c> - + - - - - + - + + + + - - - diff --git a/user_setups/linux_sdl/linux_fbdev_64bits.ini b/user_setups/linux_sdl/linux_fbdev_64bits.ini index a709efb7e..a5e10592f 100644 --- a/user_setups/linux_sdl/linux_fbdev_64bits.ini +++ b/user_setups/linux_sdl/linux_fbdev_64bits.ini @@ -73,14 +73,14 @@ build_src_filter = +<*> -<*.h> +<../.pio/libdeps/linux_fbdev_64bits/paho/src/*.c> - +<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTClient.c> - -<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTAsync.c> - -<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTClient.c> + +<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTAsync.c> + +<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTAsyncUtils.c> -<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTVersion.c> -<../.pio/libdeps/linux_fbdev_64bits/paho/src/SSLSocket.c> - + - - - - + - + + + + - - - diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux_sdl/linux_sdl_64bits.ini index fc3287ccc..9af47c82a 100644 --- a/user_setups/linux_sdl/linux_sdl_64bits.ini +++ b/user_setups/linux_sdl/linux_sdl_64bits.ini @@ -78,14 +78,14 @@ build_src_filter = +<*> -<*.h> +<../.pio/libdeps/linux_sdl_64bits/paho/src/*.c> - +<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTClient.c> - -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsync.c> - -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTClient.c> + +<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsync.c> + +<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsyncUtils.c> -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTVersion.c> -<../.pio/libdeps/linux_sdl_64bits/paho/src/SSLSocket.c> - + - - - - + - + + + + - - - diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index 23062b6f6..ac0ddeabe 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -102,14 +102,14 @@ build_src_filter = +<*> -<*.h> +<../.pio/libdeps/windows_gdi_64bits/paho/src/*.c> - +<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTClient.c> - -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTAsync.c> - -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTClient.c> + +<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTAsync.c> + +<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTAsyncUtils.c> -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTVersion.c> -<../.pio/libdeps/windows_gdi_64bits/paho/src/SSLSocket.c> - + - - - - + - + + + + - - - diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini index bd4338b11..9e20993da 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -108,14 +108,14 @@ build_src_filter = +<*> -<*.h> +<../.pio/libdeps/windows_sdl_64bits/paho/src/*.c> - +<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTClient.c> - -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTAsync.c> - -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTClient.c> + +<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTAsync.c> + +<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTAsyncUtils.c> -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTVersion.c> -<../.pio/libdeps/windows_sdl_64bits/paho/src/SSLSocket.c> - + - - - - + - + + + + - - - From d77428db54b129b6cafef65e1e6691909d03c640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 10 Feb 2024 23:58:37 +0100 Subject: [PATCH 30/36] Allow publishing MQTT message even with action tag --- src/hasp/hasp_event.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hasp/hasp_event.cpp b/src/hasp/hasp_event.cpp index 9a5cc2bff..4f06e5171 100644 --- a/src/hasp/hasp_event.cpp +++ b/src/hasp/hasp_event.cpp @@ -52,13 +52,14 @@ static bool script_event_handler(const char* eventname, const char* action, cons StaticJsonDocument<64> filter; filter[eventname] = true; + filter["pub"] = true; DeserializationError jsonError = deserializeJson(doc, action, DeserializationOption::Filter(filter)); if(!jsonError) { JsonVariant json = doc[eventname].as(); if(json.isNull()) { LOG_DEBUG(TAG_EVENT, F("Skipping event: name=%s, data=%s"), eventname, data); - return true; + goto end; } else { LOG_DEBUG(TAG_EVENT, F("Handling event: name=%s, data=%s"), eventname, data); } @@ -82,6 +83,9 @@ static bool script_event_handler(const char* eventname, const char* action, cons } else { dispatch_json_error(TAG_EVENT, jsonError); } + +end: + if(doc["pub"].is()) return !doc["pub"].as(); return true; } From 9b3c88492ce37dd6d9fd472530177ae2dbd82657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 12 Feb 2024 16:32:38 +0100 Subject: [PATCH 31/36] Switch to tty7 on POSIX fbdev --- src/dev/posix/hasp_posix.cpp | 2 +- src/drv/tft/tft_driver_posix_fbdev.cpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp index e5f1b1735..ad020e4b8 100644 --- a/src/dev/posix/hasp_posix.cpp +++ b/src/dev/posix/hasp_posix.cpp @@ -203,7 +203,7 @@ void PosixDevice::update_backlight() f << brightness; f.close(); } else { - perror("Brightness write failed"); + perror("Brightness write failed (are you root?)"); } } #endif diff --git a/src/drv/tft/tft_driver_posix_fbdev.cpp b/src/drv/tft/tft_driver_posix_fbdev.cpp index 2961b7289..7abafa58a 100644 --- a/src/drv/tft/tft_driver_posix_fbdev.cpp +++ b/src/drv/tft/tft_driver_posix_fbdev.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #if USE_BSD_EVDEV #include @@ -83,6 +84,15 @@ static void* gui_entrypoint(void* arg) void TftFbdevDrv::init(int32_t w, int h) { + // try to switch the active tty to tty7 + int tty_fd = open("/dev/tty0", O_WRONLY); + if(tty_fd == -1) { + perror("Couldn't open /dev/tty0 (try running as root)"); + } else { + if(ioctl(tty_fd, VT_ACTIVATE, 7) == -1) perror("Couldn't change active tty"); + } + close(tty_fd); + // check active tty std::ifstream f; f.open("/sys/class/tty/tty0/active"); @@ -92,9 +102,9 @@ void TftFbdevDrv::init(int32_t w, int h) f.close(); // try to hide the cursor - int tty_fd = open(tty.c_str(), O_WRONLY); + tty_fd = open(tty.c_str(), O_WRONLY); if(tty_fd == -1) { - perror("Couldn't open tty"); + perror("Couldn't open active tty (try running as root)"); } else { write(tty_fd, "\033[?25l", 6); } From b0969892fdae9e01688f51c9bc079971a7ba8e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 12 Feb 2024 18:20:00 +0100 Subject: [PATCH 32/36] Workaround "clearpage all" crashing on PC build --- src/hasp/hasp_dispatch.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index b5795d160..dbf420621 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -967,7 +967,14 @@ void dispatch_page(const char*, const char* payload, uint8_t source) void dispatch_clear_page(const char*, const char* page, uint8_t source) { if(!strcasecmp(page, "all")) { +#if !HASP_TARGET_PC hasp_init(); +#else + // workaround for "clearpage all" deadlocking or crashing on PC build (when called from non-LVGL thread) + for(uint8_t pageid = 0; pageid <= HASP_NUM_PAGES; pageid++) { + haspPages.clear(pageid); + } +#endif return; } From 55f39f02d08122121d85576c6557a22dc0094d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 12 Feb 2024 18:24:43 +0100 Subject: [PATCH 33/36] Revert changes unrelated to PC build --- include/hasp_conf.h | 4 - src/hasp/hasp_dispatch.cpp | 117 ++----------------- src/hasp/hasp_dispatch.h | 3 +- src/hasp/hasp_event.cpp | 93 ++++++--------- src/hasp_config.h | 1 - src/hasp_gui.cpp | 35 ------ src/hasp_gui.h | 1 - user_setups/darwin_sdl/darwin_sdl_64bits.ini | 3 +- user_setups/linux_sdl/linux_fbdev_64bits.ini | 3 +- user_setups/linux_sdl/linux_sdl_64bits.ini | 3 +- user_setups/win32/windows_gdi_64bits.ini | 3 +- user_setups/win32/windows_sdl_64bits.ini | 3 +- 12 files changed, 46 insertions(+), 223 deletions(-) diff --git a/include/hasp_conf.h b/include/hasp_conf.h index e36b8925c..d7b666cbc 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -181,10 +181,6 @@ #define HASP_NUM_GPIO_CONFIG 8 #endif -#ifndef HASP_USE_EVENT_DATA_SUBST -#define HASP_USE_EVENT_DATA_SUBST 0 -#endif - // #ifndef HASP_USE_CUSTOM // #define HASP_USE_CUSTOM 0 // #endif diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index dbf420621..e9aae6cdc 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -37,8 +37,6 @@ #endif #endif -#include - dispatch_conf_t dispatch_setings = {.teleperiod = 300}; uint16_t dispatchSecondsToNextTeleperiod = 0; @@ -50,8 +48,6 @@ haspCommand_t commands[28]; moodlight_t moodlight = {.brightness = 255}; uint8_t saved_jsonl_page = 0; -static std::map scheduled_tasks; - /* Sends the payload out on the state/subtopic */ void dispatch_state_subtopic(const char* subtopic, const char* payload) @@ -614,17 +610,11 @@ void dispatch_screenshot(const char*, const char* filename, uint8_t source) } bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source) -{ - JsonObject dummy; - return dispatch_json_variant_with_data(json, savedPage, source, dummy); -} - -bool dispatch_json_variant_with_data(JsonVariant& json, uint8_t& savedPage, uint8_t source, JsonObject& data) { if(json.is()) { // handle json as an array of commands LOG_DEBUG(TAG_MSGR, "Json ARRAY"); for(JsonVariant command : json.as()) { - dispatch_json_variant_with_data(command, savedPage, source, data); + dispatch_json_variant(command, savedPage, source); } } else if(json.is()) { // handle json as a jsonl @@ -632,23 +622,13 @@ bool dispatch_json_variant_with_data(JsonVariant& json, uint8_t& savedPage, uint hasp_new_object(json.as(), savedPage); } else if(json.is()) { // handle json as a single command - std::string command = json.as(); - -#if HASP_USE_EVENT_DATA_SUBST - if(command.find('%') != std::string::npos) { - // '%' found in command, run variable substitution - for(JsonPair kv : data) { - std::string find = "%" + std::string(kv.key().c_str()) + "%"; - std::string replace = kv.value().as(); - size_t pos = command.find(find); - if(pos == std::string::npos) continue; - command.replace(pos, find.length(), replace); - } - } -#endif + LOG_DEBUG(TAG_MSGR, "Json text = %s", json.as().c_str()); + dispatch_simple_text_command(json.as().c_str(), source); + + } else if(json.is()) { // handle json as a single command + LOG_DEBUG(TAG_MSGR, "Json text = %s", json.as()); + dispatch_simple_text_command(json.as(), source); - LOG_DEBUG(TAG_MSGR, "Json text = %s", command.c_str()); - dispatch_simple_text_command(command.c_str(), source); } else if(json.isNull()) { // event handler not found // nothing to do @@ -1425,88 +1405,6 @@ void dispatch_sleep(const char*, const char*, uint8_t source) hasp_set_wakeup_touch(false); } -static void dispatch_schedule_runner(lv_task_t* task) -{ - dispatch_text_line((const char*)task->user_data, TAG_MSGR); -} - -void dispatch_schedule(const char*, const char* payload, uint8_t source) -{ - // duplicate the string for modification - char* argline = strdup(payload); - // split argline into argv by whitespace; limit to 4 parts - char* argv[4]; - int argn = 0; - argv[argn++] = argline; - while(*argline) { - if(*argline == ' ') { - *argline = '\0'; - argv[argn++] = argline + 1; - } - argline++; - if(argn == 4) break; - } - - const char* action = argv[0]; - uint32_t id = atoi(argv[1]); - - if(strcasecmp(action, "set") == 0) { - if(argn != 4) { - LOG_ERROR(TAG_MSGR, F("Usage: schedule set ")); - goto end; - } - uint32_t period = atoi(argv[2]); - const char* command = strdup(argv[3]); - - if(scheduled_tasks.find(id) != scheduled_tasks.end()) { - // update an existing task - lv_task_t* task = scheduled_tasks[id]; - free(task->user_data); - task->period = period; - task->user_data = (void*)command; - } else { - // create a new task - lv_task_t* task = lv_task_create(dispatch_schedule_runner, period, LV_TASK_PRIO_MID, (void*)command); - scheduled_tasks[id] = task; - } - - LOG_INFO(TAG_MSGR, F("Scheduled command ID %u, every %u ms: %s"), id, period, command); - - goto end; - } - - if(argn != 2) { - LOG_ERROR(TAG_MSGR, F("Usage: schedule ")); - goto end; - } - if(scheduled_tasks.find(id) == scheduled_tasks.end()) { - LOG_ERROR(TAG_MSGR, F("Task by ID %u does not exist"), id); - goto end; - } - - { - lv_task_t* task = scheduled_tasks[id]; - if(strcasecmp(action, "del") == 0) { - free(task->user_data); - lv_task_del(task); - scheduled_tasks.erase(id); - goto end; - } - if(strcasecmp(action, "start") == 0) { - lv_task_set_prio(task, LV_TASK_PRIO_MID); - goto end; - } - if(strcasecmp(action, "stop") == 0) { - lv_task_set_prio(task, LV_TASK_PRIO_OFF); - goto end; - } - } - -end: - // release the duplicated argline - free(argv[0]); -} - void dispatch_idle_state(uint8_t state) { char topic[8]; @@ -1640,7 +1538,6 @@ void dispatchSetup() dispatch_add_command(PSTR("moodlight"), dispatch_moodlight); dispatch_add_command(PSTR("idle"), dispatch_idle); dispatch_add_command(PSTR("sleep"), dispatch_sleep); - dispatch_add_command(PSTR("schedule"), dispatch_schedule); dispatch_add_command(PSTR("statusupdate"), dispatch_statusupdate); dispatch_add_command(PSTR("clearpage"), dispatch_clear_page); dispatch_add_command(PSTR("clearfont"), dispatch_clear_font); diff --git a/src/hasp/hasp_dispatch.h b/src/hasp/hasp_dispatch.h index 53a5804a1..245da30c2 100644 --- a/src/hasp/hasp_dispatch.h +++ b/src/hasp/hasp_dispatch.h @@ -55,7 +55,6 @@ void dispatch_parse_jsonl(Stream& stream, uint8_t& saved_page_id); void dispatch_parse_jsonl(std::istream& stream, uint8_t& saved_page_id); #endif bool dispatch_json_variant(JsonVariant& json, uint8_t& savedPage, uint8_t source); -bool dispatch_json_variant_with_data(JsonVariant& json, uint8_t& savedPage, uint8_t source, JsonObject& data); void dispatch_clear_page(const char* page); void dispatch_json_error(uint8_t tag, DeserializationError& jsonError); @@ -102,4 +101,4 @@ struct haspCommand_t void (*func)(const char*, const char*, uint8_t); }; -#endif +#endif \ No newline at end of file diff --git a/src/hasp/hasp_event.cpp b/src/hasp/hasp_event.cpp index 4f06e5171..fd5eeaeef 100644 --- a/src/hasp/hasp_event.cpp +++ b/src/hasp/hasp_event.cpp @@ -42,51 +42,23 @@ void event_reset_last_value_sent() last_value_sent = INT16_MIN; } -static bool script_event_handler(const char* eventname, const char* action, const char* data) +void script_event_handler(const char* eventname, const char* json) { - if(action == NULL) { - LOG_DEBUG(TAG_EVENT, F("Skipping event: name=%s, data=%s"), eventname, data); - return false; - } StaticJsonDocument<256> doc; StaticJsonDocument<64> filter; filter[eventname] = true; - filter["pub"] = true; - DeserializationError jsonError = deserializeJson(doc, action, DeserializationOption::Filter(filter)); + DeserializationError jsonError = deserializeJson(doc, json, DeserializationOption::Filter(filter)); if(!jsonError) { - JsonVariant json = doc[eventname].as(); - if(json.isNull()) { - LOG_DEBUG(TAG_EVENT, F("Skipping event: name=%s, data=%s"), eventname, data); - goto end; - } else { - LOG_DEBUG(TAG_EVENT, F("Handling event: name=%s, data=%s"), eventname, data); - } - - JsonObject dataJson; -#if HASP_USE_EVENT_DATA_SUBST - if(data != NULL) { - StaticJsonDocument<256> jsonDoc; - if(deserializeJson(jsonDoc, data) != DeserializationError::Ok) { - LOG_ERROR(TAG_EVENT, F("Deserialization failed")); - } else { - dataJson = jsonDoc.as(); - } - } -#endif - + JsonVariant json = doc[eventname].as(); uint8_t savedPage = haspPages.get(); - if(!dispatch_json_variant_with_data(json, savedPage, TAG_EVENT, dataJson)) { + if(!dispatch_json_variant(json, savedPage, TAG_EVENT)) { LOG_WARNING(TAG_EVENT, F(D_DISPATCH_COMMAND_NOT_FOUND), eventname); } } else { dispatch_json_error(TAG_EVENT, jsonError); } - -end: - if(doc["pub"].is()) return !doc["pub"].as(); - return true; } /** @@ -282,16 +254,11 @@ static bool translate_event(lv_obj_t* obj, lv_event_t event, uint8_t& eventid) // ##################### Value Senders ######################################################## -static void event_send_object_data(lv_obj_t* obj, const char* eventname, const char* data) +static void event_send_object_data(lv_obj_t* obj, const char* data) { uint8_t pageid; uint8_t objid; - // handle object "action", abort sending if handled - if(script_event_handler(eventname, my_obj_get_action(obj), data)) { - return; - } - if(hasp_find_id_from_obj(obj, &pageid, &objid)) { if(!data) return; object_dispatch_state(pageid, objid, data); @@ -304,23 +271,23 @@ static void event_send_object_data(lv_obj_t* obj, const char* eventname, const c static void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val) { char data[512]; - char eventname[8]; { + char eventname[8]; Parser::get_event_name(eventid, eventname, sizeof(eventname)); if(const char* tag = my_obj_get_tag(obj)) snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"tag\":%s}"), eventname, val, tag); else snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d}"), eventname, val); } - event_send_object_data(obj, eventname, data); + event_send_object_data(obj, data); } // Send out events with a val and text attribute static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16_t val, const char* text) { char data[512]; - char eventname[8]; { + char eventname[8]; Parser::get_event_name(eventid, eventname, sizeof(eventname)); if(const char* tag = my_obj_get_tag(obj)) @@ -329,7 +296,7 @@ static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16 else snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":\"%s\"}"), eventname, val, text); } - event_send_object_data(obj, eventname, data); + event_send_object_data(obj, data); } // ##################### Event Handlers ######################################################## @@ -435,16 +402,16 @@ void swipe_event_handler(lv_obj_t* obj, lv_event_t event) lv_gesture_dir_t dir = lv_indev_get_gesture_dir(lv_indev_get_act()); switch(dir) { case LV_GESTURE_DIR_LEFT: - script_event_handler("left", swipe, NULL); + script_event_handler("left", swipe); break; case LV_GESTURE_DIR_RIGHT: - script_event_handler("right", swipe, NULL); + script_event_handler("right", swipe); break; case LV_GESTURE_DIR_BOTTOM: - script_event_handler("down", swipe, NULL); + script_event_handler("down", swipe); break; default: - script_event_handler("up", swipe, NULL); + script_event_handler("up", swipe); } } } @@ -465,8 +432,8 @@ void textarea_event_handler(lv_obj_t* obj, lv_event_t event) if(!translate_event(obj, event, hasp_event_id)) return; char data[1024]; - char eventname[8]; { + char eventname[8]; Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); if(const char* tag = my_obj_get_tag(obj)) @@ -477,7 +444,7 @@ void textarea_event_handler(lv_obj_t* obj, lv_event_t event) lv_textarea_get_text(obj)); } - event_send_object_data(obj, eventname, data); + event_send_object_data(obj, data); } else if(event == LV_EVENT_FOCUSED) { lv_textarea_set_cursor_hidden(obj, false); } else if(event == LV_EVENT_DEFOCUSED) { @@ -551,17 +518,23 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event) if(last_value_sent == HASP_EVENT_LOST) return; - char data[512]; - char eventname[8]; - { + if(const char* action = my_obj_get_action(obj)) { + char eventname[8]; Parser::get_event_name(last_value_sent, eventname, sizeof(eventname)); + script_event_handler(eventname, action); + } else { + char data[512]; + { + char eventname[8]; + Parser::get_event_name(last_value_sent, eventname, sizeof(eventname)); - if(const char* tag = my_obj_get_tag(obj)) - snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"tag\":%s}"), eventname, tag); - else - snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname); + if(const char* tag = my_obj_get_tag(obj)) + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"tag\":%s}"), eventname, tag); + else + snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname); + } + event_send_object_data(obj, data); } - event_send_object_data(obj, eventname, data); // Update group objects and gpios on release if(last_value_sent != LV_EVENT_LONG_PRESSED && last_value_sent != LV_EVENT_LONG_PRESSED_REPEAT) { @@ -868,8 +841,8 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) if(hasp_event_id == HASP_EVENT_CHANGED && last_color_sent.full == color.full) return; // same value as before char data[512]; - char eventname[8]; { + char eventname[8]; Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); lv_color32_t c32; @@ -891,7 +864,7 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event) eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, hsv.s, hsv.v); } - event_send_object_data(obj, eventname, data); + event_send_object_data(obj, data); // event_update_group(obj->user_data.groupid, obj, val, min, max); } @@ -918,8 +891,8 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event) return; // same object and value as before char data[512]; - char eventname[8]; { + char eventname[8]; Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname)); last_value_sent = val; @@ -934,7 +907,7 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event) PSTR("{\"event\":\"%s\",\"val\":\"%d\",\"text\":\"%04d-%02d-%02dT00:00:00Z\"}"), eventname, date->day, date->year, date->month, date->day); } - event_send_object_data(obj, eventname, data); + event_send_object_data(obj, data); // event_update_group(obj->user_data.groupid, obj, val, min, max); } diff --git a/src/hasp_config.h b/src/hasp_config.h index ca5429ae7..04160d30d 100644 --- a/src/hasp_config.h +++ b/src/hasp_config.h @@ -90,7 +90,6 @@ const char FP_GUI_BACKLIGHTINVERT[] PROGMEM = "bcklinv"; const char FP_GUI_POINTER[] PROGMEM = "cursor"; const char FP_GUI_LONG_TIME[] PROGMEM = "long"; const char FP_GUI_REPEAT_TIME[] PROGMEM = "repeat"; -const char FP_GUI_FPS[] PROGMEM = "fps"; const char FP_DEBUG_TELEPERIOD[] PROGMEM = "tele"; const char FP_DEBUG_ANSI[] PROGMEM = "ansi"; const char FP_GPIO_CONFIG[] PROGMEM = "config"; diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 5c39f5900..9fd55c9bf 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -57,8 +57,6 @@ uint32_t screenshotEtag = 0; void (*drv_display_flush_cb)(struct _disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p); static lv_disp_buf_t disp_buf; -static bool gui_initialized = false; -static uint32_t anim_fps_deferred = 0; static inline void gui_init_lvgl() { @@ -102,27 +100,6 @@ void gui_hide_pointer(bool hidden) if(cursor) lv_obj_set_hidden(cursor, hidden || !gui_settings.show_pointer); } -bool gui_set_fps(uint32_t fps) -{ - if(!gui_initialized) { - LOG_ERROR(TAG_GUI, F("GUI not initialized, deferring FPS setting")); - anim_fps_deferred = fps; - return false; - } - - bool changed = false; - uint32_t period = 1000 / fps; - // find animation task by its period - lv_task_t* task = NULL; - while(task = lv_task_get_next(task)) { - if(!(task->period == LV_DISP_DEF_REFR_PERIOD)) continue; - changed |= (task->period != period); - LOG_INFO(TAG_GUI, F("Changing animation period: %u -> %u (%u FPS)"), task->period, period, fps); - task->period = period; - } - return changed; -} - IRAM_ATTR void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) { haspTft.flush_pixels(disp, area, color_p); @@ -396,13 +373,6 @@ void guiSetup() } #endif // ESP32 && HASP_USE_ESP_MQTT - // apply deferred FPS setting - gui_initialized = true; - if(anim_fps_deferred != 0) { - gui_set_fps(anim_fps_deferred); - anim_fps_deferred = 0; - } - LOG_INFO(TAG_LVGL, F(D_SERVICE_STARTED)); } @@ -642,11 +612,6 @@ bool guiSetConfig(const JsonObject& settings) changed |= status; } - if(!settings[FPSTR(FP_GUI_FPS)].isNull()) { - uint32_t fps = settings[FPSTR(FP_GUI_FPS)].as(); - changed |= gui_set_fps(fps); - } - return changed; } #endif // HASP_USE_CONFIG diff --git a/src/hasp_gui.h b/src/hasp_gui.h index adb5ddb64..8b5b12afd 100644 --- a/src/hasp_gui.h +++ b/src/hasp_gui.h @@ -48,7 +48,6 @@ void guiEverySecond(void); void guiStart(void); void guiStop(void); void gui_hide_pointer(bool hidden); -bool gui_set_fps(uint32_t fps); /* ===== Special Event Processors ===== */ void guiCalibrate(void); diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin_sdl/darwin_sdl_64bits.ini index d9c2f28eb..52f8aaa65 100644 --- a/user_setups/darwin_sdl/darwin_sdl_64bits.ini +++ b/user_setups/darwin_sdl/darwin_sdl_64bits.ini @@ -34,8 +34,7 @@ build_flags = -D HASP_USE_GIFDECODE=0 -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 - -D HASP_USE_EVENT_DATA_SUBST=1 - -D MQTT_MAX_PACKET_SIZE=32768 + -D MQTT_MAX_PACKET_SIZE=2048 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available diff --git a/user_setups/linux_sdl/linux_fbdev_64bits.ini b/user_setups/linux_sdl/linux_fbdev_64bits.ini index a5e10592f..999a73a76 100644 --- a/user_setups/linux_sdl/linux_fbdev_64bits.ini +++ b/user_setups/linux_sdl/linux_fbdev_64bits.ini @@ -31,8 +31,7 @@ build_flags = -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 -D HASP_USE_LVGL_TASK=1 - -D HASP_USE_EVENT_DATA_SUBST=1 - -D MQTT_MAX_PACKET_SIZE=32768 + -D MQTT_MAX_PACKET_SIZE=2048 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux_sdl/linux_sdl_64bits.ini index 9af47c82a..222d86602 100644 --- a/user_setups/linux_sdl/linux_sdl_64bits.ini +++ b/user_setups/linux_sdl/linux_sdl_64bits.ini @@ -34,8 +34,7 @@ build_flags = -D HASP_USE_GIFDECODE=0 -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 - -D HASP_USE_EVENT_DATA_SUBST=1 - -D MQTT_MAX_PACKET_SIZE=32768 + -D MQTT_MAX_PACKET_SIZE=2048 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi_64bits.ini index ac0ddeabe..e8f49fad9 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi_64bits.ini @@ -30,8 +30,7 @@ build_flags = -D HASP_USE_MQTT=1 -D HASP_USE_SYSLOG=0 -D HASP_USE_LVGL_TASK=1 - -D HASP_USE_EVENT_DATA_SUBST=1 - -D MQTT_MAX_PACKET_SIZE=32768 + -D MQTT_MAX_PACKET_SIZE=2048 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini index 9e20993da..850e8ae62 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl_64bits.ini @@ -34,8 +34,7 @@ build_flags = -D HASP_USE_JPGDECODE=0 -D HASP_USE_MQTT=1 -D HASP_USE_SYSLOG=0 - -D HASP_USE_EVENT_DATA_SUBST=1 - -D MQTT_MAX_PACKET_SIZE=32768 + -D MQTT_MAX_PACKET_SIZE=2048 -D HASP_ATTRIBUTE_FAST_MEM= -D IRAM_ATTR= ; No IRAM_ATTR available -D PROGMEM= ; No PROGMEM available From 37e66cdf5b0a6d3cbe117149089ba418b43a5485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 12 Feb 2024 18:33:04 +0100 Subject: [PATCH 34/36] Rename PC build envs --- .github/workflows/build.yaml | 6 +++--- .github/workflows/build_linux.yaml | 4 ++-- .github/workflows/release.yml | 2 +- platformio_override-template.ini | 4 ++-- .../darwin_sdl.ini} | 20 +++++++++---------- .../linux_fbdev.ini} | 20 +++++++++---------- .../linux_sdl.ini} | 20 +++++++++---------- ...windows_gdi_64bits.ini => windows_gdi.ini} | 20 +++++++++---------- ...windows_sdl_64bits.ini => windows_sdl.ini} | 20 +++++++++---------- 9 files changed, 58 insertions(+), 58 deletions(-) rename user_setups/{darwin_sdl/darwin_sdl_64bits.ini => darwin/darwin_sdl.ini} (81%) rename user_setups/{linux_sdl/linux_fbdev_64bits.ini => linux/linux_fbdev.ini} (77%) rename user_setups/{linux_sdl/linux_sdl_64bits.ini => linux/linux_sdl.ini} (80%) rename user_setups/win32/{windows_gdi_64bits.ini => windows_gdi.ini} (83%) rename user_setups/win32/{windows_sdl_64bits.ini => windows_sdl.ini} (84%) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ee4f01af4..4847e5a47 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -158,7 +158,7 @@ jobs: - name: Enable Linux platform from platformio_override.ini run: | sed 's/; user_setups\/linux/user_setups\/linux/g' platformio_override-template.ini > platformio_override.ini - mkdir -p .pio/libdeps/linux_sdl_64bits/paho/src + mkdir -p .pio/libdeps/linux_sdl/paho/src - name: Install SDL2 library run: | sudo apt-get update @@ -172,10 +172,10 @@ jobs: - name: Enable Linux platform from platformio_override.ini run: | sed -i 's/; user_setups\/linux/user_setups\/linux/g' platformio_override.ini - mkdir -p .pio/libdeps/linux_sdl_64bits/paho/src + mkdir -p .pio/libdeps/linux_sdl/paho/src - name: Install SDL2 library run: | sudo apt-get update sudo apt-get install libsdl2-dev - name: Run PlatformIO - run: pio run -e linux_sdl_64bits + run: pio run -e linux_sdl diff --git a/.github/workflows/build_linux.yaml b/.github/workflows/build_linux.yaml index a4baea499..e7e77c947 100644 --- a/.github/workflows/build_linux.yaml +++ b/.github/workflows/build_linux.yaml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: environments: - - linux_sdl_64bits + - linux_sdl steps: - uses: actions/checkout@v3 @@ -43,7 +43,7 @@ jobs: - name: Enable Linux platform from platformio_override.ini run: | sed -i 's/; user_setups\/linux/user_setups\/linux/g' platformio_override.ini - mkdir -p .pio/libdeps/linux_sdl_64bits/paho/src + mkdir -p .pio/libdeps/linux_sdl/paho/src - name: Install SDL2 library run: | sudo apt-get update diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 62ef57b4f..0d4bb86df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,7 +39,7 @@ jobs: - name: Enable Linux platform from platformio_override.ini run: | sed -i 's/; user_setups\/linux/user_setups\/linux/g' platformio_override.ini - mkdir -p .pio/libdeps/linux_sdl_64bits/paho/src + mkdir -p .pio/libdeps/linux_sdl/paho/src - name: Install SDL2 library run: | sudo apt-get update diff --git a/platformio_override-template.ini b/platformio_override-template.ini index 941fe8150..f746bb26b 100644 --- a/platformio_override-template.ini +++ b/platformio_override-template.ini @@ -6,11 +6,11 @@ [platformio] extra_configs = ; Uncomment or edit the lines to show more User Setups in the PIO sidebar - ; user_setups/darwin_sdl/*.ini + ; user_setups/darwin/*.ini ; user_setups/esp32/*.ini ; user_setups/esp32s2/*.ini ; user_setups/esp32s3/*.ini - ; user_setups/linux_sdl/*.ini + ; user_setups/linux/*.ini ; user_setups/stm32f4xx/*.ini ; user_setups/win32/*.ini diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin/darwin_sdl.ini similarity index 81% rename from user_setups/darwin_sdl/darwin_sdl_64bits.ini rename to user_setups/darwin/darwin_sdl.ini index 52f8aaa65..2b3a36429 100644 --- a/user_setups/darwin_sdl/darwin_sdl_64bits.ini +++ b/user_setups/darwin/darwin_sdl.ini @@ -1,4 +1,4 @@ -[env:darwin_sdl_64bits] +[env:darwin_sdl] lib_archive = false platform = native@^1.1.4 extra_scripts = @@ -49,8 +49,8 @@ build_flags = -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=TRUE ;-D NO_PERSISTENCE - -I.pio/libdeps/darwin_sdl_64bits/paho/src - -I.pio/libdeps/darwin_sdl_64bits/ArduinoJson/src + -I.pio/libdeps/darwin_sdl/paho/src + -I.pio/libdeps/darwin_sdl/ArduinoJson/src -I lib/ArduinoJson/src -I lib/lv_fs_if !python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))" @@ -85,12 +85,12 @@ lib_ignore = build_src_filter = +<*> -<*.h> - +<../.pio/libdeps/darwin_sdl_64bits/paho/src/*.c> - -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTClient.c> - +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsync.c> - +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsyncUtils.c> - -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTVersion.c> - -<../.pio/libdeps/darwin_sdl_64bits/paho/src/SSLSocket.c> + +<../.pio/libdeps/darwin_sdl/paho/src/*.c> + -<../.pio/libdeps/darwin_sdl/paho/src/MQTTClient.c> + +<../.pio/libdeps/darwin_sdl/paho/src/MQTTAsync.c> + +<../.pio/libdeps/darwin_sdl/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/darwin_sdl/paho/src/MQTTVersion.c> + -<../.pio/libdeps/darwin_sdl/paho/src/SSLSocket.c> - + + @@ -112,4 +112,4 @@ build_src_filter = + - + - +<../.pio/libdeps/darwin_sdl_64bits/ArduinoJson/src/ArduinoJson.h> + +<../.pio/libdeps/darwin_sdl/ArduinoJson/src/ArduinoJson.h> diff --git a/user_setups/linux_sdl/linux_fbdev_64bits.ini b/user_setups/linux/linux_fbdev.ini similarity index 77% rename from user_setups/linux_sdl/linux_fbdev_64bits.ini rename to user_setups/linux/linux_fbdev.ini index 999a73a76..c0d70a27b 100644 --- a/user_setups/linux_sdl/linux_fbdev_64bits.ini +++ b/user_setups/linux/linux_fbdev.ini @@ -1,4 +1,4 @@ -[env:linux_fbdev_64bits] +[env:linux_fbdev] platform = native@^1.1.4 extra_scripts = tools/linux_build_extra.py @@ -46,8 +46,8 @@ build_flags = -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=TRUE ;-D NO_PERSISTENCE - -I.pio/libdeps/linux_fbdev_64bits/paho/src - -I.pio/libdeps/linux_fbdev_64bits/ArduinoJson/src + -I.pio/libdeps/linux_fbdev/paho/src + -I.pio/libdeps/linux_fbdev/ArduinoJson/src ; ----- Statically linked libraries -------------------- -lm @@ -71,12 +71,12 @@ lib_ignore = build_src_filter = +<*> -<*.h> - +<../.pio/libdeps/linux_fbdev_64bits/paho/src/*.c> - -<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTClient.c> - +<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTAsync.c> - +<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTAsyncUtils.c> - -<../.pio/libdeps/linux_fbdev_64bits/paho/src/MQTTVersion.c> - -<../.pio/libdeps/linux_fbdev_64bits/paho/src/SSLSocket.c> + +<../.pio/libdeps/linux_fbdev/paho/src/*.c> + -<../.pio/libdeps/linux_fbdev/paho/src/MQTTClient.c> + +<../.pio/libdeps/linux_fbdev/paho/src/MQTTAsync.c> + +<../.pio/libdeps/linux_fbdev/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/linux_fbdev/paho/src/MQTTVersion.c> + -<../.pio/libdeps/linux_fbdev/paho/src/SSLSocket.c> - + + @@ -98,4 +98,4 @@ build_src_filter = + - + - +<../.pio/libdeps/linux_fbdev_64bits/ArduinoJson/src/ArduinoJson.h> + +<../.pio/libdeps/linux_fbdev/ArduinoJson/src/ArduinoJson.h> diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux/linux_sdl.ini similarity index 80% rename from user_setups/linux_sdl/linux_sdl_64bits.ini rename to user_setups/linux/linux_sdl.ini index 222d86602..e1239f7d4 100644 --- a/user_setups/linux_sdl/linux_sdl_64bits.ini +++ b/user_setups/linux/linux_sdl.ini @@ -1,4 +1,4 @@ -[env:linux_sdl_64bits] +[env:linux_sdl] platform = native@^1.1.4 extra_scripts = tools/sdl2_build_extra.py @@ -49,8 +49,8 @@ build_flags = -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=TRUE ;-D NO_PERSISTENCE - -I.pio/libdeps/linux_sdl_64bits/paho/src - -I.pio/libdeps/linux_sdl_64bits/ArduinoJson/src + -I.pio/libdeps/linux_sdl/paho/src + -I.pio/libdeps/linux_sdl/ArduinoJson/src !python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))" ; ----- Statically linked libraries -------------------- @@ -76,12 +76,12 @@ lib_ignore = build_src_filter = +<*> -<*.h> - +<../.pio/libdeps/linux_sdl_64bits/paho/src/*.c> - -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTClient.c> - +<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsync.c> - +<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsyncUtils.c> - -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTVersion.c> - -<../.pio/libdeps/linux_sdl_64bits/paho/src/SSLSocket.c> + +<../.pio/libdeps/linux_sdl/paho/src/*.c> + -<../.pio/libdeps/linux_sdl/paho/src/MQTTClient.c> + +<../.pio/libdeps/linux_sdl/paho/src/MQTTAsync.c> + +<../.pio/libdeps/linux_sdl/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/linux_sdl/paho/src/MQTTVersion.c> + -<../.pio/libdeps/linux_sdl/paho/src/SSLSocket.c> - + + @@ -103,4 +103,4 @@ build_src_filter = + - + - +<../.pio/libdeps/linux_sdl_64bits/ArduinoJson/src/ArduinoJson.h> + +<../.pio/libdeps/linux_sdl/ArduinoJson/src/ArduinoJson.h> diff --git a/user_setups/win32/windows_gdi_64bits.ini b/user_setups/win32/windows_gdi.ini similarity index 83% rename from user_setups/win32/windows_gdi_64bits.ini rename to user_setups/win32/windows_gdi.ini index e8f49fad9..00b6ee1fd 100644 --- a/user_setups/win32/windows_gdi_64bits.ini +++ b/user_setups/win32/windows_gdi.ini @@ -1,4 +1,4 @@ -[env:windows_gdi_64bits] +[env:windows_gdi] platform = native@^1.1.4 extra_scripts = tools/windows_build_extra.py @@ -55,8 +55,8 @@ build_flags = -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=TRUE ;-D NO_PERSISTENCE - -I.pio/libdeps/windows_gdi_64bits/paho/src - -I.pio/libdeps/windows_gdi_64bits/ArduinoJson/src + -I.pio/libdeps/windows_gdi/paho/src + -I.pio/libdeps/windows_gdi/ArduinoJson/src -I lib/lv_fs_if -I lib/lv_datetime -mconsole @@ -100,12 +100,12 @@ lib_ignore = build_src_filter = +<*> -<*.h> - +<../.pio/libdeps/windows_gdi_64bits/paho/src/*.c> - -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTClient.c> - +<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTAsync.c> - +<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTAsyncUtils.c> - -<../.pio/libdeps/windows_gdi_64bits/paho/src/MQTTVersion.c> - -<../.pio/libdeps/windows_gdi_64bits/paho/src/SSLSocket.c> + +<../.pio/libdeps/windows_gdi/paho/src/*.c> + -<../.pio/libdeps/windows_gdi/paho/src/MQTTClient.c> + +<../.pio/libdeps/windows_gdi/paho/src/MQTTAsync.c> + +<../.pio/libdeps/windows_gdi/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/windows_gdi/paho/src/MQTTVersion.c> + -<../.pio/libdeps/windows_gdi/paho/src/SSLSocket.c> - + + @@ -127,5 +127,5 @@ build_src_filter = + - + - +<../.pio/libdeps/windows_gdi_64bits/ArduinoJson/src/ArduinoJson.h> + +<../.pio/libdeps/windows_gdi/ArduinoJson/src/ArduinoJson.h> + diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl.ini similarity index 84% rename from user_setups/win32/windows_sdl_64bits.ini rename to user_setups/win32/windows_sdl.ini index 850e8ae62..30364c1c0 100644 --- a/user_setups/win32/windows_sdl_64bits.ini +++ b/user_setups/win32/windows_sdl.ini @@ -1,4 +1,4 @@ -[env:windows_sdl_64bits] +[env:windows_sdl] platform = native@^1.1.4 extra_scripts = tools/sdl2_build_extra.py @@ -59,8 +59,8 @@ build_flags = -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=TRUE ;-D NO_PERSISTENCE - -I.pio/libdeps/windows_sdl_64bits/paho/src - -I.pio/libdeps/windows_sdl_64bits/ArduinoJson/src + -I.pio/libdeps/windows_sdl/paho/src + -I.pio/libdeps/windows_sdl/ArduinoJson/src -I lib/lv_fs_if -I lib/lv_datetime !python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))" @@ -106,12 +106,12 @@ lib_ignore = build_src_filter = +<*> -<*.h> - +<../.pio/libdeps/windows_sdl_64bits/paho/src/*.c> - -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTClient.c> - +<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTAsync.c> - +<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTAsyncUtils.c> - -<../.pio/libdeps/windows_sdl_64bits/paho/src/MQTTVersion.c> - -<../.pio/libdeps/windows_sdl_64bits/paho/src/SSLSocket.c> + +<../.pio/libdeps/windows_sdl/paho/src/*.c> + -<../.pio/libdeps/windows_sdl/paho/src/MQTTClient.c> + +<../.pio/libdeps/windows_sdl/paho/src/MQTTAsync.c> + +<../.pio/libdeps/windows_sdl/paho/src/MQTTAsyncUtils.c> + -<../.pio/libdeps/windows_sdl/paho/src/MQTTVersion.c> + -<../.pio/libdeps/windows_sdl/paho/src/SSLSocket.c> - + + @@ -133,5 +133,5 @@ build_src_filter = + - + - +<../.pio/libdeps/windows_sdl_64bits/ArduinoJson/src/ArduinoJson.h> + +<../.pio/libdeps/windows_sdl/ArduinoJson/src/ArduinoJson.h> + From d71473a4e7ba8892d12d49c89f63568fe12ecfb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 12 Feb 2024 19:30:05 +0100 Subject: [PATCH 35/36] Reflect MQTT state with online/offline scripts --- src/mqtt/hasp_mqtt_paho_async.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/mqtt/hasp_mqtt_paho_async.cpp b/src/mqtt/hasp_mqtt_paho_async.cpp index 5485fe9e6..71136d076 100644 --- a/src/mqtt/hasp_mqtt_paho_async.cpp +++ b/src/mqtt/hasp_mqtt_paho_async.cpp @@ -94,6 +94,9 @@ int mqttPublish(const char* topic, const char* payload, size_t len, bool retain static void onConnectFailure(void* context, MQTTAsync_failureData* response) { +#if HASP_TARGET_PC + dispatch_run_script(NULL, "L:/offline.cmd", TAG_HASP); +#endif mqttConnecting = false; mqttConnected = false; LOG_ERROR(TAG_MQTT, "Connection failed, return code %d (%s)", response->code, response->message); @@ -101,6 +104,9 @@ static void onConnectFailure(void* context, MQTTAsync_failureData* response) static void onDisconnect(void* context, MQTTAsync_successData* response) { +#if HASP_TARGET_PC + dispatch_run_script(NULL, "L:/offline.cmd", TAG_HASP); +#endif mqttConnecting = false; mqttConnected = false; } @@ -124,6 +130,9 @@ static void onSubscribeFailure(void* context, MQTTAsync_failureData* response) static void connlost(void* context, char* cause) { +#if HASP_TARGET_PC + dispatch_run_script(NULL, "L:/offline.cmd", TAG_HASP); +#endif LOG_WARNING(TAG_MQTT, F(D_MQTT_DISCONNECTED ": %s"), cause); mqttConnecting = false; mqttConnected = false; @@ -341,6 +350,10 @@ static void onConnect(void* context, MQTTAsync_successData* response) #endif mqttPublish(mqttLwtTopic.c_str(), "online", 6, true); + +#if HASP_TARGET_PC + dispatch_run_script(NULL, "L:/online.cmd", TAG_HASP); +#endif } void mqttStart() From 6a8bbce6ecfbe583b2f2bcdb6864aaa0f283dd8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 15 Feb 2024 17:37:08 +0100 Subject: [PATCH 36/36] Restore lv_fs_if_init() on Arduino build --- src/hasp_config.cpp | 1 - src/hasp_gui.cpp | 1 + src/main.cpp | 5 +++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hasp_config.cpp b/src/hasp_config.cpp index 4bdb7c805..75ac0bb5d 100644 --- a/src/hasp_config.cpp +++ b/src/hasp_config.cpp @@ -265,7 +265,6 @@ DeserializationError configParseFile(String& configFile, JsonDocument& settings) } return DeserializationError::InvalidInput; #elif HASP_TARGET_PC - lv_fs_if_init(); lv_fs_file_t f; lv_fs_res_t res; lv_fs_open(&f, "L:/config.json", LV_FS_MODE_RD); diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 9fd55c9bf..13caf3176 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -208,6 +208,7 @@ static inline void gui_init_filesystems() { #if LV_USE_FS_IF != 0 LOG_VERBOSE(TAG_LVGL, F("Filesystem : " D_SETTING_ENABLED)); + lv_fs_if_init(); // auxiliary file system drivers #else LOG_VERBOSE(TAG_LVGL, F("Filesystem : " D_SETTING_DISABLED)); #endif diff --git a/src/main.cpp b/src/main.cpp index 68a51af38..b065909c2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,6 +48,11 @@ void setup() // Initialize lvgl environment lv_init(); lv_log_register_print_cb(debugLvglLogEvent); +#if HASP_USE_CONFIG + // initialize FS before running configSetup() + // normally, it's initialized in guiSetup(), but Arduino doesn't need FS in configSetup() + lv_fs_if_init(); +#endif #endif haspDevice.init();