From 78dc79aa4f5402696482c5f13707a089ed751ab9 Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Tue, 6 Oct 2020 16:33:51 -1000 Subject: [PATCH] $sd/show and handle settings in SD files (#629) * $sd/show and handle settings in SD files * Added $LocalFs/Show and fixed $LocalFs/Run output * Infer / at beginning of SD path name The LocalFS path processing code already inserts a / at the beginning of the path is one isn't present. This patch does the same for SD files. * Show $ command responses in WebUI console * Added $Settings/ListChanged AKA $SC This is useful for saving settings in a compact form that leaves defaults unchanged. * $sd/show works in idle or alarm state * Apply idle/alarm checks to SPIFFS files too --- Grbl_Esp32/src/ProcessSettings.cpp | 11 ++++ Grbl_Esp32/src/Protocol.cpp | 2 +- Grbl_Esp32/src/SDCard.cpp | 1 + Grbl_Esp32/src/SDCard.h | 1 + Grbl_Esp32/src/Settings.cpp | 69 ++++++++++++++++----- Grbl_Esp32/src/Settings.h | 9 +++ Grbl_Esp32/src/WebUI/ESPResponse.cpp | 3 - Grbl_Esp32/src/WebUI/WebSettings.cpp | 89 +++++++++++++++++++++++----- 8 files changed, 151 insertions(+), 34 deletions(-) diff --git a/Grbl_Esp32/src/ProcessSettings.cpp b/Grbl_Esp32/src/ProcessSettings.cpp index ddae1b22..11c5f768 100644 --- a/Grbl_Esp32/src/ProcessSettings.cpp +++ b/Grbl_Esp32/src/ProcessSettings.cpp @@ -159,6 +159,16 @@ Error list_settings(const char* value, WebUI::AuthenticationLevel auth_level, We } return Error::Ok; } +Error list_changed_settings(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { + for (Setting* s = Setting::List; s; s = s->next()) { + const char* value = s->getStringValue(); + if (!auth_failed(s, value, auth_level) && strcmp(value, s->getDefaultString())) { + show_setting(s->getName(), value, NULL, out); + } + } + grbl_sendf(out->client(), "(Passwords not shown)\r\n"); + return Error::Ok; +} Error list_commands(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { for (Command* cp = Command::List; cp; cp = cp->next()) { const char* name = cp->getName(); @@ -383,6 +393,7 @@ void make_grbl_commands() { new GrblCommand("+", "ExtendedSettings/List", report_extended_settings, notCycleOrHold); new GrblCommand("L", "GrblNames/List", list_grbl_names, notCycleOrHold); new GrblCommand("S", "Settings/List", list_settings, notCycleOrHold); + new GrblCommand("SC","Settings/ListChanged", list_changed_settings, notCycleOrHold); new GrblCommand("CMD", "Commands/List", list_commands, notCycleOrHold); new GrblCommand("E", "ErrorCodes/List", listErrorCodes, anyState); new GrblCommand("G", "GCode/Modes", report_gcode, anyState); diff --git a/Grbl_Esp32/src/Protocol.cpp b/Grbl_Esp32/src/Protocol.cpp index d2d3d0cb..abf37c12 100644 --- a/Grbl_Esp32/src/Protocol.cpp +++ b/Grbl_Esp32/src/Protocol.cpp @@ -142,7 +142,7 @@ void protocol_main_loop() { char fileLine[255]; if (readFileLine(fileLine, 255)) { SD_ready_next = false; - report_status_message(gc_execute_line(fileLine, SD_client), SD_client); + report_status_message(execute_line(fileLine, SD_client, SD_auth_level), SD_client); } else { char temp[50]; sd_get_current_filename(temp); diff --git a/Grbl_Esp32/src/SDCard.cpp b/Grbl_Esp32/src/SDCard.cpp index 4178cc91..f675c870 100644 --- a/Grbl_Esp32/src/SDCard.cpp +++ b/Grbl_Esp32/src/SDCard.cpp @@ -23,6 +23,7 @@ File myFile; bool SD_ready_next = false; // Grbl has processed a line and is waiting for another uint8_t SD_client = CLIENT_SERIAL; +WebUI::AuthenticationLevel SD_auth_level = WebUI::AuthenticationLevel::LEVEL_GUEST; uint32_t sd_current_line_number; // stores the most recent line number read from the SD static char comment[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated. diff --git a/Grbl_Esp32/src/SDCard.h b/Grbl_Esp32/src/SDCard.h index 4f19f8aa..a64a4e7d 100644 --- a/Grbl_Esp32/src/SDCard.h +++ b/Grbl_Esp32/src/SDCard.h @@ -31,6 +31,7 @@ const int SDCARD_BUSY_PARSING = 8; extern bool SD_ready_next; // Grbl has processed a line and is waiting for another extern uint8_t SD_client; +extern WebUI::AuthenticationLevel SD_auth_level; //bool sd_mount(); uint8_t get_sd_state(bool refresh); diff --git a/Grbl_Esp32/src/Settings.cpp b/Grbl_Esp32/src/Settings.cpp index e53c313c..3c63ed91 100644 --- a/Grbl_Esp32/src/Settings.cpp +++ b/Grbl_Esp32/src/Settings.cpp @@ -129,6 +129,12 @@ Error IntSetting::setStringValue(char* s) { return Error::Ok; } +const char* IntSetting::getDefaultString() { + static char strval[32]; + sprintf(strval, "%d", _defaultValue); + return strval; +} + const char* IntSetting::getStringValue() { static char strval[32]; @@ -226,10 +232,8 @@ const char* AxisMaskSetting::getCompatibleValue() { return strval; } -const char* AxisMaskSetting::getStringValue() { - static char strval[32]; +static char* maskToString(uint32_t mask, char* strval) { char* s = strval; - uint32_t mask = get(); for (int i = 0; i < MAX_N_AXIS; i++) { if (mask & bit(i)) { *s++ = "XYZABC"[i]; @@ -239,6 +243,16 @@ const char* AxisMaskSetting::getStringValue() { return strval; } +const char* AxisMaskSetting::getDefaultString() { + static char strval[32]; + return maskToString(_defaultValue, strval); +} + +const char* AxisMaskSetting::getStringValue() { + static char strval[32]; + return maskToString(get(), strval); +} + void AxisMaskSetting::addWebui(WebUI::JSONencoder* j) { if (getDescription()) { j->begin_webui(getName(), getDescription(), "I", getStringValue(), 0, (1 << MAX_N_AXIS) - 1); @@ -312,6 +326,12 @@ Error FloatSetting::setStringValue(char* s) { return Error::Ok; } +const char* FloatSetting::getDefaultString() { + static char strval[32]; + (void)sprintf(strval, "%.3f", _defaultValue); + return strval; +} + const char* FloatSetting::getStringValue() { static char strval[32]; (void)sprintf(strval, "%.3f", get()); @@ -395,17 +415,21 @@ Error StringSetting::setStringValue(char* s) { return Error::Ok; } -const char* StringSetting::getStringValue() { - // If the string is a password do not display it - if (_checker && ( +static bool isPassword(bool (*_checker)(char*)) { #ifdef ENABLE_WIFI - _checker == (bool (*)(char*))WebUI::WiFiConfig::isPasswordValid || -#endif - _checker == (bool (*)(char*))WebUI::COMMANDS::isLocalPasswordValid)) { - return "******"; - } else { - return _currentValue.c_str(); + if (_checker == (bool (*)(char*))WebUI::WiFiConfig::isPasswordValid) { + return true; } +#endif + return _checker == (bool (*)(char*))WebUI::COMMANDS::isLocalPasswordValid; +} + +const char* StringSetting::getDefaultString() { + // If the string is a password do not display it + return (_checker && isPassword(_checker)) ? "******" : _defaultValue.c_str(); +} +const char* StringSetting::getStringValue() { + return (_checker && isPassword(_checker)) ? "******" : get(); } void StringSetting::addWebui(WebUI::JSONencoder* j) { @@ -485,14 +509,20 @@ Error EnumSetting::setStringValue(char* s) { return Error::Ok; } -const char* EnumSetting::getStringValue() { +const char* EnumSetting::enumToString(int8_t value) { for (enum_opt_t::iterator it = _options->begin(); it != _options->end(); it++) { - if (it->second == _currentValue) { + if (it->second == value) { return it->first; } } return "???"; } +const char* EnumSetting::getDefaultString() { + return enumToString(_defaultValue); +} +const char* EnumSetting::getStringValue() { + return enumToString(get()); +} void EnumSetting::addWebui(WebUI::JSONencoder* j) { if (!getDescription()) { @@ -557,6 +587,9 @@ Error FlagSetting::setStringValue(char* s) { } return Error::Ok; } +const char* FlagSetting::getDefaultString() { + return _defaultValue ? "On" : "Off"; +} const char* FlagSetting::getStringValue() { return get() ? "On" : "Off"; } @@ -635,10 +668,14 @@ Error IPaddrSetting::setStringValue(char* s) { return Error::Ok; } +const char* IPaddrSetting::getDefaultString() { + static String s; + s = IPAddress(_defaultValue).toString(); + return s.c_str(); +} const char* IPaddrSetting::getStringValue() { static String s; - IPAddress ipaddr(get()); - s = ipaddr.toString(); + s = IPAddress(get()).toString(); return s.c_str(); } diff --git a/Grbl_Esp32/src/Settings.h b/Grbl_Esp32/src/Settings.h index 5b91c80e..6504c3dc 100644 --- a/Grbl_Esp32/src/Settings.h +++ b/Grbl_Esp32/src/Settings.h @@ -134,6 +134,7 @@ public: Error setStringValue(String s) { return setStringValue(s.c_str()); } virtual const char* getStringValue() = 0; virtual const char* getCompatibleValue() { return getStringValue(); } + virtual const char* getDefaultString() = 0; }; class IntSetting : public Setting { @@ -173,6 +174,7 @@ public: void addWebui(WebUI::JSONencoder*); Error setStringValue(char* value); const char* getStringValue(); + const char* getDefaultString(); int32_t get() { return _currentValue; } }; @@ -202,6 +204,7 @@ public: Error setStringValue(char* value); const char* getCompatibleValue(); const char* getStringValue(); + const char* getDefaultString(); int32_t get() { return _currentValue; } }; @@ -263,6 +266,7 @@ public: void addWebui(WebUI::JSONencoder*) {} Error setStringValue(char* value); const char* getStringValue(); + const char* getDefaultString(); float get() { return _currentValue; } }; @@ -296,6 +300,7 @@ public: void addWebui(WebUI::JSONencoder*); Error setStringValue(char* value); const char* getStringValue(); + const char* getDefaultString(); const char* get() { return _currentValue.c_str(); } }; @@ -310,6 +315,7 @@ private: int8_t _storedValue; int8_t _currentValue; std::map* _options; + const char* enumToString(int8_t value); public: EnumSetting(const char* description, @@ -328,6 +334,7 @@ public: void addWebui(WebUI::JSONencoder*); Error setStringValue(char* value); const char* getStringValue(); + const char* getDefaultString(); int8_t get() { return _currentValue; } }; @@ -357,6 +364,7 @@ public: Error setStringValue(char* value); const char* getCompatibleValue(); const char* getStringValue(); + const char* getDefaultString(); bool get() { return _currentValue; } }; @@ -388,6 +396,7 @@ public: void addWebui(WebUI::JSONencoder*); Error setStringValue(char* value); const char* getStringValue(); + const char* getDefaultString(); uint32_t get() { return _currentValue; } }; diff --git a/Grbl_Esp32/src/WebUI/ESPResponse.cpp b/Grbl_Esp32/src/WebUI/ESPResponse.cpp index 483b0252..ce128152 100644 --- a/Grbl_Esp32/src/WebUI/ESPResponse.cpp +++ b/Grbl_Esp32/src/WebUI/ESPResponse.cpp @@ -96,9 +96,6 @@ namespace WebUI { return; } #endif - if (_client == CLIENT_WEBUI) { - return; //this is sanity check - } grbl_send(_client, data); } diff --git a/Grbl_Esp32/src/WebUI/WebSettings.cpp b/Grbl_Esp32/src/WebUI/WebSettings.cpp index 9aa7a004..c6ae8bec 100644 --- a/Grbl_Esp32/src/WebUI/WebSettings.cpp +++ b/Grbl_Esp32/src/WebUI/WebSettings.cpp @@ -288,7 +288,11 @@ namespace WebUI { return Error::Ok; } - static Error runFile(char* parameter, AuthenticationLevel auth_level) { // ESP700 + static Error runLocalFile(char* parameter, AuthenticationLevel auth_level) { // ESP700 + if (sys.state != State::Idle) { + webPrintln("Busy"); + return Error::IdleError; + } String path = trim(parameter); if ((path.length() > 0) && (path[0] != '/')) { path = "/" + path; @@ -304,14 +308,13 @@ namespace WebUI { //until no line in file Error err; Error accumErr = Error::Ok; + uint8_t client = (espresponse) ? espresponse->client() : CLIENT_ALL; while (currentfile.available()) { String currentline = currentfile.readStringUntil('\n'); if (currentline.length() > 0) { byte line[256]; currentline.getBytes(line, 255); - // TODO Settings - feed into command interpreter - // while accumulating error codes - err = execute_line((char*)line, CLIENT_WEBUI, auth_level); + err = execute_line((char*)line, client, auth_level); if (err != Error::Ok) { accumErr = err; } @@ -322,6 +325,33 @@ namespace WebUI { return accumErr; } + static Error showLocalFile(char* parameter, AuthenticationLevel auth_level) { // ESP701 + if (sys.state != State::Idle && sys.state != State::Alarm) { + return Error::IdleError; + } + String path = trim(parameter); + if ((path.length() > 0) && (path[0] != '/')) { + path = "/" + path; + } + if (!SPIFFS.exists(path)) { + webPrintln("Error: No such file!"); + return Error::SdFileNotFound; + } + File currentfile = SPIFFS.open(path, FILE_READ); + if (!currentfile) { + return Error::SdFailedOpenFile; + } + while (currentfile.available()) { + // String currentline = currentfile.readStringUntil('\n'); + // if (currentline.length() > 0) { + // webPrintln(currentline); + // } + webPrintln(currentfile.readStringUntil('\n')); + } + currentfile.close(); + return Error::Ok; + } + #ifdef ENABLE_NOTIFICATIONS static Error showSetNotification(char* parameter, AuthenticationLevel auth_level) { // ESP610 if (*parameter == '\0') { @@ -642,12 +672,15 @@ namespace WebUI { } #ifdef ENABLE_SD_CARD - static Error runSDFile(char* parameter, AuthenticationLevel auth_level) { // ESP220 - parameter = trim(parameter); + static Error openSDFile(char* parameter) { if (*parameter == '\0') { webPrintln("Missing file name!"); return Error::InvalidValue; } + String path = trim(parameter); + if (path[0] != '/') { + path = "/" + path; + } int8_t state = get_sd_state(true); if (state != SDCARD_IDLE) { if (state == SDCARD_NOT_PRESENT) { @@ -658,14 +691,39 @@ namespace WebUI { return Error::SdFailedBusy; } } + if (!openFile(SD, path.c_str())) { + report_status_message(Error::SdFailedRead, (espresponse) ? espresponse->client() : CLIENT_ALL); + webPrintln(""); + return Error::SdFailedOpenFile; + } + return Error::Ok; + } + static Error showSDFile(char* parameter, AuthenticationLevel auth_level) { // ESP221 + if (sys.state != State::Idle && sys.state != State::Alarm) { + return Error::IdleError; + } + Error err; + if ((err = openSDFile(parameter)) != Error::Ok) { + return err; + } + SD_client = (espresponse) ? espresponse->client() : CLIENT_ALL; + char fileLine[255]; + while (readFileLine(fileLine, 255)) { + webPrintln(fileLine); + } + webPrintln(""); + closeFile(); + return Error::Ok; + } + + static Error runSDFile(char* parameter, AuthenticationLevel auth_level) { // ESP220 + Error err; if (sys.state != State::Idle) { webPrintln("Busy"); return Error::IdleError; } - if (!openFile(SD, parameter)) { - report_status_message(Error::SdFailedRead, (espresponse) ? espresponse->client() : CLIENT_ALL); - webPrintln(""); - return Error::Ok; + if ((err = openSDFile(parameter)) != Error::Ok) { + return err; } char fileLine[255]; if (!readFileLine(fileLine, 255)) { @@ -675,9 +733,10 @@ namespace WebUI { return Error::Ok; } SD_client = (espresponse) ? espresponse->client() : CLIENT_ALL; - report_status_message(gc_execute_line(fileLine, (espresponse) ? espresponse->client() : CLIENT_ALL), - (espresponse) ? espresponse->client() : CLIENT_ALL); // execute the first line - report_realtime_status((espresponse) ? espresponse->client() : CLIENT_ALL); + SD_auth_level = auth_level; + // execute the first line now; Protocol.cpp handles later ones when SD_ready_next + report_status_message(execute_line(fileLine, SD_client, SD_auth_level), SD_client); + report_realtime_status(SD_client); webPrintln(""); return Error::Ok; } @@ -962,7 +1021,8 @@ namespace WebUI { new WebCommand(NULL, WEBCMD, WG, "ESP800", "Firmware/Info", showFwInfo); new WebCommand(NULL, WEBCMD, WU, "ESP720", "LocalFS/Size", SPIFFSSize); new WebCommand("FORMAT", WEBCMD, WA, "ESP710", "LocalFS/Format", formatSpiffs); - new WebCommand("path", WEBCMD, WU, "ESP700", "LocalFS/Run", runFile); + new WebCommand("path", WEBCMD, WU, "ESP701", "LocalFS/Show", showLocalFile); + new WebCommand("path", WEBCMD, WU, "ESP700", "LocalFS/Run", runLocalFile); new WebCommand("path", WEBCMD, WU, NULL, "LocalFS/List", listLocalFiles); new WebCommand("path", WEBCMD, WU, NULL, "LocalFS/ListJSON", listLocalFilesJSON); #endif @@ -986,6 +1046,7 @@ namespace WebUI { new WebCommand(NULL, WEBCMD, WU, "ESP400", "WebUI/List", listSettings); #endif #ifdef ENABLE_SD_CARD + new WebCommand("path", WEBCMD, WU, "ESP221", "SD/Show", showSDFile); new WebCommand("path", WEBCMD, WU, "ESP220", "SD/Run", runSDFile); new WebCommand("file_or_directory_path", WEBCMD, WU, "ESP215", "SD/Delete", deleteSDObject); new WebCommand(NULL, WEBCMD, WU, "ESP210", "SD/List", listSDFiles);