mirror of
https://github.com/arendst/Tasmota.git
synced 2025-04-24 23:07:17 +00:00
272 lines
9.2 KiB
C++
Executable File
272 lines
9.2 KiB
C++
Executable File
#include "Adafruit_LvGL_Glue.h"
|
|
#include <lvgl.h>
|
|
|
|
// ARCHITECTURE-SPECIFIC TIMER STUFF ---------------------------------------
|
|
|
|
extern void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p);
|
|
|
|
// Tick interval for LittlevGL internal timekeeping; 1 to 10 ms recommended
|
|
static const int lv_tick_interval_ms = 5;
|
|
|
|
static void lv_tick_handler(void) { lv_tick_inc(lv_tick_interval_ms); }
|
|
|
|
// TOUCHSCREEN STUFF -------------------------------------------------------
|
|
|
|
// STMPE610 calibration for raw touch data
|
|
#define TS_MINX 100
|
|
#define TS_MAXX 3800
|
|
#define TS_MINY 100
|
|
#define TS_MAXY 3750
|
|
|
|
// Same, for ADC touchscreen
|
|
#define ADC_XMIN 325
|
|
#define ADC_XMAX 750
|
|
#define ADC_YMIN 240
|
|
#define ADC_YMAX 840
|
|
|
|
|
|
|
|
uint32_t Touch_Status(uint32_t sel);
|
|
|
|
static void touchscreen_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
|
|
//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) ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
|
|
data->continue_reading = false; /*No buffering now so no more data read*/
|
|
}
|
|
|
|
// OTHER LITTLEVGL VITALS --------------------------------------------------
|
|
|
|
#if LV_COLOR_DEPTH != 16
|
|
#pragma error("LV_COLOR_DEPTH must be 16")
|
|
#endif
|
|
// This isn't necessarily true, don't mention it for now. See notes later.
|
|
//#if LV_COLOR_16_SWAP != 0
|
|
// #pragma message("Set LV_COLOR_16_SWAP to 0 for best display performance")
|
|
//#endif
|
|
|
|
// Actual RAM usage will be 2X these figures, since using 2 DMA buffers...
|
|
#define LV_BUFFER_ROWS 60 // Most others have a bit more space
|
|
|
|
|
|
// // This is the flush function required for LittlevGL screen updates.
|
|
// // It receives a bounding rect and an array of pixel data (conveniently
|
|
// // already in 565 format, so the Earth was lucky there).
|
|
// static void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
|
|
// // Get pointer to glue object from indev user data
|
|
// Adafruit_LvGL_Glue *glue = (Adafruit_LvGL_Glue *)disp->user_data;
|
|
|
|
// uint16_t width = (area->x2 - area->x1 + 1);
|
|
// uint16_t height = (area->y2 - area->y1 + 1);
|
|
|
|
// // check if we are currently doing a screenshot
|
|
// if (glue->getScreenshotFile() != nullptr) {
|
|
// // save pixels to file
|
|
// int32_t btw = (width * height * LV_COLOR_DEPTH + 7) / 8;
|
|
// while (btw > 0) {
|
|
// int32_t ret = glue->getScreenshotFile()->write((const uint8_t*) color_p, btw);
|
|
// if (ret >= 0) {
|
|
// btw -= ret;
|
|
// } else {
|
|
// btw = 0; // abort
|
|
// }
|
|
// }
|
|
// lv_disp_flush_ready(disp);
|
|
// return; // ok
|
|
// // }
|
|
|
|
// Renderer *display = glue->display;
|
|
|
|
// if (!glue->first_frame) {
|
|
// //display->dmaWait(); // Wait for prior DMA transfer to complete
|
|
// //display->endWrite(); // End transaction from any prior call
|
|
// } else {
|
|
// glue->first_frame = 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);
|
|
|
|
// }
|
|
|
|
// #if (LV_USE_LOG)
|
|
// // Optional LittlevGL debug print function, writes to Serial if debug is
|
|
// // enabled when calling glue begin() function.
|
|
// static void lv_debug(lv_log_level_t level, const char *file, uint32_t line, const char *fname,
|
|
// const char *dsc) {
|
|
// Serial.print(file);
|
|
// Serial.write('@');
|
|
// Serial.print(line);
|
|
// Serial.print(":");
|
|
// Serial.print(fname);
|
|
// Serial.write("->");
|
|
// Serial.println(dsc);
|
|
// }
|
|
// #endif
|
|
|
|
|
|
// GLUE LIB FUNCTIONS ------------------------------------------------------
|
|
|
|
// Constructor
|
|
/**
|
|
* @brief Construct a new Adafruit_LvGL_Glue::Adafruit_LvGL_Glue object,
|
|
* initializing minimal variables
|
|
*
|
|
*/
|
|
Adafruit_LvGL_Glue::Adafruit_LvGL_Glue(void)
|
|
: first_frame(true), lv_pixel_buf(NULL) {
|
|
}
|
|
|
|
// Destructor
|
|
/**
|
|
* @brief Destroy the Adafruit_LvGL_Glue::Adafruit_LvGL_Glue object, freeing any
|
|
* memory previously allocated within this library.
|
|
*
|
|
*/
|
|
Adafruit_LvGL_Glue::~Adafruit_LvGL_Glue(void) {
|
|
delete[] lv_pixel_buf;
|
|
// Probably other stuff that could be deallocated here
|
|
}
|
|
|
|
// begin() function is overloaded for STMPE610 touch, ADC touch, or none.
|
|
|
|
// Pass in POINTERS to ALREADY INITIALIZED display & touch objects (user code
|
|
// should have previously called corresponding begin() functions and checked
|
|
// return states before invoking this),
|
|
// they are NOT initialized here. Debug arg is
|
|
// touch arg can be NULL (or left off) if using LittlevGL as a passive widget
|
|
// display.
|
|
|
|
/**
|
|
* @brief Configure the glue layer and the underlying LvGL code to use the given
|
|
* TFT display driver instance and touchscreen controller
|
|
*
|
|
* @param tft Pointer to an **already initialized** display object instance
|
|
* @param touch Pointer to an **already initialized** `Adafruit_STMPE610`
|
|
* touchscreen controller object instance
|
|
* @param debug Debug flag to enable debug messages. Only used if LV_USE_LOG is
|
|
* configured in LittleLVGL's lv_conf.h
|
|
* @return LvGLStatus The status of the initialization:
|
|
* * LVGL_OK : Success
|
|
* * LVGL_ERR_TIMER : Failure to set up timers
|
|
* * LVGL_ERR_ALLOC : Failure to allocate memory
|
|
*/
|
|
// LvGLStatus Adafruit_LvGL_Glue::begin(uDisplay_lvgl *tft,
|
|
// Adafruit_STMPE610 *touch, bool debug) {
|
|
// is_adc_touch = false;
|
|
// return begin(tft, (void *)touch, debug);
|
|
// }
|
|
/**
|
|
* @brief Configure the glue layer and the underlying LvGL code to use the given
|
|
* TFT display driver and touchscreen controller instances
|
|
*
|
|
* @param tft Pointer to an **already initialized** display object instance
|
|
* @param touch Pointer to an **already initialized** `TouchScreen` touchscreen
|
|
* controller object instance
|
|
* @param debug Debug flag to enable debug messages. Only used if LV_USE_LOG is
|
|
* configured in LittleLVGL's lv_conf.h
|
|
* @return LvGLStatus The status of the initialization:
|
|
* * LVGL_OK : Success
|
|
* * LVGL_ERR_TIMER : Failure to set up timers
|
|
* * LVGL_ERR_ALLOC : Failure to allocate memory
|
|
*/
|
|
// LvGLStatus Adafruit_LvGL_Glue::begin(uDisplay_lvgl *tft, TouchScreen *touch,
|
|
// bool debug) {
|
|
// is_adc_touch = true;
|
|
// return begin(tft, (void *)touch, debug);
|
|
// }
|
|
/**
|
|
* @brief Configure the glue layer and the underlying LvGL code to use the given
|
|
* TFT display driver and touchscreen controller instances
|
|
*
|
|
* @param tft Pointer to an **already initialized** display object instance
|
|
* @param debug Debug flag to enable debug messages. Only used if LV_USE_LOG is
|
|
* configured in LittleLVGL's lv_conf.h
|
|
* @return LvGLStatus The status of the initialization:
|
|
* * LVGL_OK : Success
|
|
* * LVGL_ERR_TIMER : Failure to set up timers
|
|
* * LVGL_ERR_ALLOC : Failure to allocate memory
|
|
*/
|
|
LvGLStatus Adafruit_LvGL_Glue::begin(Renderer *tft, bool debug) {
|
|
return begin(tft, (void *)NULL, debug);
|
|
}
|
|
|
|
LvGLStatus Adafruit_LvGL_Glue::begin(Renderer *tft, void *touch, bool debug) {
|
|
|
|
lv_init();
|
|
|
|
// Allocate LvGL display buffer (x2 because DMA double buffering)
|
|
LvGLStatus status = LVGL_ERR_ALLOC;
|
|
// if ((lv_pixel_buf = new lv_color_t[LV_HOR_RES_MAX * LV_BUFFER_ROWS * 2])) {
|
|
|
|
uint32_t lvgl_buffer_size;
|
|
|
|
//lvgl_buffer_size = LV_HOR_RES_MAX * LV_BUFFER_ROWS;
|
|
uint8_t flushlines = tft->lvgl_pars()->fluslines;
|
|
lvgl_buffer_size = tft->width() * (flushlines ? flushlines:LV_BUFFER_ROWS);
|
|
if (tft->lvgl_pars()->use_dma) {
|
|
lvgl_buffer_size /= 2;
|
|
lv_pixel_buf2 = new lv_color_t[lvgl_buffer_size];
|
|
if (!lv_pixel_buf2) {
|
|
return status;
|
|
}
|
|
} else {
|
|
lv_pixel_buf2 = nullptr;
|
|
}
|
|
|
|
if ((lv_pixel_buf = new lv_color_t[lvgl_buffer_size])) {
|
|
|
|
display = tft;
|
|
touchscreen = (void *)touch;
|
|
|
|
// // Initialize LvGL display buffers
|
|
// lv_disp_buf_init(
|
|
// &lv_disp_buf, lv_pixel_buf, // 1st half buf
|
|
// &lv_pixel_buf[LV_HOR_RES_MAX * LV_BUFFER_ROWS], // 2nd half buf
|
|
// LV_HOR_RES_MAX * LV_BUFFER_ROWS);
|
|
|
|
// Initialize LvGL display buffers
|
|
lv_disp_draw_buf_init(
|
|
&lv_disp_buf, lv_pixel_buf, // 1st half buf
|
|
lv_pixel_buf2, // 2nd half buf
|
|
lvgl_buffer_size);
|
|
|
|
// Initialize LvGL display driver
|
|
lv_disp_drv_init(&lv_disp_drv);
|
|
lv_disp_drv.hor_res = tft->width();
|
|
lv_disp_drv.ver_res = tft->height();
|
|
lv_disp_drv.flush_cb = lv_flush_callback;
|
|
lv_disp_drv.draw_buf = &lv_disp_buf;
|
|
lv_disp_drv.user_data = (void*)this;
|
|
lv_disp_drv_register(&lv_disp_drv);
|
|
|
|
// Initialize LvGL input device (touchscreen already started)
|
|
if (touch) { // Can also pass NULL if passive widget display
|
|
lv_indev_drv_init(&lv_indev_drv); // Basic init
|
|
lv_indev_drv.type = LV_INDEV_TYPE_POINTER; // Is pointer dev
|
|
lv_indev_drv.read_cb = touchscreen_read; // Read callback
|
|
lv_indev_drv.user_data = (void*)this;
|
|
lv_input_dev_ptr = lv_indev_drv_register(&lv_indev_drv);
|
|
}
|
|
|
|
// TIMER SETUP is architecture-specific ----------------------------
|
|
|
|
// ESP 32------------------------------------------------
|
|
tick.attach_ms(lv_tick_interval_ms, lv_tick_handler);
|
|
status = LVGL_OK;
|
|
// -----------------------------------------
|
|
}
|
|
|
|
if (status != LVGL_OK) {
|
|
delete[] lv_pixel_buf;
|
|
lv_pixel_buf = NULL;
|
|
}
|
|
|
|
return status;
|
|
}
|