Update drivers and screenshot

This commit is contained in:
fvanroie 2020-05-22 20:29:17 +02:00
parent 3011b1abc2
commit f565ebab28
6 changed files with 169 additions and 291 deletions

View File

@ -52,6 +52,7 @@ void tft_espi_init(uint8_t rotation)
tft.begin();
tft.setSwapBytes(true); /* set endianess */
tft.setRotation(rotation);
tft.fillScreen(TFT_DARKCYAN);
#ifdef USE_DMA_TO_TFT
// DMA - should work with STM32F2xx/F4xx/F7xx processors
@ -91,6 +92,28 @@ void tft_espi_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color
}
#if defined(TOUCH_CS)
void tft_espi_calibrate(uint16_t * calData)
{
tft.fillScreen(TFT_BLACK);
tft.setCursor(20, 0);
tft.setTextFont(1);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.println(PSTR("Touch corners as indicated"));
tft.setTextFont(1);
delay(500);
tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
tft.setTouch(calData);
}
void tft_espi_set_touch(uint16_t * calData)
{
tft.setTouch(calData);
}
bool tft_espi_get_touch(uint16_t * touchX, uint16_t * touchY, uint16_t threshold)
{
return tft.getTouch(touchX, touchY, threshold);

View File

@ -47,6 +47,8 @@ void tft_espi_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t co
void tft_espi_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
#if defined(TOUCH_CS)
void tft_espi_calibrate(uint16_t * calData);
void tft_espi_set_touch(uint16_t * calData);
bool tft_espi_get_touch(uint16_t * touchX, uint16_t * touchY, uint16_t threshold);
#endif

View File

@ -5,13 +5,11 @@
#include "lvgl.h"
#include "lv_drv_conf.h"
//#define USE_FSMC 1
// Display Driver
// Select Display Driver
#if defined(USE_FSMC)
#include "display/fsmc_ili9341.h"
#include "fsmc_ili9341.h"
#else
#include "display/tft_espi_drv.h"
#include "tft_espi_drv.h"
#endif
// Touch Driver
@ -21,10 +19,8 @@
// Filesystem Driver
#include "lv_fs_if.h"
//#include "TFT_eSPI.h" // moved to Display Driver
//#include "lv_zifont.h"
//#include "hasp_tft.h"
#include "hasp_debug.h"
#include "hasp_config.h"
#include "hasp_dispatch.h"
@ -50,29 +46,11 @@
#include <FS.h> // Include the SPIFFS library
#endif
#define BACKLIGHT_CHANNEL 15 // pwm channek 0-15
#define BACKLIGHT_CHANNEL 15 // pwm channel 0-15
/* ---------- Screenshot Variables ---------- */
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
#if HASP_USE_SPIFFS > 0
File pFileOut;
#endif
uint8_t guiSnapshot = 0;
#if defined(STM32F4xx)
//#include <EthernetWebServer_STM32.h>
// EthernetWebServer * webClient(0);
#endif
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WebServer.h>
ESP8266WebServer * webClient; // for snatshot
#endif
#if defined(ARDUINO_ARCH_ESP32)
#include <WebServer.h>
WebServer * webClient; // for snatshot
#endif // ESP32
/* ------------------------------------------- */
// #define LVGL_TICK_PERIOD 30
@ -125,95 +103,7 @@ static bool guiCheckSleep()
return false;
}
// static void gui_take_screenshot(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
// {
// uint i = 0;
// uint16_t c;
// uint8_t pixel[1024];
// for(int y = area->y1; y <= area->y2; y++) {
// for(int x = area->x1; x <= area->x2; x++) {
// /* Function for converting LittlevGL pixel format to RGB888 */
// // data = DISP_IMPL_lvgl_formatPixel(*color_p);
// // Complex 32 bpp
// /* pixel[i++] = (LV_COLOR_GET_B(*color_p) * 263 + 7) >> 5;
// pixel[i++] = (LV_COLOR_GET_G(*color_p) * 259 + 3) >> 6;
// pixel[i++] = (LV_COLOR_GET_R(*color_p) * 263 + 7) >> 5;
// pixel[i++] = 0xFF;*/
// // Simple 32 bpp
// // pixel[i++] = (LV_COLOR_GET_B(*color_p) << 3);
// // pixel[i++] = (LV_COLOR_GET_G(*color_p) << 2);
// // pixel[i++] = (LV_COLOR_GET_R(*color_p) << 3);
// // pixel[i++] = 0xFF;
// c = color_p->full;
// // Simple 16 bpp
// pixel[i++] = c & 0xFF;
// pixel[i++] = (c >> 8) & 0xFF;
// color_p++;
// if(i + 4 >= sizeof(pixel)) {
// switch(guiSnapshot) {
// case 1:
// // Save to local file
// pFileOut.write(pixel, i);
// break;
// case 2:
// // Send to remote client
// if(webClient->client().write(pixel, i) != i) {
// Log.warning(F("GUI: Pixelbuffer not completely sent"));
// lv_disp_flush_ready(disp); /* tell lvgl that flushing is done */
// return;
// }
// }
// i = 0;
// }
// }
// }
// if(i > 0) {
// switch(guiSnapshot) {
// case 1:
// // Save to local file
// pFileOut.write(pixel, i);
// break;
// case 2:
// // Send to remote client
// if(webClient->client().write(pixel, i) != i) {
// Log.warning(F("GUI: Pixelbuffer not completely sent"));
// }
// }
// }
// }
/* Flush VDB bytes to a stream */
static void gui_take_screenshot(uint8_t * data_p, size_t len)
{
size_t res = 0;
switch(guiSnapshot) {
#if HASP_USE_SPIFFS > 0
case 1:
res = pFileOut.write(data_p, len);
break;
#endif
case 2:
#if HASP_USE_HTTP > 0
res = httpClientWrite(data_p, len);
#endif
break;
default:
res = 0; // nothing to do
}
if(res != len) {
Log.warning(F("GUI: Pixelbuffer not completely sent"));
}
}
/* Experimetnal Display flushing */
/* Experimental Display flushing */
static void IRAM_ATTR my_flush_cb(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
#if 0
@ -226,9 +116,9 @@ static void IRAM_ATTR my_flush_cb(lv_disp_drv_t * disp, const lv_area_t * area,
tft.endWrite(); /* terminate TFT transaction */
/* Send Screenshot data */
if(guiSnapshot != 0) {
gui_take_screenshot((uint8_t *)color_p, len * sizeof(lv_color_t)); /* Number of bytes */
}
// if(guiSnapshot != 0) {
// gui_take_screenshot(disp, area, color_p);
//}
#endif
#if defined(USE_FSMC)
@ -236,96 +126,11 @@ static void IRAM_ATTR my_flush_cb(lv_disp_drv_t * disp, const lv_area_t * area,
#else
tft_espi_flush(area->x1, area->y1, area->x2, area->y2, color_p);
#endif
/* Tell lvgl that flushing is done */
lv_disp_flush_ready(disp);
}
/* Display flushing */
/*
void tft_espi_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
uint16_t c;
tft.startWrite(); // Start new TFT transaction
tft.setAddrWindow(area->x1, area->y1, (area->x2 - area->x1 + 1),
(area->y2 - area->y1 + 1)); // set the working window
if(guiSnapshot != 0) {
uint i = 0;
uint8_t pixel[1024];
for(int y = area->y1; y <= area->y2; y++) {
for(int x = area->x1; x <= area->x2; x++) {
// Function for converting LittlevGL pixel format to RGB888
// data = DISP_IMPL_lvgl_formatPixel(*color_p);
// Complex 32 bpp
// pixel[i++] = (LV_COLOR_GET_B(*color_p) * 263 + 7) >> 5;
// pixel[i++] = (LV_COLOR_GET_G(*color_p) * 259 + 3) >> 6;
// pixel[i++] = (LV_COLOR_GET_R(*color_p) * 263 + 7) >> 5;
// pixel[i++] = 0xFF;
// Simple 32 bpp
// pixel[i++] = (LV_COLOR_GET_B(*color_p) << 3);
// pixel[i++] = (LV_COLOR_GET_G(*color_p) << 2);
// pixel[i++] = (LV_COLOR_GET_R(*color_p) << 3);
// pixel[i++] = 0xFF;
c = color_p->full;
tft.writeColor(c, 1); // also update tft
// Simple 16 bpp
pixel[i++] = c & 0xFF;
pixel[i++] = (c >> 8) & 0xFF;
color_p++;
if(i + 4 >= sizeof(pixel)) {
switch(guiSnapshot) {
case 1:
// Save to local file
pFileOut.write(pixel, i);
break;
case 2:
// Send to remote client
if(webClient->client().write(pixel, i) != i) {
Log.warning(F("GUI: Pixelbuffer not completely sent"));
lv_disp_flush_ready(disp); // tell lvgl that flushing is done
return;
}
}
i = 0;
}
}
}
if(i > 0) {
switch(guiSnapshot) {
case 1:
// Save to local file
pFileOut.write(pixel, i);
break;
case 2:
// Send to remote client
if(webClient->client().write(pixel, i) != i) {
Log.warning(F("GUI: Pixelbuffer not completely sent"));
}
}
}
} else {
for(int y = area->y1; y <= area->y2; y++) {
for(int x = area->x1; x <= area->x2; x++) {
c = color_p->full;
tft.writeColor(c, 1);
color_p++;
}
}
}
tft.endWrite(); // terminate TFT transaction
lv_disp_flush_ready(disp); // tell lvgl that flushing is done
} */
/* Interrupt driven periodic handler */
static void IRAM_ATTR lv_tick_handler(void)
{
@ -596,9 +401,7 @@ bool IRAM_ATTR my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t *
return false;
#endif
if(!touched) return false;
if(guiSleeping > 0) guiCheckSleep(); // update Idle
if(touched && guiSleeping > 0) guiCheckSleep(); // update Idle
// Ignore first press?
@ -624,25 +427,14 @@ bool IRAM_ATTR my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t *
void guiCalibrate()
{
#if TOUCH_DRIVER == 0 && 0
tft.fillScreen(TFT_BLACK);
tft.setCursor(20, 0);
tft.setTextFont(1);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.println(PSTR("Touch corners as indicated"));
tft.setTextFont(1);
delay(500);
tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
#if TOUCH_DRIVER == 0 && USE_TFT_ESPI > 0
tft_espi_calibrate(calData);
for(uint8_t i = 0; i < 5; i++) {
Serial.print(calData[i]);
if(i < 4) Serial.print(", ");
}
tft.setTouch(calData);
delay(500);
lv_obj_invalidate(lv_disp_get_layer_sys(NULL));
#endif
@ -658,6 +450,10 @@ void guiSetup()
tft_espi_init(guiRotation);
#endif
#if TOUCH_DRIVER == 1
GT911_setup();
#endif
#if 0
tft.begin();
tft.setSwapBytes(true); /* set endianess */
@ -669,8 +465,8 @@ void guiSetup()
#endif
tft.setRotation(guiRotation); /* 1/3=Landscape or 0/2=Portrait orientation */
#if TOUCH_DRIVER == 0
tft.setTouch(calData);
#if TOUCH_DRIVER == 0 && USE_TFT_ESPI > 0
tft_espi_set_touch(calData);
#endif
#endif
@ -769,6 +565,29 @@ void guiSetup()
}
lv_disp_drv_register(&disp_drv);
/* Initialize Global progress bar*/
lv_obj_t * bar = lv_bar_create(lv_layer_sys(), NULL);
lv_obj_set_hidden(bar, true);
lv_bar_set_range(bar, 0, 100);
lv_bar_set_value(bar, 10, LV_ANIM_OFF);
lv_obj_set_size(bar, 200, 15);
lv_obj_align(bar, lv_layer_sys(), LV_ALIGN_CENTER, 0, -10);
lv_obj_set_user_data(bar, 10);
lv_obj_set_style_local_value_color(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_value_align(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_ALIGN_CENTER);
lv_obj_set_style_local_value_ofs_y(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, 20);
lv_obj_set_style_local_value_font(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, &lv_font_montserrat_12);
lv_obj_set_style_local_bg_color(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_bg_opa(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0);
/*Initialize the graphics library's tick*/
#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266)
tick.attach_ms(guiTickPeriod, lv_tick_handler);
#else
tick.start();
#endif
lv_tick_handler();
/*Initialize the touch pad*/
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
@ -823,7 +642,6 @@ void guiSetup()
/*Initialize the graphics library's tick*/
#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266)
tick.attach_ms(guiTickPeriod, lv_tick_handler);
#else
/*
@ -849,10 +667,6 @@ void guiSetup()
MyTim->resume();*/
tick.start();
#endif
#if TOUCH_DRIVER == 1
GT911_setup();
#endif
}
void IRAM_ATTR guiLoop()
@ -952,8 +766,9 @@ bool guiGetConfig(const JsonObject & settings)
v.set(calData[i]);
} else {
changed = true;
#if 0
tft.setTouch(calData);
#if TOUCH_DRIVER == 0 && USE_TFT_ESPI > 0
tft_espi_set_touch(calData);
#endif
}
i++;
@ -966,8 +781,9 @@ bool guiGetConfig(const JsonObject & settings)
array.add(calData[i]);
}
changed = true;
#if 0
tft.setTouch(calData);
#if TOUCH_DRIVER == 0 && USE_TFT_ESPI > 0
tft_espi_set_touch(calData);
#endif
}
@ -1025,8 +841,8 @@ bool guiSetConfig(const JsonObject & settings)
oobeSetAutoCalibrate(true);
}
#if 0
if(status) tft.setTouch(calData);
#if TOUCH_DRIVER == 0 && USE_TFT_ESPI > 0
if(status) tft_espi_set_touch(calData);
#endif
changed |= status;
}
@ -1034,6 +850,9 @@ bool guiSetConfig(const JsonObject & settings)
return changed;
}
/* **************************** SCREENSHOTS ************************************** */
#if HASP_USE_SPIFFS > 0 || HASP_USE_HTTP > 0
static void guiSetBmpHeader(uint8_t * buffer_p, int32_t data)
{
*buffer_p++ = data & 0xFF;
@ -1042,25 +861,6 @@ static void guiSetBmpHeader(uint8_t * buffer_p, int32_t data)
*buffer_p++ = (data >> 24) & 0xFF;
}
static void guiSendBmpHeader();
void guiTakeScreenshot()
{
// webClient = &client;
// lv_disp_t * disp = lv_disp_get_default();
// webClient->setContentLength(122 + disp->driver.hor_res * disp->driver.ver_res * sizeof(lv_color_t));
// webClient->send(200, PSTR("image/bmp"), "");
guiSnapshot = 2;
guiSendBmpHeader();
lv_obj_invalidate(lv_scr_act());
lv_refr_now(NULL); /* Will call our disp_drv.disp_flush function */
guiSnapshot = 0;
Log.verbose(F("GUI: Bitmap data flushed to webclient"));
}
/** Send Bitmap Header.
*
* Sends a header in BMP format for the size of the screen.
@ -1068,10 +868,11 @@ void guiTakeScreenshot()
* @note: send header before refreshing the whole screen
*
**/
static void guiSendBmpHeader()
static void gui_get_bitmap_header(uint8_t * buffer, size_t bufsize)
{
uint8_t buffer[128];
memset(buffer, 0, sizeof(buffer));
// uint8_t buffer[128];
// memset(buffer, 0, sizeof(buffer));
memset(buffer, 0, bufsize);
lv_disp_t * disp = lv_disp_get_default();
buffer[0] = 0x42; // B
@ -1109,55 +910,106 @@ static void guiSendBmpHeader()
buffer[70 + 2] = 0x69;
buffer[70 + 1] = 0x6E;
buffer[70 + 0] = 0x20;
}
void gui_flush_not_complete()
{
Log.warning(F("GUI: Pixelbuffer not completely sent"));
}
#endif // HASP_USE_SPIFFS > 0 || HASP_USE_HTTP > 0
if(guiSnapshot == 1) {
#if HASP_USE_SPIFFS > 0
size_t len = pFileOut.write(buffer, 122);
if(len != sizeof(buffer)) {
Log.warning(F("GUI: Data written does not match header size"));
} else {
Log.verbose(F("GUI: Bitmap header written"));
}
#endif
} else if(guiSnapshot == 2) {
#if HASP_USE_HTTP > 0
if(httpClientWrite(buffer, 122) != 122) {
Log.warning(F("GUI: Data sent does not match header size"));
} else {
Log.verbose(F("GUI: Bitmap header sent"));
}
#endif
}
/* Flush VDB bytes to a file */
static void gui_screenshot_to_file(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
size_t len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1); /* Number of pixels */
len *= sizeof(lv_color_t); /* Number of bytes */
size_t res = pFileOut.write((uint8_t *)color_p, len);
if(res != len) gui_flush_not_complete();
my_flush_cb(disp, area, color_p);
}
/** Take Screenshot.
*
* Flush buffer into a binary file.
*
* @note: data pixel should be formated to uint32_t RGBA. Imagemagick requirements.
* @note: data pixel should be formated to uint16_t RGB. Set by Bitmap header.
*
* @param[in] pFileName Output binary file name.
*
**/
#if HASP_USE_SPIFFS > 0
void guiTakeScreenshot(const char * pFileName)
{
uint8_t buffer[128];
gui_get_bitmap_header(buffer, sizeof(buffer));
pFileOut = SPIFFS.open(pFileName, "w");
if(pFileOut) {
if(pFileOut == 0) {
size_t len = pFileOut.write(buffer, 122);
if(len == 122) {
Log.verbose(F("GUI: Bitmap header written"));
/* Refresh screen to screenshot callback */
lv_disp_t * disp = lv_disp_get_default();
void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
flush_cb = disp->driver.flush_cb; /* store callback */
disp->driver.flush_cb = gui_screenshot_to_file;
lv_obj_invalidate(lv_scr_act());
lv_refr_now(NULL); /* Will call our disp_drv.disp_flush function */
disp->driver.flush_cb = flush_cb; /* restore callback */
Log.verbose(F("GUI: Birmap data flushed to %s"), pFileName);
} else {
Log.error(F("GUI: Data written does not match header size"));
}
pFileOut.close();
} else {
Log.warning(F("GUI: %s cannot be opened"), pFileName);
return;
}
}
#endif
guiSnapshot = 1;
guiSendBmpHeader();
#if HASP_USE_HTTP > 0
/* Flush VDB bytes to a webclient */
static void gui_screenshot_to_http(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
size_t len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1); /* Number of pixels */
len *= sizeof(lv_color_t); /* Number of bytes */
size_t res = httpClientWrite((uint8_t *)color_p, len);
if(res != len) gui_flush_not_complete();
my_flush_cb(disp, area, color_p);
}
lv_obj_invalidate(lv_scr_act());
lv_refr_now(NULL); /* Will call our disp_drv.disp_flush function */
guiSnapshot = 0;
/** Take Screenshot.
*
* Flush buffer into a http client.
*
* @note: data pixel should be formated to uint16_t RGB. Set by Bitmap header.
*
**/
void guiTakeScreenshot()
{
uint8_t buffer[128];
gui_get_bitmap_header(buffer, sizeof(buffer));
pFileOut.close();
Log.verbose(F("[Display] data flushed to %s"), pFileName);
if(httpClientWrite(buffer, 122) == 122) {
Log.verbose(F("GUI: Bitmap header sent"));
/* Refresh screen to screenshot callback */
lv_disp_t * disp = lv_disp_get_default();
void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
flush_cb = disp->driver.flush_cb; /* store callback */
disp->driver.flush_cb = gui_screenshot_to_http;
lv_obj_invalidate(lv_scr_act());
lv_refr_now(NULL); /* Will call our disp_drv.disp_flush function */
disp->driver.flush_cb = flush_cb; /* restore callback */
Log.verbose(F("GUI: Bitmap data flushed to webclient"));
} else {
Log.error(F("GUI: Data sent does not match header size"));
}
}
#endif

