1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-08-27 08:14:31 +02:00

$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
This commit is contained in:
Mitch Bradley
2020-10-06 16:33:51 -10:00
committed by GitHub
parent f0ea7c2c44
commit 78dc79aa4f
8 changed files with 151 additions and 34 deletions

View File

@@ -159,6 +159,16 @@ Error list_settings(const char* value, WebUI::AuthenticationLevel auth_level, We
} }
return Error::Ok; 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) { Error list_commands(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) {
for (Command* cp = Command::List; cp; cp = cp->next()) { for (Command* cp = Command::List; cp; cp = cp->next()) {
const char* name = cp->getName(); const char* name = cp->getName();
@@ -383,6 +393,7 @@ void make_grbl_commands() {
new GrblCommand("+", "ExtendedSettings/List", report_extended_settings, notCycleOrHold); new GrblCommand("+", "ExtendedSettings/List", report_extended_settings, notCycleOrHold);
new GrblCommand("L", "GrblNames/List", list_grbl_names, notCycleOrHold); new GrblCommand("L", "GrblNames/List", list_grbl_names, notCycleOrHold);
new GrblCommand("S", "Settings/List", list_settings, 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("CMD", "Commands/List", list_commands, notCycleOrHold);
new GrblCommand("E", "ErrorCodes/List", listErrorCodes, anyState); new GrblCommand("E", "ErrorCodes/List", listErrorCodes, anyState);
new GrblCommand("G", "GCode/Modes", report_gcode, anyState); new GrblCommand("G", "GCode/Modes", report_gcode, anyState);

View File

@@ -142,7 +142,7 @@ void protocol_main_loop() {
char fileLine[255]; char fileLine[255];
if (readFileLine(fileLine, 255)) { if (readFileLine(fileLine, 255)) {
SD_ready_next = false; 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 { } else {
char temp[50]; char temp[50];
sd_get_current_filename(temp); sd_get_current_filename(temp);

View File

@@ -23,6 +23,7 @@
File myFile; File myFile;
bool SD_ready_next = false; // Grbl has processed a line and is waiting for another bool SD_ready_next = false; // Grbl has processed a line and is waiting for another
uint8_t SD_client = CLIENT_SERIAL; 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 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. static char comment[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.

View File

@@ -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 bool SD_ready_next; // Grbl has processed a line and is waiting for another
extern uint8_t SD_client; extern uint8_t SD_client;
extern WebUI::AuthenticationLevel SD_auth_level;
//bool sd_mount(); //bool sd_mount();
uint8_t get_sd_state(bool refresh); uint8_t get_sd_state(bool refresh);

View File

@@ -129,6 +129,12 @@ Error IntSetting::setStringValue(char* s) {
return Error::Ok; return Error::Ok;
} }
const char* IntSetting::getDefaultString() {
static char strval[32];
sprintf(strval, "%d", _defaultValue);
return strval;
}
const char* IntSetting::getStringValue() { const char* IntSetting::getStringValue() {
static char strval[32]; static char strval[32];
@@ -226,10 +232,8 @@ const char* AxisMaskSetting::getCompatibleValue() {
return strval; return strval;
} }
const char* AxisMaskSetting::getStringValue() { static char* maskToString(uint32_t mask, char* strval) {
static char strval[32];
char* s = strval; char* s = strval;
uint32_t mask = get();
for (int i = 0; i < MAX_N_AXIS; i++) { for (int i = 0; i < MAX_N_AXIS; i++) {
if (mask & bit(i)) { if (mask & bit(i)) {
*s++ = "XYZABC"[i]; *s++ = "XYZABC"[i];
@@ -239,6 +243,16 @@ const char* AxisMaskSetting::getStringValue() {
return strval; 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) { void AxisMaskSetting::addWebui(WebUI::JSONencoder* j) {
if (getDescription()) { if (getDescription()) {
j->begin_webui(getName(), getDescription(), "I", getStringValue(), 0, (1 << MAX_N_AXIS) - 1); 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; return Error::Ok;
} }
const char* FloatSetting::getDefaultString() {
static char strval[32];
(void)sprintf(strval, "%.3f", _defaultValue);
return strval;
}
const char* FloatSetting::getStringValue() { const char* FloatSetting::getStringValue() {
static char strval[32]; static char strval[32];
(void)sprintf(strval, "%.3f", get()); (void)sprintf(strval, "%.3f", get());
@@ -395,17 +415,21 @@ Error StringSetting::setStringValue(char* s) {
return Error::Ok; return Error::Ok;
} }
const char* StringSetting::getStringValue() { static bool isPassword(bool (*_checker)(char*)) {
// If the string is a password do not display it
if (_checker && (
#ifdef ENABLE_WIFI #ifdef ENABLE_WIFI
_checker == (bool (*)(char*))WebUI::WiFiConfig::isPasswordValid || if (_checker == (bool (*)(char*))WebUI::WiFiConfig::isPasswordValid) {
#endif return true;
_checker == (bool (*)(char*))WebUI::COMMANDS::isLocalPasswordValid)) {
return "******";
} else {
return _currentValue.c_str();
} }
#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) { void StringSetting::addWebui(WebUI::JSONencoder* j) {
@@ -485,14 +509,20 @@ Error EnumSetting::setStringValue(char* s) {
return Error::Ok; 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++) { for (enum_opt_t::iterator it = _options->begin(); it != _options->end(); it++) {
if (it->second == _currentValue) { if (it->second == value) {
return it->first; return it->first;
} }
} }
return "???"; return "???";
} }
const char* EnumSetting::getDefaultString() {
return enumToString(_defaultValue);
}
const char* EnumSetting::getStringValue() {
return enumToString(get());
}
void EnumSetting::addWebui(WebUI::JSONencoder* j) { void EnumSetting::addWebui(WebUI::JSONencoder* j) {
if (!getDescription()) { if (!getDescription()) {
@@ -557,6 +587,9 @@ Error FlagSetting::setStringValue(char* s) {
} }
return Error::Ok; return Error::Ok;
} }
const char* FlagSetting::getDefaultString() {
return _defaultValue ? "On" : "Off";
}
const char* FlagSetting::getStringValue() { const char* FlagSetting::getStringValue() {
return get() ? "On" : "Off"; return get() ? "On" : "Off";
} }
@@ -635,10 +668,14 @@ Error IPaddrSetting::setStringValue(char* s) {
return Error::Ok; return Error::Ok;
} }
const char* IPaddrSetting::getDefaultString() {
static String s;
s = IPAddress(_defaultValue).toString();
return s.c_str();
}
const char* IPaddrSetting::getStringValue() { const char* IPaddrSetting::getStringValue() {
static String s; static String s;
IPAddress ipaddr(get()); s = IPAddress(get()).toString();
s = ipaddr.toString();
return s.c_str(); return s.c_str();
} }

View File

@@ -134,6 +134,7 @@ public:
Error setStringValue(String s) { return setStringValue(s.c_str()); } Error setStringValue(String s) { return setStringValue(s.c_str()); }
virtual const char* getStringValue() = 0; virtual const char* getStringValue() = 0;
virtual const char* getCompatibleValue() { return getStringValue(); } virtual const char* getCompatibleValue() { return getStringValue(); }
virtual const char* getDefaultString() = 0;
}; };
class IntSetting : public Setting { class IntSetting : public Setting {
@@ -173,6 +174,7 @@ public:
void addWebui(WebUI::JSONencoder*); void addWebui(WebUI::JSONencoder*);
Error setStringValue(char* value); Error setStringValue(char* value);
const char* getStringValue(); const char* getStringValue();
const char* getDefaultString();
int32_t get() { return _currentValue; } int32_t get() { return _currentValue; }
}; };
@@ -202,6 +204,7 @@ public:
Error setStringValue(char* value); Error setStringValue(char* value);
const char* getCompatibleValue(); const char* getCompatibleValue();
const char* getStringValue(); const char* getStringValue();
const char* getDefaultString();
int32_t get() { return _currentValue; } int32_t get() { return _currentValue; }
}; };
@@ -263,6 +266,7 @@ public:
void addWebui(WebUI::JSONencoder*) {} void addWebui(WebUI::JSONencoder*) {}
Error setStringValue(char* value); Error setStringValue(char* value);
const char* getStringValue(); const char* getStringValue();
const char* getDefaultString();
float get() { return _currentValue; } float get() { return _currentValue; }
}; };
@@ -296,6 +300,7 @@ public:
void addWebui(WebUI::JSONencoder*); void addWebui(WebUI::JSONencoder*);
Error setStringValue(char* value); Error setStringValue(char* value);
const char* getStringValue(); const char* getStringValue();
const char* getDefaultString();
const char* get() { return _currentValue.c_str(); } const char* get() { return _currentValue.c_str(); }
}; };
@@ -310,6 +315,7 @@ private:
int8_t _storedValue; int8_t _storedValue;
int8_t _currentValue; int8_t _currentValue;
std::map<const char*, int8_t, cmp_str>* _options; std::map<const char*, int8_t, cmp_str>* _options;
const char* enumToString(int8_t value);
public: public:
EnumSetting(const char* description, EnumSetting(const char* description,
@@ -328,6 +334,7 @@ public:
void addWebui(WebUI::JSONencoder*); void addWebui(WebUI::JSONencoder*);
Error setStringValue(char* value); Error setStringValue(char* value);
const char* getStringValue(); const char* getStringValue();
const char* getDefaultString();
int8_t get() { return _currentValue; } int8_t get() { return _currentValue; }
}; };
@@ -357,6 +364,7 @@ public:
Error setStringValue(char* value); Error setStringValue(char* value);
const char* getCompatibleValue(); const char* getCompatibleValue();
const char* getStringValue(); const char* getStringValue();
const char* getDefaultString();
bool get() { return _currentValue; } bool get() { return _currentValue; }
}; };
@@ -388,6 +396,7 @@ public:
void addWebui(WebUI::JSONencoder*); void addWebui(WebUI::JSONencoder*);
Error setStringValue(char* value); Error setStringValue(char* value);
const char* getStringValue(); const char* getStringValue();
const char* getDefaultString();
uint32_t get() { return _currentValue; } uint32_t get() { return _currentValue; }
}; };

View File

@@ -96,9 +96,6 @@ namespace WebUI {
return; return;
} }
#endif #endif
if (_client == CLIENT_WEBUI) {
return; //this is sanity check
}
grbl_send(_client, data); grbl_send(_client, data);
} }

View File

@@ -288,7 +288,11 @@ namespace WebUI {
return Error::Ok; 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); String path = trim(parameter);
if ((path.length() > 0) && (path[0] != '/')) { if ((path.length() > 0) && (path[0] != '/')) {
path = "/" + path; path = "/" + path;
@@ -304,14 +308,13 @@ namespace WebUI {
//until no line in file //until no line in file
Error err; Error err;
Error accumErr = Error::Ok; Error accumErr = Error::Ok;
uint8_t client = (espresponse) ? espresponse->client() : CLIENT_ALL;
while (currentfile.available()) { while (currentfile.available()) {
String currentline = currentfile.readStringUntil('\n'); String currentline = currentfile.readStringUntil('\n');
if (currentline.length() > 0) { if (currentline.length() > 0) {
byte line[256]; byte line[256];
currentline.getBytes(line, 255); currentline.getBytes(line, 255);
// TODO Settings - feed into command interpreter err = execute_line((char*)line, client, auth_level);
// while accumulating error codes
err = execute_line((char*)line, CLIENT_WEBUI, auth_level);
if (err != Error::Ok) { if (err != Error::Ok) {
accumErr = err; accumErr = err;
} }
@@ -322,6 +325,33 @@ namespace WebUI {
return accumErr; 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 #ifdef ENABLE_NOTIFICATIONS
static Error showSetNotification(char* parameter, AuthenticationLevel auth_level) { // ESP610 static Error showSetNotification(char* parameter, AuthenticationLevel auth_level) { // ESP610
if (*parameter == '\0') { if (*parameter == '\0') {
@@ -642,12 +672,15 @@ namespace WebUI {
} }
#ifdef ENABLE_SD_CARD #ifdef ENABLE_SD_CARD
static Error runSDFile(char* parameter, AuthenticationLevel auth_level) { // ESP220 static Error openSDFile(char* parameter) {
parameter = trim(parameter);
if (*parameter == '\0') { if (*parameter == '\0') {
webPrintln("Missing file name!"); webPrintln("Missing file name!");
return Error::InvalidValue; return Error::InvalidValue;
} }
String path = trim(parameter);
if (path[0] != '/') {
path = "/" + path;
}
int8_t state = get_sd_state(true); int8_t state = get_sd_state(true);
if (state != SDCARD_IDLE) { if (state != SDCARD_IDLE) {
if (state == SDCARD_NOT_PRESENT) { if (state == SDCARD_NOT_PRESENT) {
@@ -658,14 +691,39 @@ namespace WebUI {
return Error::SdFailedBusy; 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) { if (sys.state != State::Idle) {
webPrintln("Busy"); webPrintln("Busy");
return Error::IdleError; return Error::IdleError;
} }
if (!openFile(SD, parameter)) { if ((err = openSDFile(parameter)) != Error::Ok) {
report_status_message(Error::SdFailedRead, (espresponse) ? espresponse->client() : CLIENT_ALL); return err;
webPrintln("");
return Error::Ok;
} }
char fileLine[255]; char fileLine[255];
if (!readFileLine(fileLine, 255)) { if (!readFileLine(fileLine, 255)) {
@@ -675,9 +733,10 @@ namespace WebUI {
return Error::Ok; return Error::Ok;
} }
SD_client = (espresponse) ? espresponse->client() : CLIENT_ALL; SD_client = (espresponse) ? espresponse->client() : CLIENT_ALL;
report_status_message(gc_execute_line(fileLine, (espresponse) ? espresponse->client() : CLIENT_ALL), SD_auth_level = auth_level;
(espresponse) ? espresponse->client() : CLIENT_ALL); // execute the first line // execute the first line now; Protocol.cpp handles later ones when SD_ready_next
report_realtime_status((espresponse) ? espresponse->client() : CLIENT_ALL); report_status_message(execute_line(fileLine, SD_client, SD_auth_level), SD_client);
report_realtime_status(SD_client);
webPrintln(""); webPrintln("");
return Error::Ok; return Error::Ok;
} }
@@ -962,7 +1021,8 @@ namespace WebUI {
new WebCommand(NULL, WEBCMD, WG, "ESP800", "Firmware/Info", showFwInfo); new WebCommand(NULL, WEBCMD, WG, "ESP800", "Firmware/Info", showFwInfo);
new WebCommand(NULL, WEBCMD, WU, "ESP720", "LocalFS/Size", SPIFFSSize); new WebCommand(NULL, WEBCMD, WU, "ESP720", "LocalFS/Size", SPIFFSSize);
new WebCommand("FORMAT", WEBCMD, WA, "ESP710", "LocalFS/Format", formatSpiffs); 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/List", listLocalFiles);
new WebCommand("path", WEBCMD, WU, NULL, "LocalFS/ListJSON", listLocalFilesJSON); new WebCommand("path", WEBCMD, WU, NULL, "LocalFS/ListJSON", listLocalFilesJSON);
#endif #endif
@@ -986,6 +1046,7 @@ namespace WebUI {
new WebCommand(NULL, WEBCMD, WU, "ESP400", "WebUI/List", listSettings); new WebCommand(NULL, WEBCMD, WU, "ESP400", "WebUI/List", listSettings);
#endif #endif
#ifdef ENABLE_SD_CARD #ifdef ENABLE_SD_CARD
new WebCommand("path", WEBCMD, WU, "ESP221", "SD/Show", showSDFile);
new WebCommand("path", WEBCMD, WU, "ESP220", "SD/Run", runSDFile); new WebCommand("path", WEBCMD, WU, "ESP220", "SD/Run", runSDFile);
new WebCommand("file_or_directory_path", WEBCMD, WU, "ESP215", "SD/Delete", deleteSDObject); new WebCommand("file_or_directory_path", WEBCMD, WU, "ESP215", "SD/Delete", deleteSDObject);
new WebCommand(NULL, WEBCMD, WU, "ESP210", "SD/List", listSDFiles); new WebCommand(NULL, WEBCMD, WU, "ESP210", "SD/List", listSDFiles);