diff --git a/include/hasp_conf.h b/include/hasp_conf.h index 04429625..0136eddd 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -2,7 +2,7 @@ #define HASP_VERSION_MAJOR 0 #define HASP_VERSION_MINOR 0 -#define HASP_VERSION_REVISION 7 +#define HASP_VERSION_REVISION 8 #define HASP_USE_APP 1 @@ -21,6 +21,9 @@ #define HASP_USE_QRCODE 1 #define HASP_USE_PNGDECODE 0 +#define HASP_NUM_INPUTS 3 // Buttons +#define HASP_NUM_OUTPUTS 3 + //#define LV_DEMO_WALLPAPER 0 /*Create a wallpaper too*/ //#define LV_HASP_HOR_RES_MAX 128 diff --git a/src/hasp_config.cpp b/src/hasp_config.cpp index df82b284..830dc40f 100644 --- a/src/hasp_config.cpp +++ b/src/hasp_config.cpp @@ -14,14 +14,11 @@ #include "hasp_wifi.h" #include "hasp_mdns.h" #include "hasp_gui.h" -#include "hasp_tft.h" +// #include "hasp_tft.h" #include "hasp_ota.h" #include "hasp_spiffs.h" #include "hasp.h" -//#define HASP_CONFIG_FILE F("/config.json") -static const char HASP_CONFIG_FILE[] PROGMEM = "/config.json"; - bool configChanged() { return false; @@ -37,7 +34,7 @@ void configLoop() void configStartDebug(bool setupdebug, String & configFile) { if(setupdebug) { - debugSetup(); // Debug started, now we can use it; HASP header sent + debugStart(); // Debug started, now we can use it; HASP header sent debugPrintln(F("FILE: [SUCCESS] SPI flash FS mounted")); spiffsList(); } @@ -46,8 +43,10 @@ void configStartDebug(bool setupdebug, String & configFile) void configGetConfig(JsonDocument & settings, bool setupdebug = false) { - String configFile = String(FPSTR(HASP_CONFIG_FILE)); - File file = SPIFFS.open(configFile, "r"); + String configFile((char *)0); + configFile.reserve(127); + configFile = String(FPSTR(HASP_CONFIG_FILE)); + File file = SPIFFS.open(configFile, "r"); if(file) { size_t size = file.size(); @@ -60,6 +59,8 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) if(!error) { file.close(); + /* Load Debug params */ + debugPreSetup(settings[F("debug")]); configStartDebug(setupdebug, configFile); // show settings in log @@ -72,6 +73,7 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) debugPrintln(String(F("CONF: ")) + output); debugPrintln(String(F("CONF: [SUCCESS] Loaded ")) + configFile); + debugSetup(settings[F("debug")]); return; } } @@ -82,7 +84,9 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) void configWriteConfig() { - String configFile = String(FPSTR(HASP_CONFIG_FILE)); + String configFile((char *)0); + configFile.reserve(127); + configFile = String(FPSTR(HASP_CONFIG_FILE)); /* Read Config File */ DynamicJsonDocument settings(2 * 1024); @@ -91,7 +95,7 @@ void configWriteConfig() debugPrintln(String(F("CONF: Config LOADED first ")) + configFile); bool changed = true; - // changed |= debugGetConfig(settings[F("debug")].to()); + changed |= debugGetConfig(settings[F("debug")].to()); changed |= guiGetConfig(settings[F("gui")].to()); changed |= haspGetConfig(settings[F("hasp")].to()); changed |= httpGetConfig(settings[F("http")].to()); @@ -133,7 +137,17 @@ void configOutput(const JsonObject & settings) String output((char *)0); output.reserve(127); serializeJson(settings, output); - String passmask = F("********"); - output.replace(settings[F("pass")].as(), passmask); + + String passmask((char *)0); + passmask.reserve(127); + passmask = F("\"pass\":\"********\""); + + String password((char *)0); + password.reserve(127); + password = F("\"pass\":\""); + password += settings[F("pass")].as(); + password += F("\""); + + if(password.length() > 2) output.replace(password, passmask); debugPrintln(String(F("CONF: ")) + output); } \ No newline at end of file diff --git a/src/hasp_config.h b/src/hasp_config.h index 8a28adb5..6047b123 100644 --- a/src/hasp_config.h +++ b/src/hasp_config.h @@ -17,10 +17,15 @@ const char F_CONFIG_USER[] PROGMEM = "user"; const char F_CONFIG_PASS[] PROGMEM = "pass"; const char F_CONFIG_SSID[] PROGMEM = "ssid"; const char F_CONFIG_GROUP[] PROGMEM = "group"; +const char F_GUI_ROTATION[] PROGMEM = "rotation"; const char F_GUI_TICKPERIOD[] PROGMEM = "tickperiod"; -const char F_GUI_IDLEPERIOD[] PROGMEM = "idle"; +const char F_GUI_IDLEPERIOD1[] PROGMEM = "idle1"; +const char F_GUI_IDLEPERIOD2[] PROGMEM = "idle2"; const char F_GUI_CALIBRATION[] PROGMEM = "calibration"; const char F_GUI_BACKLIGHTPIN[] PROGMEM = "bcklpin"; +const char F_DEBUG_TELEPERIOD[] PROGMEM = "teleperiod"; + +const char HASP_CONFIG_FILE[] PROGMEM = "/config.json"; void configSetup(JsonDocument & settings); void configLoop(void); diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp index 5dcb7d2b..55ac3f3c 100644 --- a/src/hasp_debug.cpp +++ b/src/hasp_debug.cpp @@ -9,9 +9,11 @@ #endif #include +#include "hasp_log.h" #include "hasp_hal.h" #include "hasp_debug.h" #include "hasp_config.h" +#include "hasp_dispatch.h" #ifdef USE_CONFIG_OVERRIDE #include "user_config_override.h" @@ -44,7 +46,10 @@ Syslog syslog(syslogClient, debugSyslogHost.c_str(), debugSyslogPort, debugAppNa LOG_LOCAL0); #endif -void debugSetup() +unsigned long debugLastMillis = 0; +uint16_t debugTelePeriod = 300; + +void debugStart() { #if defined(ARDUINO_ARCH_ESP32) Serial.begin(115200); /* prepare for possible serial debug */ @@ -71,9 +76,6 @@ void debugSetup() #endif } -void debugLoop() -{} - void serialPrintln(const char * debugText) { String debugTimeText((char *)0); @@ -82,7 +84,7 @@ void serialPrintln(const char * debugText) debugTimeText = F("["); debugTimeText += String(float(millis()) / 1000, 3); debugTimeText += F("s] "); - debugTimeText += ESP.getMaxFreeBlockSize(); + debugTimeText += halGetMaxFreeBlock(); debugTimeText += F("/"); debugTimeText += ESP.getFreeHeap(); debugTimeText += F(" "); @@ -119,4 +121,53 @@ void syslogSend(uint8_t log, const char * debugText) void debugStop() { Serial.flush(); -} \ No newline at end of file +} + +bool debugGetConfig(const JsonObject & settings) +{ + settings[FPSTR(F_DEBUG_TELEPERIOD)] = debugTelePeriod; + + configOutput(settings); + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool debugSetConfigLog(const JsonObject & settings, bool silent) +{ + bool changed = false; + + if(!settings[FPSTR(F_DEBUG_TELEPERIOD)].isNull()) { + if(debugTelePeriod != settings[FPSTR(F_DEBUG_TELEPERIOD)].as()) { + if(!silent) debugPrintln(F("debugTelePeriod set")); + } + changed |= debugTelePeriod != settings[FPSTR(F_DEBUG_TELEPERIOD)].as(); + + debugTelePeriod = settings[FPSTR(F_DEBUG_TELEPERIOD)].as(); + } + + if(!silent) configOutput(settings); + return changed; +} + +bool debugSetConfig(const JsonObject & settings) +{ + return debugSetConfigLog(settings, false); +} + +void debugPreSetup(JsonObject settings) +{ + debugSetConfigLog(settings, true); +} +void debugSetup(JsonObject settings) +{ + debugSetConfigLog(settings, false); +} + +void debugLoop() +{ + if(debugTelePeriod > 0 && (millis() - debugLastMillis) >= debugTelePeriod * 1000) { + dispatchStatusUpdate(); + debugLastMillis = millis(); + } +} diff --git a/src/hasp_debug.h b/src/hasp_debug.h index fc1c3533..c8ceaf61 100644 --- a/src/hasp_debug.h +++ b/src/hasp_debug.h @@ -1,8 +1,12 @@ #ifndef HASP_DEBUG_H #define HASP_DEBUG_H -void debugSetup(void); +#include "ArduinoJson.h" + +void debugPreSetup(JsonObject settings); +void debugSetup(JsonObject settings); void debugLoop(void); +void debugStart(void); void debugStop(void); void serialPrintln(String & debugText); @@ -10,4 +14,7 @@ void serialPrintln(const char * debugText); void syslogSend(uint8_t log, const char * debugText); +bool debugGetConfig(const JsonObject & settings); +bool debugSetConfig(const JsonObject & settings); + #endif \ No newline at end of file diff --git a/src/hasp_dispatch.cpp b/src/hasp_dispatch.cpp index 36c64f14..e30bcb03 100644 --- a/src/hasp_dispatch.cpp +++ b/src/hasp_dispatch.cpp @@ -15,6 +15,11 @@ void dispatchSetup() void dispatchLoop() {} +void dispatchStatusUpdate() +{ + mqttStatusUpdate(); +} + // objectattribute=value void IRAM_ATTR dispatchAttribute(String & strTopic, const char * payload) { @@ -76,19 +81,20 @@ void IRAM_ATTR dispatchCommand(String cmnd) } else if(cmnd == F("wakeup")) { haspWakeUp(); } else if(cmnd == F("screenshot")) { - guiTakeScreenshot("/screenhot.bmp"); + // guiTakeScreenshot("/screenhot.bmp"); } else if(cmnd == F("reboot") || cmnd == F("restart")) { dispatchReboot(true); } else if(cmnd == "" || cmnd == F("statusupdate")) { - mqttStatusUpdate(); + dispatchStatusUpdate(); } else { int pos = cmnd.indexOf("="); if(pos > 0) { String strTopic = cmnd.substring(0, pos); String strPayload = cmnd.substring(pos + 1, cmnd.length()); - // debugPrintln("CMND: '" + strTopic + "'='" + strPayload + "'"); dispatchAttribute(strTopic, strPayload.c_str()); + } else { + dispatchAttribute(cmnd, ""); } } } @@ -134,4 +140,11 @@ void dispatchReboot(bool saveConfig) debugPrintln(F("-------------------------------------")); ESP.restart(); delay(5000); +} + +void dispatchButton(uint8_t i, bool pressed) +{ + char buffer[127]; + snprintf_P(buffer, sizeof(buffer), PSTR("INPUT%d"), i); + mqttSendState(buffer, String(pressed ? F("ON") : F("OFF")).c_str()); } \ No newline at end of file diff --git a/src/hasp_dispatch.h b/src/hasp_dispatch.h index 458135e4..df635de4 100644 --- a/src/hasp_dispatch.h +++ b/src/hasp_dispatch.h @@ -1,7 +1,7 @@ #ifndef HASP_DISPATCH_H #define HASP_DISPATCH_H -#include +#include "ArduinoJson.h" void dispatchSetup(void); void dispatchLoop(void); @@ -15,5 +15,8 @@ void dispatchDim(String strDimLevel); void dispatchIdle(const __FlashStringHelper * state); void dispatchReboot(bool saveConfig); +void dispatchStatusUpdate(void); + +void dispatchButton(uint8_t i, bool pressed); #endif \ No newline at end of file diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 72bbce3a..d7cbc047 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -26,46 +26,64 @@ #include // Include the SPIFFS library #endif +/* ---------- Screenshot Variables ---------- */ +File pFileOut; +uint8_t guiSnapshot = 0; + #if defined(ARDUINO_ARCH_ESP8266) #include -static ESP8266WebServer * webClient; // for snatshot +ESP8266WebServer * webClient; // for snatshot #endif #if defined(ARDUINO_ARCH_ESP32) #include -static WebServer * webClient; // for snatshot -#endif // ESP32 +WebServer * webClient; // for snatshot +#endif // ESP32 +/* ------------------------------------------- */ -#define LVGL_TICK_PERIOD 30 // 30 +// #define LVGL_TICK_PERIOD 30 #ifndef TFT_BCKL #define TFT_BCKL -1 // No Backlight Control #endif +#ifndef TFT_ROTATION +#define TFT_ROTATION 0 +#endif +bool guiBacklightIsOn = true; int8_t guiDimLevel = -1; int8_t guiBacklightPin = TFT_BCKL; bool guiAutoCalibrate = true; -uint16_t guiSleepTime = 150; // 0.1 second resolution -bool guiSleeping = false; +uint16_t guiSleepTime1 = 60; // 1 second resolution +uint16_t guiSleepTime2 = 120; // 1 second resolution +uint8_t guiSleeping = 0; // 0 = off, 1 = short, 2 = long uint8_t guiTickPeriod = 50; -static Ticker tick; /* timer for interrupt handler */ -static TFT_eSPI tft = TFT_eSPI(); /* TFT instance */ +uint8_t guiRotation = TFT_ROTATION; +static Ticker tick; /* timer for interrupt handler */ +static TFT_eSPI tft; // = TFT_eSPI(); /* TFT instance */ static uint16_t calData[5] = {0, 65535, 0, 65535, 0}; -static File pFileOut; -static uint8_t guiSnapshot = 0; - bool IRAM_ATTR guiCheckSleep() { - bool shouldSleep = lv_disp_get_inactive_time(NULL) > guiSleepTime * 100; - if(shouldSleep && !guiSleeping) { - dispatchIdle(F("LONG")); - guiSleeping = true; - } else if(!shouldSleep && guiSleeping) { - dispatchIdle(F("OFF")); - guiSleeping = false; + if(lv_disp_get_inactive_time(NULL) >= (guiSleepTime1 + guiSleepTime2) * 1000) { + if(guiSleeping != 2) { + dispatchIdle(F("LONG")); + guiSleeping = 2; + } + return true; + } else if(lv_disp_get_inactive_time(NULL) >= guiSleepTime1 * 1000) { + if(guiSleeping != 1) { + dispatchIdle(F("SHORT")); + guiSleeping = 1; + } + return true; + } else { + if(guiSleeping != 0) { + dispatchIdle(F("OFF")); + guiSleeping = 0; + } + return false; } - return shouldSleep; } #if LV_USE_LOG != 0 @@ -73,7 +91,7 @@ bool IRAM_ATTR guiCheckSleep() void debugLvgl(lv_log_level_t level, const char * file, uint32_t line, const char * dsc) { char msg[127]; - sprintf(msg, PSTR("LVGL: %s@%d->%s"), file, line, dsc); + snprintf(msg, sizeof(msg), PSTR("LVGL: %s@%d->%s"), file, line, dsc); debugPrintln(msg); } #endif @@ -90,10 +108,21 @@ void tft_espi_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * c /* Function for converting LittlevGL pixel format to RGB888 */ // data = DISP_IMPL_lvgl_formatPixel(*color_p); - 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; + // 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; + + // Simple 16 bpp + // pixel[i++] = color_p->full & 0xFF; + // pixel[i++] = (color_p->full >> 8) & 0xFF; color_p++; // i += 4; @@ -156,17 +185,17 @@ static void IRAM_ATTR lv_tick_handler(void) } /* Reading input device (simulated encoder here) */ -bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data) +/*bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data) { static int32_t last_diff = 0; - int32_t diff = 0; /* Dummy - no movement */ - int btn_state = LV_INDEV_STATE_REL; /* Dummy - no press */ + int32_t diff = 0; // Dummy - no movement + int btn_state = LV_INDEV_STATE_REL; // Dummy - no press data->enc_diff = diff - last_diff; data->state = btn_state; last_diff = diff; return false; -} +}*/ void guiFirstCalibration() { @@ -188,7 +217,7 @@ bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) return false; } - bool shouldSleep = guiCheckSleep(); + guiCheckSleep(); // Ignore first press? @@ -243,25 +272,37 @@ void guiSetup(TFT_eSPI & screen, JsonObject settings) tft = screen; guiSetConfig(settings); + guiBacklightIsOn = guiDimLevel > 0; + + tft.begin(); /* TFT init */ tft.setTouch(calData); + tft.setRotation(guiRotation); /* 1/3=Landscape or 0/2=Portrait orientation */ lv_init(); #if defined(ARDUINO_ARCH_ESP32) /* allocate on iram (or psram ?) */ - buffer_size = 19200; // 38 KBytes + buffer_size = 16 * 1024u; // 32 KBytes static lv_color_t * guiVdbBuffer = (lv_color_t *)malloc(sizeof(lv_color_t) * buffer_size); static lv_disp_buf_t disp_buf; lv_disp_buf_init(&disp_buf, guiVdbBuffer, NULL, buffer_size); #else /* allocate on heap */ - static lv_color_t guiVdbBuffer[1024 * 3]; // 6 KBytes + static lv_color_t guiVdbBuffer[3 * 1024u]; // 6 KBytes buffer_size = sizeof(guiVdbBuffer) / sizeof(guiVdbBuffer[0]); static lv_disp_buf_t disp_buf; lv_disp_buf_init(&disp_buf, guiVdbBuffer, NULL, buffer_size); #endif - debugPrintln(String(F("LVGL: MEM size : ")) + String(LV_MEM_SIZE)); - debugPrintln(String(F("LVGL: VDB size : ")) + String((size_t)sizeof(lv_color_t) * buffer_size)); + + char buffer[127]; + snprintf_P(buffer, sizeof(buffer), PSTR("LVGL: Rotation : %d"), guiRotation); + debugPrintln(buffer); + + snprintf_P(buffer, sizeof(buffer), PSTR("LVGL: MEM size : %d"), LV_MEM_SIZE); + debugPrintln(buffer); + + snprintf_P(buffer, sizeof(buffer), PSTR("LVGL: VFB size : %d"), (size_t)sizeof(lv_color_t) * buffer_size); + debugPrintln(buffer); #if LV_USE_LOG != 0 debugPrintln(F("LVGL: Registering lvgl logging handler")); @@ -273,21 +314,25 @@ void guiSetup(TFT_eSPI & screen, JsonObject settings) png_decoder_init(); #endif +#if LV_USE_FS_IF != 0 + lv_fs_if_init(); +#endif + /* Initialize the display driver */ lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); disp_drv.flush_cb = tft_espi_flush; disp_drv.buffer = &disp_buf; -#if(TFT_ROTATION == 0 || TFT_ROTATION == 2 || TFT_ROTATION == 4 || TFT_ROTATION == 6) - /* 1/3=Landscape or 0/2=Portrait orientation */ - // Normal width & height - disp_drv.hor_res = TFT_WIDTH; // From User_Setup.h - disp_drv.ver_res = TFT_HEIGHT; // From User_Setup.h -#else - // Swapped width & height - disp_drv.hor_res = TFT_HEIGHT; // From User_Setup.h - disp_drv.ver_res = TFT_WIDTH; // From User_Setup.h -#endif + if(guiRotation == 0 || guiRotation == 2 || guiRotation == 4 || guiRotation == 6) { + /* 1/3=Landscape or 0/2=Portrait orientation */ + // Normal width & height + disp_drv.hor_res = TFT_WIDTH; // From User_Setup.h + disp_drv.ver_res = TFT_HEIGHT; // From User_Setup.h + } else { + // Swapped width & height + disp_drv.hor_res = TFT_HEIGHT; // From User_Setup.h + disp_drv.ver_res = TFT_WIDTH; // From User_Setup.h + } lv_disp_drv_register(&disp_drv); /*Initialize the touch pad*/ @@ -336,22 +381,17 @@ void guiSetup(TFT_eSPI & screen, JsonObject settings) /*Initialize the graphics library's tick*/ tick.attach_ms(guiTickPeriod, lv_tick_handler); -#if LV_USE_FS_IF != 0 - lv_fs_if_init(); -#endif - /* Setup Backlight Control Pin */ if(guiBacklightPin >= 0) { - char msg[127]; - sprintf(msg, PSTR("LVGL: Backlight Pin = %i"), guiBacklightPin); - debugPrintln(msg); + snprintf(buffer, sizeof(buffer), PSTR("LVGL: Backlight Pin = %i"), guiBacklightPin); + debugPrintln(buffer); #if defined(ARDUINO_ARCH_ESP32) // configure LED PWM functionalitites - ledcSetup(0, 1000, 10); + ledcSetup(100, 1000, 10); // attach the channel to the GPIO to be controlled pinMode(guiBacklightPin, OUTPUT); - ledcAttachPin(guiBacklightPin, 0); + ledcAttachPin(guiBacklightPin, 99); #else pinMode(guiBacklightPin, OUTPUT); #endif @@ -366,17 +406,42 @@ void IRAM_ATTR guiLoop() void guiStop() {} +bool guiGetBacklight(bool lighton) +{ + return guiBacklightIsOn; +} + +void guiSetBacklight(bool lighton) +{ + guiBacklightIsOn = lighton; + + if(guiBacklightPin >= 0) { + +#if defined(ARDUINO_ARCH_ESP32) + ledcWrite(99, lighton ? 1023 : 0); // ledChannel and value +#else + analogWrite(guiBacklightPin, lighton ? 1023 : 0); +#endif + + } else { + guiBacklightIsOn = true; + } +} + void guiSetDim(uint8_t level) { if(guiBacklightPin >= 0) { guiDimLevel = level >= 0 ? level : 0; guiDimLevel = guiDimLevel <= 100 ? guiDimLevel : 100; + if(guiBacklightIsOn) { // The backlight is ON #if defined(ARDUINO_ARCH_ESP32) - ledcWrite(0, map(guiDimLevel, 0, 100, 0, 1023)); // ledChannel and value + ledcWrite(99, map(guiDimLevel, 0, 100, 0, 1023)); // ledChannel and value #else - analogWrite(guiBacklightPin, map(guiDimLevel, 0, 100, 0, 1023)); + analogWrite(guiBacklightPin, map(guiDimLevel, 0, 100, 0, 1023)); #endif + } + } else { guiDimLevel = -1; } @@ -391,8 +456,10 @@ int8_t guiGetDim() bool guiGetConfig(const JsonObject & settings) { settings[FPSTR(F_GUI_TICKPERIOD)] = guiTickPeriod; - settings[FPSTR(F_GUI_IDLEPERIOD)] = guiSleepTime; + settings[FPSTR(F_GUI_IDLEPERIOD1)] = guiSleepTime1; + settings[FPSTR(F_GUI_IDLEPERIOD2)] = guiSleepTime2; settings[FPSTR(F_GUI_BACKLIGHTPIN)] = guiBacklightPin; + settings[FPSTR(F_GUI_ROTATION)] = guiRotation; JsonArray array = settings[FPSTR(F_GUI_CALIBRATION)].to(); for(int i = 0; i < 5; i++) { @@ -429,13 +496,31 @@ bool guiSetConfig(const JsonObject & settings) guiBacklightPin = settings[FPSTR(F_GUI_BACKLIGHTPIN)].as(); } - if(!settings[FPSTR(F_GUI_IDLEPERIOD)].isNull()) { - if(guiSleepTime != settings[FPSTR(F_GUI_IDLEPERIOD)].as()) { - debugPrintln(F("guiSleepTime set")); + if(!settings[FPSTR(F_GUI_IDLEPERIOD1)].isNull()) { + if(guiSleepTime1 != settings[FPSTR(F_GUI_IDLEPERIOD1)].as()) { + debugPrintln(F("guiSleepTime1 set")); } - changed |= guiSleepTime != settings[FPSTR(F_GUI_IDLEPERIOD)].as(); + changed |= guiSleepTime1 != settings[FPSTR(F_GUI_IDLEPERIOD1)].as(); - guiSleepTime = settings[FPSTR(F_GUI_IDLEPERIOD)].as(); + guiSleepTime1 = settings[FPSTR(F_GUI_IDLEPERIOD1)].as(); + } + + if(!settings[FPSTR(F_GUI_IDLEPERIOD2)].isNull()) { + if(guiSleepTime2 != settings[FPSTR(F_GUI_IDLEPERIOD2)].as()) { + debugPrintln(F("guiSleepTime2 set")); + } + changed |= guiSleepTime2 != settings[FPSTR(F_GUI_IDLEPERIOD2)].as(); + + guiSleepTime2 = settings[FPSTR(F_GUI_IDLEPERIOD2)].as(); + } + + if(!settings[FPSTR(F_GUI_ROTATION)].isNull()) { + if(guiRotation != settings[FPSTR(F_GUI_ROTATION)].as()) { + debugPrintln(F("guiRotation set")); + } + changed |= guiRotation != settings[FPSTR(F_GUI_ROTATION)].as(); + + guiRotation = settings[FPSTR(F_GUI_ROTATION)].as(); } if(!settings[FPSTR(F_GUI_CALIBRATION)].isNull()) { @@ -463,6 +548,66 @@ bool guiSetConfig(const JsonObject & settings) return changed; } +void guiSendBmpHeader() +{ + uint8_t buffer[54]; + memset(buffer, 0, sizeof(buffer)); + + lv_disp_t * disp = lv_disp_get_default(); + buffer[0] = 0x42; + buffer[1] = 0x4D; + + buffer[10 + 0] = sizeof(buffer); // full header size + buffer[14 + 0] = sizeof(buffer) - 14; // dib header size + buffer[26 + 0] = 1; // number of color planes + buffer[28 + 0] = 24; // bbp + buffer[30 + 0] = 0; // compression, 0 = RGB / 3 = RGBA + + // file size + int32_t res = sizeof(buffer) + disp->driver.hor_res * disp->driver.ver_res * buffer[28] / 8; + buffer[2 + 3] = (res >> 24) & 0xFF; + buffer[2 + 2] = (res >> 16) & 0xFF; + buffer[2 + 1] = (res >> 8) & 0xFF; + buffer[2 + 0] = res & 0xFF; + + // horizontal resolution + res = disp->driver.hor_res; + buffer[18 + 3] = (res >> 24) & 0xFF; + buffer[18 + 2] = (res >> 16) & 0xFF; + buffer[18 + 1] = (res >> 8) & 0xFF; + buffer[18 + 0] = res & 0xFF; + + // vertical resolution + res = -disp->driver.ver_res; // top down lines + buffer[22 + 3] = (res >> 24) & 0xFF; + buffer[22 + 2] = (res >> 16) & 0xFF; + buffer[22 + 1] = (res >> 8) & 0xFF; + buffer[22 + 0] = res & 0xFF; + + // bitmp size + res = disp->driver.hor_res * disp->driver.ver_res * buffer[28 + 0] / 8; //* 2; + buffer[34 + 3] = (res >> 24) & 0xFF; + buffer[34 + 2] = (res >> 16) & 0xFF; + buffer[34 + 1] = (res >> 8) & 0xFF; + buffer[34 + 0] = res & 0xFF; + + if(guiSnapshot == 1) { + size_t len = pFileOut.write(buffer, sizeof(*buffer)); + if(len != sizeof(buffer)) { + errorPrintln(F("GUI: %sData written does not match header size")); + } else { + debugPrintln(F("GUI: Bitmap header written")); + } + + } else if(guiSnapshot == 2) { + if(webClient->client().write(buffer, sizeof(buffer)) != sizeof(buffer)) { + errorPrintln(F("GUI: %sData sent does not match header size")); + } else { + debugPrintln(F("GUI: Bitmap header sent")); + } + } +} + /** Flush buffer. * * Flush buffer into a binary file. @@ -476,20 +621,14 @@ void guiTakeScreenshot(const char * pFileName) { pFileOut = SPIFFS.open(pFileName, "w"); - uint8_t bmpheader[138] = {0x42, 0x4D, 0x8A, 0xB0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0x7C, - 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x20, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x42, 0x47, 0x52, 0x73}; - - pFileOut.write(bmpheader, sizeof(bmpheader)); - if(pFileOut == NULL) { printf("[Display] error: %s cannot be opened", pFileName); return; } guiSnapshot = 1; + guiSendBmpHeader(); + lv_obj_invalidate(lv_scr_act()); lv_refr_now(NULL); /* Will call our disp_drv.disp_flush function */ guiSnapshot = 0; @@ -507,19 +646,9 @@ void guiTakeScreenshot(ESP8266WebServer & client) { webClient = &client; - uint8_t bmpheader[138] = {0x42, 0x4D, 0x8A, 0xB0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0x7C, - 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x20, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x42, 0x47, 0x52, 0x73}; - - if(webClient->client().write(bmpheader, sizeof(bmpheader)) != sizeof(bmpheader)) { - errorPrintln(F("GUI: %sData sent does not match header size")); - } else { - debugPrintln(F("GUI: Bitmap header sent")); - } - guiSnapshot = 2; + guiSendBmpHeader(); + lv_obj_invalidate(lv_scr_act()); lv_refr_now(NULL); /* Will call our disp_drv.disp_flush function */ guiSnapshot = 0; diff --git a/src/hasp_tft.cpp b/src/hasp_tft.cpp index fdbb7291..f3640249 100644 --- a/src/hasp_tft.cpp +++ b/src/hasp_tft.cpp @@ -15,30 +15,7 @@ int8_t getPinName(int8_t pin); void tftSetup(TFT_eSPI & tft, JsonObject settings) { - uint8_t rotation = TFT_ROTATION; - if(settings[F_TFT_ROTATION]) rotation = settings[F_TFT_ROTATION]; - uint32_t frequency = SPI_FREQUENCY; - if(settings[F_TFT_FREQUENCY]) frequency = settings[F_TFT_FREQUENCY]; - - char buffer[127]; - sprintf_P(buffer, PSTR("TFT: %d rotation / %d frequency"), rotation, frequency); - debugPrintln(buffer); - - tft.begin(); /* TFT init */ - tft.setRotation(rotation); /* 1/3=Landscape or 0/2=Portrait orientation */ - tftShowConfig(tft); - /* Load Calibration data */ - -#if defined(ARDUINO_ARCH_ESP8266) - uint16_t calData[5] = {238, 3529, 369, 3532, 6}; -#else - uint16_t calData[5] = {294, 3410, 383, 3491, 4}; -#endif - // uint16_t calData[5] = {0, 0, 0, 0, 0}; - uint8_t calDataOK = 0; - - tft.setTouch(calData); } void tftLoop() diff --git a/src/main.cpp b/src/main.cpp index 0bba396b..c031f827 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,10 +63,12 @@ void setup() sdcardSetup(); #endif + // debugSetup(settings[F("debug")]); + /* Init Graphics */ TFT_eSPI screen = TFT_eSPI(); - tftSetup(screen, settings[F("tft")]); guiSetup(screen, settings[F("gui")]); + tftSetup(screen, settings[F("tft")]); /* Init GUI Application */ haspSetup(settings[F("hasp")]); @@ -136,7 +138,8 @@ void loop() #endif // otaLoop(wifiIsConnected); + debugLoop(); #endif - delay(1); + // delay(1); } \ No newline at end of file