diff --git a/Grbl_Esp32/src/Grbl.cpp b/Grbl_Esp32/src/Grbl.cpp index d0b2199f..3eb8c382 100644 --- a/Grbl_Esp32/src/Grbl.cpp +++ b/Grbl_Esp32/src/Grbl.cpp @@ -71,12 +71,14 @@ void grbl_init() { machine_init(); // user supplied function for special initialization // Initialize system state. + if (sys.state != State::ConfigAlarm) { #ifdef FORCE_INITIALIZATION_ALARM - // Force Grbl into an ALARM state upon a power-cycle or hard reset. - sys.state = State::Alarm; + // Force Grbl into an ALARM state upon a power-cycle or hard reset. + sys.state = State::Alarm; #else - sys.state = State::Idle; + sys.state = State::Idle; #endif + } // Check for power-up and set system alarm if homing is enabled to force homing cycle // by setting Grbl's alarm state. Alarm locks out all g-code commands, including the // startup scripts, but allows access to settings and internal commands. Only a homing @@ -84,7 +86,7 @@ void grbl_init() { // NOTE: The startup script will run after successful completion of the homing cycle, but // not after disabling the alarm locks. Prevents motion startup blocks from crashing into // things uncontrollably. Very bad. - if (config->_homingInitLock && homingAxes()) { + if (config->_homingInitLock && homingAxes() && sys.state != State::ConfigAlarm) { // If there is an axis with homing configured, enter Alarm state on startup sys.state = State::Alarm; } @@ -108,6 +110,7 @@ void grbl_init() { } catch (const AssertionFailed& ex) { // This means something is terribly broken: info_serial("Critical error in run_once: %s", ex.what()); + sys.state = State::ConfigAlarm; sleep(10000); throw; } diff --git a/Grbl_Esp32/src/Limits.cpp b/Grbl_Esp32/src/Limits.cpp index bfdda4b7..d273dbb6 100644 --- a/Grbl_Esp32/src/Limits.cpp +++ b/Grbl_Esp32/src/Limits.cpp @@ -46,7 +46,7 @@ void IRAM_ATTR isr_limit_switches(void* /*unused */) { // moves in the planner and serial buffers are all cleared and newly sent blocks will be // locked out until a homing cycle or a kill lock command. Allows the user to disable the hard // limit setting if their limits are constantly triggering after a reset and move their axes. - if (sys.state != State::Alarm && sys.state != State::Homing) { + if (sys.state != State::Alarm && sys.state != State::ConfigAlarm && sys.state != State::Homing) { if (sys_rt_exec_alarm == ExecAlarm::None) { #ifdef ENABLE_SOFTWARE_DEBOUNCE // we will start a task that will recheck the switches after a small delay diff --git a/Grbl_Esp32/src/MachineConfig.cpp b/Grbl_Esp32/src/MachineConfig.cpp index 137e2517..fc9abf71 100644 --- a/Grbl_Esp32/src/MachineConfig.cpp +++ b/Grbl_Esp32/src/MachineConfig.cpp @@ -570,18 +570,22 @@ bool MachineConfig::load(const char* filename) { // That way, we can always check if the yaml is there, and if it's not, load the yaml.new. } catch (const Configuration::ParseException& ex) { + sys.state = State::ConfigAlarm; auto startNear = ex.Near(); auto endNear = (startNear + 10) > (buffer + filesize) ? (buffer + filesize) : (startNear + 10); StringRange near(startNear, endNear); log_error("Configuration parse error: " << ex.What() << " @ " << ex.LineNumber() << ":" << ex.ColumnNumber() << " near " << near); } catch (const AssertionFailed& ex) { + sys.state = State::ConfigAlarm; // Get rid of buffer and return log_error("Configuration loading failed: " << ex.what()); } catch (std::exception& ex) { + sys.state = State::ConfigAlarm; // Log exception: log_error("Configuration validation error: " << ex.what()); } catch (...) { + sys.state = State::ConfigAlarm; // Get rid of buffer and return log_error("Unknown error while processing config file"); } diff --git a/Grbl_Esp32/src/MachineConfig.h b/Grbl_Esp32/src/MachineConfig.h index bdae0827..e88f852f 100644 --- a/Grbl_Esp32/src/MachineConfig.h +++ b/Grbl_Esp32/src/MachineConfig.h @@ -321,7 +321,7 @@ public: class MachineConfig : public Configuration::Configurable { public: MachineConfig() = default; - + Axes* _axes = nullptr; SPIBus* _spi = nullptr; I2SOBus* _i2so = nullptr; diff --git a/Grbl_Esp32/src/NutsBolts.h b/Grbl_Esp32/src/NutsBolts.h index 189b8492..8c1d0833 100644 --- a/Grbl_Esp32/src/NutsBolts.h +++ b/Grbl_Esp32/src/NutsBolts.h @@ -20,8 +20,6 @@ along with Grbl. If not, see . */ -#include "Config.h" - // #define false 0 // #define true 1 diff --git a/Grbl_Esp32/src/Pin.cpp b/Grbl_Esp32/src/Pin.cpp index 1bf2689c..05bc9d4f 100644 --- a/Grbl_Esp32/src/Pin.cpp +++ b/Grbl_Esp32/src/Pin.cpp @@ -41,7 +41,7 @@ #endif Pins::PinDetail* Pin::undefinedPin = new Pins::VoidPinDetail(); -Pins::PinDetail* Pin::errorPin = new Pins::ErrorPinDetail(); +Pins::PinDetail* Pin::errorPin = new Pins::ErrorPinDetail("unknown"); bool Pin::parse(StringRange tmp, Pins::PinDetail*& pinImplementation) { String str = tmp.str(); @@ -151,7 +151,7 @@ Pin Pin::create(const StringRange& str) { pin_error("Setting up pin [%s] failed. Details: %s\r\n", str.str().c_str(), ex.what()); (void)ex; // Get rid of compiler warning - return Pin(pinImplementation); + return Pin(new Pins::ErrorPinDetail(str.str())); } } diff --git a/Grbl_Esp32/src/Pins/ErrorPinDetail.cpp b/Grbl_Esp32/src/Pins/ErrorPinDetail.cpp index 8eaa99c7..a61aba45 100644 --- a/Grbl_Esp32/src/Pins/ErrorPinDetail.cpp +++ b/Grbl_Esp32/src/Pins/ErrorPinDetail.cpp @@ -19,15 +19,30 @@ #include "ErrorPinDetail.h" #include "../Assert.h" +#ifdef ESP32 +#include "../Report.h" +#endif + namespace Pins { - ErrorPinDetail::ErrorPinDetail() : PinDetail(0) {} + ErrorPinDetail::ErrorPinDetail(const String& descr) : PinDetail(0), _description(descr) {} PinCapabilities ErrorPinDetail::capabilities() const { return PinCapabilities::Error; } +#ifdef ESP32 + void ErrorPinDetail::write(int high) { info_all("Cannot write to pin %s. The config is incorrect.", _description.c_str()); } + int ErrorPinDetail::read() { info_all("Cannot read from pin %s. The config is incorrect.", _description.c_str()); } + void ErrorPinDetail::setAttr(PinAttributes value) { + info_all("Cannot set mode on pin %s. The config is incorrect.", _description.c_str()); + } + +#else void ErrorPinDetail::write(int high) { Assert(false, "Cannot write to an error pin."); } int ErrorPinDetail::read() { Assert(false, "Cannot read from an error pin."); } void ErrorPinDetail::setAttr(PinAttributes value) { /* Fine, this won't get you anywhere. */ } + +#endif + PinAttributes ErrorPinDetail::getAttr() const { return PinAttributes::None; } String ErrorPinDetail::toString() { return "ERROR_PIN"; } diff --git a/Grbl_Esp32/src/Pins/ErrorPinDetail.h b/Grbl_Esp32/src/Pins/ErrorPinDetail.h index 5a1af166..73a34b96 100644 --- a/Grbl_Esp32/src/Pins/ErrorPinDetail.h +++ b/Grbl_Esp32/src/Pins/ErrorPinDetail.h @@ -23,8 +23,10 @@ namespace Pins { class ErrorPinDetail : public PinDetail { + String _description; + public: - ErrorPinDetail(); + ErrorPinDetail(const String& descr); PinCapabilities capabilities() const override; diff --git a/Grbl_Esp32/src/Protocol.cpp b/Grbl_Esp32/src/Protocol.cpp index 6afcddb5..892238c3 100644 --- a/Grbl_Esp32/src/Protocol.cpp +++ b/Grbl_Esp32/src/Protocol.cpp @@ -87,7 +87,7 @@ Error execute_line(char* line, uint8_t client, WebUI::AuthenticationLevel auth_l return system_execute_line(line, client, auth_level); } // Everything else is gcode. Block if in alarm or jog mode. - if (sys.state == State::Alarm || sys.state == State::Jog) { + if (sys.state == State::Alarm || sys.state == State::ConfigAlarm || sys.state == State::Jog) { return Error::SystemGcLock; } return gc_execute_line(line, client); @@ -137,7 +137,9 @@ void protocol_main_loop() { // Check for and report alarm state after a reset, error, or an initial power up. // NOTE: Sleep mode disables the stepper drivers and position can't be guaranteed. // Re-initialize the sleep state as an ALARM mode to ensure user homes or acknowledges. - if (sys.state == State::Alarm || sys.state == State::Sleep) { + if (sys.state == State::ConfigAlarm) { + report_feedback_message(Message::AlarmLock); + } else if (sys.state == State::Alarm || sys.state == State::Sleep) { report_feedback_message(Message::AlarmLock); sys.state = State::Alarm; // Ensure alarm state is set. } else { @@ -325,6 +327,7 @@ static void protocol_do_motion_cancel() { // will handle and clear multiple planner block motions. switch (sys.state) { case State::Alarm: + case State::ConfigAlarm: case State::CheckMode: return; // Do not set motionCancel @@ -356,6 +359,7 @@ static void protocol_do_feedhold() { rtFeedHold = false; rtCycleStart = false; // Cancel any pending start switch (sys.state) { + case State::ConfigAlarm: case State::Alarm: case State::CheckMode: case State::SafetyDoor: @@ -390,6 +394,8 @@ static void protocol_do_safety_door() { rtCycleStart = false; // Cancel any pending start report_feedback_message(Message::SafetyDoorAjar); switch (sys.state) { + case State::ConfigAlarm: + return; case State::Alarm: case State::CheckMode: case State::Sleep: @@ -443,6 +449,7 @@ static void protocol_do_safety_door() { static void protocol_do_sleep() { rtSleep = false; switch (sys.state) { + case State::ConfigAlarm: case State::Alarm: sys.suspend.bit.retractComplete = true; sys.suspend.bit.holdComplete = true; @@ -518,6 +525,7 @@ static void protocol_do_cycle_start() { } } break; + case State::ConfigAlarm: case State::Alarm: case State::CheckMode: case State::Sleep: @@ -552,6 +560,7 @@ static void protocol_do_cycle_stop() { break; } // Fall through + case State::ConfigAlarm: case State::Alarm: case State::CheckMode: case State::Idle: @@ -686,6 +695,7 @@ void protocol_exec_rt_system() { #endif // Reload step segment buffer switch (sys.state) { + case State::ConfigAlarm: case State::Alarm: case State::CheckMode: case State::Idle: diff --git a/Grbl_Esp32/src/Report.cpp b/Grbl_Esp32/src/Report.cpp index 864d2b06..cd85bc2e 100644 --- a/Grbl_Esp32/src/Report.cpp +++ b/Grbl_Esp32/src/Report.cpp @@ -858,6 +858,7 @@ char* report_state_text() { case State::Homing: strcpy(state, "Home"); break; + case State::ConfigAlarm: case State::Alarm: strcpy(state, "Alarm"); break; diff --git a/Grbl_Esp32/src/Report.h b/Grbl_Esp32/src/Report.h index bc6a774e..b1f26d06 100644 --- a/Grbl_Esp32/src/Report.h +++ b/Grbl_Esp32/src/Report.h @@ -1,6 +1,10 @@ #pragma once #include "Error.h" +#include "NutsBolts.h" +#include "Exec.h" + +#include /* Report.h - Header for system level commands and real-time processes diff --git a/Grbl_Esp32/src/System.h b/Grbl_Esp32/src/System.h index da05b606..c66c31b3 100644 --- a/Grbl_Esp32/src/System.h +++ b/Grbl_Esp32/src/System.h @@ -40,6 +40,7 @@ enum class State : uint8_t { Jog, // Jogging mode. SafetyDoor, // Safety door is ajar. Feed holds and de-energizes system. Sleep, // Sleep state. + ConfigAlarm, // You can't do anything but fix your config file. }; // Step segment generator state flags. diff --git a/Grbl_Esp32/src/WebUI/WebSettings.cpp b/Grbl_Esp32/src/WebUI/WebSettings.cpp index 77f249a3..feaafade 100644 --- a/Grbl_Esp32/src/WebUI/WebSettings.cpp +++ b/Grbl_Esp32/src/WebUI/WebSettings.cpp @@ -678,7 +678,7 @@ namespace WebUI { static Error runSDFile(char* parameter, AuthenticationLevel auth_level) { // ESP220 Error err; - if (sys.state == State::Alarm) { + if (sys.state == State::Alarm || sys.state == State::ConfigAlarm) { webPrintln("Alarm"); return Error::IdleError; }