From 2223e5722af82753dc8ae335d691644ae55d1ab8 Mon Sep 17 00:00:00 2001 From: fvanroie <15969459+fvanroie@users.noreply.github.com> Date: Sun, 21 Feb 2021 20:45:43 +0100 Subject: [PATCH] Move to haspTft class --- src/drv/tft_driver.h | 48 +++++++++ src/drv/tft_driver_sdl2.h | 93 ++++++++++++++++++ src/drv/tft_driver_tftesp.cpp | 7 ++ src/drv/tft_driver_tftespi.h | 177 ++++++++++++++++++++++++++++++++++ src/hasp_gui.cpp | 95 +++++------------- 5 files changed, 347 insertions(+), 73 deletions(-) create mode 100644 src/drv/tft_driver.h create mode 100644 src/drv/tft_driver_sdl2.h create mode 100644 src/drv/tft_driver_tftesp.cpp create mode 100644 src/drv/tft_driver_tftespi.h diff --git a/src/drv/tft_driver.h b/src/drv/tft_driver.h new file mode 100644 index 00000000..a44dfba4 --- /dev/null +++ b/src/drv/tft_driver.h @@ -0,0 +1,48 @@ +/* MIT License - Copyright (c) 2020 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_BASE_TFT_DRIVER_H +#define HASP_BASE_TFT_DRIVER_H + +#ifdef ARDUINO +#include "Arduino.h" +#endif +#include "lvgl.h" + +namespace dev { + +class BaseTft { + public: + virtual void init(int w, int h) + {} + virtual void show_info() + {} + virtual void set_rotation(uint8_t rotation) + {} + virtual void set_invert(bool invert_display) + {} + static void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) + {} +}; + +} // namespace dev + +#if defined(ESP32) +#warning Building for ESP32 Devices +#include "tft_driver_tftespi.h" +#elif defined(ESP8266) +#warning Building for ESP8266 Devices +#include "tft_driver_tftespi.h" +#elif defined(STM32F4) +#warning Building for STM32F4xx Devices +#include "tft_driver_tftespi.h" +#elif defined(WINDOWS) +#warning Building for Win32 Devices +#include "tft_driver_sdl2.h" +#else +#warning Building for Generic Devices +using dev::BaseTft; +extern dev::BaseTft haspTft; +#endif + +#endif \ No newline at end of file diff --git a/src/drv/tft_driver_sdl2.h b/src/drv/tft_driver_sdl2.h new file mode 100644 index 00000000..0419427a --- /dev/null +++ b/src/drv/tft_driver_sdl2.h @@ -0,0 +1,93 @@ +/* MIT License - Copyright (c) 2020 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_SDL2_DRIVER_H +#define HASP_SDL2_DRIVER_H + +#include "lvgl.h" +#include + +#include "display/monitor.h" +#include "indev/mouse.h" + +#include "tft_driver.h" +#include "dev/device.h" +#include "hasp_debug.h" + +//#include "bootscreen.h" // Sketch tab header for xbm images + +namespace dev { + +/** + * A task to measure the elapsed time for LittlevGL + * @param data unused + * @return never return + */ +static int tick_thread(void* data) +{ + (void)data; + + while(1) { + SDL_Delay(5); /*Sleep for 5 millisecond*/ + lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/ + } + + return 0; +} + +class TftSdl2 : BaseTft { + public: + void init(int w, int h) + { + +// Workaround for sdl2 `-m32` crash +// https://bugs.launchpad.net/ubuntu/+source/libsdl2/+bug/1775067/comments/7 +#ifndef WIN32 + setenv("DBUS_FATAL_WARNINGS", "0", 1); +#endif + + /* Add a display + * Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/ + monitor_init(); + monitor_title(haspDevice.get_hostname()); + + /* Add the mouse as input device + * Use the 'mouse' driver which reads the PC's mouse*/ + mouse_init(); + + /* Tick init. + * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed + * Create an SDL thread to do this*/ + SDL_CreateThread(tick_thread, "tick", NULL); + } + void show_info() + { + SDL_version linked; + SDL_GetVersion(&linked); + LOG_VERBOSE(TAG_TFT, F("SDL2 : v%d.%d.%d"), linked.major, linked.minor, linked.patch); + LOG_VERBOSE(TAG_TFT, F("Driver : SDL2")); + } + + void splashscreen() + { + // tft.fillScreen(TFT_DARKCYAN); + // int x = (tft.width() - logoWidth) / 2; + // int y = (tft.height() - logoHeight) / 2; + // tft.drawXBitmap(x, y, bootscreen, logoWidth, logoHeight, TFT_WHITE); + } + void set_rotation(uint8_t rotation) + {} + void set_invert(bool invert) + {} + static void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) + { + monitor_flush(disp, area, color_p); + } +}; + +} // namespace dev + +using dev::TftSdl2; +extern dev::TftSdl2 haspTft; + +#endif \ No newline at end of file diff --git a/src/drv/tft_driver_tftesp.cpp b/src/drv/tft_driver_tftesp.cpp new file mode 100644 index 00000000..2928d035 --- /dev/null +++ b/src/drv/tft_driver_tftesp.cpp @@ -0,0 +1,7 @@ +/* MIT License - Copyright (c) 2020 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifdef ARDUINO +#include "tft_driver_tftespi.h" +dev::TftEspi haspTft; +#endif \ No newline at end of file diff --git a/src/drv/tft_driver_tftespi.h b/src/drv/tft_driver_tftespi.h new file mode 100644 index 00000000..d6e46793 --- /dev/null +++ b/src/drv/tft_driver_tftespi.h @@ -0,0 +1,177 @@ +/* MIT License - Copyright (c) 2020 Francis Van Roie + For full license information read the LICENSE file in the project folder */ + +#ifndef HASP_TFTESPI_DRIVER_H +#define HASP_TFTESPI_DRIVER_H + +#ifdef ARDUINO +#include "Arduino.h" +#endif + +#include "lvgl.h" +#include "tft_espi.h" + +#include "tft_driver.h" +#include "hal/hasp_hal.h" +#include "dev/device.h" +#include "hasp_debug.h" + +#include "bootscreen.h" // Sketch tab header for xbm images + +namespace dev { + +class TftEspi : BaseTft { + + public: + void init(int w, int h) + { + tft.begin(); + tft.setSwapBytes(true); /* set endianess */ + } + void show_info() + { + + setup_t tftSetup; + tft.getSetup(tftSetup); + + LOG_VERBOSE(TAG_TFT, F("TFT_eSPI : v%s"), tftSetup.version.c_str()); + LOG_VERBOSE(TAG_TFT, F("Transactns : %s"), (tftSetup.trans == 1) ? PSTR("Yes") : PSTR("No")); + LOG_VERBOSE(TAG_TFT, F("Interface : %s"), (tftSetup.serial == 1) ? PSTR("SPI") : PSTR("Parallel")); + +#if defined(ARDUINO_ARCH_ESP8266) + LOG_VERBOSE(TAG_TFT, F("SPI overlap: %s"), (tftSetup.overlap == 1) ? PSTR("Yes") : PSTR("No")); +#endif + + if(tftSetup.tft_driver != 0xE9D) // For ePaper displays the size is defined in the sketch + { + LOG_VERBOSE(TAG_TFT, F("Driver : %s"), halDisplayDriverName().c_str()); // tftSetup.tft_driver); + LOG_VERBOSE(TAG_TFT, F("Resolution : %ix%i"), tftSetup.tft_width, tftSetup.tft_height); + } else if(tftSetup.tft_driver == 0xE9D) + LOG_VERBOSE(TAG_TFT, F("Driver = ePaper")); + + // Offsets, not all used yet + tftOffsetInfo(0, tftSetup.r0_x_offset, tftSetup.r0_y_offset); + tftOffsetInfo(1, tftSetup.r1_x_offset, tftSetup.r1_y_offset); + tftOffsetInfo(2, tftSetup.r2_x_offset, tftSetup.r2_y_offset); + tftOffsetInfo(3, tftSetup.r3_x_offset, tftSetup.r3_y_offset); + /* replaced by tftOffsetInfo + // if(tftSetup.r1_x_offset != 0) Serial.printf("R1 x offset = %i \n", tftSetup.r1_x_offset); + // if(tftSetup.r1_y_offset != 0) Serial.printf("R1 y offset = %i \n", tftSetup.r1_y_offset); + // if(tftSetup.r2_x_offset != 0) Serial.printf("R2 x offset = %i \n", tftSetup.r2_x_offset); + // if(tftSetup.r2_y_offset != 0) Serial.printf("R2 y offset = %i \n", tftSetup.r2_y_offset); + // if(tftSetup.r3_x_offset != 0) Serial.printf("R3 x offset = %i \n", tftSetup.r3_x_offset); + // if(tftSetup.r3_y_offset != 0) Serial.printf("R3 y offset = %i \n", tftSetup.r3_y_offset); + */ + + tftPinInfo(F("MOSI"), tftSetup.pin_tft_mosi); + tftPinInfo(F("MISO"), tftSetup.pin_tft_miso); + tftPinInfo(F("SCLK"), tftSetup.pin_tft_clk); + +#if defined(ARDUINO_ARCH_ESP8266) + if(tftSetup.overlap == true) { + LOG_VERBOSE(TAG_TFT, F("Overlap selected, following pins MUST be used:")); + + LOG_VERBOSE(TAG_TFT, F("MOSI : SD1 (GPIO 8)")); + LOG_VERBOSE(TAG_TFT, F("MISO : SD0 (GPIO 7)")); + LOG_VERBOSE(TAG_TFT, F("SCK : CLK (GPIO 6)")); + LOG_VERBOSE(TAG_TFT, F("TFT_CS : D3 (GPIO 0)")); + + LOG_VERBOSE(TAG_TFT, F("TFT_DC and TFT_RST pins can be tftSetup defined")); + } +#endif + + tftPinInfo(F("TFT_CS"), tftSetup.pin_tft_cs); + tftPinInfo(F("TFT_DC"), tftSetup.pin_tft_dc); + tftPinInfo(F("TFT_RST"), tftSetup.pin_tft_rst); + + tftPinInfo(F("TOUCH_CS"), tftSetup.pin_tch_cs); + + tftPinInfo(F("TFT_WR"), tftSetup.pin_tft_wr); + tftPinInfo(F("TFT_RD"), tftSetup.pin_tft_rd); + + tftPinInfo(F("TFT_D0"), tftSetup.pin_tft_d0); + tftPinInfo(F("TFT_D1"), tftSetup.pin_tft_d1); + tftPinInfo(F("TFT_D2"), tftSetup.pin_tft_d2); + tftPinInfo(F("TFT_D3"), tftSetup.pin_tft_d3); + tftPinInfo(F("TFT_D4"), tftSetup.pin_tft_d4); + tftPinInfo(F("TFT_D5"), tftSetup.pin_tft_d5); + tftPinInfo(F("TFT_D6"), tftSetup.pin_tft_d6); + tftPinInfo(F("TFT_D7"), tftSetup.pin_tft_d7); + + if(tftSetup.serial == 1) { + LOG_VERBOSE(TAG_TFT, F("Display SPI freq. : %d.%d MHz"), tftSetup.tft_spi_freq / 10, + tftSetup.tft_spi_freq % 10); + } + if(tftSetup.pin_tch_cs != -1) { + LOG_VERBOSE(TAG_TFT, F("Touch SPI freq. : %d.%d MHz"), tftSetup.tch_spi_freq / 10, + tftSetup.tch_spi_freq % 10); + } + } + void splashscreen() + { + tft.fillScreen(TFT_DARKCYAN); + int x = (tft.width() - logoWidth) / 2; + int y = (tft.height() - logoHeight) / 2; + tft.drawXBitmap(x, y, bootscreen, logoWidth, logoHeight, TFT_WHITE); + } + void set_rotation(uint8_t rotation) + { + LOG_VERBOSE(TAG_TFT, F("Rotation : %d"), rotation); + tft.setRotation(rotation); + } + void set_invert(bool invert) + { + char buffer[4]; + memcpy_P(buffer, invert ? PSTR("yes") : PSTR("no"), sizeof(buffer)); + + LOG_VERBOSE(TAG_TFT, F("Invert Disp: %s"), buffer); + tft.invertDisplay(invert); + } + void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) + { + size_t len = lv_area_get_size(area); + + /* Update TFT */ + tft.startWrite(); /* Start new TFT transaction */ + tft.setWindow(area->x1, area->y1, area->x2, area->y2); /* set the working window */ +#ifdef USE_DMA_TO_TFT + tft.pushPixelsDMA((uint16_t*)color_p, len); /* Write words at once */ +#else + tft.pushPixels((uint16_t*)color_p, len); /* Write words at once */ +#endif + tft.endWrite(); /* terminate TFT transaction */ + + /* Tell lvgl that flushing is done */ + lv_disp_flush_ready(disp); + } + + private: + TFT_eSPI tft; + + void tftOffsetInfo(uint8_t pin, uint8_t x_offset, uint8_t y_offset) + { + if(x_offset != 0) { + LOG_VERBOSE(TAG_TFT, F("R%u x offset = %i"), pin, x_offset); + } + if(y_offset != 0) { + LOG_VERBOSE(TAG_TFT, F("R%u y offset = %i"), pin, y_offset); + } + } + + void tftPinInfo(const __FlashStringHelper* pinfunction, int8_t pin) + { + if(pin != -1) { + char buffer[64]; + snprintf_P(buffer, sizeof(buffer), PSTR("%-11s: %s (GPIO %02d)"), pinfunction, halGpioName(pin).c_str(), + pin); + LOG_VERBOSE(TAG_TFT, buffer); + } + } +}; + +} // namespace dev + +using dev::TftEspi; +extern dev::TftEspi haspTft; + +#endif \ No newline at end of file diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index cc9f2706..7063d104 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -12,7 +12,9 @@ #include "lv_fs_if.h" // Device Drivers +#include "drv/tft_driver.h" #include "dev/device.h" + #include "drv/hasp_drv_display.h" #include "drv/hasp_drv_touch.h" @@ -79,6 +81,10 @@ gui_conf_t gui_settings = {.show_pointer = false, // { // lv_tick_inc(LVGL_TICK_PERIOD); // } +void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) +{ + haspTft.flush_pixels(disp, area, color_p); +} void guiCalibrate(void) { @@ -105,6 +111,12 @@ void guiSetup(void) lv_log_register_print_cb(debugLvglLogEvent); #endif + // Initialize the TFT + haspTft.init(240, 320); + haspTft.set_rotation(gui_settings.rotation); + haspTft.set_invert(gui_settings.invert_display); + haspTft.show_info(); + /* Create the Virtual Device Buffers */ #if defined(ARDUINO_ARCH_ESP32) @@ -163,14 +175,8 @@ void guiSetup(void) /* Initialize the display driver */ lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); - disp_drv.buffer = &disp_buf; - -#if defined(WINDOWS) - disp_drv.flush_cb = monitor_flush; -#else - drv_display_init(&disp_drv, gui_settings.rotation, - gui_settings.invert_display); // Set display driver callback & rotation -#endif + disp_drv.buffer = &disp_buf; + disp_drv.flush_cb = gui_flush_cb; disp_drv.hor_res = TFT_WIDTH; disp_drv.ver_res = TFT_HEIGHT; lv_disp_t* display = lv_disp_drv_register(&disp_drv); @@ -206,18 +212,6 @@ void guiSetup(void) /* Setup Backlight Control Pin */ haspDevice.set_backlight_pin(gui_settings.backlight_pin); - // if(gui_settings.backlight_pin >= 0) { - // LOG_VERBOSE(TAG_GUI, F("Backlight : Pin %d"), gui_settings.backlight_pin); - - // #if defined(ARDUINO_ARCH_ESP32) - // ledcSetup(BACKLIGHT_CHANNEL, 20000, 12); - // ledcAttachPin(gui_settings.backlight_pin, BACKLIGHT_CHANNEL); - // #elif defined(ARDUINO_ARCH_ESP8266) - // pinMode(gui_settings.backlight_pin, OUTPUT); - // #endif - // } - LOG_VERBOSE(TAG_GUI, F("Rotation : %d"), gui_settings.rotation); - LOG_VERBOSE(TAG_LVGL, F("Version : %u.%u.%u %s"), LVGL_VERSION_MAJOR, LVGL_VERSION_MINOR, LVGL_VERSION_PATCH, PSTR(LVGL_VERSION_INFO)); @@ -321,57 +315,6 @@ void guiStop() // #endif } -//////////////////////////////////////////////////////////////////////////////////////////////////// -/* -bool guiGetBacklight() -{ - return guiBacklightIsOn; -} - -void guiSetBacklight(bool lighton) -{ - guiBacklightIsOn = lighton; - - if(!lighton) hasp_enable_wakeup_touch(); - - if(gui_settings.backlight_pin >= 0) { - -#if defined(ARDUINO_ARCH_ESP32) - ledcWrite(BACKLIGHT_CHANNEL, lighton ? map(guiDimLevel, 0, 100, 0, 4095) : 0); // ledChannel and value -#else - analogWrite(gui_settings.backlight_pin, lighton ? map(guiDimLevel, 0, 100, 0, 1023) : 0); -#endif - - } else { - guiBacklightIsOn = true; - } -} - -void guiSetDim(int8_t level) -{ - if(gui_settings.backlight_pin >= 0) { - guiDimLevel = level >= 0 ? level : 0; - guiDimLevel = guiDimLevel <= 100 ? guiDimLevel : 100; - - if(guiBacklightIsOn) { // The backlight is ON -#if defined(ARDUINO_ARCH_ESP32) - ledcWrite(BACKLIGHT_CHANNEL, map(guiDimLevel, 0, 100, 0, 4095)); // ledChannel and value -#else - analogWrite(gui_settings.backlight_pin, map(guiDimLevel, 0, 100, 0, 1023)); -#endif - } - - } else { - guiDimLevel = -1; - } -} - -int8_t guiGetDim() -{ - return guiDimLevel; -} -*/ - //////////////////////////////////////////////////////////////////////////////////////////////////// #if HASP_USE_CONFIG > 0 bool guiGetConfig(const JsonObject& settings) @@ -587,7 +530,10 @@ static void gui_screenshot_to_file(lv_disp_drv_t* disp, const lv_area_t* area, l 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(); - drv_display_flush_cb(disp, area, color_p); // indirect callback to flush screenshot data to the screen + + // indirect callback to flush screenshot data to the screen + // drv_display_flush_cb(disp, area, color_p); + haspTft.flush_pixels(disp, area, color_p); } /** Take Screenshot. @@ -642,7 +588,10 @@ static void gui_screenshot_to_http(lv_disp_drv_t* disp, const lv_area_t* area, l len *= sizeof(lv_color_t); /* Number of bytes */ size_t res = httpClientWrite((uint8_t*)color_p, len); if(res != len) gui_flush_not_complete(); - drv_display_flush_cb(disp, area, color_p); + + // indirect callback to flush screenshot data to the screen + // drv_display_flush_cb(disp, area, color_p); + haspTft.flush_pixels(disp, area, color_p); } /** Take Screenshot.