diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt index cd607eb63..60d8966e3 100644 --- a/radio/src/gui/colorlcd/CMakeLists.txt +++ b/radio/src/gui/colorlcd/CMakeLists.txt @@ -192,7 +192,7 @@ list(TRANSFORM LVGL_FONT_SOURCES_MINIMAL PREPEND ${RADIO_SRC_DIR}/) set(BOOTLOADER_SRC ${BOOTLOADER_SRC} ${LVGL_SOURCES_MINIMAL} ${LVGL_FONT_SOURCES_MINIMAL} - ${RADIO_SRC_DIR}/gui/colorlcd/lcd.cpp + ${RADIO_SRC_DIR}/gui/colorlcd/boot_lcd.cpp ${RADIO_SRC_DIR}/gui/colorlcd/fonts.cpp ${RADIO_SRC_DIR}/gui/colorlcd/colors.cpp ${RADIO_SRC_DIR}/gui/colorlcd/bitmaps.cpp diff --git a/radio/src/gui/colorlcd/boot_lcd.cpp b/radio/src/gui/colorlcd/boot_lcd.cpp new file mode 100644 index 000000000..0ce2ca9d5 --- /dev/null +++ b/radio/src/gui/colorlcd/boot_lcd.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "lcd.h" + +#include + +#if LV_USE_GPU_STM32_DMA2D +#include +#else +#include "dma2d.h" +#endif + +#include "bitmapbuffer.h" +#include "board.h" +#include "etx_lv_theme.h" + +pixel_t LCD_FIRST_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; +pixel_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; + +BitmapBuffer lcdBuffer1(BMP_RGB565, LCD_W, LCD_H, + (uint16_t*)LCD_FIRST_FRAME_BUFFER); +BitmapBuffer lcdBuffer2(BMP_RGB565, LCD_W, LCD_H, + (uint16_t*)LCD_SECOND_FRAME_BUFFER); + +BitmapBuffer* lcdFront = &lcdBuffer1; +BitmapBuffer* lcd = &lcdBuffer2; + +static lv_disp_draw_buf_t disp_buf; +static lv_disp_drv_t disp_drv; + +static lv_disp_t disp; + +// Call backs +static void (*lcd_flush_cb)(lv_disp_drv_t*, uint16_t* buffer, + const rect_t& area) = nullptr; + +void lcdSetFlushCb(void (*cb)(lv_disp_drv_t*, uint16_t*, const rect_t&)) +{ + lcd_flush_cb = cb; +} + +static lv_disp_drv_t* refr_disp = nullptr; + +static void flushLcd(lv_disp_drv_t* disp_drv, const lv_area_t* area, + lv_color_t* color_p) +{ + if (lcd_flush_cb) { + refr_disp = disp_drv; + + rect_t copy_area = {area->x1, area->y1, area->x2 - area->x1 + 1, + area->y2 - area->y1 + 1}; + + lcd_flush_cb(disp_drv, (uint16_t*)color_p, copy_area); + } + + lv_disp_flush_ready(disp_drv); +} + +static void clear_frame_buffers() +{ + memset(LCD_FIRST_FRAME_BUFFER, 0, sizeof(LCD_FIRST_FRAME_BUFFER)); + memset(LCD_SECOND_FRAME_BUFFER, 0, sizeof(LCD_SECOND_FRAME_BUFFER)); +} + +static void init_lvgl_disp_drv() +{ + lv_disp_draw_buf_init(&disp_buf, lcdFront->getData(), lcd->getData(), LCD_W * LCD_H); + lv_disp_drv_init(&disp_drv); /*Basic initialization*/ + + disp_drv.draw_buf = &disp_buf; /*Set an initialized buffer*/ + disp_drv.flush_cb = flushLcd; /*Set a flush callback to draw to the display*/ + disp_drv.wait_cb = nullptr; /*Set a wait callback*/ + + disp_drv.hor_res = LCD_W; /*Set the horizontal resolution in pixels*/ + disp_drv.ver_res = LCD_H; /*Set the vertical resolution in pixels*/ + disp_drv.full_refresh = 0; + +#if !defined(LCD_VERTICAL_INVERT) + disp_drv.direct_mode = 1; +#elif defined(RADIO_F16) + disp_drv.direct_mode = (hardwareOptions.pcbrev > 0) ? 1 : 0; +#else + disp_drv.direct_mode = 0; +#endif +} + +void lcdInitDisplayDriver() +{ + static bool lcdDriverStarted = false; + // we already have a display: exit + if (lcdDriverStarted) return; + lcdDriverStarted = true; + +#if LV_USE_GPU_STM32_DMA2D + // Init only DMA2D + lv_draw_stm32_dma2d_init(); +#else + DMAInit(); +#endif + + // Clear buffers first + clear_frame_buffers(); + lcdSetInitalFrameBuffer(lcdFront->getData()); + + // Init hardware LCD driver + lcdInit(); + backlightInit(); + + init_lvgl_disp_drv(); + + // allow drawing at any moment + lv_memset_00(&disp, sizeof(lv_disp_t)); + disp.driver = &disp_drv; + _lv_refr_set_disp_refreshing(&disp); + + if (disp_drv.draw_ctx == NULL) { + lv_draw_ctx_t* draw_ctx = + (lv_draw_ctx_t*)lv_mem_alloc(disp_drv.draw_ctx_size); + LV_ASSERT_MALLOC(draw_ctx); + if (draw_ctx == NULL) return; + disp_drv.draw_ctx_init(&disp_drv, draw_ctx); + disp_drv.draw_ctx = draw_ctx; + } + + lv_draw_ctx_t* draw_ctx = disp_drv.draw_ctx; + lcd->setDrawCtx(draw_ctx); + lcdFront->setDrawCtx(draw_ctx); +} + +void lcdClear() { lcd->clear(); } + +// Direct drawing - used by boot loader + +void lcdInitDirectDrawing() +{ + static lv_area_t screen_area = {0, 0, LCD_W - 1, LCD_H - 1}; + + lv_draw_ctx_t* draw_ctx = disp_drv.draw_ctx; + draw_ctx->buf = disp_drv.draw_buf->buf_act; + draw_ctx->buf_area = &screen_area; + draw_ctx->clip_area = &screen_area; + lcd->setData((pixel_t*)draw_ctx->buf); + lcd->reset(); +} + +// +// Private code copied and adapted from LVGL / lv_refr.c +// (_call_flush_cb & _draw_buf_flush) +// +static void _call_flush_cb(lv_disp_drv_t* drv, const lv_area_t* area, + lv_color_t* color_p) +{ + lv_area_t offset_area = {.x1 = (lv_coord_t)(area->x1 + drv->offset_x), + .y1 = (lv_coord_t)(area->y1 + drv->offset_y), + .x2 = (lv_coord_t)(area->x2 + drv->offset_x), + .y2 = (lv_coord_t)(area->y2 + drv->offset_y)}; + + drv->flush_cb(drv, &offset_area, color_p); +} + +static void _draw_buf_flush(lv_disp_t* disp) +{ + lv_disp_draw_buf_t* draw_buf = lv_disp_get_draw_buf(disp); + + /*Flush the rendered content to the display*/ + lv_draw_ctx_t* draw_ctx = disp->driver->draw_ctx; + if (draw_ctx->wait_for_finish) draw_ctx->wait_for_finish(draw_ctx); + + /* In double buffered mode wait until the other buffer is freed + * and driver is ready to receive the new buffer */ + if (draw_buf->buf1 && draw_buf->buf2) { + while (draw_buf->flushing) { + if (disp->driver->wait_cb) disp->driver->wait_cb(disp->driver); + } + } + + draw_buf->flushing = 1; + draw_buf->flushing_last = 1; + + if (disp->driver->flush_cb) { + _call_flush_cb(disp->driver, draw_ctx->buf_area, + (lv_color_t*)draw_ctx->buf); + } + + /*If there are 2 buffers swap them. */ + if (draw_buf->buf1 && draw_buf->buf2) { + if (draw_buf->buf_act == draw_buf->buf1) + draw_buf->buf_act = draw_buf->buf2; + else + draw_buf->buf_act = draw_buf->buf1; + } +} + +void lcdRefresh() +{ + lv_disp_t* d = _lv_refr_get_disp_refreshing(); + _draw_buf_flush(d); +} diff --git a/radio/src/gui/colorlcd/lcd.cpp b/radio/src/gui/colorlcd/lcd.cpp index 64777be12..3ab34ef0b 100644 --- a/radio/src/gui/colorlcd/lcd.cpp +++ b/radio/src/gui/colorlcd/lcd.cpp @@ -23,14 +23,12 @@ #include -#if LV_USE_GPU_STM32_DMA2D -#include -#endif - #include "bitmapbuffer.h" #include "board.h" -#include "dma2d.h" #include "etx_lv_theme.h" +#if !LV_USE_GPU_STM32_DMA2D && !defined(SIMU) +#include "dma2d.h" +#endif pixel_t LCD_FIRST_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; pixel_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; @@ -40,16 +38,12 @@ BitmapBuffer lcdBuffer1(BMP_RGB565, LCD_W, LCD_H, BitmapBuffer lcdBuffer2(BMP_RGB565, LCD_W, LCD_H, (uint16_t*)LCD_SECOND_FRAME_BUFFER); -BitmapBuffer* lcdFront = &lcdBuffer1; -BitmapBuffer* lcd = &lcdBuffer2; +static BitmapBuffer* lcdFront = &lcdBuffer1; +static BitmapBuffer* lcd = &lcdBuffer2; static lv_disp_draw_buf_t disp_buf; static lv_disp_drv_t disp_drv; -#if defined(BOOT) -static lv_disp_t disp; -#endif - // Call backs static void (*lcd_wait_cb)(lv_disp_drv_t*) = nullptr; static void (*lcd_flush_cb)(lv_disp_drv_t*, uint16_t* buffer, @@ -67,7 +61,7 @@ static lv_disp_drv_t* refr_disp = nullptr; static void flushLcd(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) { -#if (!defined(LCD_VERTICAL_INVERT) || defined(RADIO_F16)) && !defined(BOOT) +#if !defined(LCD_VERTICAL_INVERT) || defined(RADIO_F16) #if defined(RADIO_F16) if (hardwareOptions.pcbrev > 0) #endif @@ -123,13 +117,10 @@ static void init_lvgl_disp_drv() disp_drv.full_refresh = 0; #if !defined(LCD_VERTICAL_INVERT) - disp_drv.full_refresh = 1; disp_drv.direct_mode = 1; #elif defined(RADIO_F16) - disp_drv.full_refresh = 1; disp_drv.direct_mode = (hardwareOptions.pcbrev > 0) ? 1 : 0; #else - disp_drv.full_refresh = 0; disp_drv.direct_mode = 0; #endif } @@ -141,15 +132,14 @@ void lcdInitDisplayDriver() if (lcdDriverStarted) return; lcdDriverStarted = true; -#if !defined(BOOT) +#if !LV_USE_GPU_STM32_DMA2D && !defined(SIMU) + DMAInit(); +#endif + // Full LVGL init in firmware mode lv_init(); // Initialise styles useMainStyle(); -#elif LV_USE_GPU_STM32_DMA2D - // Otherwise init only DMA2D - lv_draw_stm32_dma2d_init(); -#endif // Clear buffers first clear_frame_buffers(); @@ -161,115 +151,23 @@ void lcdInitDisplayDriver() init_lvgl_disp_drv(); -#if !defined(BOOT) // Register the driver and save the created display object - lv_disp_t* d = lv_disp_drv_register(&disp_drv); + lv_disp_drv_register(&disp_drv); // remove all styles on default screen (makes it transparent as well) lv_obj_remove_style_all(lv_scr_act()); - - // transparent background: - // - this prevents LVGL overwritting things drawn directly into the bitmap - // buffer - lv_disp_set_bg_opa(d, LV_OPA_TRANSP); - - // allow drawing at any moment - _lv_refr_set_disp_refreshing(d); -#else - // allow drawing at any moment - lv_memset_00(&disp, sizeof(lv_disp_t)); - disp.driver = &disp_drv; - _lv_refr_set_disp_refreshing(&disp); - - if (disp_drv.draw_ctx == NULL) { - lv_draw_ctx_t* draw_ctx = - (lv_draw_ctx_t*)lv_mem_alloc(disp_drv.draw_ctx_size); - LV_ASSERT_MALLOC(draw_ctx); - if (draw_ctx == NULL) return; - disp_drv.draw_ctx_init(&disp_drv, draw_ctx); - disp_drv.draw_ctx = draw_ctx; - } -#endif - - lv_draw_ctx_t* draw_ctx = disp_drv.draw_ctx; - lcd->setDrawCtx(draw_ctx); - lcdFront->setDrawCtx(draw_ctx); } -void lcdClear() { lcd->clear(); } - void lcdFlushed() { + // Only used in simulator + // its possible to get here before flushLcd is ever called. // so check for nullptr first. (Race condition if you put breakpoints in // startup code) if (refr_disp != nullptr) lv_disp_flush_ready(refr_disp); } -// Direct drawing - used by boot loader and battery charging state - -void lcdInitDirectDrawing() -{ - static lv_area_t screen_area = {0, 0, LCD_W - 1, LCD_H - 1}; - - lv_draw_ctx_t* draw_ctx = disp_drv.draw_ctx; - draw_ctx->buf = disp_drv.draw_buf->buf_act; - draw_ctx->buf_area = &screen_area; - draw_ctx->clip_area = &screen_area; - lcd->setData((pixel_t*)draw_ctx->buf); - lcd->reset(); -} - -// -// Private code copied and adapted from LVGL / lv_refr.c -// (_call_flush_cb & _draw_buf_flush) -// -static void _call_flush_cb(lv_disp_drv_t* drv, const lv_area_t* area, - lv_color_t* color_p) -{ - lv_area_t offset_area = {.x1 = (lv_coord_t)(area->x1 + drv->offset_x), - .y1 = (lv_coord_t)(area->y1 + drv->offset_y), - .x2 = (lv_coord_t)(area->x2 + drv->offset_x), - .y2 = (lv_coord_t)(area->y2 + drv->offset_y)}; - - drv->flush_cb(drv, &offset_area, color_p); -} - -static void _draw_buf_flush(lv_disp_t* disp) -{ - lv_disp_draw_buf_t* draw_buf = lv_disp_get_draw_buf(disp); - - /*Flush the rendered content to the display*/ - lv_draw_ctx_t* draw_ctx = disp->driver->draw_ctx; - if (draw_ctx->wait_for_finish) draw_ctx->wait_for_finish(draw_ctx); - - /* In double buffered mode wait until the other buffer is freed - * and driver is ready to receive the new buffer */ - if (draw_buf->buf1 && draw_buf->buf2) { - while (draw_buf->flushing) { - if (disp->driver->wait_cb) disp->driver->wait_cb(disp->driver); - } - } - - draw_buf->flushing = 1; - draw_buf->flushing_last = 1; - - if (disp->driver->flush_cb) { - _call_flush_cb(disp->driver, draw_ctx->buf_area, - (lv_color_t*)draw_ctx->buf); - } - - /*If there are 2 buffers swap them. */ - if (draw_buf->buf1 && draw_buf->buf2) { - if (draw_buf->buf_act == draw_buf->buf1) - draw_buf->buf_act = draw_buf->buf2; - else - draw_buf->buf_act = draw_buf->buf1; - } -} - -void lcdRefresh() -{ - lv_disp_t* d = _lv_refr_get_disp_refreshing(); - _draw_buf_flush(d); -} +#if defined(SIMU) +void lcdRefresh() {} +#endif diff --git a/radio/src/gui/colorlcd/libui/bitmapbuffer.h b/radio/src/gui/colorlcd/libui/bitmapbuffer.h index 2ce096141..0d9f2ca08 100644 --- a/radio/src/gui/colorlcd/libui/bitmapbuffer.h +++ b/radio/src/gui/colorlcd/libui/bitmapbuffer.h @@ -262,9 +262,3 @@ class BitmapBuffer lv_obj_t* canvas = nullptr; lv_draw_ctx_t* draw_ctx = nullptr; }; - -// Back buffer to draw -extern BitmapBuffer* lcd; - -// Buffer currently on display -extern BitmapBuffer* lcdFront; diff --git a/radio/src/gui/colorlcd/lv_conf.h b/radio/src/gui/colorlcd/lv_conf.h index e77693771..81a42bd77 100644 --- a/radio/src/gui/colorlcd/lv_conf.h +++ b/radio/src/gui/colorlcd/lv_conf.h @@ -205,11 +205,7 @@ #define LV_USE_GPU_ARM2D 0 /*Use STM32's DMA2D (aka Chrom Art) GPU*/ -#if defined(SIMU) - #define LV_USE_GPU_STM32_DMA2D 0 -#else //SIMU - #define LV_USE_GPU_STM32_DMA2D 1 -#endif +#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 diff --git a/radio/src/targets/common/arm/stm32/dma2d.cpp b/radio/src/targets/common/arm/stm32/dma2d.cpp index 9ee878bef..50b417649 100644 --- a/radio/src/targets/common/arm/stm32/dma2d.cpp +++ b/radio/src/targets/common/arm/stm32/dma2d.cpp @@ -25,6 +25,35 @@ #include "libopenui_defines.h" #include "dma2d.h" +#if !LV_USE_GPU_STM32_DMA2D +/** + * Turn on the peripheral and set output color mode, this only needs to be done once + * + * Copied from LVGL code + */ +void DMAInit(void) +{ + // Enable DMA2D clock +#if defined(STM32F4) || defined(STM32F7) || defined(STM32U5) + RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; // enable DMA2D + // wait for hardware access to complete + __asm volatile("DSB\n"); + volatile uint32_t temp = RCC->AHB1ENR; + LV_UNUSED(temp); +#elif defined(STM32H7) + RCC->AHB3ENR |= RCC_AHB3ENR_DMA2DEN; + // wait for hardware access to complete + __asm volatile("DSB\n"); + volatile uint32_t temp = RCC->AHB3ENR; + LV_UNUSED(temp); +#else +# warning "LVGL can't enable the clock of DMA2D" +#endif + // AHB master timer configuration + DMA2D->AMTCR = 0; // AHB bus guaranteed dead time disabled +} +#endif + void DMACopyBitmap(uint16_t *dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint16_t *src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, diff --git a/radio/src/targets/common/arm/stm32/dma2d.h b/radio/src/targets/common/arm/stm32/dma2d.h index 879180a8a..d13e69ca0 100644 --- a/radio/src/targets/common/arm/stm32/dma2d.h +++ b/radio/src/targets/common/arm/stm32/dma2d.h @@ -23,7 +23,7 @@ #include "edgetx_types.h" -#if !defined(SIMU) +#if !defined(SIMU) && !defined(BOOT) static inline void DMAWait() { while(DMA2D->CR & DMA2D_CR_START); @@ -32,6 +32,7 @@ static inline void DMAWait() static inline void DMAWait() {} #endif +void DMAInit(); void DMAFillRect(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color); void DMACopyBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, uint16_t h); void DMACopyAlphaBitmap(uint16_t * dest, uint16_t destw, uint16_t desth, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t srch, uint16_t srcx, uint16_t srcy, uint16_t w, uint16_t h); diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index 9cfcae79f..5846a79eb 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -234,14 +234,6 @@ void boardInit() #else ledGreen(); #endif - -#if !defined(LCD_VERTICAL_INVERT) - lcdSetInitalFrameBuffer(lcdFront->getData()); -#elif defined(RADIO_F16) - if(hardwareOptions.pcbrev > 0) { - lcdSetInitalFrameBuffer(lcdFront->getData()); - } -#endif } #endif diff --git a/radio/src/targets/nv14/board.cpp b/radio/src/targets/nv14/board.cpp index e5c37ee18..7adad24bf 100644 --- a/radio/src/targets/nv14/board.cpp +++ b/radio/src/targets/nv14/board.cpp @@ -218,8 +218,6 @@ void boardInit() #if defined(RTCLOCK) rtcInit(); // RTC must be initialized before rambackupRestore() is called #endif - - lcdSetInitalFrameBuffer(lcdFront->getData()); } extern void rtcDisableBackupReg(); diff --git a/radio/src/targets/pl18/battery_driver.cpp b/radio/src/targets/pl18/battery_driver.cpp index 399f2c0ed..557251b9e 100644 --- a/radio/src/targets/pl18/battery_driver.cpp +++ b/radio/src/targets/pl18/battery_driver.cpp @@ -315,47 +315,75 @@ void ledChargingInfo(uint16_t chargeState) { #endif } +static Window* chargeWindow = nullptr; + void drawChargingInfo(uint16_t chargeState) { - static int progress = 0; - const char* text = chargeState == CHARGE_STARTED ? STR_BATTERYCHARGING : STR_BATTERYFULL; - int h = 0; - LcdFlags color = 0; - if (CHARGE_STARTED == chargeState) - { - if (progress >= 100) - { - progress = 0; - } - else - { - progress += 25; - } - text = STR_BATTERYCHARGING; - h = ((BATTERY_H_INNER * progress) / 100); - color = COLOR_THEME_EDIT; + static int progress = -1; + static StaticText* stateText = nullptr; + static lv_obj_t* battBox = nullptr; + + const char* text; + int h; + LcdColorIndex color = COLOR_THEME_EDIT_INDEX; + + switch (chargeState) { + case CHARGE_STARTED: + progress += 1; + if (progress > 4) progress = 0; + text = STR_BATTERYCHARGING; + h = ((BATTERY_H_INNER * progress) / 4); + break; + case CHARGE_FINISHED: + text = STR_BATTERYFULL; + h = BATTERY_H_INNER; + break; + default: + text = STR_BATTERYNONE; + h = BATTERY_H_INNER; + color = COLOR_THEME_PRIMARY1_INDEX; + break; } - else if (CHARGE_FINISHED == chargeState) - { - text = STR_BATTERYFULL; - h = BATTERY_H_INNER; - color = COLOR_THEME_EDIT; - } - else - { - text = STR_BATTERYNONE; - h = BATTERY_H_INNER; - color = COLOR_THEME_PRIMARY1; + + if (chargeWindow == nullptr) { + chargeWindow = new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}); + etx_solid_bg(chargeWindow->getLvObj(), COLOR_THEME_PRIMARY1_INDEX); + + stateText = new StaticText(chargeWindow, {0, LCD_H - 50, LCD_W, 50}, "", COLOR_THEME_PRIMARY2_INDEX, CENTERED); + + lv_obj_t* box = lv_obj_create(chargeWindow->getLvObj()); + lv_obj_set_pos(box, (LCD_W - BATTERY_W) / 2, BATTERY_TOP); + lv_obj_set_size(box, BATTERY_W, BATTERY_H); + lv_obj_set_style_border_opa(box, LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_width(box, 2, LV_PART_MAIN); + etx_border_color(box, COLOR_THEME_PRIMARY2_INDEX); + + box = lv_obj_create(chargeWindow->getLvObj()); + lv_obj_set_pos(box, (LCD_W - BATTERY_CONNECTOR_W) / 2, BATTERY_TOP - BATTERY_CONNECTOR_H); + lv_obj_set_size(box, BATTERY_CONNECTOR_W, BATTERY_CONNECTOR_H); + etx_solid_bg(box, COLOR_THEME_PRIMARY2_INDEX); + + battBox = lv_obj_create(chargeWindow->getLvObj()); } + stateText->setText(text); + + lv_obj_set_pos(battBox, (LCD_W - BATTERY_W_INNER) / 2, BATTERY_TOP_INNER + BATTERY_H_INNER - h); + lv_obj_set_size(battBox, BATTERY_W_INNER, h); + etx_solid_bg(battBox, color); + + LvglWrapper::instance()->run(); + lv_refr_now(nullptr); + BACKLIGHT_ENABLE(); - lcd->drawSizedText(LCD_W / 2, LCD_H - 50, text, strlen(text), CENTERED | COLOR_THEME_PRIMARY2); - - lcd->drawFilledRect((LCD_W - BATTERY_W) / 2, BATTERY_TOP, BATTERY_W, BATTERY_H, SOLID, COLOR_THEME_PRIMARY2); - lcd->drawFilledRect((LCD_W - BATTERY_W_INNER) / 2, BATTERY_TOP_INNER, BATTERY_W_INNER, BATTERY_H_INNER, SOLID, COLOR_THEME_PRIMARY1); - - lcd->drawFilledRect((LCD_W - BATTERY_W_INNER) / 2, BATTERY_TOP_INNER + BATTERY_H_INNER - h, BATTERY_W_INNER, h, SOLID, color); - lcd->drawFilledRect((LCD_W - BATTERY_CONNECTOR_W) / 2, BATTERY_TOP - BATTERY_CONNECTOR_H, BATTERY_CONNECTOR_W, BATTERY_CONNECTOR_H, SOLID, COLOR_THEME_PRIMARY2); } + +void battery_charge_end() +{ + chargeWindow->clear(); + delete chargeWindow; + chargeWindow = nullptr; +} + #define CHARGE_INFO_DURATION 5000 // ms //this method should be called by timer interrupt or by GPIO interrupt @@ -385,6 +413,12 @@ void handle_battery_charge(uint32_t last_press_time) lastState = chargeState; } + if (!lcdInited) { + lcdInited = true; + backlightInit(); + lcdInitDisplayDriver(); + } + if (updateTime == 0 || ((timersGetMsTick() - updateTime) >= 500)) { updateTime = timersGetMsTick(); @@ -392,25 +426,17 @@ void handle_battery_charge(uint32_t last_press_time) if(now > info_until) { info_until = 0; - lcd->clear(); BACKLIGHT_DISABLE(); if(lcdInited) { lcdOff(); } } else { - if (!lcdInited) { - backlightInit(); - lcdInit(); - lcdInitDisplayDriver(); - lcdInited = true; - } else { + if (lcdInited) { lcdOn(); } - lcdInitDirectDrawing(); - lcd->clear(); drawChargingInfo(chargeState); - // DEBUG INFO + // DEBUG INFO - TODO delete or replace with LVGL objects #if 0 char buffer[1024]; @@ -431,8 +457,6 @@ void handle_battery_charge(uint32_t last_press_time) sprintf(buffer, "%d", isChargerActive()); lcd->drawSizedText(100, 130, buffer, strlen(buffer), CENTERED | COLOR_THEME_PRIMARY2); #endif - - lcdRefresh(); } } diff --git a/radio/src/targets/pl18/battery_driver.h b/radio/src/targets/pl18/battery_driver.h index a03ac70d6..25a087d26 100644 --- a/radio/src/targets/pl18/battery_driver.h +++ b/radio/src/targets/pl18/battery_driver.h @@ -19,14 +19,7 @@ * GNU General Public License for more details. */ -/*************************************************************************************************** - -***************************************************************************************************/ -#ifndef __BATTERY_DRIVER_H__ - #define __BATTERY_DRIVER_H__ -/*************************************************************************************************** - -***************************************************************************************************/ +#pragma once #include "board.h" #include "hal.h" @@ -54,5 +47,4 @@ extern void handle_battery_charge(uint32_t last_press_time); extern uint16_t get_battery_charge_state(); extern uint16_t getBatteryVoltage(); // returns current battery voltage in 10mV steps extern bool isChargerActive(); - -#endif +extern void battery_charge_end(); diff --git a/radio/src/targets/pl18/board.cpp b/radio/src/targets/pl18/board.cpp index f8f6fccb6..c165689c8 100644 --- a/radio/src/targets/pl18/board.cpp +++ b/radio/src/targets/pl18/board.cpp @@ -260,6 +260,7 @@ void boardInit() press_end = 0; } } + battery_charge_end(); } keysInit(); @@ -287,8 +288,6 @@ void boardInit() ledGreen(); #endif #endif - - lcdSetInitalFrameBuffer(lcdFront->getData()); } extern void rtcDisableBackupReg(); diff --git a/radio/src/targets/st16/battery_driver.cpp b/radio/src/targets/st16/battery_driver.cpp index 415a14d4c..134073b4e 100644 --- a/radio/src/targets/st16/battery_driver.cpp +++ b/radio/src/targets/st16/battery_driver.cpp @@ -230,47 +230,75 @@ void ledChargingInfo(uint16_t chargeState) { #endif } +static Window* chargeWindow = nullptr; + void drawChargingInfo(uint16_t chargeState) { - static int progress = 0; - const char* text = chargeState == CHARGE_STARTED ? STR_BATTERYCHARGING : STR_BATTERYFULL; - int h = 0; - LcdFlags color = 0; - if (CHARGE_STARTED == chargeState) - { - if (progress >= 100) - { - progress = 0; - } - else - { - progress += 25; - } - text = STR_BATTERYCHARGING; - h = ((BATTERY_H_INNER * progress) / 100); - color = COLOR_THEME_EDIT; + static int progress = -1; + static StaticText* stateText = nullptr; + static lv_obj_t* battBox = nullptr; + + const char* text; + int h; + LcdColorIndex color = COLOR_THEME_EDIT_INDEX; + + switch (chargeState) { + case CHARGE_STARTED: + progress += 1; + if (progress > 4) progress = 0; + text = STR_BATTERYCHARGING; + h = ((BATTERY_H_INNER * progress) / 4); + break; + case CHARGE_FINISHED: + text = STR_BATTERYFULL; + h = BATTERY_H_INNER; + break; + default: + text = STR_BATTERYNONE; + h = BATTERY_H_INNER; + color = COLOR_THEME_PRIMARY1_INDEX; + break; } - else if (CHARGE_FINISHED == chargeState) - { - text = STR_BATTERYFULL; - h = BATTERY_H_INNER; - color = COLOR_THEME_EDIT; - } - else - { - text = STR_BATTERYNONE; - h = BATTERY_H_INNER; - color = COLOR_THEME_PRIMARY1; + + if (chargeWindow == nullptr) { + chargeWindow = new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}); + etx_solid_bg(chargeWindow->getLvObj(), COLOR_THEME_PRIMARY1_INDEX); + + stateText = new StaticText(chargeWindow, {0, LCD_H - 50, LCD_W, 50}, "", COLOR_THEME_PRIMARY2_INDEX, CENTERED); + + lv_obj_t* box = lv_obj_create(chargeWindow->getLvObj()); + lv_obj_set_pos(box, (LCD_W - BATTERY_W) / 2, BATTERY_TOP); + lv_obj_set_size(box, BATTERY_W, BATTERY_H); + lv_obj_set_style_border_opa(box, LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_width(box, 2, LV_PART_MAIN); + etx_border_color(box, COLOR_THEME_PRIMARY2_INDEX); + + box = lv_obj_create(chargeWindow->getLvObj()); + lv_obj_set_pos(box, (LCD_W - BATTERY_CONNECTOR_W) / 2, BATTERY_TOP - BATTERY_CONNECTOR_H); + lv_obj_set_size(box, BATTERY_CONNECTOR_W, BATTERY_CONNECTOR_H); + etx_solid_bg(box, COLOR_THEME_PRIMARY2_INDEX); + + battBox = lv_obj_create(chargeWindow->getLvObj()); } + stateText->setText(text); + + lv_obj_set_pos(battBox, (LCD_W - BATTERY_W_INNER) / 2, BATTERY_TOP_INNER + BATTERY_H_INNER - h); + lv_obj_set_size(battBox, BATTERY_W_INNER, h); + etx_solid_bg(battBox, color); + + LvglWrapper::instance()->run(); + lv_refr_now(nullptr); + BACKLIGHT_ENABLE(); - lcd->drawSizedText(LCD_W / 2, LCD_H - 50, text, strlen(text), CENTERED | COLOR_THEME_PRIMARY2); - - lcd->drawFilledRect((LCD_W - BATTERY_W) / 2, BATTERY_TOP, BATTERY_W, BATTERY_H, SOLID, COLOR_THEME_PRIMARY2); - lcd->drawFilledRect((LCD_W - BATTERY_W_INNER) / 2, BATTERY_TOP_INNER, BATTERY_W_INNER, BATTERY_H_INNER, SOLID, COLOR_THEME_PRIMARY1); - - lcd->drawFilledRect((LCD_W - BATTERY_W_INNER) / 2, BATTERY_TOP_INNER + BATTERY_H_INNER - h, BATTERY_W_INNER, h, SOLID, color); - lcd->drawFilledRect((LCD_W - BATTERY_CONNECTOR_W) / 2, BATTERY_TOP - BATTERY_CONNECTOR_H, BATTERY_CONNECTOR_W, BATTERY_CONNECTOR_H, SOLID, COLOR_THEME_PRIMARY2); } + +void battery_charge_end() +{ + chargeWindow->clear(); + delete chargeWindow; + chargeWindow = nullptr; +} + #define CHARGE_INFO_DURATION 5000 // ms //this method should be called by timer interrupt or by GPIO interrupt @@ -300,6 +328,12 @@ void handle_battery_charge(uint32_t last_press_time) lastState = chargeState; } + if (!lcdInited) { + lcdInited = true; + backlightInit(); + lcdInitDisplayDriver(); + } + if (updateTime == 0 || ((timersGetMsTick() - updateTime) >= 500)) { updateTime = timersGetMsTick(); @@ -307,25 +341,17 @@ void handle_battery_charge(uint32_t last_press_time) if(now > info_until) { info_until = 0; - lcd->clear(); BACKLIGHT_DISABLE(); if(lcdInited) { lcdOff(); } } else { - if (!lcdInited) { - backlightInit(); - lcdInit(); - lcdInitDisplayDriver(); - lcdInited = true; - } else { + if (lcdInited) { lcdOn(); } - lcdInitDirectDrawing(); - lcd->clear(); drawChargingInfo(chargeState); - // DEBUG INFO + // DEBUG INFO - TODO delete or replace with LVGL objects #if 0 char buffer[1024]; @@ -338,8 +364,6 @@ void handle_battery_charge(uint32_t last_press_time) sprintf(buffer, "%d", isChargerActive()); lcd->drawSizedText(100, 130, buffer, strlen(buffer), CENTERED | COLOR_THEME_PRIMARY2); #endif - - lcdRefresh(); } } diff --git a/radio/src/targets/st16/battery_driver.h b/radio/src/targets/st16/battery_driver.h index eaf85365b..2db5db60a 100644 --- a/radio/src/targets/st16/battery_driver.h +++ b/radio/src/targets/st16/battery_driver.h @@ -19,14 +19,7 @@ * GNU General Public License for more details. */ -/*************************************************************************************************** - -***************************************************************************************************/ -#ifndef __BATTERY_DRIVER_H__ - #define __BATTERY_DRIVER_H__ -/*************************************************************************************************** - -***************************************************************************************************/ +#pragma once #include "board.h" #include "hal.h" @@ -47,5 +40,4 @@ extern void handle_battery_charge(uint32_t last_press_time); extern uint16_t get_battery_charge_state(); extern uint16_t getBatteryVoltage(); // returns current battery voltage in 10mV steps extern bool isChargerActive(); - -#endif +extern void battery_charge_end(); diff --git a/radio/src/targets/st16/board.cpp b/radio/src/targets/st16/board.cpp index 0c3dfb736..bf5046d53 100644 --- a/radio/src/targets/st16/board.cpp +++ b/radio/src/targets/st16/board.cpp @@ -233,6 +233,8 @@ void boardInit() boardOff(); } else { uint32_t press_end_touch = press_end; + extern void rotaryEncoderCheck(); + rotaryEncoderCheck(); rotenc_t value = rotaryEncoderGetValue(); if (value != lastEncoderValue) { lastEncoderValue = value; @@ -244,6 +246,7 @@ void boardInit() press_end = 0; } } + battery_charge_end(); } #endif @@ -259,8 +262,6 @@ void boardInit() #if defined(RTCLOCK) rtcInit(); // RTC must be initialized before rambackupRestore() is called #endif - - lcdSetInitalFrameBuffer(lcdFront->getData()); } extern void rtcDisableBackupReg(); diff --git a/radio/src/targets/stm32h7s78-dk/board.cpp b/radio/src/targets/stm32h7s78-dk/board.cpp index fcf925fab..289d77d77 100644 --- a/radio/src/targets/stm32h7s78-dk/board.cpp +++ b/radio/src/targets/stm32h7s78-dk/board.cpp @@ -126,7 +126,6 @@ void boardInit() delay_ms(50); // GT911 is a bit slow on power ON touchPanelInit(); - lcdSetInitalFrameBuffer(lcdFront->getData()); } extern void rtcDisableBackupReg();