diff --git a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp index f605d2728..2f0fecdde 100644 --- a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp +++ b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp @@ -153,6 +153,13 @@ void Renderer::DrawStringAt(int16_t x, int16_t y, const char* text, uint16_t col int refcolumn = x; sFONT *xfont = selected_font; +/* + if (font == 5 && !drawmode) { + // clear bckground + int16_t x1,y1; + uint16_t w,h; + Adafruit_GFX::getTextBounds(text, 0, 0, &x1, &y1, &w, &h); + }*/ #ifndef USE_EPD_FONTS font=0; #endif @@ -297,13 +304,15 @@ void Renderer::setTextFont(uint8_t f) { void Renderer::SetRamfont(uint8_t *font) { + ramfont = (GFXfont*)font; - uint32_t bitmap_offset = (uint32_t)ramfont->bitmap; - uint32_t glyph_offset = (uint32_t)ramfont->glyph; - - ramfont->bitmap = (uint8_t*)((uint32_t)font + bitmap_offset); - ramfont->glyph = (GFXglyph*)((uint32_t)font + glyph_offset); + if (font) { + uint32_t bitmap_offset = (uint32_t)ramfont->bitmap; + uint32_t glyph_offset = (uint32_t)ramfont->glyph; + ramfont->bitmap = (uint8_t*)((uint32_t)font + bitmap_offset); + ramfont->glyph = (GFXglyph*)((uint32_t)font + glyph_offset); + } setFont(ramfont); } @@ -588,6 +597,33 @@ void Renderer::scrollTo(uint16_t y) { } +void Renderer::SetPwrCB(pwr_cb cb) { + +} +void Renderer::SetDimCB(dim_cb cb) { + +} + +uint16_t Renderer::fgcol(void) { + return 0; +} +uint16_t Renderer::bgcol(void) { + return 0; +} +int8_t Renderer::color_type(void) { + return 0; +} + +void Renderer::Splash(void) { + +} + +const char dname[1] = {0}; + +char *Renderer::devname(void) { + return (char*)dname; +} + void VButton::xdrawButton(bool inverted) { wr_redir=1; drawButton(inverted); diff --git a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h index c0e244c6c..29d62f53b 100644 --- a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h +++ b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h @@ -16,6 +16,8 @@ // a. in class GFX setCursor,setTextSize => virtual // b. textcolor,textbgcolor => public; +typedef void (*pwr_cb)(uint8_t); +typedef void (*dim_cb)(uint8_t); class Renderer : public Adafruit_GFX { //Paint(unsigned char* image, int width, int height); @@ -42,12 +44,21 @@ public: virtual void setScrollMargins(uint16_t top, uint16_t bottom); virtual void scrollTo(uint16_t y); virtual void TS_RotConvert(int16_t *x, int16_t *y); + virtual void SetPwrCB(pwr_cb cb); + virtual void SetDimCB(dim_cb cb); + virtual uint16_t fgcol(void); + virtual uint16_t bgcol(void); + virtual int8_t color_type(void); + virtual void Splash(void); + virtual char *devname(void); void setDrawMode(uint8_t mode); uint8_t drawmode; virtual void FastString(uint16_t x,uint16_t y,uint16_t tcolor, const char* str); void setTextSize(uint8_t s); virtual uint8_t *allocate_framebuffer(uint32_t size); + pwr_cb pwr_cbp = 0; + dim_cb dim_cbp = 0; private: void DrawCharAt(int16_t x, int16_t y, char ascii_char,int16_t colored); inline void drawFastVLineInternal(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline)); diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp index a0403e927..9a9a3c5fb 100755 --- a/lib/lib_display/UDisplay/uDisplay.cpp +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -31,6 +31,17 @@ uint16_t uDisplay::GetColorFromIndex(uint8_t index) { return udisp_colors[index]; } +uint16_t uDisplay::fgcol(void) { + return fg_col; +} +uint16_t uDisplay::bgcol(void) { + return bg_col; +} + +int8_t uDisplay::color_type(void) { + return col_type; +} + uDisplay::~uDisplay(void) { if (framebuffer) { @@ -40,6 +51,8 @@ uDisplay::~uDisplay(void) { uDisplay::uDisplay(char *lp) : Renderer(800, 600) { // analyse decriptor + pwr_cbp = 0; + dim_cbp = 0; framebuffer = 0; col_mode = 16; sa_mode = 16; @@ -915,8 +928,8 @@ void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) SPI_CS_HIGH SPI_END_TRANSACTION } else { - SPI_CS_LOW SPI_BEGIN_TRANSACTION + SPI_CS_LOW setAddrWindow_int(x0, y0, x1 - x0, y1 - y0 ); } } @@ -1092,7 +1105,11 @@ void uDisplay::DisplayOnff(int8_t on) { return; } - udisp_bpwr(on); + if (pwr_cbp) { + pwr_cbp(on); + } + +// udisp_bpwr(on); if (interface == _UDSP_I2C) { if (on) { @@ -1162,7 +1179,10 @@ void uDisplay::dim(uint8_t dim) { if (bpanel >= 0) { ledcWrite(ESP32_PWM_CHANNEL, dimmer); } else { - udisp_dimm(dim); + //udisp_dimm(dim); + if (dim_cbp) { + dim_cbp(dim); + } } #endif diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h index 8cf0aff7f..bb54d948c 100755 --- a/lib/lib_display/UDisplay/uDisplay.h +++ b/lib/lib_display/UDisplay/uDisplay.h @@ -79,9 +79,9 @@ class uDisplay : public Renderer { void DisplayOnff(int8_t on); void Splash(void); char *devname(void); - uint16_t fgcol(void) const { return fg_col; }; - uint16_t bgcol(void) const { return bg_col; }; - int8_t color_type(void) const { return col_type; }; + uint16_t fgcol(void); + uint16_t bgcol(void); + int8_t color_type(void); void dim(uint8_t dim); uint16_t GetColorFromIndex(uint8_t index); void setRotation(uint8_t m); @@ -90,6 +90,8 @@ class uDisplay : public Renderer { void pushColors(uint16_t *data, uint16_t len, boolean first); void TS_RotConvert(int16_t *x, int16_t *y); void invertDisplay(boolean i); + void SetPwrCB(pwr_cb cb) { pwr_cbp = cb; }; + void SetDimCB(dim_cb cb) { dim_cbp = cb; }; private: void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); diff --git a/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.cpp b/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.cpp index 8f9e62570..cbe6b5e1c 100644 --- a/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.cpp +++ b/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.cpp @@ -22,107 +22,15 @@ static void lv_tick_handler(void) { lv_tick_inc(lv_tick_interval_ms); } #define ADC_YMIN 240 #define ADC_YMAX 840 + +uint32_t Touch_Status(uint32_t sel); + static bool touchscreen_read(struct _lv_indev_drv_t *indev_drv, lv_indev_data_t *data) { -// static lv_coord_t last_x = 0, last_y = 0; -// static uint8_t release_count = 0; - -// // Get pointer to glue object from indev user data -// Adafruit_LvGL_Glue *glue = (Adafruit_LvGL_Glue *)indev_drv->user_data; -// uDisplay_lvgl *disp = glue->display; - -// if (glue->is_adc_touch) { -// TouchScreen *touch = (TouchScreen *)glue->touchscreen; -// TSPoint p = touch->getPoint(); -// // Serial.printf("%d %d %d\r\n", p.x, p.y, p.z); -// // Having an issue with spurious z=0 results from TouchScreen lib. -// // Since touch is polled periodically, workaround is to watch for -// // several successive z=0 results, and only then regard it as -// // a release event (otherwise still touched). -// if (p.z < touch->pressureThreshhold) { // A zero-ish value -// release_count += (release_count < 255); -// if (release_count >= 4) { -// data->state = LV_INDEV_STATE_REL; // Is REALLY RELEASED -// } else { -// data->state = LV_INDEV_STATE_PR; // Is STILL PRESSED -// } -// } else { -// release_count = 0; // Reset release counter -// data->state = LV_INDEV_STATE_PR; // Is PRESSED -// switch (glue->display->getRotation()) { -// case 0: -// last_x = map(p.x, ADC_XMIN, ADC_XMAX, 0, disp->width() - 1); -// last_y = map(p.y, ADC_YMAX, ADC_YMIN, 0, disp->height() - 1); -// break; -// case 1: -// last_x = map(p.y, ADC_YMAX, ADC_YMIN, 0, disp->width() - 1); -// last_y = map(p.x, ADC_XMAX, ADC_XMIN, 0, disp->height() - 1); -// break; -// case 2: -// last_x = map(p.x, ADC_XMAX, ADC_XMIN, 0, disp->width() - 1); -// last_y = map(p.y, ADC_YMIN, ADC_YMAX, 0, disp->height() - 1); -// break; -// case 3: -// last_x = map(p.y, ADC_YMIN, ADC_YMAX, 0, disp->width() - 1); -// last_y = map(p.x, ADC_XMIN, ADC_XMAX, 0, disp->height() - 1); -// break; -// } -// } -// data->point.x = last_x; // Last-pressed coordinates -// data->point.y = last_y; -// return false; // No buffering of ADC touch data -// } else { -// uint8_t fifo; // Number of points in touchscreen FIFO -// bool moar = false; -// Adafruit_STMPE610 *touch = (Adafruit_STMPE610 *)glue->touchscreen; -// // Before accessing SPI touchscreen, wait on any in-progress -// // DMA screen transfer to finish (shared bus). -// //disp->dmaWait(); -// // disp->endWrite(); -// if ((fifo = touch->bufferSize())) { // 1 or more points await -// data->state = LV_INDEV_STATE_PR; // Is PRESSED -// TS_Point p = touch->getPoint(); -// // Serial.printf("%d %d %d\r\n", p.x, p.y, p.z); -// // On big TFT FeatherWing, raw X axis is flipped?? -// if ((glue->display->width() == 480) || (glue->display->height() == 480)) { -// p.x = (TS_MINX + TS_MAXX) - p.x; -// } -// switch (glue->display->getRotation()) { -// case 0: -// last_x = map(p.x, TS_MAXX, TS_MINX, 0, disp->width() - 1); -// last_y = map(p.y, TS_MINY, TS_MAXY, 0, disp->height() - 1); -// break; -// case 1: -// last_x = map(p.y, TS_MINY, TS_MAXY, 0, disp->width() - 1); -// last_y = map(p.x, TS_MINX, TS_MAXX, 0, disp->height() - 1); -// break; -// case 2: -// last_x = map(p.x, TS_MINX, TS_MAXX, 0, disp->width() - 1); -// last_y = map(p.y, TS_MAXY, TS_MINY, 0, disp->height() - 1); -// break; -// case 3: -// last_x = map(p.y, TS_MAXY, TS_MINY, 0, disp->width() - 1); -// last_y = map(p.x, TS_MAXX, TS_MINX, 0, disp->height() - 1); -// break; -// } -// moar = (fifo > 1); // true if more in FIFO, false if last point -// #if defined(NRF52_SERIES) -// // Not sure what's up here, but nRF doesn't seem to always poll -// // the FIFO size correctly, causing false release events. If it -// // looks like we've read the last point from the FIFO, pause -// // briefly to allow any more FIFO events to pile up. This -// // doesn't seem to be necessary on SAMD or ESP32. ??? -// if (!moar) { -// delay(50); -// } -// #endif -// } else { // FIFO empty -// data->state = LV_INDEV_STATE_REL; // Is RELEASED -// } - -// data->point.x = last_x; // Last-pressed coordinates -// data->point.y = last_y; -// return moar; -// } + //lv_coord_t last_x = 0, last_y = 0; + //static uint8_t release_count = 0; + data->point.x = Touch_Status(1); // Last-pressed coordinates + data->point.y = Touch_Status(2); + data->state = Touch_Status(0); return false; /*No buffering now so no more data read*/ } @@ -165,7 +73,7 @@ static void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_col return; // ok } - uDisplay_lvgl *display = glue->display; + Renderer *display = glue->display; if (!glue->first_frame) { //display->dmaWait(); // Wait for prior DMA transfer to complete @@ -174,11 +82,9 @@ static void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_col glue->first_frame = false; } - // display->startWrite(); - // display->setAddrWindow(area->x1, area->y1, width, height); - display->writePixels(area->x1, area->y1, width, height, - (uint16_t *)color_p, width * height); - // display->pushColors((uint16_t *)color_p, width * height, false); + display->setAddrWindow(area->x1, area->y1, area->x1+width, area->y1+height); + display->pushColors((uint16_t *)color_p, width * height, true); + display->setAddrWindow(0,0,0,0); lv_disp_flush_ready(disp); } @@ -286,11 +192,11 @@ Adafruit_LvGL_Glue::~Adafruit_LvGL_Glue(void) { * * LVGL_ERR_TIMER : Failure to set up timers * * LVGL_ERR_ALLOC : Failure to allocate memory */ -LvGLStatus Adafruit_LvGL_Glue::begin(uDisplay_lvgl *tft, bool debug) { +LvGLStatus Adafruit_LvGL_Glue::begin(Renderer *tft, bool debug) { return begin(tft, (void *)NULL, debug); } -LvGLStatus Adafruit_LvGL_Glue::begin(uDisplay_lvgl *tft, void *touch, bool debug) { +LvGLStatus Adafruit_LvGL_Glue::begin(Renderer *tft, void *touch, bool debug) { lv_init(); // #if (LV_USE_LOG) diff --git a/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.h b/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.h index f60f86d41..2a5c3e81b 100644 --- a/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.h +++ b/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.h @@ -2,7 +2,7 @@ #define _ADAFRUIT_LVGL_GLUE_H_ #include // LittlevGL core lib -#include +#include #include // ESP32-specific timer lib #include @@ -27,10 +27,11 @@ public: // bool debug = false); // LvGLStatus begin(uDisplay_lvgl *tft, TouchScreen *touch, // bool debug = false); - LvGLStatus begin(uDisplay_lvgl *tft, bool debug = false); + LvGLStatus begin(Renderer *tft, bool debug = false); + LvGLStatus begin(Renderer *tft, void *touch, bool debug); // These items need to be public for some internal callbacks, // but should be avoided by user code please! - uDisplay_lvgl *display; ///< Pointer to the SPITFT display instance + Renderer *display; ///< Pointer to the SPITFT display instance void *touchscreen; ///< Pointer to the touchscreen object to use bool is_adc_touch; ///< determines if the touchscreen controlelr is ADC based bool first_frame; ///< Tracks if a call to `lv_flush_callback` needs to wait @@ -40,7 +41,6 @@ public: void stopScreenshot(void) { screenshot = nullptr; } private: - LvGLStatus begin(uDisplay_lvgl *tft, void *touch, bool debug); lv_disp_drv_t lv_disp_drv; lv_disp_buf_t lv_disp_buf; lv_color_t *lv_pixel_buf; diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index e7c83435f..ff71dd4c8 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -2621,6 +2621,15 @@ chknext: tind->bits.is_string = 0; return lp + len; } +#ifdef USE_LVGL + if (!strncmp(vname, "lvgl(", 5)) { + lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); + fvar = lvgl_test(fvar); + lp++; + len = 0; + goto exit; + } +#endif break; case 'm': if (!strncmp(vname, "med(", 4)) { @@ -7704,6 +7713,192 @@ void cpy2lf(char *dst, uint32_t dstlen, char *src) { } } +#ifdef USE_LVGL +#include +#include "lvgl.h" + + +const char ili9342[] PROGMEM = +":H,ILI9342,320,240,16,SPI,1,*,*,*,*,*,*,*,40\n" +":S,2,1,3,0,100,100\n" +":I\n" +"EF,3,03,80,02\n" +"CF,3,00,C1,30\n" +"ED,4,64,03,12,81\n" +"E8,3,85,00,78\n" +"CB,5,39,2C,00,34,02\n" +"F7,1,20\n" +"EA,2,00,00\n" +"C0,1,23\n" +"C1,1,10\n" +"C5,2,3e,28\n" +"C7,1,86\n" +"36,1,48\n" +"37,1,00\n" +"3A,1,55\n" +"B1,2,00,18\n" +"B6,3,08,82,27\n" +"F2,1,00\n" +"26,1,01\n" +"E0,0F,0F,31,2B,0C,0E,08,4E,F1,37,07,10,03,0E,09,00\n" +"E1,0F,00,0E,14,03,11,07,31,C1,48,08,0F,0C,31,36,0F\n" +"21,80\n" +"11,80\n" +"29,80\n" +":o,28\n" +":O,29\n" +":A,2A,2B,2C,16\n" +":R,36\n" +":0,08,00,00,00\n" +":1,A8,00,00,01\n" +":2,C8,00,00,02\n" +":3,68,00,00,03\n" +":i,21,20\n" +":TI2,38,22,21\n" +"#\n"; + +void start_lvgl(const char * uconfig); + +void btn_event_cb(lv_obj_t * btn, lv_event_t event); +void btn_event_cb(lv_obj_t * btn, lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + AddLog_P(LOG_LEVEL_INFO,PSTR(">>> clicked")); + } + AddLog_P(LOG_LEVEL_INFO,PSTR(">>> clicked")); +} + + +int32_t lvgl_test(int32_t p) { + start_lvgl(ili9342); + lv_obj_clean(lv_scr_act()); + + lv_obj_t *label1 = lv_label_create(lv_scr_act(), NULL); + + /*Modify the Label's text*/ + lv_label_set_text(label1, "Hello world!"); + + /* Align the Label to the center + * NULL means align on parent (which is the screen now) + * 0, 0 at the end means an x, y offset after alignment*/ + lv_obj_align(label1, NULL, LV_ALIGN_CENTER, 0, 0); + + + lvgl_setup(); + + /*Add a button*/ + lv_obj_t *btn1 = lv_btn_create(lv_scr_act(), NULL); /*Add to the active screen*/ + lv_obj_set_pos(btn1, 2, 2); /*Adjust the position*/ + lv_obj_set_size(btn1, 96, 30); /* set size of button */ + lv_obj_set_event_cb(btn1, btn_event_cb); + + /*Add text*/ + lv_obj_t *label = lv_label_create(btn1, NULL); /*Put on 'btn1'*/ + lv_label_set_text(label, "Click"); + + + + return 0; +} + +lv_obj_t *tabview, // LittlevGL tabview object + *gauge, // Gauge object (on first of three tabs) + *chart, // Chart object (second tab) + *canvas; // Canvas object (third tab) +uint8_t active_tab = 0, // Index of currently-active tab (0-2) + prev_tab = 0; // Index of previously-active tab +lv_chart_series_t *series; // 'Series' data for the bar chart +lv_draw_line_dsc_t draw_dsc; // Drawing style (for canvas) is similarly global + +#define CANVAS_WIDTH 200 // Dimensions in pixels +#define CANVAS_HEIGHT 150 + +void lvgl_setup(void) { + // Create a tabview object, by default this covers the full display. + tabview = lv_tabview_create(lv_disp_get_scr_act(NULL), NULL); + // The CLUE display has a lot of pixels and can't refresh very fast. + // To show off the tabview animation, let's slow it down to 1 second. + lv_tabview_set_anim_time(tabview, 1000); + + // Because they're referenced any time an object is drawn, styles need + // to be permanent in scope; either declared globally (outside all + // functions), or static. The styles used on tabs are never modified after + // they're used here, so let's use static on those... + static lv_style_t tab_style, tab_background_style, indicator_style; + + // This is the background style "behind" the tabs. This is what shows + // through for "off" (inactive) tabs -- a vertical green gradient, + // minimal padding around edges (zero at bottom). + lv_style_init(&tab_background_style); + lv_style_set_bg_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x408040)); + lv_style_set_bg_grad_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x304030)); + lv_style_set_bg_grad_dir(&tab_background_style, LV_STATE_DEFAULT, LV_GRAD_DIR_VER); + lv_style_set_pad_top(&tab_background_style, LV_STATE_DEFAULT, 2); + lv_style_set_pad_left(&tab_background_style, LV_STATE_DEFAULT, 2); + lv_style_set_pad_right(&tab_background_style, LV_STATE_DEFAULT, 2); + lv_style_set_pad_bottom(&tab_background_style, LV_STATE_DEFAULT, 0); + lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BG, &tab_background_style); + + // Style for tabs. Active tab is white with opaque background, inactive + // tabs are transparent so the background shows through (only the white + // text is seen). A little top & bottom padding reduces scrunchyness. + lv_style_init(&tab_style); + lv_style_set_pad_top(&tab_style, LV_STATE_DEFAULT, 3); + lv_style_set_pad_bottom(&tab_style, LV_STATE_DEFAULT, 10); + lv_style_set_bg_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_WHITE); + lv_style_set_bg_opa(&tab_style, LV_STATE_CHECKED, LV_OPA_100); + lv_style_set_text_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_style_set_bg_opa(&tab_style, LV_STATE_DEFAULT, LV_OPA_TRANSP); + lv_style_set_text_color(&tab_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BTN, &tab_style); + + // Style for the small indicator bar that appears below the active tab. + lv_style_init(&indicator_style); + lv_style_set_bg_color(&indicator_style, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_style_set_size(&indicator_style, LV_STATE_DEFAULT, 5); + lv_obj_add_style(tabview, LV_TABVIEW_PART_INDIC, &indicator_style); + + // Back to creating widgets... + + // Add three tabs to the tabview + lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Gauge"); + lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Chart"); + lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Canvas"); + + // And then add stuff in each tab... + + // The first tab holds a gauge. To keep the demo simple, let's just use + // the default style and range (0-100). See LittlevGL docs for options. + gauge = lv_gauge_create(tab1, NULL); + lv_obj_set_size(gauge, 186, 186); + lv_obj_align(gauge, NULL, LV_ALIGN_CENTER, 0, 0); + + // Second tab, make a chart... + chart = lv_chart_create(tab2, NULL); + lv_obj_set_size(chart, 200, 180); + lv_obj_align(chart, NULL, LV_ALIGN_CENTER, 0, 0); + lv_chart_set_type(chart, LV_CHART_TYPE_COLUMN); + // For simplicity, we'll stick with the chart's default 10 data points: + series = lv_chart_add_series(chart, LV_COLOR_RED); + lv_chart_init_points(chart, series, 0); + // Make each column shift left as new values enter on right: + lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT); + + // Third tab is a canvas, which we'll fill with random colored lines. + // LittlevGL draw functions only work on TRUE_COLOR canvas. +/* canvas = lv_canvas_create(tab3, NULL); + lv_canvas_set_buffer(canvas, canvas_buffer, + CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR); + lv_obj_align(canvas, NULL, LV_ALIGN_CENTER, 0, 0); + lv_canvas_fill_bg(canvas, LV_COLOR_WHITE, LV_OPA_100); + + // Set up canvas line-drawing style based on defaults. + // Later we'll change color settings when drawing each line. + lv_draw_line_dsc_init(&draw_dsc); + */ +} + + +#endif /*********************************************************************************************\ * Interface @@ -7868,6 +8063,12 @@ bool Xdrv10(uint8_t function) case FUNC_EVERY_100_MSECOND: ScripterEvery100ms(); break; +#ifdef USE_LVGL + case FUNC_EVERY_50_MSECOND: + lv_task_handler(); + break; +#endif // USE_LVGL + case FUNC_EVERY_SECOND: ScriptEverySecond(); break; diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index 166d38bc0..1736e6a2c 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -824,27 +824,36 @@ extern FS *ffsp; char fname[32]; *ep = 0; ep++; - if (*cp != '/') { - fname[0] = '/'; - fname[1] = 0; + if (*cp == '-' && *(cp + 1) == 0) { + if (ram_font) { + free (ram_font); + ram_font = 0; + if (renderer) renderer->SetRamfont(0); + } + cp = ep; } else { - fname[0] = 0; - } - strlcat(fname, cp, sizeof(fname)); - if (!strstr(cp, ".fnt")) { - strlcat(fname, ".fnt", sizeof(fname)); - } - if (ffsp) { - File fp; - fp = ffsp->open(fname, "r"); - if (fp > 0) { - uint32_t size = fp.size(); - if (ram_font) free (ram_font); - ram_font = (uint8_t*)special_malloc(size + 4); - fp.read((uint8_t*)ram_font, size); - fp.close(); - if (renderer) renderer->SetRamfont(ram_font); - //Serial.printf("Font loaded: %s\n",fname ); + if (*cp != '/') { + fname[0] = '/'; + fname[1] = 0; + } else { + fname[0] = 0; + } + strlcat(fname, cp, sizeof(fname)); + if (!strstr(cp, ".fnt")) { + strlcat(fname, ".fnt", sizeof(fname)); + } + if (ffsp) { + File fp; + fp = ffsp->open(fname, "r"); + if (fp > 0) { + uint32_t size = fp.size(); + if (ram_font) free (ram_font); + ram_font = (uint8_t*)special_malloc(size + 4); + fp.read((uint8_t*)ram_font, size); + fp.close(); + if (renderer) renderer->SetRamfont(ram_font); + //Serial.printf("Font loaded: %s\n",fname ); + } } } cp = ep; diff --git a/tasmota/xdrv_54_lvgl.ino b/tasmota/xdrv_54_lvgl.ino index 4bc89ec40..717d279e0 100644 --- a/tasmota/xdrv_54_lvgl.ino +++ b/tasmota/xdrv_54_lvgl.ino @@ -20,7 +20,7 @@ #ifdef USE_LVGL -#include +#include #include "lvgl.h" #define XDRV_54 54 @@ -37,7 +37,7 @@ * you should lock on the very same semaphore! */ SemaphoreHandle_t xGuiSemaphore; -uDisplay_lvgl * udisp = nullptr; +//uDisplay * udisp = nullptr; // necessary for compilation uint8_t color_type_lvgl = 0; @@ -121,7 +121,7 @@ static void guiTask(void *pvParameter) { /************************************************************ * Callbacks for file system access from LVGL - * + * * Useful to load fonts or images from file system ************************************************************/ @@ -217,7 +217,7 @@ static lv_fs_res_t lvbe_fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos) return LV_FS_RES_OK; } else { return LV_FS_RES_UNKNOWN; - } + } } static lv_fs_res_t lvbe_fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p); @@ -238,11 +238,14 @@ static lv_fs_res_t lvbe_fs_remove(lv_fs_drv_t * drv, const char *path) { /************************************************************ * Initialize the display / touchscreen drivers then launch lvgl - * + * * We use Adafruit_LvGL_Glue to leverage the Adafruit * display ecosystem. ************************************************************/ +Renderer *Init_uDisplay(const char *desc, int8_t cs); + + void start_lvgl(const char * uconfig); void start_lvgl(const char * uconfig) { @@ -251,25 +254,22 @@ void start_lvgl(const char * uconfig) { return; } - if (udisp == nullptr) { - udisp = new uDisplay_lvgl((char*)uconfig); + if (uconfig && !renderer) { +#ifdef USE_UNIVERSAL_DISPLAY + renderer = Init_uDisplay((char*)uconfig, -1); + if (!renderer) return; +#else + return; +#endif } - udisp->Init(); - - // Settings.display_width = udisp->width(); - // Settings.display_height = udisp->height(); - - udisp->DisplayInit(0 /* DISPLAY_INIT_MODE */, Settings.display_size, Settings.display_rotate, Settings.display_font); - udisp->dim(Settings.display_dimmer); - // ************************************************** // Initialize the glue between Adafruit and LVGL // ************************************************** glue = new Adafruit_LvGL_Glue(); // Initialize glue, passing in address of display & touchscreen - LvGLStatus status = glue->begin(udisp); + LvGLStatus status = glue->begin(renderer, (void*)1, false); if (status != LVGL_OK) { AddLog(LOG_LEVEL_ERROR, PSTR("Glue error %d"), status); return; @@ -277,8 +277,10 @@ void start_lvgl(const char * uconfig) { // Set the default background color of the display // This is normally overriden by an opaque screen on top +#ifdef USE_BERRY lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_from_uint32(USE_LVGL_BG_DEFAULT)); lv_obj_set_style_local_bg_opa(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER); +#endif #if LV_USE_LOG lv_log_register_print_cb(lvbe_debug); @@ -319,6 +321,8 @@ void start_lvgl(const char * uconfig) { * Otherwise there can be problem such as memory corruption and so on. * NOTE: When not using Wi-Fi nor Bluetooth you can pin the guiTask to core 0 */ xTaskCreatePinnedToCore(guiTask, "gui", 4096*2, NULL, 0, NULL, 1); + + AddLog(LOG_LEVEL_INFO, PSTR("LVGL initialized")); } /*********************************************************************************************\