View File

@ -52,11 +52,12 @@ void tftShowConfig(TFT_eSPI & tft)
tft.getSetup(tftSetup);
Log.verbose(F("TFT: TFT_eSPI : v%s"), tftSetup.version.c_str());
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_32)
Log.verbose(F("TFT: Processor : ESP%x"), tftSetup.esp);
#else
Log.verbose(F("TFT: Processor : STM%x"), tftSetup.esp);
#endif
// #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
// Log.verbose(F("TFT: Processor : ESP%x"), tftSetup.esp);
// #else
// Log.verbose(F("TFT: Processor : STM%x"), tftSetup.esp);
// #endif
Log.verbose(F("TFT: Processor : %s"), halGetChipModel());
Log.verbose(F("TFT: CPU freq. : %i MHz"), halGetCpuFreqMHz());
#if defined(ARDUINO_ARCH_ESP8266)
@ -70,7 +71,7 @@ void tftShowConfig(TFT_eSPI & tft)
if(tftSetup.tft_driver != 0xE9D) // For ePaper displays the size is defined in the sketch
{
Log.verbose(F("TFT: Driver : %s"),halDisplayDriverName().c_str()); // tftSetup.tft_driver);
Log.verbose(F("TFT: Driver : %s"), halDisplayDriverName().c_str()); // tftSetup.tft_driver);
Log.verbose(F("TFT: Resolution : %ix%i"), tftSetup.tft_width, tftSetup.tft_height);
} else if(tftSetup.tft_driver == 0xE9D)
Log.verbose(F("Driver = ePaper"));