memory optimization, only three tabs in memory at the same time
This commit is contained in:
parent
4227372859
commit
b98a06e91c
32 changed files with 1114 additions and 1080 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <Arduino.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
@ -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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <lvgl.h>
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <lvgl.h>
|
||||
|
||||
const char * const tabName_appleTV = "Apple TV";
|
||||
void register_gui_appleTV(void);
|
||||
|
||||
#endif /*__GUI_APPLETV_H__*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 <BleKeyboard.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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <lvgl.h>
|
||||
|
||||
const char * const tabName_smarthome = "Smart Home";
|
||||
void register_gui_smarthome(void);
|
||||
|
||||
#endif /*__GUI_SMARTHOME_H__*/
|
||||
|
|
|
@ -1,35 +1,93 @@
|
|||
#include <lvgl.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/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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,20 +4,45 @@
|
|||
#include <lvgl.h>
|
||||
#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__*/
|
||||
|
|
404
Platformio/src/gui_general_and_keys/guiMemoryOptimizer.cpp
Normal file
404
Platformio/src/gui_general_and_keys/guiMemoryOptimizer.cpp
Normal file
|
@ -0,0 +1,404 @@
|
|||
#include <Arduino.h>
|
||||
#include <lvgl.h>
|
||||
#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<list_of_guis_to_be_shown.size(); i++) {
|
||||
if (list_of_guis_to_be_shown[i] == currentGUIname) {
|
||||
Serial.printf("Startup: found GUI with name \"%s\" in \"list_of_guis_to_be_shown\" at position %d\r\n", currentGUIname.c_str(), i);
|
||||
// save position so that "guis_doAfterSliding" can use it
|
||||
tabs_in_memory[0].listIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, int oldTabID, int newTabID, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2) {
|
||||
// Here the magic for dynamic creation and deletion of lvgl objects happens to keep memory usage low.
|
||||
// The next and previous tab must always be available in the tabview, because they can already been seen during the animation.
|
||||
// And you always need 3 tabs, otherwise you even could not slide to the next or previous tab.
|
||||
// So we always have 3 tabs.
|
||||
// After the animation, the tabview and hence all tabs are deleted and recreated.
|
||||
|
||||
bool isInitialization = ((oldTabID == -1) && (newTabID == -1));
|
||||
if (isInitialization) {
|
||||
Serial.printf("Startup: will initially create the tabs to be shown\r\n");
|
||||
} else {
|
||||
Serial.printf("Changing from oldTabID %d \"%s\" to newTabID %d \"%s\"\r\n",
|
||||
oldTabID, list_of_guis_to_be_shown.at(tabs_in_memory[oldTabID].listIndex).c_str(),
|
||||
newTabID, list_of_guis_to_be_shown.at(tabs_in_memory[newTabID].listIndex).c_str());
|
||||
}
|
||||
|
||||
// save the ids of the tabs we had in memory before
|
||||
for (int i=0; i<3; i++) {
|
||||
tabs_in_memory_previous_listIndex[i] = tabs_in_memory[i].listIndex;
|
||||
}
|
||||
|
||||
// the old tabs need to be notified that they will be deleted so that they can persist their state if needed
|
||||
if (!isInitialization) notify_active_tabs_before_delete();
|
||||
// clear current tabview
|
||||
clear_tabview(*tabview);
|
||||
// clear current panel for page indicator
|
||||
clear_panel(*panel, *img1, *img2);
|
||||
|
||||
// only optional: delete and create the whole screen. Not necessary.
|
||||
// Only used for a test. init_gui_status_bar() would need to be called again at a suitable place, because the status bar would also be deleted.
|
||||
// lv_obj_t * oldscr = lv_scr_act();
|
||||
// // create new screen
|
||||
// lv_obj_t * newscr = lv_obj_create(NULL);
|
||||
// // load this new screen
|
||||
// lv_scr_load(newscr);
|
||||
// lv_obj_del(oldscr);
|
||||
|
||||
// recreate the tabview
|
||||
lv_obj_t* newTabview = create_tabview();
|
||||
*tabview = newTabview;
|
||||
// Create the tabs. Use strategy "3 tabs at maximum" to keep memory usage low.
|
||||
// Set the tab we swiped to as active
|
||||
doTabCreation_strategyMax3(*tabview, oldTabID, newTabID);
|
||||
|
||||
// Create the panel for the page indicator. Panel itself takes about 2136 bytes for three tabs.
|
||||
lv_obj_t* newPanel = create_panel();
|
||||
*panel = newPanel;
|
||||
*img1 = lv_img_create(lv_scr_act());
|
||||
*img2 = lv_img_create(lv_scr_act());
|
||||
fillPanelWithPageIndicator_strategyMax3(*panel, *img1, *img2);
|
||||
|
||||
// now, as the correct tab is active, register again the events for the tabview
|
||||
lv_obj_add_event_cb(*tabview, tabview_tab_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
lv_obj_add_event_cb(lv_tabview_get_content(*tabview), tabview_content_is_scrolling_event_cb, LV_EVENT_SCROLL, NULL);
|
||||
// Initialize scroll position of the page indicator
|
||||
lv_event_send(lv_tabview_get_content(*tabview), LV_EVENT_SCROLL, NULL);
|
||||
|
||||
}
|
7
Platformio/src/gui_general_and_keys/guiMemoryOptimizer.h
Normal file
7
Platformio/src/gui_general_and_keys/guiMemoryOptimizer.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef __GUIMEMORYOPTIMIZER_H__
|
||||
#define __GUIMEMORYOPTIMIZER_H__
|
||||
|
||||
void gui_memoryOptimizer_prepare_startup();
|
||||
void gui_memoryOptimizer_doAfterSliding_deletionAndCreation(lv_obj_t** tabview, int oldTabID, int newTabID, lv_obj_t** panel, lv_obj_t** img1, lv_obj_t** img2);
|
||||
|
||||
#endif /*__GUIMEMORYOPTIMIZER_H__*/
|
|
@ -1,31 +1,37 @@
|
|||
#include <Arduino.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <lvgl.h>
|
||||
#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<std::string, gui_definition> 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<std::string> list_of_guis_to_be_shown;
|
||||
std::string currentGUIname = "";
|
||||
|
||||
std::list<gui_definition> 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<gui_definition>::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<gui_definition>::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)});
|
||||
|
||||
}
|
||||
|
|
|
@ -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_<nameOfGUI>();" 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 <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <lvgl.h>
|
||||
|
||||
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<std::string, gui_definition> registered_guis_byName_map;
|
||||
extern std::vector<std::string> 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__*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <lvgl.h>
|
||||
#include <string>
|
||||
|
||||
const char * const tabName_irReceiver = "IR Receiver";
|
||||
void register_gui_irReceiver(void);
|
||||
void showNewIRmessage(String);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <lvgl.h>
|
||||
|
||||
const char * const tabName_numpad = "Numpad";
|
||||
void register_gui_numpad(void);
|
||||
|
||||
#endif /*__GUI_NUMPAD_H__*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__*/
|
||||
|
|
|
@ -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 <stdint.h>
|
||||
|
||||
/*====================
|
||||
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 <stdlib.h> /*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 <SDL2/SDL.h>
|
||||
/*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 <stdint.h>
|
||||
#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 <stdio.h>
|
||||
#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_<CONST> 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"*/
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
117
Platformio/src/hardware/memoryUsage.cpp
Normal file
117
Platformio/src/hardware/memoryUsage.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include <Arduino.h>
|
||||
#include <lvgl.h>
|
||||
#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<strlen(buffer); i++) {
|
||||
if (buffer[i] == '.') {
|
||||
buffer[i] = ',';
|
||||
}
|
||||
}
|
||||
if (MemoryUsageLabel != NULL) {
|
||||
// Serial.printf("inside doLogMemoryUsage: will do GUI log %s\r\n", buffer);
|
||||
lv_label_set_text(MemoryUsageLabel, buffer);
|
||||
}
|
||||
} else {
|
||||
if (MemoryUsageLabel != NULL) {
|
||||
lv_label_set_text(MemoryUsageLabel, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
Platformio/src/hardware/memoryUsage.h
Normal file
10
Platformio/src/hardware/memoryUsage.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef __MEMORYUSAGE_H__
|
||||
#define __MEMORYUSAGE_H__
|
||||
|
||||
//#define SHOW_USED_MEMORY_INSTEAD_OF_FREE_IN_GUI // comment it out to see free memory instead of used memory in GUI. Serial log will always show both.
|
||||
|
||||
bool getShowMemoryUsage();
|
||||
void setShowMemoryUsage(bool aShowMemoryUsage);
|
||||
void doLogMemoryUsage(void);
|
||||
|
||||
#endif /*__MEMORYUSAGE_H__*/
|
|
@ -5,7 +5,7 @@
|
|||
#include "secrets.h"
|
||||
#include "commandHandler.h"
|
||||
|
||||
#ifdef ENABLE_WIFI_AND_MQTT
|
||||
#if ENABLE_WIFI_AND_MQTT == 1
|
||||
WiFiClient espClient;
|
||||
PubSubClient mqttClient(espClient);
|
||||
|
||||
|
@ -22,6 +22,7 @@ void WiFiEvent(WiFiEvent_t event){
|
|||
// Set status bar icon based on WiFi status
|
||||
if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP || event == ARDUINO_EVENT_WIFI_STA_GOT_IP6) {
|
||||
if (WifiLabel != NULL) {lv_label_set_text(WifiLabel, LV_SYMBOL_WIFI);}
|
||||
Serial.printf("WiFi connected, IP address: %s\r\n", WiFi.localIP().toString().c_str());
|
||||
|
||||
} else if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) {
|
||||
if (WifiLabel != NULL) {lv_label_set_text(WifiLabel, "");}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "commandHandler.h"
|
||||
|
||||
#ifdef ENABLE_WIFI_AND_MQTT
|
||||
#if ENABLE_WIFI_AND_MQTT == 1
|
||||
|
||||
#include "WiFi.h"
|
||||
#include <PubSubClient.h>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue