1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-08-26 15:54:29 +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;
}
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);

View File

@@ -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);

View File

@@ -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.

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 uint8_t SD_client;
extern WebUI::AuthenticationLevel SD_auth_level;
//bool sd_mount();
uint8_t get_sd_state(bool refresh);

View File

@@ -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();
}

View File

@@ -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<const char*, int8_t, cmp_str>* _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; }
};

View File

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

View File

@@ -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);