fix(color): screen refresh may be slower on some radios after update to LVGL 8.4 (#6349)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 <lvgl/lvgl.h>
|
||||
|
||||
#if LV_USE_GPU_STM32_DMA2D
|
||||
#include <lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h>
|
||||
#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);
|
||||
}
|
||||
+16
-118
@@ -23,14 +23,12 @@
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#if LV_USE_GPU_STM32_DMA2D
|
||||
#include <lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h>
|
||||
#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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -126,7 +126,6 @@ void boardInit()
|
||||
|
||||
delay_ms(50); // GT911 is a bit slow on power ON
|
||||
touchPanelInit();
|
||||
lcdSetInitalFrameBuffer(lcdFront->getData());
|
||||
}
|
||||
|
||||
extern void rtcDisableBackupReg();
|
||||
|
||||
Reference in New Issue
Block a user