diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 4f3cb011..1265a5db 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -74,6 +74,8 @@ lv_obj_t* cursor; uint16_t tft_width = TFT_WIDTH; uint16_t tft_height = TFT_HEIGHT; +bool screenshotIsDirty = true; + static lv_disp_buf_t disp_buf; // #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) @@ -174,6 +176,7 @@ void gui_hide_pointer(bool hidden) IRAM_ATTR 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); + screenshotIsDirty = true; } IRAM_ATTR bool gui_touch_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data) @@ -461,7 +464,8 @@ void guiStop() #if HASP_USE_CONFIG > 0 bool guiGetConfig(const JsonObject& settings) { - bool changed = false; + bool changed = false; + bool backlight_invert = haspDevice.get_backlight_invert(); uint16_t guiSleepTime1; uint16_t guiSleepTime2; hasp_get_sleep_time(guiSleepTime1, guiSleepTime2); @@ -478,6 +482,9 @@ bool guiGetConfig(const JsonObject& settings) if(gui_settings.backlight_pin != settings[FPSTR(FP_GUI_BACKLIGHTPIN)].as()) changed = true; settings[FPSTR(FP_GUI_BACKLIGHTPIN)] = gui_settings.backlight_pin; + if(backlight_invert != settings[FPSTR(FP_GUI_BACKLIGHTINVERT)].as()) changed = true; + settings[FPSTR(FP_GUI_BACKLIGHTINVERT)] = (uint8_t)backlight_invert; + if(gui_settings.rotation != settings[FPSTR(FP_GUI_ROTATION)].as()) changed = true; settings[FPSTR(FP_GUI_ROTATION)] = gui_settings.rotation; @@ -535,7 +542,8 @@ bool guiGetConfig(const JsonObject& settings) bool guiSetConfig(const JsonObject& settings) { configOutput(settings, TAG_GUI); - bool changed = false; + bool changed = false; + uint8_t backlight_invert = haspDevice.get_backlight_invert(); uint16_t guiSleepTime1; uint16_t guiSleepTime2; @@ -543,12 +551,14 @@ bool guiSetConfig(const JsonObject& settings) // changed |= configSet(guiTickPeriod, settings[FPSTR(FP_GUI_TICKPERIOD)], F("guiTickPeriod")); changed |= configSet(gui_settings.backlight_pin, settings[FPSTR(FP_GUI_BACKLIGHTPIN)], F("guiBacklightPin")); + changed |= configSet(backlight_invert, settings[FPSTR(FP_GUI_BACKLIGHTINVERT)], F("guiBacklightInvert")); changed |= configSet(guiSleepTime1, settings[FPSTR(FP_GUI_IDLEPERIOD1)], F("guiSleepTime1")); changed |= configSet(guiSleepTime2, settings[FPSTR(FP_GUI_IDLEPERIOD2)], F("guiSleepTime2")); changed |= configSet(gui_settings.rotation, settings[FPSTR(FP_GUI_ROTATION)], F("gui_settings.rotation")); changed |= configSet(gui_settings.invert_display, settings[FPSTR(FP_GUI_INVERT)], F("guiInvertDisplay")); hasp_set_sleep_time(guiSleepTime1, guiSleepTime2); + haspDevice.set_backlight_invert(backlight_invert); // Update if changed if(!settings[FPSTR(FP_GUI_POINTER)].isNull()) { if(gui_settings.show_pointer != settings[FPSTR(FP_GUI_POINTER)].as()) { @@ -746,10 +756,16 @@ void guiTakeScreenshot() 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 */ + screenshotIsDirty = false; LOG_VERBOSE(TAG_GUI, F("Bitmap data flushed to webclient")); } else { LOG_ERROR(TAG_GUI, F("Data sent does not match header size")); } } + +bool guiScreenshotIsDirty() +{ + return screenshotIsDirty; +} #endif diff --git a/src/hasp_gui.h b/src/hasp_gui.h index ac13077c..91998d10 100644 --- a/src/hasp_gui.h +++ b/src/hasp_gui.h @@ -49,6 +49,7 @@ void gui_hide_pointer(bool hidden); void guiCalibrate(void); void guiTakeScreenshot(const char* pFileName); // to file void guiTakeScreenshot(void); // webclient +bool guiScreenshotIsDirty(); /* ===== Read/Write Configuration ===== */ #if HASP_USE_CONFIG > 0 diff --git a/src/sys/svc/hasp_http.cpp b/src/sys/svc/hasp_http.cpp index 98082b9c..47024895 100644 --- a/src/sys/svc/hasp_http.cpp +++ b/src/sys/svc/hasp_http.cpp @@ -22,6 +22,7 @@ #if HASP_USE_HTTP > 0 #include "sys/net/hasp_network.h" +#include "sys/net/hasp_time.h" #if(HASP_USE_CAPTIVE_PORTAL > 0) && (HASP_USE_WIFI > 0) #include @@ -322,9 +323,10 @@ bool saveConfig() #endif } else if(save == String(PSTR("gui"))) { - settings[FPSTR(FP_GUI_POINTER)] = webServer.hasArg(PSTR("cursor")); - settings[FPSTR(FP_GUI_INVERT)] = webServer.hasArg(PSTR("invert")); - updated = guiSetConfig(settings.as()); + settings[FPSTR(FP_GUI_POINTER)] = webServer.hasArg(PSTR("cursor")); + settings[FPSTR(FP_GUI_INVERT)] = webServer.hasArg(PSTR("invert")); + settings[FPSTR(FP_GUI_BACKLIGHTINVERT)] = webServer.hasArg(PSTR("bcklinv")); + updated = guiSetConfig(settings.as()); } else if(save == String(PSTR("debug"))) { settings[FPSTR(FP_DEBUG_ANSI)] = webServer.hasArg(PSTR("ansi")); @@ -427,6 +429,16 @@ static void webHandleScreenshot() } } + // Check if screenshot bitmap is dirty + if(webServer.hasArg(F("d"))) { + if(guiScreenshotIsDirty()) + webServer.send(200, F("text/text"), "1"); + else + webServer.send(304, F("text/text"), "0"); + return; + } + + // Send bitmap if(webServer.hasArg(F("q"))) { lv_disp_t* disp = lv_disp_get_default(); webServer.setContentLength(66 + disp->driver.hor_res * disp->driver.ver_res * sizeof(lv_color_t)); @@ -447,9 +459,9 @@ static void webHandleScreenshot() httpMessage += F("

