From b98a06e91c4a810446d36f04e057e4ab3beb3950 Mon Sep 17 00:00:00 2001 From: KlausMu Date: Sun, 10 Mar 2024 14:41:50 +0100 Subject: [PATCH] memory optimization, only three tabs in memory at the same time --- Platformio/platformio.ini | 70 +- Platformio/src/commandHandler.cpp | 2 +- Platformio/src/commandHandler.h | 5 +- Platformio/src/device_appleTV/gui_appleTV.cpp | 24 +- Platformio/src/device_appleTV/gui_appleTV.h | 1 + .../device_keyboard_ble.cpp | 6 +- .../device_keyboard_ble/device_keyboard_ble.h | 6 +- .../device_keyboard_mqtt.h | 6 +- .../src/device_smarthome/gui_smarthome.cpp | 107 +-- .../src/device_smarthome/gui_smarthome.h | 1 + .../src/gui_general_and_keys/guiBase.cpp | 340 +++++--- Platformio/src/gui_general_and_keys/guiBase.h | 37 +- .../guiMemoryOptimizer.cpp | 404 ++++++++++ .../gui_general_and_keys/guiMemoryOptimizer.h | 7 + .../src/gui_general_and_keys/guiRegistry.cpp | 46 +- .../src/gui_general_and_keys/guiRegistry.h | 34 +- .../gui_general_and_keys/gui_irReceiver.cpp | 26 +- .../src/gui_general_and_keys/gui_irReceiver.h | 1 + .../src/gui_general_and_keys/gui_numpad.cpp | 21 +- .../src/gui_general_and_keys/gui_numpad.h | 1 + .../src/gui_general_and_keys/gui_settings.cpp | 67 +- .../src/gui_general_and_keys/gui_settings.h | 1 + Platformio/src/gui_general_and_keys/lv_conf.h | 762 ------------------ Platformio/src/hardware/battery.cpp | 30 +- Platformio/src/hardware/memoryUsage.cpp | 117 +++ Platformio/src/hardware/memoryUsage.h | 10 + Platformio/src/hardware/mqtt.cpp | 3 +- Platformio/src/hardware/mqtt.h | 2 +- Platformio/src/hardware/sleep.cpp | 2 +- Platformio/src/main.cpp | 40 +- Platformio/src/preferencesStorage.cpp | 7 +- Platformio/src/scenes/sceneHandler.cpp | 8 +- 32 files changed, 1114 insertions(+), 1080 deletions(-) create mode 100644 Platformio/src/gui_general_and_keys/guiMemoryOptimizer.cpp create mode 100644 Platformio/src/gui_general_and_keys/guiMemoryOptimizer.h delete mode 100644 Platformio/src/gui_general_and_keys/lv_conf.h create mode 100644 Platformio/src/hardware/memoryUsage.cpp create mode 100644 Platformio/src/hardware/memoryUsage.h diff --git a/Platformio/platformio.ini b/Platformio/platformio.ini index 0e9c492..5e86ab6 100644 --- a/Platformio/platformio.ini +++ b/Platformio/platformio.ini @@ -18,31 +18,83 @@ board_build.f_cpu = 240000000L board_build.partitions = huge_app.csv upload_speed = 1000000 lib_deps = - sparkfun/SparkFun LIS3DH Arduino Library@^1.0.3 - crankyoldgit/IRremoteESP8266@^2.8.4 + bodmer/TFT_eSPI@^2.5.23 adafruit/Adafruit FT6206 Library@^1.0.6 lvgl/lvgl@^8.3.4 - bodmer/TFT_eSPI@^2.5.23 + sparkfun/SparkFun LIS3DH Arduino Library@^1.0.3 + crankyoldgit/IRremoteESP8266@^2.8.4 knolleary/PubSubClient@^2.8 h2zero/NimBLE-Arduino@^1.4.1 + ;chris--a/Keypad@^3.1.1 ;t-vk/ESP32 BLE Keyboard@^0.3.2 build_flags = - -D DISABLE_ALL_LIBRARY_WARNINGS=1 ; for TFT_eSPI - -D USE_NIMBLE=1 ; for BLE Keyboard - -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG - -D LV_CONF_PATH=../../../../src/gui_general_and_keys/lv_conf.h + ;-- OMOTE ----------------------------------------------------------------- + -D ENABLE_WIFI_AND_MQTT=1 + -D ENABLE_BLUETOOTH=1 + ;-- Arduino log ----------------------------------------------------------- + ;-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE + ;-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_ERROR + ;-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_WARN + -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO + ;-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG + ;-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE + ;-- lvgl ------------------------------------------------------------------ + ; lvgl variant 1: + ; Don't use lv_conf.h. Tweak params via platfom.ini. See lv_conf_internal.h line 31. Don't change this line. + -D LV_CONF_SKIP=1 + ; use millis() from "Arduino.h" to tell the elapsed time in milliseconds + -D LV_TICK_CUSTOM=1 + ; dynamic memory. Takes as much as it gets from heap (DRAM). Needs approx. 25%-30% more memory than static memory. + ;-D LV_MEM_CUSTOM=1 + ; static memory, will be allocated in static DRAM + -D LV_MEM_CUSTOM=0 + -D LV_MEM_SIZE="(32U * 1024U)" + ; fonts and theme + -D LV_FONT_MONTSERRAT_10=1 + -D LV_FONT_MONTSERRAT_12=1 + -D LV_FONT_MONTSERRAT_16=1 + -D LV_FONT_MONTSERRAT_24=1 + -D LV_THEME_DEFAULT_DARK=1 + ; don't build examples + -D LV_BUILD_EXAMPLES=0 + ; Enable the log module + -D LV_USE_LOG=1 + -D LV_LOG_PRINTF=1 + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_TRACE + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_WARN + -D LV_LOG_LEVEL=LV_LOG_LEVEL_ERROR + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_USER + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_NONE + ; trace really gives a lot of messages ... + ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_TRACE + ; --- + ; Enable asserts if an operation is failed or an invalid data is found. + ; If LV_USE_LOG is enabled an error message will be printed on failure*/ + ; /*Check if the styles are properly initialized. (Very fast, recommended)*/ + -D LV_USE_ASSERT_STYLE=1 + ; /*Check the integrity of `lv_mem` after critical operations. (Slow)*/ + ;-D LV_USE_ASSERT_MEM_INTEGRITY=1 + ; /*Check the object's type and existence (e.g. not deleted). (Slow)*/ + ;-D LV_USE_ASSERT_OBJ=1 + ; --------- + ; lvgl variant 2: + ; or define where lv_conf.h is, relative to the `lvgl` folder + ;-D LV_CONF_PATH=../../../../src/gui_general_and_keys/lv_conf.h + ;-- TFT_eSPI -------------------------------------------------------------- + -D DISABLE_ALL_LIBRARY_WARNINGS=1 ; The following lines replace the TFT_eSPI User_setup.h-file -D USER_SETUP_LOADED=1 -D ILI9341_DRIVER=1 -D TFT_WIDTH=240 -D TFT_HEIGHT=320 + ;-D TFT_MISO -D TFT_MOSI=23 -D TFT_SCLK=18 -D TFT_CS=5 -D TFT_DC=9 -D TFT_RST=-1 -D SPI_FREQUENCY=40000000 ; 40MHz default, some displays might support 80MHz - -D SPI_TOUCH_FREQUENCY=2500000 ; TFT_eSPI fonts are disabled by default ;-D LOAD_GLCD=1 ;-D LOAD_FONT2=1 @@ -52,3 +104,5 @@ build_flags = ;-D LOAD_FONT8=1 ;-D LOAD_GFXFF=1 ;-D SMOOTH_FONT=1 + ;-- for BLE Keyboard. Don't change this line! ----------------------------- + -D USE_NIMBLE=1 diff --git a/Platformio/src/commandHandler.cpp b/Platformio/src/commandHandler.cpp index 65a83d3..7cb5eb7 100644 --- a/Platformio/src/commandHandler.cpp +++ b/Platformio/src/commandHandler.cpp @@ -126,7 +126,7 @@ void executeCommandWithData(std::string command, commandData commandData, std::s break; } - #ifdef ENABLE_WIFI_AND_MQTT + #if ENABLE_WIFI_AND_MQTT == 1 case MQTT: { auto current = commandData.commandPayloads.begin(); std::string topic = *current; diff --git a/Platformio/src/commandHandler.h b/Platformio/src/commandHandler.h index 1a03e90..ddbe791 100644 --- a/Platformio/src/commandHandler.h +++ b/Platformio/src/commandHandler.h @@ -1,9 +1,6 @@ #ifndef __COMMANDHANDLER_H__ #define __COMMANDHANDLER_H__ -#define ENABLE_WIFI_AND_MQTT // Comment out to disable WiFi -#define ENABLE_BLUETOOTH // Comment out to disable Bluetooth - #include #include #include @@ -104,7 +101,7 @@ enum commandHandlers { IR_SONY, IR_RC5, IR_DENON, - #ifdef ENABLE_WIFI_AND_MQTT + #if ENABLE_WIFI_AND_MQTT == 1 MQTT, #endif #ifdef ENABLE_KEYBOARD_BLE diff --git a/Platformio/src/device_appleTV/gui_appleTV.cpp b/Platformio/src/device_appleTV/gui_appleTV.cpp index c167194..8f34620 100644 --- a/Platformio/src/device_appleTV/gui_appleTV.cpp +++ b/Platformio/src/device_appleTV/gui_appleTV.cpp @@ -1,5 +1,6 @@ #include #include "device_appleTV/device_appleTV.h" +#include "device_appleTV/gui_appleTV.h" #include "gui_general_and_keys/guiBase.h" #include "gui_general_and_keys/guiRegistry.h" #include "hardware/tft.h" @@ -17,11 +18,9 @@ static void appleKey_event_cb(lv_event_t* e) { Serial.println(50 + (int)e->user_data); } -void init_gui_tab_appleTV(lv_obj_t* tabview) { +void create_tab_content_appleTV(lv_obj_t* tab) { - lv_obj_t* tab = lv_tabview_add_tab(tabview, "Apple TV"); - - // Add content to the Apple TV tab (3) + // Add content to the Apple TV tab // Add a nice apple tv logo lv_obj_t* appleImg = lv_img_create(tab); lv_img_set_src(appleImg, &appleTvIcon); @@ -52,22 +51,15 @@ void init_gui_tab_appleTV(lv_obj_t* tabview) { lv_obj_set_style_img_recolor(appleImg, lv_color_white(), LV_PART_MAIN); lv_obj_set_style_img_recolor_opa(appleImg, LV_OPA_COVER, LV_PART_MAIN); lv_obj_align(appleImg, LV_ALIGN_CENTER, 0, 0); - + } -void init_gui_pageIndicator_appleTV(lv_obj_t* panel) { - // Create actual (non-clickable) buttons for every tab - lv_obj_t* btn = lv_btn_create(panel); - lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); - lv_obj_set_size(btn, 150, lv_pct(100)); - lv_obj_t* label = lv_label_create(btn); - lv_label_set_text_fmt(label, "Apple TV"); - lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); - lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); +void notify_tab_before_delete_appleTV(void) { + // remember to set all pointers to lvgl objects to NULL if they might be accessed from outside. + // They must check if object is NULL and must not use it if so } void register_gui_appleTV(void){ - register_gui(& init_gui_tab_appleTV, & init_gui_pageIndicator_appleTV); + register_gui(std::string(tabName_appleTV), & create_tab_content_appleTV, & notify_tab_before_delete_appleTV); } diff --git a/Platformio/src/device_appleTV/gui_appleTV.h b/Platformio/src/device_appleTV/gui_appleTV.h index b7dd127..ea5ed81 100644 --- a/Platformio/src/device_appleTV/gui_appleTV.h +++ b/Platformio/src/device_appleTV/gui_appleTV.h @@ -3,6 +3,7 @@ #include +const char * const tabName_appleTV = "Apple TV"; void register_gui_appleTV(void); #endif /*__GUI_APPLETV_H__*/ diff --git a/Platformio/src/device_keyboard_ble/device_keyboard_ble.cpp b/Platformio/src/device_keyboard_ble/device_keyboard_ble.cpp index 2cedda5..adb201b 100644 --- a/Platformio/src/device_keyboard_ble/device_keyboard_ble.cpp +++ b/Platformio/src/device_keyboard_ble/device_keyboard_ble.cpp @@ -38,16 +38,16 @@ bool blinkBluetoothLabelIsOn = false; void update_keyboard_ble_status() { if (bleKeyboard.isConnected()) { - lv_label_set_text(BluetoothLabel, LV_SYMBOL_BLUETOOTH); + if (BluetoothLabel != NULL) {lv_label_set_text(BluetoothLabel, LV_SYMBOL_BLUETOOTH);} bleKeyboard.setBatteryLevel(battery_percentage); } else { if(millis() - blinkBluetoothLabelLastChange >= 1000){ blinkBluetoothLabelIsOn = !blinkBluetoothLabelIsOn; if (blinkBluetoothLabelIsOn) { - lv_label_set_text(BluetoothLabel, LV_SYMBOL_BLUETOOTH); + if (BluetoothLabel != NULL) {lv_label_set_text(BluetoothLabel, LV_SYMBOL_BLUETOOTH);} } else { - lv_label_set_text(BluetoothLabel, ""); + if (BluetoothLabel != NULL) {lv_label_set_text(BluetoothLabel, "");} } blinkBluetoothLabelLastChange = millis(); } diff --git a/Platformio/src/device_keyboard_ble/device_keyboard_ble.h b/Platformio/src/device_keyboard_ble/device_keyboard_ble.h index b39506c..b907f42 100644 --- a/Platformio/src/device_keyboard_ble/device_keyboard_ble.h +++ b/Platformio/src/device_keyboard_ble/device_keyboard_ble.h @@ -8,10 +8,8 @@ #ifdef ENABLE_KEYBOARD_BLE -#include "commandHandler.h" - -#if defined(ENABLE_KEYBOARD_BLE) && !defined(ENABLE_BLUETOOTH) -static_assert(false, "You have to use \"#define ENABLE_BLUETOOTH\" in \"commandHandler.h\" when having \"#define ENABLE_KEYBOARD_BLE\""); +#if defined(ENABLE_KEYBOARD_BLE) && !(ENABLE_BLUETOOTH == 1) +static_assert(false, "You have to use \"-D ENABLE_BLUETOOTH=1\" in \"platformio.ini\" when having \"#define ENABLE_KEYBOARD_BLE\""); #endif #include diff --git a/Platformio/src/device_keyboard_mqtt/device_keyboard_mqtt.h b/Platformio/src/device_keyboard_mqtt/device_keyboard_mqtt.h index f41f360..7380966 100644 --- a/Platformio/src/device_keyboard_mqtt/device_keyboard_mqtt.h +++ b/Platformio/src/device_keyboard_mqtt/device_keyboard_mqtt.h @@ -10,10 +10,8 @@ // if you activate the MQTT keyboard, consider changing the mapping of the keyboard commands to the MQTT keyboard in file "commandHandler.h" -#include "commandHandler.h" - -#if defined(ENABLE_KEYBOARD_MQTT) && !defined(ENABLE_WIFI_AND_MQTT) -static_assert(false, "You have to use \"#define ENABLE_WIFI_AND_MQTT\" in \"commandHandler.h\" when having \"#define ENABLE_KEYBOARD_MQTT\""); +#if defined(ENABLE_KEYBOARD_MQTT) && !(ENABLE_WIFI_AND_MQTT == 1) +static_assert(false, "You have to use \"-D ENABLE_WIFI_AND_MQTT=1\" in \"platformio.ini\" when having \"#define ENABLE_KEYBOARD_MQTT\""); #endif #define KEYBOARD_MQTT_UP "Keyboard_mqtt_up" diff --git a/Platformio/src/device_smarthome/gui_smarthome.cpp b/Platformio/src/device_smarthome/gui_smarthome.cpp index 8fcdfc3..be07d36 100644 --- a/Platformio/src/device_smarthome/gui_smarthome.cpp +++ b/Platformio/src/device_smarthome/gui_smarthome.cpp @@ -4,41 +4,50 @@ #include "gui_general_and_keys/guiRegistry.h" #include "hardware/tft.h" #include "device_smarthome/device_smarthome.h" +#include "device_smarthome/gui_smarthome.h" #include "commandHandler.h" // LVGL declarations LV_IMG_DECLARE(lightbulb); +static lv_obj_t* lightToggleA; +static lv_obj_t* lightToggleB; +static lv_obj_t* sliderA; +static lv_obj_t* sliderB; + +static bool lightToggleAstate = false; +static bool lightToggleBstate = false; +static int32_t sliderAvalue = 0; +static int32_t sliderBvalue = 0; + // Smart Home Toggle Event handler -static void smartHomeToggle_event_cb(lv_event_t * e){ +static void smartHomeToggle_event_cb(lv_event_t* e){ std::string payload; if (lv_obj_has_state(lv_event_get_target(e), LV_STATE_CHECKED)) payload = "true"; else payload = "false"; // Publish an MQTT message based on the event user data - #ifdef ENABLE_WIFI_AND_MQTT + #if ENABLE_WIFI_AND_MQTT == 1 if((int)e->user_data == 1) executeCommand(SMARTHOME_MQTT_BULB1_SET, payload); if((int)e->user_data == 2) executeCommand(SMARTHOME_MQTT_BULB2_SET, payload); #endif } // Smart Home Slider Event handler -static void smartHomeSlider_event_cb(lv_event_t * e){ +static void smartHomeSlider_event_cb(lv_event_t* e){ lv_obj_t * slider = lv_event_get_target(e); char payload[8]; dtostrf(lv_slider_get_value(slider), 1, 2, payload); std::string payload_str(payload); // Publish an MQTT message based on the event user data - #ifdef ENABLE_WIFI_AND_MQTT + #if ENABLE_WIFI_AND_MQTT == 1 if((int)e->user_data == 1) executeCommand(SMARTHOME_MQTT_BULB1_BRIGHTNESS_SET, payload); if((int)e->user_data == 2) executeCommand(SMARTHOME_MQTT_BULB2_BRIGHTNESS_SET, payload); #endif } -void init_gui_tab_smarthome(lv_obj_t* tabview) { +void create_tab_content_smarthome(lv_obj_t* tab) { - lv_obj_t* tab = lv_tabview_add_tab(tabview, "Smart Home"); - - // Add content to the smart home tab (4) + // Add content to the smart home tab lv_obj_set_layout(tab, LV_LAYOUT_FLEX); lv_obj_set_flex_flow(tab, LV_FLEX_FLOW_COLUMN); lv_obj_set_scrollbar_mode(tab, LV_SCROLLBAR_MODE_ACTIVE); @@ -61,25 +70,30 @@ void init_gui_tab_smarthome(lv_obj_t* tabview) { menuLabel = lv_label_create(menuBox); lv_label_set_text(menuLabel, "Floor Lamp"); lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 22, 3); - lv_obj_t* lightToggleA = lv_switch_create(menuBox); + lightToggleA = lv_switch_create(menuBox); + if (lightToggleAstate) { + lv_obj_add_state(lightToggleA, LV_STATE_CHECKED); + } else { + // lv_obj_clear_state(lightToggleA, LV_STATE_CHECKED); + } lv_obj_set_size(lightToggleA, 40, 22); lv_obj_align(lightToggleA, LV_ALIGN_TOP_RIGHT, 0, 0); lv_obj_set_style_bg_color(lightToggleA, lv_color_lighten(color_primary, 50), LV_PART_MAIN); lv_obj_set_style_bg_color(lightToggleA, color_primary, LV_PART_INDICATOR); lv_obj_add_event_cb(lightToggleA, smartHomeToggle_event_cb, LV_EVENT_VALUE_CHANGED, (void*)1); - lv_obj_t* slider = lv_slider_create(menuBox); - lv_slider_set_range(slider, 0, 100); - lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30), LV_PART_INDICATOR); - lv_obj_set_style_bg_grad_color(slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), LV_PART_INDICATOR); - lv_obj_set_style_bg_grad_dir(slider, LV_GRAD_DIR_HOR, LV_PART_INDICATOR); - lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB); - lv_obj_set_style_bg_opa(slider, 255, LV_PART_MAIN); - lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), LV_PART_MAIN); - lv_slider_set_value(slider, 255, LV_ANIM_OFF); - lv_obj_set_size(slider, lv_pct(90), 10); - lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 37); - lv_obj_add_event_cb(slider, smartHomeSlider_event_cb, LV_EVENT_VALUE_CHANGED, (void*)1); + sliderA = lv_slider_create(menuBox); + lv_slider_set_range(sliderA, 0, 100); + lv_obj_set_style_bg_color(sliderA, lv_color_lighten(lv_color_black(), 30), LV_PART_INDICATOR); + lv_obj_set_style_bg_grad_color(sliderA, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), LV_PART_INDICATOR); + lv_obj_set_style_bg_grad_dir(sliderA, LV_GRAD_DIR_HOR, LV_PART_INDICATOR); + lv_obj_set_style_bg_color(sliderA, lv_color_white(), LV_PART_KNOB); + lv_obj_set_style_bg_opa(sliderA, 255, LV_PART_MAIN); + lv_obj_set_style_bg_color(sliderA, lv_color_lighten(color_primary, 50), LV_PART_MAIN); + lv_slider_set_value(sliderA, sliderAvalue, LV_ANIM_OFF); + lv_obj_set_size(sliderA, lv_pct(90), 10); + lv_obj_align(sliderA, LV_ALIGN_TOP_MID, 0, 37); + lv_obj_add_event_cb(sliderA, smartHomeSlider_event_cb, LV_EVENT_VALUE_CHANGED, (void*)1); // Add another menu box for a second appliance menuBox = lv_obj_create(tab); @@ -96,25 +110,30 @@ void init_gui_tab_smarthome(lv_obj_t* tabview) { menuLabel = lv_label_create(menuBox); lv_label_set_text(menuLabel, "Ceiling Light"); lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 22, 3); - lv_obj_t* lightToggleB = lv_switch_create(menuBox); + lightToggleB = lv_switch_create(menuBox); + if (lightToggleBstate) { + lv_obj_add_state(lightToggleB, LV_STATE_CHECKED); + } else { + // lv_obj_clear_state(lightToggleB, LV_STATE_CHECKED); + } lv_obj_set_size(lightToggleB, 40, 22); lv_obj_align(lightToggleB, LV_ALIGN_TOP_RIGHT, 0, 0); lv_obj_set_style_bg_color(lightToggleB, lv_color_lighten(color_primary, 50), LV_PART_MAIN); lv_obj_set_style_bg_color(lightToggleB, color_primary, LV_PART_INDICATOR); lv_obj_add_event_cb(lightToggleB, smartHomeToggle_event_cb, LV_EVENT_VALUE_CHANGED, (void*)2); - slider = lv_slider_create(menuBox); - lv_slider_set_range(slider, 0, 100); - lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30), LV_PART_INDICATOR); - lv_obj_set_style_bg_grad_color(slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), LV_PART_INDICATOR); - lv_obj_set_style_bg_grad_dir(slider, LV_GRAD_DIR_HOR, LV_PART_INDICATOR); - lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB); - lv_obj_set_style_bg_opa(slider, 255, LV_PART_MAIN); - lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), LV_PART_MAIN); - lv_slider_set_value(slider, 255, LV_ANIM_OFF); - lv_obj_set_size(slider, lv_pct(90), 10); - lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 37); - lv_obj_add_event_cb(slider, smartHomeSlider_event_cb, LV_EVENT_VALUE_CHANGED, (void*)2); + sliderB = lv_slider_create(menuBox); + lv_slider_set_range(sliderB, 0, 100); + lv_obj_set_style_bg_color(sliderB, lv_color_lighten(lv_color_black(), 30), LV_PART_INDICATOR); + lv_obj_set_style_bg_grad_color(sliderB, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), LV_PART_INDICATOR); + lv_obj_set_style_bg_grad_dir(sliderB, LV_GRAD_DIR_HOR, LV_PART_INDICATOR); + lv_obj_set_style_bg_color(sliderB, lv_color_white(), LV_PART_KNOB); + lv_obj_set_style_bg_opa(sliderB, 255, LV_PART_MAIN); + lv_obj_set_style_bg_color(sliderB, lv_color_lighten(color_primary, 50), LV_PART_MAIN); + lv_slider_set_value(sliderB, sliderBvalue, LV_ANIM_OFF); + lv_obj_set_size(sliderB, lv_pct(90), 10); + lv_obj_align(sliderB, LV_ALIGN_TOP_MID, 0, 37); + lv_obj_add_event_cb(sliderB, smartHomeSlider_event_cb, LV_EVENT_VALUE_CHANGED, (void*)2); // Add another room (empty for now) @@ -128,19 +147,15 @@ void init_gui_tab_smarthome(lv_obj_t* tabview) { } -void init_gui_pageIndicator_smarthome(lv_obj_t* panel) { - // Create actual (non-clickable) buttons for every tab - lv_obj_t* btn = lv_btn_create(panel); - lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); - lv_obj_set_size(btn, 150, lv_pct(100)); - lv_obj_t* label = lv_label_create(btn); - lv_label_set_text_fmt(label, "Smart Home"); - lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); - lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); - +void notify_tab_before_delete_smarthome(void) { + // remember to set all pointers to lvgl objects to NULL if they might be accessed from outside. + // They must check if object is NULL and must not use it if so + lightToggleAstate = lv_obj_has_state(lightToggleA, LV_STATE_CHECKED); + lightToggleBstate = lv_obj_has_state(lightToggleB, LV_STATE_CHECKED); + sliderAvalue = lv_slider_get_value(sliderA); + sliderBvalue = lv_slider_get_value(sliderB); } void register_gui_smarthome(void){ - register_gui(& init_gui_tab_smarthome, & init_gui_pageIndicator_smarthome); + register_gui(std::string(tabName_smarthome), & create_tab_content_smarthome, & notify_tab_before_delete_smarthome); } diff --git a/Platformio/src/device_smarthome/gui_smarthome.h b/Platformio/src/device_smarthome/gui_smarthome.h index c283431..f3dd1c1 100644 --- a/Platformio/src/device_smarthome/gui_smarthome.h +++ b/Platformio/src/device_smarthome/gui_smarthome.h @@ -3,6 +3,7 @@ #include +const char * const tabName_smarthome = "Smart Home"; void register_gui_smarthome(void); #endif /*__GUI_SMARTHOME_H__*/ diff --git a/Platformio/src/gui_general_and_keys/guiBase.cpp b/Platformio/src/gui_general_and_keys/guiBase.cpp index d41618e..6bac1fd 100644 --- a/Platformio/src/gui_general_and_keys/guiBase.cpp +++ b/Platformio/src/gui_general_and_keys/guiBase.cpp @@ -1,35 +1,93 @@ #include #include "hardware/tft.h" #include "hardware/sleep.h" +#include "hardware/memoryUsage.h" #include "gui_general_and_keys/guiBase.h" #include "gui_general_and_keys/guiRegistry.h" +#include "gui_general_and_keys/guiMemoryOptimizer.h" -lv_obj_t* panel; lv_color_t color_primary = lv_color_hex(0x303030); // gray +lv_obj_t* MemoryUsageLabel = NULL; lv_obj_t* WifiLabel = NULL; -lv_obj_t* BluetoothLabel; -lv_obj_t* objBattPercentage; -lv_obj_t* objBattIcon; -lv_obj_t* SceneLabel; -byte currentScreen = 1; // Current Device to control (allows switching mappings between devices) +lv_obj_t* BluetoothLabel = NULL; +lv_obj_t* BattPercentageLabel = NULL; +lv_obj_t* BattIconLabel = NULL; +lv_obj_t* SceneLabel = NULL; +uint32_t currentTabID = -1; // id of the current tab +uint32_t oldTabID = -1; -// LVGL declarations -LV_IMG_DECLARE(gradientLeft); -LV_IMG_DECLARE(gradientRight); +lv_obj_t* tabview = NULL; +// page indicator +lv_obj_t* panel = NULL; +lv_obj_t* img1 = NULL; +lv_obj_t* img2 = NULL; + +static bool global_styles_already_initialized = false; +lv_style_t panel_style; +#ifdef drawRedBorderAroundMainWidgets +lv_style_t style_red_border; +#endif // Helper Functions ----------------------------------------------------------------------------------------------------------------------- -// Set the page indicator scroll position relative to the tabview scroll position -static void store_scroll_value_event_cb(lv_event_t* e){ - float bias = (150.0 + 8.0) / 240.0; - int offset = 240 / 2 - 150 / 2 - 8 - 50 - 3; - lv_obj_t* screen = lv_event_get_target(e); - lv_obj_scroll_to_x(panel, lv_obj_get_scroll_x(screen) * bias - offset, LV_ANIM_OFF); +// Set the page indicator (panel) scroll position relative to the tabview content scroll position +// this is a callback if the CONTENT of the tabview is scrolled (LV_EVENT_SCROLL) +void tabview_content_is_scrolling_event_cb(lv_event_t* e){ + if (panel == NULL) { return;} + + float bias = float(150.0 + 8.0) / 240.0; + // screenwidth indicator ?? 2 small hidden buttons ?? + int offset = 240 / 2 - 150 / 2 - 8 - 2*50 / 2 -4; + // get the object to which the event is sent + lv_obj_t* tabviewContent = lv_event_get_target(e); + + // Get the x coordinate of object and scroll panel accordingly + int16_t tabviewX = lv_obj_get_scroll_x(tabviewContent); + // the last events we receive are 0, 238 and 476. But should be 0, 240 and 480. Otherwise page indicator jumps a litte bit after recreation of tabs. + if ((tabviewX >= 237) && (tabviewX <= 240)) {tabviewX = 240;} + if ((tabviewX >= 475) && (tabviewX <= 480)) {tabviewX = 480;} + // we need 158 more (the size of one page indicator), because we always have one more page indicator at the beginning and at the end (so normally 5 when having 3 tabs) + int16_t panelX = tabviewX * bias - offset + 158; + // Serial.printf("scroll %d to %d\r\n", tabviewX, panelX); + lv_obj_scroll_to_x(panel, panelX, LV_ANIM_OFF); + // lv_obj_scroll_to_x(panel, lv_obj_get_scroll_x(tabviewContent) * bias - offset, LV_ANIM_OFF); } -// Update current screen when the tabview page is changes -static void tabview_device_event_cb(lv_event_t* e){ - currentScreen = lv_tabview_get_tab_act(lv_event_get_target(e)); +// ----------------------- +static bool waitBeforeActionAfterSlidingAnimationEnded = false; +static unsigned long waitBeforeActionAfterSlidingAnimationEnded_timerStart; +// This is the callback when the animation of the tab sliding ended +void tabview_animation_ready_cb(lv_anim_t* a) { + // Unfortunately, the animation has not completely ended here. We cannot do the recreation of the tabs here. + // We have to wait some more milliseconds or at least one cycle of lv_timer_handler(); + // calling lv_timer_handler(); here does not help + // lv_timer_handler(); + // guis_doAfterSliding(oldTabID, currentTabID); + + waitBeforeActionAfterSlidingAnimationEnded = true; + waitBeforeActionAfterSlidingAnimationEnded_timerStart = millis(); +} + +// Update currentTabID when a new tab is selected +// this is a callback if the tabview is changed (LV_EVENT_VALUE_CHANGED) +// Sent when a new tab is selected by sliding or clicking the tab button. lv_tabview_get_tab_act(tabview) returns the zero based index of the current tab. +void tabview_tab_changed_event_cb(lv_event_t* e){ + if (lv_event_get_code(e) == LV_EVENT_VALUE_CHANGED) { + + oldTabID = currentTabID; + currentTabID = lv_tabview_get_tab_act(lv_event_get_target(e)); + + // Wait until the animation ended, then call "guis_doAfterSliding(oldTabID, currentTabID);" + // https://forum.lvgl.io/t/delete-a-tab-after-the-tabview-scroll-animation-is-complete/3155/4 + lv_obj_t* myTabview = lv_event_get_target(e); + lv_obj_t* tabContainer = lv_tabview_get_content(myTabview); + // https://docs.lvgl.io/8.3/overview/animation.html?highlight=lv_anim_get#_CPPv411lv_anim_getPv18lv_anim_exec_xcb_t + // (lv_anim_exec_xcb_t) lv_obj_set_x does not find an animation. NULL is good as well. + lv_anim_t* anim = lv_anim_get(tabContainer, NULL); // (lv_anim_exec_xcb_t) lv_obj_set_x); + if(anim) { + lv_anim_set_ready_cb(anim, tabview_animation_ready_cb); + } + } } // Display flushing @@ -38,8 +96,12 @@ void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *colo uint32_t h = ( area->y2 - area->y1 + 1 ); tft.startWrite(); - tft.setAddrWindow( area->x1, area->y1, w, h ); - tft.pushPixelsDMA( ( uint16_t * )&color_p->full, w * h); + tft.setAddrWindow(area->x1, area->y1, w, h); + #ifdef useTwoBuffersForlvgl + tft.pushPixelsDMA((uint16_t*)&color_p->full, w * h); + #else + tft.pushColors((uint16_t*)&color_p->full, w * h, true); + #endif tft.endWrite(); lv_disp_flush_ready( disp ); @@ -77,18 +139,23 @@ void my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data){ } static lv_disp_draw_buf_t draw_buf; -// static lv_color_t bufA[ screenWidth * screenHeight / 10 ]; -// static lv_color_t bufB[ screenWidth * screenHeight / 10 ]; +void setMainWidgetsHeightAndPosition(); +void init_gui_status_bar(); +void init_gui_memoryUsage_bar(); void init_gui(void) { // Setup LVGL --------------------------------------------------------------------------------------------- lv_init(); + #ifdef useTwoBuffersForlvgl lv_color_t * bufA = (lv_color_t *) malloc(sizeof(lv_color_t) * screenWidth * screenHeight / 10); lv_color_t * bufB = (lv_color_t *) malloc(sizeof(lv_color_t) * screenWidth * screenHeight / 10); - - lv_disp_draw_buf_init( &draw_buf, bufA, bufB, screenWidth * screenHeight / 10 ); + lv_disp_draw_buf_init(&draw_buf, bufA, bufB, screenWidth * screenHeight / 10); + #else + lv_color_t * bufA = (lv_color_t *) malloc(sizeof(lv_color_t) * screenWidth * screenHeight / 10); + lv_disp_draw_buf_init(&draw_buf, bufA, NULL, screenWidth * screenHeight / 10); + #endif // Initialize the display driver -------------------------------------------------------------------------- static lv_disp_drv_t disp_drv; @@ -106,114 +173,187 @@ void init_gui(void) { indev_drv.read_cb = my_touchpad_read; lv_indev_drv_register( &indev_drv ); - - // --- LVGL UI Configuration --- - + // -- draw red border around the main widgets ------------------------------------------------------------- + if (!global_styles_already_initialized) { + // Style the panel background. Will be initialized only once and reused in fillPanelWithPageIndicator_strategyMax3 + lv_style_init(&panel_style); + lv_style_set_pad_all(&panel_style, 3); + lv_style_set_border_width(&panel_style, 0); + lv_style_set_bg_opa(&panel_style, LV_OPA_TRANSP); + #ifdef drawRedBorderAroundMainWidgets + lv_style_init(&style_red_border); + lv_style_set_border_side(&style_red_border, LV_BORDER_SIDE_FULL); + lv_style_set_border_color(&style_red_border, lv_color_hex(0xff0000)); + lv_style_set_border_width(&style_red_border, 1); + global_styles_already_initialized = true; + #endif + } // Set the background color ------------------------------------------------------------------------------- lv_obj_set_style_bg_color(lv_scr_act(), lv_color_black(), LV_PART_MAIN); + // set default height and position of main widgets + setMainWidgetsHeightAndPosition(); + // At startup, set current GUI according to currentGUIname, and create the content of that tab (and the previous and the next) for the first time + guis_doTabCreationAtStartup(); + // memoryUsage bar + init_gui_memoryUsage_bar(); + // status bar + init_gui_status_bar(); +} - // Setup a scrollable tabview for devices and settings ---------------------------------------------------- - lv_obj_t* tabview; - tabview = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, 0); // Hide tab labels by setting their height to 0 - lv_obj_set_style_bg_color(tabview, lv_color_black(), LV_PART_MAIN); - lv_obj_set_size(tabview, screenWidth, 270); // 270 = screenHeight(320) - panel(30) - statusbar(20) - lv_obj_align(tabview, LV_ALIGN_TOP_MID, 0, 20); +int panelHeight; +int memoryUsageBarTop; +int memoryUsageBarHeight; +int statusbarTop; +int statusbarHeight; +int tabviewTop; +int tabviewHeight; +int labelsPositionTop; - // Add all the tabs here - create_gui_tabs_from_gui_registry(tabview); +void setMainWidgetsHeightAndPosition() { + panelHeight = 30; + memoryUsageBarTop = 0; + memoryUsageBarHeight = getShowMemoryUsage() ? 14 : 0; + statusbarTop = memoryUsageBarTop + memoryUsageBarHeight; + statusbarHeight = 20; + tabviewTop = statusbarTop + statusbarHeight; + tabviewHeight = 320 - memoryUsageBarHeight - statusbarHeight - panelHeight; + labelsPositionTop = -2; +} - // Set current page according to the current screen - lv_tabview_set_act(tabview, currentScreen, LV_ANIM_OFF); +lv_obj_t* memoryUsageBar; +lv_obj_t* statusbar; +void showMemoryUsageBar(bool showBar) { + setMainWidgetsHeightAndPosition(); - // Create a page indicator at the bottom ------------------------------------------------------------------ - panel = lv_obj_create(lv_scr_act()); - lv_obj_clear_flag(panel, LV_OBJ_FLAG_CLICKABLE); // This indicator will not be clickable - lv_obj_set_size(panel, screenWidth, 30); - lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_ROW); - lv_obj_align(panel, LV_ALIGN_BOTTOM_MID, 0, 0); - lv_obj_set_scrollbar_mode(panel, LV_SCROLLBAR_MODE_OFF); - // This small hidden button enables the page indicator to scroll further - lv_obj_t* btn = lv_btn_create(panel); - lv_obj_set_size(btn, 50, lv_pct(100)); - lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); - lv_obj_set_style_opa(btn, LV_OPA_TRANSP, LV_PART_MAIN); - - // Create actual (non-clickable) buttons for every tab - create_gui_pageIndicators_from_gui_registry(panel); - - // This small hidden button enables the page indicator to scroll further - btn = lv_btn_create(panel); - lv_obj_set_size(btn, 50, lv_pct(100)); - lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); - lv_obj_set_style_opa(btn, LV_OPA_TRANSP, LV_PART_MAIN); - - // Make the indicator scroll together with the tabs by creating a scroll event - lv_obj_add_event_cb(lv_tabview_get_content(tabview), store_scroll_value_event_cb, LV_EVENT_SCROLL, NULL); - lv_obj_add_event_cb(tabview, tabview_device_event_cb, LV_EVENT_VALUE_CHANGED, NULL); - // Initialize scroll position for the indicator - lv_event_send(lv_tabview_get_content(tabview), LV_EVENT_SCROLL, NULL); + lv_obj_set_size(memoryUsageBar, 240, memoryUsageBarHeight); + lv_obj_align(memoryUsageBar, LV_ALIGN_TOP_MID, 0, memoryUsageBarTop); + lv_obj_set_size(statusbar, 240, statusbarHeight); + lv_obj_align(statusbar, LV_ALIGN_TOP_MID, 0, statusbarTop); + lv_obj_set_size(tabview, screenWidth, tabviewHeight); + lv_obj_align(tabview, LV_ALIGN_TOP_MID, 0, tabviewTop); - // Style the panel background - static lv_style_t style_btn; - lv_style_init(&style_btn); - lv_style_set_pad_all(&style_btn, 3); - lv_style_set_border_width(&style_btn, 0); - lv_style_set_bg_opa(&style_btn, LV_OPA_TRANSP); - lv_obj_add_style(panel, &style_btn, 0); + return; - // Make the indicator fade out at the sides using gradient bitmaps - lv_obj_t* img1 = lv_img_create(lv_scr_act()); - lv_img_set_src(img1, &gradientLeft); - lv_obj_align(img1, LV_ALIGN_BOTTOM_LEFT, 0, 0); - lv_obj_set_size(img1, 30, 30); // stretch the 1-pixel high image to 30px - lv_obj_t* img2 = lv_img_create(lv_scr_act()); - lv_img_set_src(img2, &gradientRight); - lv_obj_align(img2, LV_ALIGN_BOTTOM_RIGHT, 0, 0); - lv_obj_set_size(img2, 30, 30); + if (showBar) { + // lv_obj_clear_flag(memoryUsageBar, LV_OBJ_FLAG_HIDDEN); + lv_obj_set_size(memoryUsageBar, 240, memoryUsageBarHeight); + lv_obj_align(memoryUsageBar, LV_ALIGN_TOP_MID, 0, memoryUsageBarTop); + lv_obj_set_size(statusbar, 240, statusbarHeight); + lv_obj_align(statusbar, LV_ALIGN_TOP_MID, 0, statusbarTop); + lv_obj_set_size(tabview, screenWidth, tabviewHeight); + lv_obj_align(tabview, LV_ALIGN_TOP_MID, 0, tabviewTop); + } else { + // lv_obj_add_flag(memoryUsageBar, LV_OBJ_FLAG_HIDDEN); + } +} +void init_gui_memoryUsage_bar() { + // Create a memory status text bar at the top ------------------------------------------------------------- + memoryUsageBar = lv_btn_create(lv_scr_act()); + lv_obj_set_size(memoryUsageBar, 240, memoryUsageBarHeight); + lv_obj_set_style_shadow_width(memoryUsageBar, 0, LV_PART_MAIN); + lv_obj_set_style_bg_color(memoryUsageBar, lv_color_black(), LV_PART_MAIN); + #ifdef drawRedBorderAroundMainWidgets + lv_obj_add_style(memoryUsageBar, &style_red_border, LV_PART_MAIN); + #endif + lv_obj_set_style_radius(memoryUsageBar, 0, LV_PART_MAIN); + lv_obj_set_style_pad_all(memoryUsageBar, 0, LV_PART_MAIN); + lv_obj_align(memoryUsageBar, LV_ALIGN_TOP_MID, 0, memoryUsageBarTop); + + MemoryUsageLabel = lv_label_create(memoryUsageBar); + lv_label_set_text(MemoryUsageLabel, ""); + lv_obj_align(MemoryUsageLabel, LV_ALIGN_TOP_LEFT, 0, labelsPositionTop); + lv_obj_set_style_text_font(MemoryUsageLabel, &lv_font_montserrat_12, LV_PART_MAIN); + lv_label_set_recolor(MemoryUsageLabel, true); +} + +void init_gui_status_bar() { // Create a status bar at the top ------------------------------------------------------------------------- - lv_obj_t* statusbar = lv_btn_create(lv_scr_act()); - lv_obj_set_size(statusbar, 240, 20); + statusbar = lv_btn_create(lv_scr_act()); + lv_obj_set_size(statusbar, 240, statusbarHeight); lv_obj_set_style_shadow_width(statusbar, 0, LV_PART_MAIN); lv_obj_set_style_bg_color(statusbar, lv_color_black(), LV_PART_MAIN); + #ifdef drawRedBorderAroundMainWidgets + lv_obj_add_style(statusbar, &style_red_border, LV_PART_MAIN); + #endif lv_obj_set_style_radius(statusbar, 0, LV_PART_MAIN); - lv_obj_align(statusbar, LV_ALIGN_TOP_MID, 0, 0); + lv_obj_set_style_pad_all(statusbar, 0, LV_PART_MAIN); + lv_obj_align(statusbar, LV_ALIGN_TOP_MID, 0, statusbarTop); + int labelsPositionTopStatusbar = labelsPositionTop + 3; // WiFi ------------------------------------------------------------------------- WifiLabel = lv_label_create(statusbar); lv_label_set_text(WifiLabel, ""); - lv_obj_align(WifiLabel, LV_ALIGN_LEFT_MID, -8, 0); + lv_obj_align(WifiLabel, LV_ALIGN_TOP_LEFT, 0, labelsPositionTopStatusbar +1); lv_obj_set_style_text_font(WifiLabel, &lv_font_montserrat_12, LV_PART_MAIN); - // Bluetooth -------------------------------------------------------------------- BluetoothLabel = lv_label_create(statusbar); lv_label_set_text(BluetoothLabel, ""); - lv_obj_align(BluetoothLabel, LV_ALIGN_LEFT_MID, 12, 0); + lv_obj_align(BluetoothLabel, LV_ALIGN_TOP_LEFT, 20, labelsPositionTopStatusbar); lv_obj_set_style_text_font(BluetoothLabel, &lv_font_montserrat_12, LV_PART_MAIN); - // Scene ------------------------------------------------------------------------ SceneLabel = lv_label_create(statusbar); lv_label_set_text(SceneLabel, ""); - lv_obj_align(SceneLabel, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(SceneLabel, LV_ALIGN_TOP_MID, 0, labelsPositionTopStatusbar); lv_obj_set_style_text_font(SceneLabel, &lv_font_montserrat_12, LV_PART_MAIN); - // Battery ---------------------------------------------------------------------- - objBattPercentage = lv_label_create(statusbar); - lv_label_set_text(objBattPercentage, ""); -// lv_obj_align(objBattPercentage, LV_ALIGN_RIGHT_MID, -16, 0); - lv_obj_align(objBattPercentage, LV_ALIGN_RIGHT_MID, -20, 0); - lv_obj_set_style_text_font(objBattPercentage, &lv_font_montserrat_12, LV_PART_MAIN); - objBattIcon = lv_label_create(statusbar); - lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_EMPTY); - lv_obj_align(objBattIcon, LV_ALIGN_RIGHT_MID, 8, 0); - lv_obj_set_style_text_font(objBattIcon, &lv_font_montserrat_16, LV_PART_MAIN); - - // --- End of LVGL configuration --- + BattPercentageLabel = lv_label_create(statusbar); + lv_label_set_text(BattPercentageLabel, ""); + lv_obj_align(BattPercentageLabel, LV_ALIGN_TOP_RIGHT, -28, labelsPositionTopStatusbar); + lv_obj_set_style_text_font(BattPercentageLabel, &lv_font_montserrat_12, LV_PART_MAIN); + BattIconLabel = lv_label_create(statusbar); + lv_label_set_text(BattIconLabel, LV_SYMBOL_BATTERY_EMPTY); + lv_obj_align(BattIconLabel, LV_ALIGN_TOP_RIGHT, 0, labelsPositionTopStatusbar -1); + lv_obj_set_style_text_font(BattIconLabel, &lv_font_montserrat_16, LV_PART_MAIN); } +static bool waitOneLoop = false; void gui_loop(void) { + // after the sliding animation ended, we have to wait one cycle of gui_loop() before we can do the recreation of the tabs + if (waitBeforeActionAfterSlidingAnimationEnded) { + waitOneLoop = true; + waitBeforeActionAfterSlidingAnimationEnded = false; + } else if (waitOneLoop) { + waitOneLoop = false; + guis_doAfterSliding(oldTabID, currentTabID); + }; + // // as alternative, we could wait some milliseconds. But one cycle of gui_loop() works well. + // if (waitBeforeActionAfterSlidingAnimationEnded) { + // if (millis() - waitBeforeActionAfterSlidingAnimationEnded_timerStart >= 5) { + // guis_doAfterSliding(oldTabID, currentTabID); + // waitBeforeActionAfterSlidingAnimationEnded = false; + // } + // } + lv_timer_handler(); } + +void guis_doTabCreationAtStartup() { + gui_memoryOptimizer_prepare_startup(); + + guis_doAfterSliding(-1, -1); +} + +void guis_doAfterSliding(int oldTabID, int newTabID) { + gui_memoryOptimizer_doAfterSliding_deletionAndCreation(&tabview, oldTabID, newTabID, &panel, &img1, &img2); + + doLogMemoryUsage(); +} + +void setActiveTab(uint32_t index, lv_anim_enable_t anim_en) { + // unsigned long startTime = millis(); + if (anim_en == LV_ANIM_ON) { + lv_tabview_set_act(tabview, index, LV_ANIM_ON); + // startTime = millis(); + // while (millis() - startTime < 1000) { + // lv_timer_handler(); + // } + } else { + lv_tabview_set_act(tabview, index, LV_ANIM_OFF); + // lv_timer_handler(); + // log_memory(); + } +} diff --git a/Platformio/src/gui_general_and_keys/guiBase.h b/Platformio/src/gui_general_and_keys/guiBase.h index fa8de52..6d7621e 100644 --- a/Platformio/src/gui_general_and_keys/guiBase.h +++ b/Platformio/src/gui_general_and_keys/guiBase.h @@ -4,20 +4,45 @@ #include #include "../hardware/tft.h" +// ----------------------- +// https://docs.lvgl.io/8.3/porting/display.html?highlight=lv_disp_draw_buf_init#buffering-modes +// With two buffers, the rendering and refreshing of the display become parallel operations +// Second buffer needs 15.360 bytes more memory in heap. +#define useTwoBuffersForlvgl + // LVGL declarations LV_IMG_DECLARE(high_brightness); LV_IMG_DECLARE(low_brightness); -extern lv_obj_t* objBattPercentage; -extern lv_obj_t* objBattIcon; -extern lv_obj_t* SceneLabel; -extern lv_color_t color_primary; - +extern lv_obj_t* MemoryUsageLabel; extern lv_obj_t* WifiLabel; extern lv_obj_t* BluetoothLabel; +extern lv_obj_t* SceneLabel; +extern lv_obj_t* BattPercentageLabel; +extern lv_obj_t* BattIconLabel; -extern byte currentScreen; // Current screen that is shown +//#define drawRedBorderAroundMainWidgets +#ifdef drawRedBorderAroundMainWidgets +extern lv_style_t style_red_border; +#endif +extern lv_style_t panel_style; +extern int tabviewTop; +extern int tabviewHeight; +extern int panelHeight; + +extern lv_color_t color_primary; + +extern uint32_t currentTabID; void init_gui(void); void gui_loop(void); +void tabview_content_is_scrolling_event_cb(lv_event_t* e); +void tabview_tab_changed_event_cb(lv_event_t* e); + +void guis_doTabCreationAtStartup(); +void guis_doAfterSliding(int oldTabID, int newTabID); +void setActiveTab(uint32_t index, lv_anim_enable_t anim_en); + +void showMemoryUsageBar(bool showBar); + #endif /*__GUIBASE_H__*/ diff --git a/Platformio/src/gui_general_and_keys/guiMemoryOptimizer.cpp b/Platformio/src/gui_general_and_keys/guiMemoryOptimizer.cpp new file mode 100644 index 0000000..435878c --- /dev/null +++ b/Platformio/src/gui_general_and_keys/guiMemoryOptimizer.cpp @@ -0,0 +1,404 @@ +#include +#include +#include "gui_general_and_keys/guiRegistry.h" +#include "gui_general_and_keys/guiBase.h" + +struct tab_in_memory { + lv_obj_t* tab; + int listIndex; +}; +tab_in_memory tabs_in_memory[3] = {{NULL, -1}, {NULL, -1}, {NULL, -1}}; +int tabs_in_memory_previous_listIndex[3]= {-1 , -1, -1}; + +void notify_active_tabs_before_delete() { + Serial.printf(" Will notify tabs about deletion\r\n"); + std::string nameOfTab; + for (int index=0; index <= 2; index++) { + if (tabs_in_memory[index].listIndex == -1) { + Serial.printf(" Will not notify tab %d about deletion because it does not exist\r\n", index); + continue; + } + + nameOfTab = list_of_guis_to_be_shown.at(tabs_in_memory[index].listIndex); + if (nameOfTab == "") { + Serial.printf(" Will not notify tab %d about deletion because it is not set\r\n", index); + } else if (registered_guis_byName_map.count(nameOfTab) == 0) { + Serial.printf(" Can not notify tab %d about deletion because name \"%s\" was not found in registry\r\n", index, nameOfTab.c_str()); + } else { + Serial.printf(" Will notify tab %d with name \"%s\" about deletion\r\n", index, nameOfTab.c_str()); + registered_guis_byName_map.at(nameOfTab).this_notify_tab_before_delete(); + } + } +} + +void clear_tabview(lv_obj_t* tabview) { + if (tabview != NULL) { + // first remove events for the tabview + lv_obj_remove_event_cb(tabview, tabview_tab_changed_event_cb); + lv_obj_remove_event_cb(tabview, tabview_content_is_scrolling_event_cb); + // delete tabview + lv_obj_del(tabview); + tabview = NULL; + } + + // set struct tabs_in_memory to NULL + tabs_in_memory[0] = {NULL, -1}; + tabs_in_memory[1] = {NULL, -1}; + tabs_in_memory[2] = {NULL, -1}; + +} + +void clear_panel(lv_obj_t* panel, lv_obj_t* img1, lv_obj_t* img2) { + if (panel != NULL) { + lv_obj_del(panel); + panel = NULL; + } + if (img1 != NULL) { + lv_obj_del(img1); + img1 = NULL; + } + if (img2 != NULL) { + lv_obj_del(img2); + img2 = NULL; + } + +} + +lv_obj_t* create_tabview() { + // Setup a scrollable tabview for devices and settings ---------------------------------------------------- + lv_obj_t* tabview = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, 0); // Hide tab labels by setting their height to 0 + #ifdef drawRedBorderAroundMainWidgets + lv_obj_add_style(tabview, &style_red_border, LV_PART_MAIN); + #endif + lv_obj_set_style_bg_color(tabview, lv_color_black(), LV_PART_MAIN); + lv_obj_set_size(tabview, screenWidth, tabviewHeight); + lv_obj_align(tabview, LV_ALIGN_TOP_MID, 0, tabviewTop); + return tabview; +} + +lv_obj_t* create_panel() { + // Create a page indicator at the bottom ------------------------------------------------------------------ + lv_obj_t* panel = lv_obj_create(lv_scr_act()); + lv_obj_clear_flag(panel, LV_OBJ_FLAG_CLICKABLE); // This indicator will not be clickable + lv_obj_set_size(panel, screenWidth, panelHeight); + lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_ROW); + lv_obj_align(panel, LV_ALIGN_BOTTOM_MID, 0, 0); + lv_obj_set_scrollbar_mode(panel, LV_SCROLLBAR_MODE_OFF); + + return panel; +} + +std::string get_name_of_gui_to_be_shown(int index) { + if (index == -1) { + return ""; + } else if (index <= list_of_guis_to_be_shown.size() -1) { + return list_of_guis_to_be_shown.at(index); + } else { + return ""; + } +} + +void create_new_tab(lv_obj_t* tabview, uint32_t tabs_in_memory_index) { + std::string nameOfTab = get_name_of_gui_to_be_shown(tabs_in_memory[tabs_in_memory_index].listIndex); + + if (nameOfTab == "") { + Serial.printf(" Will not create new tab at index %d because no name was provided\r\n", tabs_in_memory_index); + } else if (registered_guis_byName_map.count(nameOfTab) == 0) { + Serial.printf(" Will not create new tab at index %d because name %s was not found in registry\r\n", tabs_in_memory_index, nameOfTab.c_str()); + } else { + Serial.printf(" Will create tab with name \"%s\" at index %d\r\n", nameOfTab.c_str(), tabs_in_memory_index); + // create tab and save pointer to tab in tabs_in_memory + tabs_in_memory[tabs_in_memory_index].tab = lv_tabview_add_tab(tabview, nameOfTab.c_str()); + // let the gui create it's content + registered_guis_byName_map.at(nameOfTab).this_create_tab_content(tabs_in_memory[tabs_in_memory_index].tab); + } +} + +void doTabCreation_strategyMax3(lv_obj_t* tabview, uint32_t oldTabID, uint32_t newTabID) { + // create up to three tabs and the content of the tabs + /* + example: list_of_guis_to_be_shown: 0 1 2 3 4 + in memory active + 0 1 -1 0 <- first state, special case - also the initial state + 0 1 2 1 + 1 2 3 1 + 2 3 4 1 + 3 4 -1 1 <- last state, special case + */ + + int tabToBeActivated = -1; + int oldListIndex = -1; + + if ((oldTabID == -1) && (newTabID == -1)) { + // This is the initialization after the ESP32 has booted. + + if ((tabs_in_memory_previous_listIndex[0] < list_of_guis_to_be_shown.size()) && (tabs_in_memory_previous_listIndex[0] != -1)) { + // In gui_memoryOptimizer_prepare_startup, the index of currentGUIname in list_of_guis_to_be_shown was saved, if found. + // We can resume at this old state. + oldListIndex = tabs_in_memory_previous_listIndex[0] ; + if (oldListIndex == 0) { + // first state + Serial.printf(" Startup: will resume where we went to sleep with \"first state\"\r\n"); + tabs_in_memory[0] = {NULL, 0}; + // take care if there is only one gui in list + tabs_in_memory[1] = {NULL, list_of_guis_to_be_shown.size() >= 2 ? 1 : -1}; + tabs_in_memory[2] = {NULL, -1}; + tabToBeActivated = 0; + } else if (oldListIndex == list_of_guis_to_be_shown.size() -1) { + // last state + Serial.printf(" Startup: will resume where we went to sleep with \"last state\"\r\n"); + tabs_in_memory[0] = {NULL, oldListIndex -1}; + tabs_in_memory[1] = {NULL, oldListIndex}; + tabs_in_memory[2] = {NULL, -1}; + tabToBeActivated = 1; + } else { + // any other state + Serial.printf(" Startup: will resume where we went to sleep with \"state between\"\r\n"); + tabs_in_memory[0] = {NULL, oldListIndex -1}; + tabs_in_memory[1] = {NULL, oldListIndex}; + tabs_in_memory[2] = {NULL, oldListIndex +1}; + tabToBeActivated = 1; + } + } else { + Serial.printf(" Startup: cannot resume old state, so we will show the first tabs from \"list_of_guis_to_be_shown\" as initial state\r\n"); + // take care if there is no gui in list + tabs_in_memory[0] = {NULL, list_of_guis_to_be_shown.size() != 0 ? 0 : -1}; + // take care if there is only one gui in list + tabs_in_memory[1] = {NULL, list_of_guis_to_be_shown.size() >= 2 ? 1 : -1}; + tabs_in_memory[2] = {NULL, -1}; + tabToBeActivated = 0; + } + } else if (oldTabID > newTabID) { + // swipe to previous item in list + Serial.printf(" Will swipe to previous item in list\r\n"); + oldListIndex = tabs_in_memory_previous_listIndex[1]; + if ((oldListIndex == 1)) { + // next state is the "first state" + tabs_in_memory[0] = {NULL, 0}; + tabs_in_memory[1] = {NULL, 1}; + tabs_in_memory[2] = {NULL, -1}; + tabToBeActivated = 0; + } else { + tabs_in_memory[0] = {NULL, oldListIndex -2}; + tabs_in_memory[1] = {NULL, oldListIndex -1}; + tabs_in_memory[2] = {NULL, oldListIndex}; + tabToBeActivated = 1; + } + } else { + // swipe to next item in list + Serial.printf(" Will swipe to next item in list\r\n"); + if (tabs_in_memory_previous_listIndex[2] == -1) { + // last state was the first state + oldListIndex = tabs_in_memory_previous_listIndex[0]; // is always 0 + } else { + oldListIndex = tabs_in_memory_previous_listIndex[1]; + } + if (oldListIndex == list_of_guis_to_be_shown.size() -2) { + // next state is the "last state" + tabs_in_memory[0] = {NULL, oldListIndex}; + tabs_in_memory[1] = {NULL, oldListIndex +1}; + tabs_in_memory[2] = {NULL, -1}; + tabToBeActivated = 1; + } else { + tabs_in_memory[0] = {NULL, oldListIndex}; + tabs_in_memory[1] = {NULL, oldListIndex +1}; + tabs_in_memory[2] = {NULL, oldListIndex +2}; + tabToBeActivated = 1; + } + } + + // create the tabs + Serial.printf(" Will create tabs. List indices of the three tabs are %d, %d, %d, tab nr %d will be activated\r\n", tabs_in_memory[0].listIndex, tabs_in_memory[1].listIndex, tabs_in_memory[2].listIndex, tabToBeActivated); + for (int i=0; i<3; i++) { + create_new_tab(tabview, i); + } + + if (list_of_guis_to_be_shown.size() > 0) { + std::string nameOfNewActiveTab = list_of_guis_to_be_shown.at(tabs_in_memory[tabToBeActivated].listIndex); + Serial.printf(" New visible tab is \"%s\"\r\n", nameOfNewActiveTab.c_str()); + + // set the tab we swiped to as active + setActiveTab(tabToBeActivated, LV_ANIM_OFF); + currentGUIname = nameOfNewActiveTab; + currentTabID = tabToBeActivated; + } +} + +LV_IMG_DECLARE(gradientLeft); +LV_IMG_DECLARE(gradientRight); + +void fillPanelWithPageIndicator_strategyMax3(lv_obj_t* panel, lv_obj_t* img1, lv_obj_t* img2) { + Serial.printf(" Will fill panel with page indicators\r\n"); + + if (list_of_guis_to_be_shown.size() == 0) { + Serial.printf(" no tab available, so no page indicators\r\n"); + // at least add the style + lv_obj_add_style(panel, &panel_style, 0); + #ifdef drawRedBorderAroundMainWidgets + lv_obj_add_style(panel, &style_red_border, LV_PART_MAIN); + #endif + return; + } + + // This small hidden button enables the page indicator to scroll further + lv_obj_t* btn = lv_btn_create(panel); + lv_obj_set_size(btn, 50, lv_pct(100)); + lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); + lv_obj_set_style_opa(btn, LV_OPA_TRANSP, LV_PART_MAIN); + +/* + There needs to be two more screen indicators because of their different size (158 for page indicator, 240 for whole tab) + In some cases they need to have color black, if they are before the first tab or after the last tab. + In all other cases, they have color "color_primary". See this list: + example: list_of_guis_to_be_shown: 0 1 2 3 4 + in memory color active + 0 1 -1 b p p p 0 <- first state, special case - also the initial state + 0 1 2 b p p p p 1 + 1 2 3 p p p p p 1 + 2 3 4 p p p p b 1 + 3 4 -1 p p p b 1 <- last state, special case +*/ + // first page indicator before the first tab + btn = lv_btn_create(panel); + lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_size(btn, 150, lv_pct(100)); + if (tabs_in_memory[0].listIndex == 0) { + lv_obj_set_style_bg_color(btn, lv_color_black(), LV_PART_MAIN); + } else { + lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); + } + + // create the panel content for the three guis (or less) which are currently in memory + std::string nameOfTab; + for (int i=0; i<3; i++) { + if (tabs_in_memory[i].listIndex != -1) { + nameOfTab = get_name_of_gui_to_be_shown(tabs_in_memory[i].listIndex); + + // Create actual (non-clickable) buttons for every tab + lv_obj_t* btn = lv_btn_create(panel); + lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_size(btn, 150, lv_pct(100)); + lv_obj_t* label = lv_label_create(btn); + lv_label_set_text_fmt(label, nameOfTab.c_str()); + lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); + lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); + } + } + + // last page indicator after the last tab + btn = lv_btn_create(panel); + lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_size(btn, 150, lv_pct(100)); + // 4 at last position 4 at middle position only one tab available overall + if ((tabs_in_memory[2].listIndex == list_of_guis_to_be_shown.size()-1) || (tabs_in_memory[1].listIndex == list_of_guis_to_be_shown.size()-1) || (tabs_in_memory[1].listIndex == -1)) { + lv_obj_set_style_bg_color(btn, lv_color_black(), LV_PART_MAIN); + } else { + lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); + } + + // This small hidden button enables the page indicator to scroll further + btn = lv_btn_create(panel); + lv_obj_set_size(btn, 50, lv_pct(100)); + lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); + lv_obj_set_style_opa(btn, LV_OPA_TRANSP, LV_PART_MAIN); + + // creation of style was moved to init_gui(void) + // otherwise repeated calls of lv_style_init will lead to a memory leak of about 46 bytes each time + // https://docs.lvgl.io/8.3/overview/style.html?highlight=lv_style_t#initialize-styles-and-set-get-properties + lv_obj_add_style(panel, &panel_style, 0); + #ifdef drawRedBorderAroundMainWidgets + lv_obj_add_style(panel, &style_red_border, LV_PART_MAIN); + #endif + + // Make the indicator fade out at the sides using gradient bitmaps + // Bitmaps are above the buttons and labels + // don't create it here + // img1 = lv_img_create(lv_scr_act()); + lv_img_set_src(img1, &gradientLeft); + lv_obj_align(img1, LV_ALIGN_BOTTOM_LEFT, 0, 0); + lv_obj_set_size(img1, panelHeight, panelHeight); // stretch the 1-pixel high image to 30px + #ifdef drawRedBorderAroundMainWidgets + lv_obj_add_style(img1, &style_red_border, LV_PART_MAIN); + #endif + // don't create it here + // img2 = lv_img_create(lv_scr_act()); + lv_img_set_src(img2, &gradientRight); + lv_obj_align(img2, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + lv_obj_set_size(img2, panelHeight, panelHeight); + #ifdef drawRedBorderAroundMainWidgets + lv_obj_add_style(img2, &style_red_border, LV_PART_MAIN); + #endif + +} + +void gui_memoryOptimizer_prepare_startup() { + // find index of currentGUIname in list_of_guis_to_be_shown + for (int i=0; i +#include #include #include +#include #include #include "guiRegistry.h" +#include "gui_general_and_keys/guiBase.h" -// https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work -struct gui_definition { - init_gui_tab this_init_gui_tab; - init_gui_pageIndicator this_init_gui_pageIndicator; -}; +// ------------------------------------------------------------------------------------ +// this is a map of the registered_guis that can be accessed by name +std::map registered_guis_byName_map; +// This is the list of the guis that we want to be available when swiping. Need not to be all the guis that have been registered, can be only a subset. +// You can swipe through these guis. Will be in the order you place them here in the vector. +std::vector list_of_guis_to_be_shown; +std::string currentGUIname = ""; -std::list registered_guis; +// ------------------------------------------------------------------------------------ -void register_gui(init_gui_tab a_init_gui_tab, init_gui_pageIndicator a_gui_pageIndicator) { - registered_guis.push_back(gui_definition{a_init_gui_tab, a_gui_pageIndicator}); -} - -void create_gui_tabs_from_gui_registry(lv_obj_t* tabview) { - std::list::iterator it; - for (it = registered_guis.begin(); it != registered_guis.end(); ++it) { - it->this_init_gui_tab(tabview); +void register_gui(std::string a_name, create_tab_content a_create_tab_content, notify_tab_before_delete a_notify_tab_before_delete) { + + if (registered_guis_byName_map.count(a_name) > 0) { + Serial.printf("ERROR!!!: you cannot register two guis having the same name '%s'\r\n", a_name.c_str()); + return; } -} -void create_gui_pageIndicators_from_gui_registry(lv_obj_t* panel) { - std::list::iterator it; - for (it = registered_guis.begin(); it != registered_guis.end(); ++it) { - it->this_init_gui_pageIndicator(panel); - } + gui_definition new_gui_definition = gui_definition{a_name, a_create_tab_content, a_notify_tab_before_delete}; + + // put the gui_definition in a map that can be accessed by name + registered_guis_byName_map[a_name] = new_gui_definition; + + // By default, put all registered guis in the sequence of guis to be shown + // Later we will have scene specific sequences of guis + list_of_guis_to_be_shown.insert(list_of_guis_to_be_shown.end(), {std::string(a_name)}); + } diff --git a/Platformio/src/gui_general_and_keys/guiRegistry.h b/Platformio/src/gui_general_and_keys/guiRegistry.h index f2f22b1..2007fba 100644 --- a/Platformio/src/gui_general_and_keys/guiRegistry.h +++ b/Platformio/src/gui_general_and_keys/guiRegistry.h @@ -2,7 +2,7 @@ #define __GUIREGISTRY_H__ /* - If you want to create a new GUI for the touch screen, then + If you want to create a new GUI (tab in terms of lvgl) for the touch screen, then - copy one of the existing GUIs, e.g. gui_numpad.cpp and gui_numpad.h - place the files in the right folder: - in folder "gui_general_and_keys" if they are of general purpose, not only for a specific device @@ -12,18 +12,34 @@ - rename the functions, they must not have the same name as the ones in the file you copied from - call "register_gui_();" in main.cpp - Technically spoken, to register a GUI, you need to provide two function pointers: - - one for creating the tab - - one for creating the page indicator at the bottom of the tab + register_gui(std::string(tabName), & create_tab_content_settings, & notify_tab_before_delete_settings); + + Technically spoken, to register a GUI, you need to provide several function pointers: + - one for creating the content of the tab + - one to persist the state of the gui before it will be deleted, if needed + - and the name of the tab */ #include +#include +#include #include -typedef void (*init_gui_tab)(lv_obj_t* tabview); -typedef void (*init_gui_pageIndicator)(lv_obj_t* tabview); +typedef void (*create_tab_content)(lv_obj_t* tab); +typedef void (*notify_tab_before_delete)(void); -void register_gui(init_gui_tab a_init_gui_tab, init_gui_pageIndicator a_gui_pageIndicator); -void create_gui_tabs_from_gui_registry(lv_obj_t* tabview); -void create_gui_pageIndicators_from_gui_registry(lv_obj_t* panel); +// https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work +struct gui_definition { + std::string this_name; + create_tab_content this_create_tab_content; + notify_tab_before_delete this_notify_tab_before_delete; + uint32_t this_tabID; + lv_obj_t* this_tab; +}; + +extern std::map registered_guis_byName_map; +extern std::vector list_of_guis_to_be_shown; +extern std::string currentGUIname; + +void register_gui(std::string a_name, create_tab_content a_create_tab_content, notify_tab_before_delete a_notify_tab_before_delete); #endif /*__GUIREGISTRY_H__*/ diff --git a/Platformio/src/gui_general_and_keys/gui_irReceiver.cpp b/Platformio/src/gui_general_and_keys/gui_irReceiver.cpp index c2fae2f..da1710e 100644 --- a/Platformio/src/gui_general_and_keys/gui_irReceiver.cpp +++ b/Platformio/src/gui_general_and_keys/gui_irReceiver.cpp @@ -6,6 +6,7 @@ #include "hardware/infrared_receiver.h" #include "gui_general_and_keys/guiBase.h" #include "gui_general_and_keys/guiRegistry.h" +#include "gui_general_and_keys/gui_irReceiver.h" lv_obj_t* menuBoxToggle; lv_obj_t* menuBoxMessages; @@ -65,7 +66,7 @@ void showNewIRmessage(String message) { } // IR receiver on Switch Event handler -static void IRReceiverOnSetting_event_cb(lv_event_t * e){ +static void IRReceiverOnSetting_event_cb(lv_event_t* e){ irReceiverEnabled = lv_obj_has_state(lv_event_get_target(e), LV_STATE_CHECKED); if (irReceiverEnabled) { Serial.println("will turn on IR receiver"); @@ -83,11 +84,9 @@ static void IRReceiverOnSetting_event_cb(lv_event_t * e){ } } -void init_gui_tab_irReceiver(lv_obj_t* tabview) { +void create_tab_content_irReceiver(lv_obj_t* tab) { - lv_obj_t* tab = lv_tabview_add_tab(tabview, "IR Receiver"); - - // Add content to the settings tab + // Add content to the irReceiver tab // With a flex layout, setting groups/boxes will position themselves automatically lv_obj_set_layout(tab, LV_LAYOUT_FLEX); lv_obj_set_flex_flow(tab, LV_FLEX_FLOW_COLUMN); @@ -120,20 +119,15 @@ void init_gui_tab_irReceiver(lv_obj_t* tabview) { lv_obj_align(irReceivedMessage[i], LV_ALIGN_TOP_LEFT, 0, 0 + i*11); } printReceivedMessages(true); + } -void init_gui_pageIndicator_irReceiver(lv_obj_t* panel) { - // Create actual (non-clickable) buttons for every tab - lv_obj_t* btn = lv_btn_create(panel); - lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); - lv_obj_set_size(btn, 150, lv_pct(100)); - lv_obj_t* label = lv_label_create(btn); - lv_label_set_text_fmt(label, "IR Receiver"); - lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); - lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); +void notify_tab_before_delete_irReceiver(void) { + // remember to set all pointers to lvgl objects to NULL if they might be accessed from outside. + // They must check if object is NULL and must not use it if so + } void register_gui_irReceiver(void){ - register_gui(& init_gui_tab_irReceiver, & init_gui_pageIndicator_irReceiver); + register_gui(std::string(tabName_irReceiver), & create_tab_content_irReceiver, & notify_tab_before_delete_irReceiver); } diff --git a/Platformio/src/gui_general_and_keys/gui_irReceiver.h b/Platformio/src/gui_general_and_keys/gui_irReceiver.h index 7320235..830a517 100644 --- a/Platformio/src/gui_general_and_keys/gui_irReceiver.h +++ b/Platformio/src/gui_general_and_keys/gui_irReceiver.h @@ -4,6 +4,7 @@ #include #include +const char * const tabName_irReceiver = "IR Receiver"; void register_gui_irReceiver(void); void showNewIRmessage(String); diff --git a/Platformio/src/gui_general_and_keys/gui_numpad.cpp b/Platformio/src/gui_general_and_keys/gui_numpad.cpp index 6fbedc3..dbdb68d 100644 --- a/Platformio/src/gui_general_and_keys/gui_numpad.cpp +++ b/Platformio/src/gui_general_and_keys/gui_numpad.cpp @@ -3,6 +3,7 @@ #include "device_samsungTV/device_samsungTV.h" #include "gui_general_and_keys/guiBase.h" #include "gui_general_and_keys/guiRegistry.h" +#include "gui_general_and_keys/gui_numpad.h" #include "commandHandler.h" #include "scenes/sceneHandler.h" #include "scenes/scene_TV.h" @@ -28,9 +29,7 @@ static void virtualKeypad_event_cb(lv_event_t* e) { } } -void init_gui_tab_numpad(lv_obj_t* tabview) { - - lv_obj_t* tab = lv_tabview_add_tab(tabview, "Numpad"); +void create_tab_content_numpad(lv_obj_t* tab) { // Configure number button grid static lv_coord_t col_dsc[] = { LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST }; // equal x distribution @@ -79,23 +78,15 @@ void init_gui_tab_numpad(lv_obj_t* tabview) { } // Create a shared event for all button inside container lv_obj_add_event_cb(cont, virtualKeypad_event_cb, LV_EVENT_CLICKED, NULL); - } -void init_gui_pageIndicator_numpad(lv_obj_t* panel) { - // Create actual (non-clickable) buttons for every tab - lv_obj_t* btn = lv_btn_create(panel); - lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); - lv_obj_set_size(btn, 150, lv_pct(100)); - lv_obj_t* label = lv_label_create(btn); - lv_label_set_text_fmt(label, "Numpad"); - lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); - lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); +void notify_tab_before_delete_numpad(void) { + // remember to set all pointers to lvgl objects to NULL if they might be accessed from outside. + // They must check if object is NULL and must not use it if so } void register_gui_numpad(void){ - register_gui(& init_gui_tab_numpad, & init_gui_pageIndicator_numpad); + register_gui(std::string(tabName_numpad), & create_tab_content_numpad, & notify_tab_before_delete_numpad); } diff --git a/Platformio/src/gui_general_and_keys/gui_numpad.h b/Platformio/src/gui_general_and_keys/gui_numpad.h index 7cdb1af..7915f81 100644 --- a/Platformio/src/gui_general_and_keys/gui_numpad.h +++ b/Platformio/src/gui_general_and_keys/gui_numpad.h @@ -3,6 +3,7 @@ #include +const char * const tabName_numpad = "Numpad"; void register_gui_numpad(void); #endif /*__GUI_NUMPAD_H__*/ diff --git a/Platformio/src/gui_general_and_keys/gui_settings.cpp b/Platformio/src/gui_general_and_keys/gui_settings.cpp index 004e18c..e112fd4 100644 --- a/Platformio/src/gui_general_and_keys/gui_settings.cpp +++ b/Platformio/src/gui_general_and_keys/gui_settings.cpp @@ -2,26 +2,28 @@ #include "preferencesStorage.h" #include "hardware/tft.h" #include "hardware/sleep.h" +#include "hardware/memoryUsage.h" #include "gui_general_and_keys/guiBase.h" #include "gui_general_and_keys/guiRegistry.h" +#include "gui_general_and_keys/gui_settings.h" lv_obj_t* objBattSettingsVoltage; lv_obj_t* objBattSettingsPercentage; //lv_obj_t* objBattSettingsIscharging; // Slider Event handler -static void bl_slider_event_cb(lv_event_t * e){ +static void bl_slider_event_cb(lv_event_t* e){ lv_obj_t * slider = lv_event_get_target(e); backlight_brightness = constrain(lv_slider_get_value(slider), 60, 255); } // Wakeup by IMU Switch Event handler -static void WakeEnableSetting_event_cb(lv_event_t * e){ +static void WakeEnableSetting_event_cb(lv_event_t* e){ wakeupByIMUEnabled = lv_obj_has_state(lv_event_get_target(e), LV_STATE_CHECKED); } // timout event handler -static void timout_event_cb(lv_event_t * e){ +static void timout_event_cb(lv_event_t* e){ lv_obj_t * drop = lv_event_get_target(e); uint16_t selected = lv_dropdown_get_selected(drop); switch (selected) { @@ -39,10 +41,12 @@ static void timout_event_cb(lv_event_t * e){ save_preferences(); } -void init_gui_tab_settings(lv_obj_t* tabview) { - - lv_obj_t* tab = lv_tabview_add_tab(tabview, "Settings"); +// show memory usage event handler +static void showMemoryUsage_event_cb(lv_event_t* e) { + setShowMemoryUsage(lv_obj_has_state(lv_event_get_target(e), LV_STATE_CHECKED)); +} +void create_tab_content_settings(lv_obj_t* tab) { // Add content to the settings tab // With a flex layout, setting groups/boxes will position themselves automatically @@ -50,7 +54,7 @@ void init_gui_tab_settings(lv_obj_t* tabview) { lv_obj_set_flex_flow(tab, LV_FLEX_FLOW_COLUMN); lv_obj_set_scrollbar_mode(tab, LV_SCROLLBAR_MODE_ACTIVE); - // Add a label, then a box for the display settings + // Add a label, then a box for the display settings ----------------------------------------- lv_obj_t* menuLabel = lv_label_create(tab); lv_label_set_text(menuLabel, "Display"); @@ -87,7 +91,11 @@ void init_gui_tab_settings(lv_obj_t* tabview) { lv_obj_align(wakeToggle, LV_ALIGN_TOP_RIGHT, 0, 29); lv_obj_set_style_bg_color(wakeToggle, lv_color_hex(0x505050), LV_PART_MAIN); lv_obj_add_event_cb(wakeToggle, WakeEnableSetting_event_cb, LV_EVENT_VALUE_CHANGED, NULL); - if(wakeupByIMUEnabled) lv_obj_add_state(wakeToggle, LV_STATE_CHECKED); // set default state + if (wakeupByIMUEnabled) { + lv_obj_add_state(wakeToggle, LV_STATE_CHECKED); + } else { + // lv_obj_clear_state(wakeToggle, LV_STATE_CHECKED); + } menuLabel = lv_label_create(menuBox); lv_label_set_text(menuLabel, "Timeout"); @@ -141,7 +149,7 @@ void init_gui_tab_settings(lv_obj_t* tabview) { // lv_label_set_text(menuLabel, LV_SYMBOL_RIGHT); // lv_obj_align(menuLabel, LV_ALIGN_TOP_RIGHT, 0, 32); - // Another setting for the battery + // Another setting for the battery ---------------------------------------------------------- menuLabel = lv_label_create(tab); lv_label_set_text(menuLabel, "Battery"); menuBox = lv_obj_create(tab); @@ -158,21 +166,38 @@ void init_gui_tab_settings(lv_obj_t* tabview) { // objBattSettingsIscharging = lv_label_create(menuBox); // lv_label_set_text(objBattSettingsIscharging, "Is charging:"); // lv_obj_align(objBattSettingsIscharging, LV_ALIGN_TOP_LEFT, 0, 64); + + + // Memory statistics ------------------------------------------------------------------------ + menuLabel = lv_label_create(tab); + lv_label_set_text(menuLabel, "Memory usage"); + menuBox = lv_obj_create(tab); + lv_obj_set_size(menuBox, lv_pct(100), 48); + lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN); + lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN); + + menuLabel = lv_label_create(menuBox); + lv_label_set_text(menuLabel, "Show mem usage"); + lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 3); + lv_obj_t* memoryUsageToggle = lv_switch_create(menuBox); + lv_obj_set_size(memoryUsageToggle, 40, 22); + lv_obj_align(memoryUsageToggle, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_obj_set_style_bg_color(memoryUsageToggle, lv_color_hex(0x505050), LV_PART_MAIN); + lv_obj_add_event_cb(memoryUsageToggle, showMemoryUsage_event_cb, LV_EVENT_VALUE_CHANGED, NULL); + if (getShowMemoryUsage()) { + lv_obj_add_state(memoryUsageToggle, LV_STATE_CHECKED); + } else { + // lv_obj_clear_state(memoryUsageToggle, LV_STATE_CHECKED); + } } -void init_gui_pageIndicator_settings(lv_obj_t* panel) { - // Create actual (non-clickable) buttons for every tab - lv_obj_t* btn = lv_btn_create(panel); - lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); - lv_obj_set_size(btn, 150, lv_pct(100)); - lv_obj_t* label = lv_label_create(btn); - lv_label_set_text_fmt(label, "Settings"); - lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); - lv_obj_set_style_bg_color(btn, color_primary, LV_PART_MAIN); - +void notify_tab_before_delete_settings(void) { + // remember to set all pointers to lvgl objects to NULL if they might be accessed from outside. + // They must check if object is NULL and must not use it if so + objBattSettingsVoltage = NULL; + objBattSettingsPercentage = NULL; } void register_gui_settings(void){ - register_gui(& init_gui_tab_settings, & init_gui_pageIndicator_settings); + register_gui(std::string(tabName_settings), & create_tab_content_settings, & notify_tab_before_delete_settings); } diff --git a/Platformio/src/gui_general_and_keys/gui_settings.h b/Platformio/src/gui_general_and_keys/gui_settings.h index 94918bf..69f5f0f 100644 --- a/Platformio/src/gui_general_and_keys/gui_settings.h +++ b/Platformio/src/gui_general_and_keys/gui_settings.h @@ -7,6 +7,7 @@ extern lv_obj_t* objBattSettingsVoltage; extern lv_obj_t* objBattSettingsPercentage; //extern lv_obj_t* objBattSettingsIscharging; +const char * const tabName_settings = "Settings"; void register_gui_settings(void); #endif /*__GUI_SETTINGS_H__*/ diff --git a/Platformio/src/gui_general_and_keys/lv_conf.h b/Platformio/src/gui_general_and_keys/lv_conf.h deleted file mode 100644 index 60127fd..0000000 --- a/Platformio/src/gui_general_and_keys/lv_conf.h +++ /dev/null @@ -1,762 +0,0 @@ -/** - * @file lv_conf.h - * Configuration file for v8.3.5 - */ - -/* - * Copy this file as `lv_conf.h` - * 1. simply next to the `lvgl` folder - * 2. or any other places and - * - define `LV_CONF_INCLUDE_SIMPLE` - * - add the path as include path - */ - -/* clang-format off */ -#if 1 /*Set it to "1" to enable content*/ - -#ifndef LV_CONF_H -#define LV_CONF_H - -#include - -/*==================== - COLOR SETTINGS - *====================*/ - -/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/ -#define LV_COLOR_DEPTH 16 - -/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/ -#define LV_COLOR_16_SWAP 0 - -/*Enable features to draw on transparent background. - *It's required if opa, and transform_* style properties are used. - *Can be also used if the UI is above another layer, e.g. an OSD menu or video player.*/ -#define LV_COLOR_SCREEN_TRANSP 0 - -/* Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently. - * 0: round down, 64: round up from x.75, 128: round up from half, 192: round up from x.25, 254: round up */ -#define LV_COLOR_MIX_ROUND_OFS 0 - -/*Images pixels with this color will not be drawn if they are chroma keyed)*/ -#define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) /*pure green*/ - -/*========================= - MEMORY SETTINGS - *=========================*/ - -/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/ -#define LV_MEM_CUSTOM 0 -#if LV_MEM_CUSTOM == 0 - /*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/ - #define LV_MEM_SIZE (48U * 1024U) /*[bytes]*/ - - /*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/ - #define LV_MEM_ADR 0 /*0: unused*/ - /*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/ - #if LV_MEM_ADR == 0 - #undef LV_MEM_POOL_INCLUDE - #undef LV_MEM_POOL_ALLOC - #endif - -#else /*LV_MEM_CUSTOM*/ - #define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ - #define LV_MEM_CUSTOM_ALLOC malloc - #define LV_MEM_CUSTOM_FREE free - #define LV_MEM_CUSTOM_REALLOC realloc -#endif /*LV_MEM_CUSTOM*/ - -/*Number of the intermediate memory buffer used during rendering and other internal processing mechanisms. - *You will see an error log message if there wasn't enough buffers. */ -#define LV_MEM_BUF_MAX_NUM 16 - -/*Use the standard `memcpy` and `memset` instead of LVGL's own functions. (Might or might not be faster).*/ -#define LV_MEMCPY_MEMSET_STD 0 - -/*==================== - HAL SETTINGS - *====================*/ - -/*Default display refresh period. LVG will redraw changed areas with this period time*/ -#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/ - -/*Input device read period in milliseconds*/ -#define LV_INDEV_DEF_READ_PERIOD 30 /*[ms]*/ - -/*Use a custom tick source that tells the elapsed time in milliseconds. - *It removes the need to manually update the tick with `lv_tick_inc()`)*/ -#define LV_TICK_CUSTOM 1 -#if LV_TICK_CUSTOM - #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ - #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ - /*If using lvgl as ESP32 component*/ - // #define LV_TICK_CUSTOM_INCLUDE "esp_timer.h" - // #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((esp_timer_get_time() / 1000LL)) -#endif /*LV_TICK_CUSTOM*/ - -/*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. - *(Not so important, you can adjust it to modify default sizes and spaces)*/ -#define LV_DPI_DEF 130 /*[px/inch]*/ - -/*======================= - * FEATURE CONFIGURATION - *=======================*/ - -/*------------- - * Drawing - *-----------*/ - -/*Enable complex draw engine. - *Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/ -#define LV_DRAW_COMPLEX 1 -#if LV_DRAW_COMPLEX != 0 - - /*Allow buffering some shadow calculation. - *LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius` - *Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/ - #define LV_SHADOW_CACHE_SIZE 0 - - /* Set number of maximally cached circle data. - * The circumference of 1/4 circle are saved for anti-aliasing - * radius * 4 bytes are used per circle (the most often used radiuses are saved) - * 0: to disable caching */ - #define LV_CIRCLE_CACHE_SIZE 4 -#endif /*LV_DRAW_COMPLEX*/ - -/** - * "Simple layers" are used when a widget has `style_opa < 255` to buffer the widget into a layer - * and blend it as an image with the given opacity. - * Note that `bg_opa`, `text_opa` etc don't require buffering into layer) - * The widget can be buffered in smaller chunks to avoid using large buffers. - * - * - LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate it - * - LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated. - * - * Both buffer sizes are in bytes. - * "Transformed layers" (where transform_angle/zoom properties are used) use larger buffers - * and can't be drawn in chunks. So these settings affects only widgets with opacity. - */ -#define LV_LAYER_SIMPLE_BUF_SIZE (24 * 1024) -#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE (3 * 1024) - -/*Default image cache size. Image caching keeps the images opened. - *If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added) - *With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images. - *However the opened images might consume additional RAM. - *0: to disable caching*/ -#define LV_IMG_CACHE_DEF_SIZE 0 - -/*Number of stops allowed per gradient. Increase this to allow more stops. - *This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/ -#define LV_GRADIENT_MAX_STOPS 2 - -/*Default gradient buffer size. - *When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again. - *LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes. - *If the cache is too small the map will be allocated only while it's required for the drawing. - *0 mean no caching.*/ -#define LV_GRAD_CACHE_DEF_SIZE 0 - -/*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display) - *LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface - *The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */ -#define LV_DITHER_GRADIENT 0 -#if LV_DITHER_GRADIENT - /*Add support for error diffusion dithering. - *Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing. - *The increase in memory consumption is (24 bits * object's width)*/ - #define LV_DITHER_ERROR_DIFFUSION 0 -#endif - -/*Maximum buffer size to allocate for rotation. - *Only used if software rotation is enabled in the display driver.*/ -#define LV_DISP_ROT_MAX_BUF (10*1024) - -/*------------- - * GPU - *-----------*/ - -/*Use Arm's 2D acceleration library Arm-2D */ -#define LV_USE_GPU_ARM2D 0 - -/*Use STM32's DMA2D (aka Chrom Art) GPU*/ -#define LV_USE_GPU_STM32_DMA2D 0 -#if LV_USE_GPU_STM32_DMA2D - /*Must be defined to include path of CMSIS header of target processor - e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ - #define LV_GPU_DMA2D_CMSIS_INCLUDE -#endif - -/*Use SWM341's DMA2D GPU*/ -#define LV_USE_GPU_SWM341_DMA2D 0 -#if LV_USE_GPU_SWM341_DMA2D - #define LV_GPU_SWM341_DMA2D_INCLUDE "SWM341.h" -#endif - -/*Use NXP's PXP GPU iMX RTxxx platforms*/ -#define LV_USE_GPU_NXP_PXP 0 -#if LV_USE_GPU_NXP_PXP - /*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c) - * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS - * has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected. - *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() - */ - #define LV_USE_GPU_NXP_PXP_AUTO_INIT 0 -#endif - -/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/ -#define LV_USE_GPU_NXP_VG_LITE 0 - -/*Use SDL renderer API*/ -#define LV_USE_GPU_SDL 0 -#if LV_USE_GPU_SDL - #define LV_GPU_SDL_INCLUDE_PATH - /*Texture cache size, 8MB by default*/ - #define LV_GPU_SDL_LRU_SIZE (1024 * 1024 * 8) - /*Custom blend mode for mask drawing, disable if you need to link with older SDL2 lib*/ - #define LV_GPU_SDL_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6)) -#endif - -/*------------- - * Logging - *-----------*/ - -/*Enable the log module*/ -#define LV_USE_LOG 0 -#if LV_USE_LOG - - /*How important log should be added: - *LV_LOG_LEVEL_TRACE A lot of logs to give detailed information - *LV_LOG_LEVEL_INFO Log important events - *LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem - *LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail - *LV_LOG_LEVEL_USER Only logs added by the user - *LV_LOG_LEVEL_NONE Do not log anything*/ - #define LV_LOG_LEVEL LV_LOG_LEVEL_WARN - - /*1: Print the log with 'printf'; - *0: User need to register a callback with `lv_log_register_print_cb()`*/ - #define LV_LOG_PRINTF 0 - - /*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/ - #define LV_LOG_TRACE_MEM 1 - #define LV_LOG_TRACE_TIMER 1 - #define LV_LOG_TRACE_INDEV 1 - #define LV_LOG_TRACE_DISP_REFR 1 - #define LV_LOG_TRACE_EVENT 1 - #define LV_LOG_TRACE_OBJ_CREATE 1 - #define LV_LOG_TRACE_LAYOUT 1 - #define LV_LOG_TRACE_ANIM 1 - -#endif /*LV_USE_LOG*/ - -/*------------- - * Asserts - *-----------*/ - -/*Enable asserts if an operation is failed or an invalid data is found. - *If LV_USE_LOG is enabled an error message will be printed on failure*/ -#define LV_USE_ASSERT_NULL 1 /*Check if the parameter is NULL. (Very fast, recommended)*/ -#define LV_USE_ASSERT_MALLOC 1 /*Checks is the memory is successfully allocated or no. (Very fast, recommended)*/ -#define LV_USE_ASSERT_STYLE 0 /*Check if the styles are properly initialized. (Very fast, recommended)*/ -#define LV_USE_ASSERT_MEM_INTEGRITY 0 /*Check the integrity of `lv_mem` after critical operations. (Slow)*/ -#define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/ - -/*Add a custom handler when assert happens e.g. to restart the MCU*/ -#define LV_ASSERT_HANDLER_INCLUDE -#define LV_ASSERT_HANDLER while(1); /*Halt by default*/ - -/*------------- - * Others - *-----------*/ - -/*1: Show CPU usage and FPS count*/ -#define LV_USE_PERF_MONITOR 0 -#if LV_USE_PERF_MONITOR - #define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT -#endif - -/*1: Show the used memory and the memory fragmentation - * Requires LV_MEM_CUSTOM = 0*/ -#define LV_USE_MEM_MONITOR 0 -#if LV_USE_MEM_MONITOR - #define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT -#endif - -/*1: Draw random colored rectangles over the redrawn areas*/ -#define LV_USE_REFR_DEBUG 0 - -/*Change the built in (v)snprintf functions*/ -#define LV_SPRINTF_CUSTOM 0 -#if LV_SPRINTF_CUSTOM - #define LV_SPRINTF_INCLUDE - #define lv_snprintf snprintf - #define lv_vsnprintf vsnprintf -#else /*LV_SPRINTF_CUSTOM*/ - #define LV_SPRINTF_USE_FLOAT 0 -#endif /*LV_SPRINTF_CUSTOM*/ - -#define LV_USE_USER_DATA 1 - -/*Garbage Collector settings - *Used if lvgl is bound to higher level language and the memory is managed by that language*/ -#define LV_ENABLE_GC 0 -#if LV_ENABLE_GC != 0 - #define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ -#endif /*LV_ENABLE_GC*/ - -/*===================== - * COMPILER SETTINGS - *====================*/ - -/*For big endian systems set to 1*/ -#define LV_BIG_ENDIAN_SYSTEM 0 - -/*Define a custom attribute to `lv_tick_inc` function*/ -#define LV_ATTRIBUTE_TICK_INC - -/*Define a custom attribute to `lv_timer_handler` function*/ -#define LV_ATTRIBUTE_TIMER_HANDLER - -/*Define a custom attribute to `lv_disp_flush_ready` function*/ -#define LV_ATTRIBUTE_FLUSH_READY - -/*Required alignment size for buffers*/ -#define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1 - -/*Will be added where memories needs to be aligned (with -Os data might not be aligned to boundary by default). - * E.g. __attribute__((aligned(4)))*/ -#define LV_ATTRIBUTE_MEM_ALIGN - -/*Attribute to mark large constant arrays for example font's bitmaps*/ -#define LV_ATTRIBUTE_LARGE_CONST - -/*Compiler prefix for a big array declaration in RAM*/ -#define LV_ATTRIBUTE_LARGE_RAM_ARRAY - -/*Place performance critical functions into a faster memory (e.g RAM)*/ -#define LV_ATTRIBUTE_FAST_MEM - -/*Prefix variables that are used in GPU accelerated operations, often these need to be placed in RAM sections that are DMA accessible*/ -#define LV_ATTRIBUTE_DMA - -/*Export integer constant to binding. This macro is used with constants in the form of LV_ that - *should also appear on LVGL binding API such as Micropython.*/ -#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /*The default value just prevents GCC warning*/ - -/*Extend the default -32k..32k coordinate range to -4M..4M by using int32_t for coordinates instead of int16_t*/ -#define LV_USE_LARGE_COORD 0 - -/*================== - * FONT USAGE - *===================*/ - -/*Montserrat fonts with ASCII range and some symbols using bpp = 4 - *https://fonts.google.com/specimen/Montserrat*/ -#define LV_FONT_MONTSERRAT_8 0 -#define LV_FONT_MONTSERRAT_10 1 -#define LV_FONT_MONTSERRAT_12 1 -#define LV_FONT_MONTSERRAT_14 1 -#define LV_FONT_MONTSERRAT_16 1 -#define LV_FONT_MONTSERRAT_18 0 -#define LV_FONT_MONTSERRAT_20 0 -#define LV_FONT_MONTSERRAT_22 0 -#define LV_FONT_MONTSERRAT_24 1 -#define LV_FONT_MONTSERRAT_26 0 -#define LV_FONT_MONTSERRAT_28 0 -#define LV_FONT_MONTSERRAT_30 0 -#define LV_FONT_MONTSERRAT_32 0 -#define LV_FONT_MONTSERRAT_34 0 -#define LV_FONT_MONTSERRAT_36 0 -#define LV_FONT_MONTSERRAT_38 0 -#define LV_FONT_MONTSERRAT_40 0 -#define LV_FONT_MONTSERRAT_42 0 -#define LV_FONT_MONTSERRAT_44 0 -#define LV_FONT_MONTSERRAT_46 0 -#define LV_FONT_MONTSERRAT_48 0 - -/*Demonstrate special features*/ -#define LV_FONT_MONTSERRAT_12_SUBPX 0 -#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/ -#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Persian letters and all their forms*/ -#define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/ - -/*Pixel perfect monospace fonts*/ -#define LV_FONT_UNSCII_8 0 -#define LV_FONT_UNSCII_16 0 - -/*Optionally declare custom fonts here. - *You can use these fonts as default font too and they will be available globally. - *E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/ -#define LV_FONT_CUSTOM_DECLARE - -/*Always set a default font*/ -#define LV_FONT_DEFAULT &lv_font_montserrat_14 - -/*Enable handling large font and/or fonts with a lot of characters. - *The limit depends on the font size, font face and bpp. - *Compiler error will be triggered if a font needs it.*/ -#define LV_FONT_FMT_TXT_LARGE 0 - -/*Enables/disables support for compressed fonts.*/ -#define LV_USE_FONT_COMPRESSED 0 - -/*Enable subpixel rendering*/ -#define LV_USE_FONT_SUBPX 0 -#if LV_USE_FONT_SUBPX - /*Set the pixel order of the display. Physical order of RGB channels. Doesn't matter with "normal" fonts.*/ - #define LV_FONT_SUBPX_BGR 0 /*0: RGB; 1:BGR order*/ -#endif - -/*Enable drawing placeholders when glyph dsc is not found*/ -#define LV_USE_FONT_PLACEHOLDER 1 - -/*================= - * TEXT SETTINGS - *=================*/ - -/** - * Select a character encoding for strings. - * Your IDE or editor should have the same character encoding - * - LV_TXT_ENC_UTF8 - * - LV_TXT_ENC_ASCII - */ -#define LV_TXT_ENC LV_TXT_ENC_UTF8 - -/*Can break (wrap) texts on these chars*/ -#define LV_TXT_BREAK_CHARS " ,.;:-_" - -/*If a word is at least this long, will break wherever "prettiest" - *To disable, set to a value <= 0*/ -#define LV_TXT_LINE_BREAK_LONG_LEN 0 - -/*Minimum number of characters in a long word to put on a line before a break. - *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ -#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 - -/*Minimum number of characters in a long word to put on a line after a break. - *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ -#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 - -/*The control character to use for signalling text recoloring.*/ -#define LV_TXT_COLOR_CMD "#" - -/*Support bidirectional texts. Allows mixing Left-to-Right and Right-to-Left texts. - *The direction will be processed according to the Unicode Bidirectional Algorithm: - *https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ -#define LV_USE_BIDI 0 -#if LV_USE_BIDI - /*Set the default direction. Supported values: - *`LV_BASE_DIR_LTR` Left-to-Right - *`LV_BASE_DIR_RTL` Right-to-Left - *`LV_BASE_DIR_AUTO` detect texts base direction*/ - #define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO -#endif - -/*Enable Arabic/Persian processing - *In these languages characters should be replaced with an other form based on their position in the text*/ -#define LV_USE_ARABIC_PERSIAN_CHARS 0 - -/*================== - * WIDGET USAGE - *================*/ - -/*Documentation of the widgets: https://docs.lvgl.io/latest/en/html/widgets/index.html*/ - -#define LV_USE_ARC 1 - -#define LV_USE_BAR 1 - -#define LV_USE_BTN 1 - -#define LV_USE_BTNMATRIX 1 - -#define LV_USE_CANVAS 1 - -#define LV_USE_CHECKBOX 1 - -#define LV_USE_DROPDOWN 1 /*Requires: lv_label*/ - -#define LV_USE_IMG 1 /*Requires: lv_label*/ - -#define LV_USE_LABEL 1 -#if LV_USE_LABEL - #define LV_LABEL_TEXT_SELECTION 1 /*Enable selecting text of the label*/ - #define LV_LABEL_LONG_TXT_HINT 1 /*Store some extra info in labels to speed up drawing of very long texts*/ -#endif - -#define LV_USE_LINE 1 - -#define LV_USE_ROLLER 1 /*Requires: lv_label*/ -#if LV_USE_ROLLER - #define LV_ROLLER_INF_PAGES 7 /*Number of extra "pages" when the roller is infinite*/ -#endif - -#define LV_USE_SLIDER 1 /*Requires: lv_bar*/ - -#define LV_USE_SWITCH 1 - -#define LV_USE_TEXTAREA 1 /*Requires: lv_label*/ -#if LV_USE_TEXTAREA != 0 - #define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/ -#endif - -#define LV_USE_TABLE 1 - -/*================== - * EXTRA COMPONENTS - *==================*/ - -/*----------- - * Widgets - *----------*/ -#define LV_USE_ANIMIMG 1 - -#define LV_USE_CALENDAR 0 -#if LV_USE_CALENDAR - #define LV_CALENDAR_WEEK_STARTS_MONDAY 0 - #if LV_CALENDAR_WEEK_STARTS_MONDAY - #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"} - #else - #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"} - #endif - - #define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} - #define LV_USE_CALENDAR_HEADER_ARROW 1 - #define LV_USE_CALENDAR_HEADER_DROPDOWN 1 -#endif /*LV_USE_CALENDAR*/ - -#define LV_USE_CHART 1 - -#define LV_USE_COLORWHEEL 1 - -#define LV_USE_IMGBTN 0 - -#define LV_USE_KEYBOARD 1 - -#define LV_USE_LED 1 - -#define LV_USE_LIST 1 - -#define LV_USE_MENU 1 - -#define LV_USE_METER 1 - -#define LV_USE_MSGBOX 1 - -#define LV_USE_SPAN 1 -#if LV_USE_SPAN - /*A line text can contain maximum num of span descriptor */ - #define LV_SPAN_SNIPPET_STACK_SIZE 64 -#endif - -#define LV_USE_SPINBOX 1 - -#define LV_USE_SPINNER 1 - -#define LV_USE_TABVIEW 1 - -#define LV_USE_TILEVIEW 1 - -#define LV_USE_WIN 0 - -/*----------- - * Themes - *----------*/ - -/*A simple, impressive and very complete theme*/ -#define LV_USE_THEME_DEFAULT 1 -#if LV_USE_THEME_DEFAULT - - /*0: Light mode; 1: Dark mode*/ - #define LV_THEME_DEFAULT_DARK 1 - - /*1: Enable grow on press*/ - #define LV_THEME_DEFAULT_GROW 1 - - /*Default transition time in [ms]*/ - #define LV_THEME_DEFAULT_TRANSITION_TIME 80 -#endif /*LV_USE_THEME_DEFAULT*/ - -/*A very simple theme that is a good starting point for a custom theme*/ -#define LV_USE_THEME_BASIC 1 - -/*A theme designed for monochrome displays*/ -#define LV_USE_THEME_MONO 1 - -/*----------- - * Layouts - *----------*/ - -/*A layout similar to Flexbox in CSS.*/ -#define LV_USE_FLEX 1 - -/*A layout similar to Grid in CSS.*/ -#define LV_USE_GRID 1 - -/*--------------------- - * 3rd party libraries - *--------------------*/ - -/*File system interfaces for common APIs */ - -/*API for fopen, fread, etc*/ -#define LV_USE_FS_STDIO 0 -#if LV_USE_FS_STDIO - #define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ - #define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ - #define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ -#endif - -/*API for open, read, etc*/ -#define LV_USE_FS_POSIX 0 -#if LV_USE_FS_POSIX - #define LV_FS_POSIX_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ - #define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ - #define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ -#endif - -/*API for CreateFile, ReadFile, etc*/ -#define LV_USE_FS_WIN32 0 -#if LV_USE_FS_WIN32 - #define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ - #define LV_FS_WIN32_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ - #define LV_FS_WIN32_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ -#endif - -/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/ -#define LV_USE_FS_FATFS 0 -#if LV_USE_FS_FATFS - #define LV_FS_FATFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ - #define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ -#endif - -/*PNG decoder library*/ -#define LV_USE_PNG 0 - -/*BMP decoder library*/ -#define LV_USE_BMP 0 - -/* JPG + split JPG decoder library. - * Split JPG is a custom format optimized for embedded systems. */ -#define LV_USE_SJPG 0 - -/*GIF decoder library*/ -#define LV_USE_GIF 0 - -/*QR code library*/ -#define LV_USE_QRCODE 0 - -/*FreeType library*/ -#define LV_USE_FREETYPE 0 -#if LV_USE_FREETYPE - /*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/ - #define LV_FREETYPE_CACHE_SIZE (16 * 1024) - #if LV_FREETYPE_CACHE_SIZE >= 0 - /* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */ - /* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */ - /* if font size >= 256, must be configured as image cache */ - #define LV_FREETYPE_SBIT_CACHE 0 - /* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */ - /* (0:use system defaults) */ - #define LV_FREETYPE_CACHE_FT_FACES 0 - #define LV_FREETYPE_CACHE_FT_SIZES 0 - #endif -#endif - -/*Rlottie library*/ -#define LV_USE_RLOTTIE 0 - -/*FFmpeg library for image decoding and playing videos - *Supports all major image formats so do not enable other image decoder with it*/ -#define LV_USE_FFMPEG 0 -#if LV_USE_FFMPEG - /*Dump input information to stderr*/ - #define LV_FFMPEG_DUMP_FORMAT 0 -#endif - -/*----------- - * Others - *----------*/ - -/*1: Enable API to take snapshot for object*/ -#define LV_USE_SNAPSHOT 0 - -/*1: Enable Monkey test*/ -#define LV_USE_MONKEY 0 - -/*1: Enable grid navigation*/ -#define LV_USE_GRIDNAV 0 - -/*1: Enable lv_obj fragment*/ -#define LV_USE_FRAGMENT 0 - -/*1: Support using images as font in label or span widgets */ -#define LV_USE_IMGFONT 0 - -/*1: Enable a published subscriber based messaging system */ -#define LV_USE_MSG 0 - -/*1: Enable Pinyin input method*/ -/*Requires: lv_keyboard*/ -#define LV_USE_IME_PINYIN 0 -#if LV_USE_IME_PINYIN - /*1: Use default thesaurus*/ - /*If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesauruss*/ - #define LV_IME_PINYIN_USE_DEFAULT_DICT 1 - /*Set the maximum number of candidate panels that can be displayed*/ - /*This needs to be adjusted according to the size of the screen*/ - #define LV_IME_PINYIN_CAND_TEXT_NUM 6 - - /*Use 9 key input(k9)*/ - #define LV_IME_PINYIN_USE_K9_MODE 1 - #if LV_IME_PINYIN_USE_K9_MODE == 1 - #define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3 - #endif // LV_IME_PINYIN_USE_K9_MODE -#endif - -/*================== -* EXAMPLES -*==================*/ - -/*Enable the examples to be built with the library*/ -#define LV_BUILD_EXAMPLES 0 - -/*=================== - * DEMO USAGE - ====================*/ - -/*Show some widget. It might be required to increase `LV_MEM_SIZE` */ -#define LV_USE_DEMO_WIDGETS 0 -#if LV_USE_DEMO_WIDGETS -#define LV_DEMO_WIDGETS_SLIDESHOW 0 -#endif - -/*Demonstrate the usage of encoder and keyboard*/ -#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0 - -/*Benchmark your system*/ -#define LV_USE_DEMO_BENCHMARK 0 -#if LV_USE_DEMO_BENCHMARK -/*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/ -#define LV_DEMO_BENCHMARK_RGB565A8 0 -#endif - -/*Stress test for LVGL*/ -#define LV_USE_DEMO_STRESS 0 - -/*Music player demo*/ -#define LV_USE_DEMO_MUSIC 0 -#if LV_USE_DEMO_MUSIC - #define LV_DEMO_MUSIC_SQUARE 0 - #define LV_DEMO_MUSIC_LANDSCAPE 0 - #define LV_DEMO_MUSIC_ROUND 0 - #define LV_DEMO_MUSIC_LARGE 0 - #define LV_DEMO_MUSIC_AUTO_PLAY 0 -#endif - -/*--END OF LV_CONF_H--*/ - -#endif /*LV_CONF_H*/ - -#endif /*End of "Content enable"*/ diff --git a/Platformio/src/hardware/battery.cpp b/Platformio/src/hardware/battery.cpp index 283f0e2..6bb5683 100644 --- a/Platformio/src/hardware/battery.cpp +++ b/Platformio/src/hardware/battery.cpp @@ -37,8 +37,8 @@ void update_battery_stats(void) { sprintf(buffer1, "Voltage: %.2f V", (float)battery_voltage / 1000); // GUI settings - lv_label_set_text_fmt(objBattSettingsVoltage, buffer1); - lv_label_set_text_fmt(objBattSettingsPercentage, "Percentage: %d%%", battery_percentage); + if (objBattSettingsVoltage != NULL) {lv_label_set_text_fmt(objBattSettingsVoltage, buffer1);} + if (objBattSettingsPercentage != NULL) {lv_label_set_text_fmt(objBattSettingsPercentage, "Percentage: %d%%", battery_percentage);} //lv_label_set_text_fmt(objBattSettingsIscharging, "Is charging: %s", battery_ischarging ? "yes" : "no"); // GUI status bar at the top @@ -55,21 +55,23 @@ void update_battery_stats(void) { } // if (battery_ischarging /*|| (!battery_ischarging && battery_voltage > 4350)*/){ - // // lv_label_set_text(objBattPercentage, ""); - // // lv_label_set_text_fmt(objBattPercentage, "%d%%", battery_percentage); - // // lv_label_set_text_fmt(objBattPercentage, "%.1f, %d%%", (float)battery_voltage / 1000, battery_percentage); - // lv_label_set_text(objBattPercentage, buffer2); - // lv_label_set_text(objBattIcon, LV_SYMBOL_USB); + // // if (BattPercentageLabel != NULL) {lv_label_set_text(BattPercentageLabel, "");} + // // lv_label_set_text_fmt(BattPercentageLabel, "%d%%", battery_percentage); + // // lv_label_set_text_fmt(BattPercentageLabel, "%.1f, %d%%", (float)battery_voltage / 1000, battery_percentage); + // if (BattPercentageLabel != NULL) {lv_label_set_text(BattPercentageLabel, buffer2);} + // if (BattIconLabel != NULL) {lv_label_set_text(BattIconLabel, LV_SYMBOL_USB);} // } else { // Update status bar battery indicator - // lv_label_set_text_fmt(objBattPercentage, "%.1f, %d%%", (float)battery_voltage / 1000, battery_percentage); - lv_label_set_text(objBattPercentage, buffer2); - if(battery_percentage > 95) lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_FULL); - else if(battery_percentage > 75) lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_3); - else if(battery_percentage > 50) lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_2); - else if(battery_percentage > 25) lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_1); - else lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_EMPTY); + // lv_label_set_text_fmt(BattPercentageLabel, "%.1f, %d%%", (float)battery_voltage / 1000, battery_percentage); + if (BattPercentageLabel != NULL) {lv_label_set_text(BattPercentageLabel, buffer2);} + if (BattIconLabel != NULL) { + if(battery_percentage > 95) lv_label_set_text(BattIconLabel, LV_SYMBOL_BATTERY_FULL); + else if(battery_percentage > 75) lv_label_set_text(BattIconLabel, LV_SYMBOL_BATTERY_3); + else if(battery_percentage > 50) lv_label_set_text(BattIconLabel, LV_SYMBOL_BATTERY_2); + else if(battery_percentage > 25) lv_label_set_text(BattIconLabel, LV_SYMBOL_BATTERY_1); + else lv_label_set_text(BattIconLabel, LV_SYMBOL_BATTERY_EMPTY); + } } } diff --git a/Platformio/src/hardware/memoryUsage.cpp b/Platformio/src/hardware/memoryUsage.cpp new file mode 100644 index 0000000..02a1041 --- /dev/null +++ b/Platformio/src/hardware/memoryUsage.cpp @@ -0,0 +1,117 @@ +#include +#include +#include "gui_general_and_keys/guiBase.h" + +bool showMemoryUsage = 0; + +#if LV_MEM_CUSTOM == 0 +lv_mem_monitor_t mon; +#endif + +static unsigned long updateSerialLogTimer = 0; + +bool getShowMemoryUsage() { + return showMemoryUsage; +} +void setShowMemoryUsage(bool aShowMemoryUsage) { + showMemoryUsage = aShowMemoryUsage; + showMemoryUsageBar(showMemoryUsage); +} + +void doLogMemoryUsage() { + // Serial.println("inside doLogMemoryUsage"); + + int thresholdForESP32HeapFreeWarning; // in bytes free in heap + #if (ENABLE_WIFI_AND_MQTT == 1) && (ENABLE_BLUETOOTH == 1) + thresholdForESP32HeapFreeWarning = 15000; + #elif ENABLE_WIFI_AND_MQTT == 1 + thresholdForESP32HeapFreeWarning = 11000; + #elif ENABLE_BLUETOOTH == 1 + thresholdForESP32HeapFreeWarning = 5000; + #elif ENABLE_WIFI_AND_MQTT == 1 + thresholdForESP32HeapFreeWarning = 5000; + #endif + bool doESPHeapWarning = (ESP.getFreeHeap() < thresholdForESP32HeapFreeWarning); + + bool doLVGLMemoryWarning = false; + #if LV_MEM_CUSTOM == 0 + int thresholdForLVGLmemoryFreeWarning = 20; // in percentage free + lv_mem_monitor(&mon); + doLVGLMemoryWarning = ((100 - mon.used_pct) < thresholdForLVGLmemoryFreeWarning); + #endif + + // Serial log every 5 sec + if(millis() - updateSerialLogTimer >= 5000) { + // Serial.println("inside doLogMemoryUsage: will do serial log"); + updateSerialLogTimer = millis(); + + if (doESPHeapWarning) { + Serial.println("WARNING: ESP heap is getting low. You might encounter weird behaviour of your OMOTE, especially when using WiFi and/or BLE."); + } + Serial.printf( + "ESP32 heap: size: %6lu, used: %6lu (%2.0f%%), free: %6lu (%2.0f%%), heapMax: %6lu, heapMin: %6lu\r\n", + ESP.getHeapSize(), + ESP.getHeapSize() - ESP.getFreeHeap(), float(ESP.getHeapSize() - ESP.getFreeHeap()) / ESP.getHeapSize() * 100, + ESP.getFreeHeap(), float(ESP.getFreeHeap()) / ESP.getHeapSize() * 100, + ESP.getMaxAllocHeap(), ESP.getMinFreeHeap()); + + #if LV_MEM_CUSTOM == 0 + if (doLVGLMemoryWarning) { + Serial.println("WARNING: LVGL memory is getting low. You GUI might stop working. In that case, increase \"-D LV_MEM_SIZE\" in platformio.ini"); + } + Serial.printf( + "lvgl memory: size: %6lu, used: %6lu (%2d%%), free: %6lu (%2d%%), max_used: %6lu, free_biggest: %6lu, frag_pct: %2d%%\r\n", + mon.total_size, + mon.total_size - mon.free_size, mon.used_pct, + mon.free_size, 100-mon.used_pct, + mon.max_used, mon.free_biggest_size, mon.frag_pct); + #endif + } else { + // Serial.println("inside doLogMemoryUsage: serial log skipped"); + } + + if (showMemoryUsage) { + char buffer[80]; + std::string ESP32HeapWarnBegin = "#00ff00 "; // green + std::string ESP32HeapWarnEnd = "#"; + std::string LVGLMemorWarnBegin = "#00ff00 "; // green + std::string LVGLMemorWarnEnd = "#"; + if (doESPHeapWarning) { + ESP32HeapWarnBegin = "#ff0000 "; // red + ESP32HeapWarnEnd = "#"; + } + if (doLVGLMemoryWarning) { + LVGLMemorWarnBegin = "#ff0000 "; // red + LVGLMemorWarnEnd = "#"; + } + #if LV_MEM_CUSTOM != 0 + #ifdef SHOW_USED_MEMORY_INSTEAD_OF_FREE_IN_GUI + + sprintf(buffer, ESP32HeapWarnBegin.append("%lu/%lu (%.0f%%)").append(ESP32HeapWarnEnd).c_str() , ESP.getHeapSize()-ESP.getFreeHeap(), ESP.getHeapSize(), float(ESP.getHeapSize()-ESP.getFreeHeap()) / ESP.getHeapSize() * 100); + #else + sprintf(buffer, ESP32HeapWarnBegin.append("%lu/%lu (%.0f%%)").append(ESP32HeapWarnEnd).c_str() , ESP.getFreeHeap(), ESP.getHeapSize(), float(ESP.getFreeHeap()) / ESP.getHeapSize() * 100); + #endif + #else + #ifdef SHOW_USED_MEMORY_INSTEAD_OF_FREE_IN_GUI + sprintf(buffer, ESP32HeapWarnBegin.append("%lu/%lu (%.0f%%)").append(ESP32HeapWarnEnd).append(" / ").append(LVGLMemorWarnBegin).append("%lu/%lu (%d%%)").append(LVGLMemorWarnEnd).c_str(), ESP.getHeapSize()-ESP.getFreeHeap(), ESP.getHeapSize(), float(ESP.getHeapSize()-ESP.getFreeHeap()) / ESP.getHeapSize() * 100, mon.total_size - mon.free_size, mon.total_size, mon.used_pct); + #else + sprintf(buffer, ESP32HeapWarnBegin.append("%lu/%lu (%.0f%%)").append(ESP32HeapWarnEnd).append(" / ").append(LVGLMemorWarnBegin).append("%lu/%lu (%d%%)").append(LVGLMemorWarnEnd).c_str(), ESP.getFreeHeap(), ESP.getHeapSize(), float(ESP.getFreeHeap()) / ESP.getHeapSize() * 100, mon.free_size, mon.total_size, 100-mon.used_pct); + #endif + #endif + + for (int i=0; i diff --git a/Platformio/src/hardware/sleep.cpp b/Platformio/src/hardware/sleep.cpp index 0d3bd41..d837f95 100644 --- a/Platformio/src/hardware/sleep.cpp +++ b/Platformio/src/hardware/sleep.cpp @@ -108,7 +108,7 @@ void enterSleep(){ configIMUInterrupts(); IMU.readRegister(&intDataRead, LIS3DH_INT1_SRC);//really clear interrupt - #ifdef ENABLE_WIFI_AND_MQTT + #if ENABLE_WIFI_AND_MQTT == 1 // Power down modem WiFi.disconnect(); WiFi.mode(WIFI_OFF); diff --git a/Platformio/src/main.cpp b/Platformio/src/main.cpp index be1c3d5..730dc5a 100644 --- a/Platformio/src/main.cpp +++ b/Platformio/src/main.cpp @@ -11,16 +11,18 @@ #include "hardware/mqtt.h" #include "hardware/infrared_sender.h" #include "hardware/infrared_receiver.h" +#include "hardware/memoryUsage.h" // devices #include "device_samsungTV/device_samsungTV.h" #include "device_yamahaAmp/device_yamahaAmp.h" +#include "device_denonAvr/device_denonAvr.h" #include "device_smarthome/device_smarthome.h" #include "device_appleTV/device_appleTV.h" #include "device_keyboard_mqtt/device_keyboard_mqtt.h" #include "device_keyboard_ble/device_keyboard_ble.h" -#include "device_denonAvr/device_denonAvr.h" // gui and keys #include "gui_general_and_keys/guiBase.h" +#include "gui_general_and_keys/guiRegistry.h" #include "gui_general_and_keys/gui_irReceiver.h" #include "gui_general_and_keys/gui_settings.h" #include "gui_general_and_keys/gui_numpad.h" @@ -64,6 +66,7 @@ void setup() { // register commands for the devices register_device_samsung(); register_device_yamaha(); + register_device_denon(); register_device_smarthome(); register_device_appleTV(); #ifdef ENABLE_KEYBOARD_MQTT @@ -72,10 +75,9 @@ void setup() { #ifdef ENABLE_KEYBOARD_BLE register_device_keyboard_ble(); #endif - register_device_denon(); register_specialCommands(); - // register the GUIs. They will be displayed in the order they are registered. + // register the GUIs. They will be displayed in the order they have been registered. register_gui_irReceiver(); register_gui_settings(); register_gui_numpad(); @@ -93,27 +95,29 @@ void setup() { setLabelCurrentScene(); // init WiFi - needs to be after gui because WifiLabel must be available - #ifdef ENABLE_WIFI_AND_MQTT + #if ENABLE_WIFI_AND_MQTT == 1 init_mqtt(); #endif - Serial.print("Setup finished in "); - Serial.print(millis()); - Serial.println("ms."); + Serial.printf("Setup finished in %lu ms.\r\n", millis()); } // Loop ------------------------------------------------------------------------------------------------------------------------------------ -void loop() { +void loop() { // Update Backlight brightness update_backligthBrighness(); - // Update LVGL UI gui_loop(); - // Blink debug LED at 1 Hz update_userled(); + // Keypad Handling + keypad_loop(); + // IR receiver + if (irReceiverEnabled) { + infraredReceiver_loop(); + } // Refresh IMU data at 10Hz static unsigned long IMUTaskTimer = millis(); @@ -124,26 +128,18 @@ void loop() { // Update battery and BLE stats at 1Hz static unsigned long updateStatusTimer = millis(); - if(millis() - updateStatusTimer >= 1000){ - update_battery_stats(); + if(millis() - updateStatusTimer >= 1000) { updateStatusTimer = millis(); + update_battery_stats(); - #ifdef ENABLE_BLUETOOTH + #if ENABLE_BLUETOOTH == 1 // adjust this if you implement other bluetooth devices than the BLE keyboard #ifdef ENABLE_KEYBOARD_BLE update_keyboard_ble_status(); #endif #endif - // Serial.printf("heapSize: %lu, heapFree: %lu, heapMin: %lu, heapMax: %lu\r\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap()); - - } - - // Keypad Handling - keypad_loop(); - - if (irReceiverEnabled) { - infraredReceiver_loop(); + doLogMemoryUsage(); } } diff --git a/Platformio/src/preferencesStorage.cpp b/Platformio/src/preferencesStorage.cpp index 631cb76..89f01ab 100644 --- a/Platformio/src/preferencesStorage.cpp +++ b/Platformio/src/preferencesStorage.cpp @@ -2,6 +2,7 @@ #include "hardware/sleep.h" #include "hardware/tft.h" #include "gui_general_and_keys/guiBase.h" +#include "gui_general_and_keys/guiRegistry.h" #include "commandHandler.h" #include "scenes/sceneHandler.h" @@ -14,10 +15,10 @@ void init_preferences(void) { wakeupByIMUEnabled = preferences.getBool("wkpByIMU"); actualSleepTimeout = preferences.getUInt("slpTimeout"); backlight_brightness = preferences.getUChar("blBrightness"); - currentScreen = preferences.getUChar("currentScreen"); currentScene = std::string(preferences.getString("currentScene").c_str()); + currentGUIname = std::string(preferences.getString("currentGUIname").c_str()); - // Serial.printf("Preferences restored: brightness %d, screen %d, scene %s\r\n", backlight_brightness, currentScreen, currentScene.c_str()); + // Serial.printf("Preferences restored: brightness %d, GUI %s, scene %s\r\n", backlight_brightness, currentGUIname.c_str(), currentScene.c_str()); } else { // Serial.printf("No preferences to restore\r\n"); } @@ -29,8 +30,8 @@ void save_preferences(void) { preferences.putBool("wkpByIMU", wakeupByIMUEnabled); preferences.putUInt("slpTimeout", actualSleepTimeout); preferences.putUChar("blBrightness", backlight_brightness); - preferences.putUChar("currentScreen", currentScreen); preferences.putString("currentScene", currentScene.c_str()); + preferences.putString("currentGUIname", currentGUIname.c_str()); if(!preferences.getBool("alreadySetUp")) preferences.putBool("alreadySetUp", true); preferences.end(); } diff --git a/Platformio/src/scenes/sceneHandler.cpp b/Platformio/src/scenes/sceneHandler.cpp index 366815f..30608e8 100644 --- a/Platformio/src/scenes/sceneHandler.cpp +++ b/Platformio/src/scenes/sceneHandler.cpp @@ -24,7 +24,7 @@ void handleScene(std::string command, commandData commandData, std::string addit Serial.printf("scene: will switch from old scene %s to new scene %s\r\n", currentScene.c_str(), scene_name.c_str()); } - lv_label_set_text(SceneLabel, "changing..."); + if (SceneLabel != NULL) {lv_label_set_text(SceneLabel, "changing...");} gui_loop(); // end old scene @@ -45,11 +45,13 @@ void handleScene(std::string command, commandData commandData, std::string addit currentScene = scene_name; - lv_label_set_text(SceneLabel, currentScene.c_str()); + if (SceneLabel != NULL) {lv_label_set_text(SceneLabel, currentScene.c_str());} Serial.printf("scene: scene handling finished, new scene %s is active\r\n", currentScene.c_str()); } void setLabelCurrentScene() { - lv_label_set_text(SceneLabel, currentScene.c_str()); + if ((SceneLabel != NULL) && sceneExists(currentScene)) { + lv_label_set_text(SceneLabel, currentScene.c_str()); + } }