"); // Automatic refresh - httpMessage += F("
" D_HTTP_PREV_PAGE ""); - httpMessage += F("" D_HTTP_REFRESH ""); - httpMessage += F("" D_HTTP_NEXT_PAGE "
"); + httpMessage += F("
" D_HTTP_PREV_PAGE ""); + httpMessage += F("" D_HTTP_REFRESH ""); + httpMessage += F("" D_HTTP_NEXT_PAGE "
"); httpMessage += FPSTR(MAIN_MENU_BUTTON); webSendHeader(haspDevice.get_hostname(), httpMessage.length(), false); @@ -512,12 +524,33 @@ static void webHandleApiConfig() { // http://plate01/about if(!httpIsAuthenticated(F("api"))) return; + if(webServer.method() != HTTP_GET && webServer.method() != HTTP_POST) { + return; + } + DynamicJsonDocument doc(800); + JsonObject settings; String contentType = getContentType(F(".json")); String endpoint((char*)0); endpoint = webServer.pathArg(0); - JsonObject settings = doc.to(); // Settings are invalid, force creation of an empty JsonObject + String postBody = webServer.arg("plain"); + + if(webServer.method() == HTTP_GET) { + // Make sure we have a valid JsonObject to start from + settings = doc.to(); + + } else if(webServer.method() == HTTP_POST) { + DeserializationError jsonError = deserializeJson(doc, postBody); + if(jsonError) { // Couldn't parse incoming JSON command + dispatch_json_error(TAG_HTTP, jsonError); + return; + } + settings = doc.as(); + } else { + webServer.send(400, contentType, "Bad Request"); + return; + } if(!strcasecmp_P(endpoint.c_str(), PSTR("wifi"))) { wifiGetConfig(settings); @@ -529,22 +562,38 @@ static void webHandleApiConfig() guiGetConfig(settings); } else if(!strcasecmp_P(endpoint.c_str(), PSTR("debug"))) { debugGetConfig(settings); + } else if(!strcasecmp_P(endpoint.c_str(), PSTR("time"))) { + if(webServer.method() == HTTP_POST) { + configOutput(settings, TAG_HTTP); + timeSetConfig(settings); + } + settings = doc.to(); + timeGetConfig(settings); + configOutput(settings, TAG_HTTP); } else { webServer.send(400, contentType, "Bad Request"); return; } + LOG_WARNING(TAG_HTTP, "%s - %d", __FILE__, __LINE__); // Mask non-blank passwords if(!settings[FPSTR(FP_CONFIG_PASS)].isNull() && settings[FPSTR(FP_CONFIG_PASS)].as().length() != 0) { settings[FPSTR(FP_CONFIG_PASS)] = D_PASSWORD_MASK; } + LOG_WARNING(TAG_HTTP, "%s - %d", __FILE__, __LINE__); doc.shrinkToFit(); + LOG_WARNING(TAG_HTTP, "%s - %d", __FILE__, __LINE__); const size_t size = measureJson(doc) + 1; + LOG_WARNING(TAG_HTTP, "%s - %d", __FILE__, __LINE__); char jsondata[size]; + LOG_WARNING(TAG_HTTP, "%s - %d", __FILE__, __LINE__); memset(jsondata, 0, size); + LOG_WARNING(TAG_HTTP, "%s - %d", __FILE__, __LINE__); serializeJson(doc, jsondata, size); + LOG_WARNING(TAG_HTTP, "%s - %d", __FILE__, __LINE__); webServer.send(200, contentType, jsondata); + LOG_WARNING(TAG_HTTP, "%s - %d", __FILE__, __LINE__); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1185,7 +1234,7 @@ static void webHandleGuiConfig() // if(settings[FPSTR(FP_GUI_POINTER)].as()) httpMessage += F(" checked"); httpMessage += F(">Show Pointer"); - // Backlight + // Backlight Pin int8_t bcklpin = settings[FPSTR(FP_GUI_BACKLIGHTPIN)].as(); httpMessage += F("
"); httpMessage += F("
"); + // Backlight Invert + httpMessage += F("
"); + httpMessage += F("
Invert Backlight
"); + // Submit & End Form httpMessage += F(""); httpMessage += F(""); @@ -2177,7 +2231,6 @@ static void webSendCssVars() webSendCached(200, PSTR("text/css"), HTTP_CSS.c_str(), HTTP_CSS.length()); } - //////////////////////////////////////////////////////////////////////////////////////////////////// static inline void webStartConfigPortal() {