diff --git a/CMakeLists.txt b/CMakeLists.txt index 230010f..4f2e121 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,8 @@ target_sources(grbl INTERFACE ${CMAKE_CURRENT_LIST_DIR}/stepper.c ${CMAKE_CURRENT_LIST_DIR}/system.c ${CMAKE_CURRENT_LIST_DIR}/tool_change.c + ${CMAKE_CURRENT_LIST_DIR}/alarms.c + ${CMAKE_CURRENT_LIST_DIR}/errors.c ) target_include_directories(grbl INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/README.md b/README.md index 64c6bf9..016b008 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20210819, see the [changelog](changelog.md) for details. +Latest build date is 20210907, see the [changelog](changelog.md) for details. __NOTE:__ Drivers built with more than three axes configured \(`N_AXIS` > `3`\) will force a settings reset when upgraded. Backup and restore of settings is recommended for these. --- @@ -77,5 +77,7 @@ List of Supported G-Codes: *** number of outputs supported dependent on driver implementation. ``` +Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes. + --- -2021-07-26 +2021-09-08 diff --git a/alarms.c b/alarms.c new file mode 100644 index 0000000..35ce01e --- /dev/null +++ b/alarms.c @@ -0,0 +1,59 @@ +/* + alarms.c - + + Part of grblHAL + + Copyright (c) 2017-2021 Terje Io + Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC + Copyright (c) 2009-2011 Simen Svale Skogsrud + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ + +#include + +#include "grbl.h" +#include "core_handlers.h" + +PROGMEM static const alarm_detail_t alarm_detail[] = { + { Alarm_HardLimit, "Hard limit", "Hard limit has been triggered. Machine position is likely lost due to sudden halt. Re-homing is highly recommended." }, + { Alarm_SoftLimit, "Soft limit", "Soft limit alarm. G-code motion target exceeds machine travel. Machine position retained. Alarm may be safely unlocked." }, + { Alarm_AbortCycle, "Abort during cycle", "Reset while in motion. Machine position is likely lost due to sudden halt. Re-homing is highly recommended." }, + { Alarm_ProbeFailInitial, "Probe fail", "Probe fail. Probe is not in the expected initial state before starting probe cycle when G38.2 and G38.3 is not triggered and G38.4 and G38.5 is triggered." }, + { Alarm_ProbeFailContact, "Probe fail", "Probe fail. Probe did not contact the workpiece within the programmed travel for G38.2 and G38.4." }, + { Alarm_HomingFailReset, "Homing fail", "Homing fail. The active homing cycle was reset." }, + { Alarm_HomingFailDoor, "Homing fail", "Homing fail. Safety door was opened during homing cycle." }, + { Alarm_FailPulloff, "Homing fail", "Homing fail. Pull off travel failed to clear limit switch. Try increasing pull-off setting or check wiring." }, + { Alarm_HomingFailApproach, "Homing fail", "Homing fail. Could not find limit switch within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring." }, + { Alarm_EStop, "EStop", "EStop asserted. Clear and reset" }, + { Alarm_HomingRequried, "Homing required", "Homing required. Execute homing command ($H) to continue." }, + { Alarm_LimitsEngaged, "Limit switch engaged", "Limit switch engaged. Clear before continuing." }, + { Alarm_ProbeProtect, "Probe protection triggered", "Probe protection triggered. Clear before continuing." }, + { Alarm_Spindle, "Spindle at speed timeout", "Spindle at speed timeout. Clear before continuing." }, + { Alarm_HomingFailAutoSquaringApproach, "Homing fail", "Homing fail. Could not find second limit switch for auto squared axis within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring." }, + { Alarm_SelftestFailed, "Selftest failed", "Power on selftest (POS) failed." }, + { Alarm_MotorFault, "Motor fault", "Motor fault." } +}; + +static alarm_details_t details = { + .alarms = alarm_detail, + .n_alarms = sizeof(alarm_detail) / sizeof(alarm_detail_t) +}; + +alarm_details_t *alarms_get_details (void) +{ + details.on_get_alarms = grbl.on_get_alarms; + + return &details; +} diff --git a/alarms.h b/alarms.h index 5d10396..8ac1230 100644 --- a/alarms.h +++ b/alarms.h @@ -43,7 +43,8 @@ typedef enum { Alarm_Spindle = 14, Alarm_HomingFailAutoSquaringApproach = 15, Alarm_SelftestFailed = 16, - Alarm_MotorFault = 17 + Alarm_MotorFault = 17, + Alarm_AlarmMax = Alarm_MotorFault } alarm_code_t; typedef struct { @@ -52,25 +53,16 @@ typedef struct { const char *description; } alarm_detail_t; -PROGMEM static const alarm_detail_t alarm_detail[] = { - { Alarm_HardLimit, "Hard limit", "Hard limit has been triggered. Machine position is likely lost due to sudden halt. Re-homing is highly recommended." }, - { Alarm_SoftLimit, "Soft limit", "Soft limit alarm. G-code motion target exceeds machine travel. Machine position retained. Alarm may be safely unlocked." }, - { Alarm_AbortCycle, "Abort during cycle", "Reset while in motion. Machine position is likely lost due to sudden halt. Re-homing is highly recommended." }, - { Alarm_ProbeFailInitial, "Probe fail", "Probe fail. Probe is not in the expected initial state before starting probe cycle when G38.2 and G38.3 is not triggered and G38.4 and G38.5 is triggered." }, - { Alarm_ProbeFailContact, "Probe fail", "Probe fail. Probe did not contact the workpiece within the programmed travel for G38.2 and G38.4." }, - { Alarm_HomingFailReset, "Homing fail", "Homing fail. The active homing cycle was reset." }, - { Alarm_HomingFailDoor, "Homing fail", "Homing fail. Safety door was opened during homing cycle." }, - { Alarm_FailPulloff, "Homing fail", "Homing fail. Pull off travel failed to clear limit switch. Try increasing pull-off setting or check wiring." }, - { Alarm_HomingFailApproach, "Homing fail", "Homing fail. Could not find limit switch within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring." }, - { Alarm_EStop, "EStop", "EStop asserted. Clear and reset" }, - { Alarm_HomingRequried, "Homing required", "Homing required. Execute homing command ($H) to continue." }, - { Alarm_LimitsEngaged, "Limit switch engaged", "Limit switch engaged. Clear before continuing." }, - { Alarm_ProbeProtect, "Probe protection triggered", "Probe protection triggered. Clear before continuing." }, - { Alarm_Spindle, "Spindle at speed timeout", "Spindle at speed timeout. Clear before continuing." }, - { Alarm_HomingFailAutoSquaringApproach, "Homing fail", "Homing fail. Could not find second limit switch for auto squared axis within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring." }, - { Alarm_SelftestFailed, "Selftest failed", "Power on selftest (POS) failed." }, - { Alarm_MotorFault, "Motor fault", "Motor fault." } -}; +typedef struct alarm_details { + const uint16_t n_alarms; + const alarm_detail_t *alarms; + struct alarm_details *(*on_get_alarms)(void); +} alarm_details_t; + +// NOTE: this must match the signature of on_get_alarms in the alarm_details_t struct above! +typedef alarm_details_t *(*on_get_alarms_ptr)(void); + +alarm_details_t *alarms_get_details (void); #endif diff --git a/changelog.md b/changelog.md index 18f69ed..1f8ece3 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,17 @@ ## grblHAL changelog +Build 20210907: + +Core: +* Improved HAL/core stream handling for plugin issued [realtime commands](http://svn.io-engineering.com/grblHAL/html/structgrbl__t.html#a2ff011529d0a7809a44c8609490e0306). +* Some minor bug fixes and added rudimentary settings validations relevant when switching board map files. + +Drivers & plugins: +* Fixed regression in encoder plugin. +* Updated all drivers and relevant plugins for HAL/core API changes. +* Added PWM inversion option to [iMXRT1062 driver](https://github.com/grblHAL/iMXRT1062). +* Significantly improved [STM32F7xx driver](https://github.com/grblHAL/STM32F7xx), still work in progress. + Build 20210819: Core: diff --git a/config.h b/config.h index b7f1525..c1691c1 100644 --- a/config.h +++ b/config.h @@ -416,19 +416,14 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change! // #define INVERT_LIMIT_BIT_MASK (X_AXIS_BIT|Y_AXIS_BIT) // Default disabled. Uncomment to enable. // For inverting the probe pin use DEFAULT_INVERT_PROBE_BIT in defaults.h -// Inverts the spindle enable pin from low-disabled/high-enabled to low-enabled/high-disabled. Useful -// for some pre-built electronic boards. -// NOTE: If VARIABLE_SPINDLE is enabled(default), this option has no effect as the PWM output and -// spindle enable are combined to one pin. If you need both this option and spindle speed PWM, -// uncomment the config option USE_SPINDLE_DIR_AS_ENABLE_PIN below. +// Inverts the selected spindle output signals from active high to active low. Useful for some pre-built electronic boards. // #define INVERT_SPINDLE_ENABLE_PIN 1 // Default disabled. Uncomment to enable. // #define INVERT_SPINDLE_CCW_PIN 1 // Default disabled. Uncomment to enable. NOTE: not supported by all drivers. // #define INVERT_SPINDLE_PWM_PIN 1 // Default disabled. Uncomment to enable. NOTE: not supported by all drivers. -// Inverts the selected coolant pin from low-disabled/high-enabled to low-enabled/high-disabled. Useful -// for some pre-built electronic boards. +// Inverts the selected coolant signals from active high to active low. Useful for some pre-built electronic boards. // #define INVERT_COOLANT_FLOOD_PIN 1 // Default disabled. Uncomment to enable. -// #define INVERT_COOLANT_MIST_PIN 1 // Default disabled. Note: Enable M7 mist coolant in config.h +// #define INVERT_COOLANT_MIST_PIN 1 // Default disabled. Note: not supported by all drivers. // Used by variable spindle output only. This forces the PWM output to a minimum duty cycle when enabled. diff --git a/core_handlers.h b/core_handlers.h index e0e5889..1e22ccc 100644 --- a/core_handlers.h +++ b/core_handlers.h @@ -27,6 +27,8 @@ #include "system.h" #include "stream.h" +#include "alarms.h" +#include "errors.h" #include "settings.h" #include "report.h" @@ -61,6 +63,9 @@ typedef struct { // Core event handler and other entry points. // Most of the event handlers defaults to NULL, a few is set up to call a dummy handler for simpler code. +typedef bool (*enqueue_gcode_ptr)(char *data); +typedef bool (*protocol_enqueue_realtime_command_ptr)(char c); + typedef void (*on_state_change_ptr)(sys_state_t state); typedef void (*on_probe_completed_ptr)(void); typedef void (*on_program_completed_ptr)(program_flow_t program_flow, bool check_mode); @@ -70,10 +75,9 @@ typedef bool (*on_unknown_realtime_cmd_ptr)(char c); typedef void (*on_report_options_ptr)(bool newopt); typedef void (*on_report_command_help_ptr)(void); typedef void (*on_global_settings_restore_ptr)(void); -typedef setting_details_t *(*on_get_settings_ptr)(void); // NOTE: this must match the signature of the same definition in - // the setting_details_t structure in settings.h! typedef void (*on_realtime_report_ptr)(stream_write_ptr stream_write, report_tracking_flags_t report); typedef void (*on_unknown_feedback_message_ptr)(stream_write_ptr stream_write); +typedef void (*on_stream_changed_ptr)(stream_type_t type); typedef bool (*on_laser_ppi_enable_ptr)(uint_fast16_t ppi, uint_fast16_t pulse_length); typedef status_code_t (*on_unknown_sys_command_ptr)(sys_state_t state, char *line); // return Status_Unhandled. typedef status_code_t (*on_user_command_ptr)(char *line); @@ -91,6 +95,8 @@ typedef struct { on_report_options_ptr on_report_options; on_report_command_help_ptr on_report_command_help; on_global_settings_restore_ptr on_global_settings_restore; + on_get_alarms_ptr on_get_alarms; + on_get_errors_ptr on_get_errors; on_get_settings_ptr on_get_settings; on_realtime_report_ptr on_realtime_report; on_unknown_feedback_message_ptr on_unknown_feedback_message; @@ -98,9 +104,11 @@ typedef struct { on_unknown_sys_command_ptr on_unknown_sys_command; // return Status_Unhandled if not handled. on_get_commands_ptr on_get_commands; on_user_command_ptr on_user_command; + on_stream_changed_ptr on_stream_changed; on_laser_ppi_enable_ptr on_laser_ppi_enable; // core entry points - set up by core before driver_init() is called. - bool (*protocol_enqueue_gcode)(char *data); + enqueue_gcode_ptr enqueue_gcode; + enqueue_realtime_command_ptr enqueue_realtime_command; } grbl_t; extern grbl_t grbl; diff --git a/errors.c b/errors.c new file mode 100644 index 0000000..32b2b33 --- /dev/null +++ b/errors.c @@ -0,0 +1,97 @@ +/* + errors.c - + + Part of grblHAL + + Copyright (c) 2017-2021 Terje Io + Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC + Copyright (c) 2009-2011 Simen Svale Skogsrud + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ + +#include + +#include "grbl.h" +#include "core_handlers.h" + +PROGMEM static const status_detail_t status_detail[] = { + { Status_OK, "ok", NULL }, + { Status_ExpectedCommandLetter, "Expected command letter", "G-code words consist of a letter and a value. Letter was not found." }, + { Status_BadNumberFormat, "Bad number format", "Missing the expected G-code word value or numeric value format is not valid." }, + { Status_InvalidStatement, "Invalid statement", "'$' system command was not recognized or supported." }, + { Status_NegativeValue, "Value < 0", "Negative value received for an expected positive value." }, + { Status_HomingDisabled, "Homing disabled", "Homing cycle failure. Homing is not configured via settings." }, + { Status_SettingStepPulseMin, "Value < 2 microseconds", "Step pulse time must be greater or equal to 2 microseconds." }, + { Status_SettingReadFail, "Settings read failed. Using defaults", "A settings read failed. Auto-restoring affected settings to default values." }, + { Status_IdleError, "Not idle", "'$' command cannot be used unless controller state is IDLE. Ensures smooth operation during a job." }, + { Status_SystemGClock, "G-code lock", "G-code commands are locked out during alarm or jog state." }, + { Status_SoftLimitError, "Homing not enabled", "Soft limits cannot be enabled without homing also enabled." }, + { Status_Overflow, "Line overflow", "Max characters per line exceeded. Received command line was not executed." }, + { Status_MaxStepRateExceeded, "Max step rate too high", "'$' setting value cause the step rate to exceed the maximum supported." }, + { Status_CheckDoor, "Check Door", "Safety door detected as opened and door state initiated." }, + { Status_LineLengthExceeded, "Line length exceeded", "Build info or startup line exceeded line length limit. Line not stored." }, + { Status_TravelExceeded, "Travel exceeded", "Jog target exceeds machine travel. Jog command has been ignored." }, + { Status_InvalidJogCommand, "Invalid jog command", "Jog command has no '=' or contains prohibited g-code." }, + { Status_SettingDisabledLaser, "Setting disabled", "Laser mode requires PWM output." }, + { Status_Reset, "Reset asserted", "" }, + { Status_NonPositiveValue, "Non positive value", "" }, + { Status_GcodeUnsupportedCommand, "Unsupported command", "Unsupported or invalid g-code command found in block." }, + { Status_GcodeModalGroupViolation, "Modal group violation", "More than one g-code command from same modal group found in block." }, + { Status_GcodeUndefinedFeedRate, "Undefined feed rate", "Feed rate has not yet been set or is undefined." }, + { Status_GcodeCommandValueNotInteger, "Invalid gcode ID:23", "G-code command in block requires an integer value." }, + { Status_GcodeAxisCommandConflict, "Invalid gcode ID:24", "More than one g-code command that requires axis words found in block." }, + { Status_GcodeWordRepeated, "Invalid gcode ID:25", "Repeated g-code word found in block." }, + { Status_GcodeNoAxisWords, "Invalid gcode ID:26", "No axis words found in block for g-code command or current modal state which requires them." }, + { Status_GcodeInvalidLineNumber, "Invalid gcode ID:27", "Line number value is invalid." }, + { Status_GcodeValueWordMissing, "Invalid gcode ID:28", "G-code command is missing a required value word." }, + { Status_GcodeUnsupportedCoordSys, "Invalid gcode ID:29", "G59.x work coordinate systems are not supported." }, + { Status_GcodeG53InvalidMotionMode, "Invalid gcode ID:30", "G53 only allowed with G0 and G1 motion modes." }, + { Status_GcodeAxisWordsExist, "Invalid gcode ID:31", "Axis words found in block when no command or current modal state uses them." }, + { Status_GcodeNoAxisWordsInPlane, "Invalid gcode ID:32", "G2 and G3 arcs require at least one in-plane axis word." }, + { Status_GcodeInvalidTarget, "Invalid gcode ID:33", "Motion command target is invalid." }, + { Status_GcodeArcRadiusError, "Invalid gcode ID:34", "Arc radius value is invalid." }, + { Status_GcodeNoOffsetsInPlane, "Invalid gcode ID:35", "G2 and G3 arcs require at least one in-plane offset word." }, + { Status_GcodeUnusedWords, "Invalid gcode ID:36", "Unused value words found in block." }, + { Status_GcodeG43DynamicAxisError, "Invalid gcode ID:37", "G43.1 dynamic tool length offset is not assigned to configured tool length axis." }, + { Status_GcodeIllegalToolTableEntry, "Invalid gcode ID:38", "Tool number greater than max supported value or undefined tool selected." }, + { Status_GcodeValueOutOfRange, "Invalid gcode ID:39", "Value out of range." }, + { Status_GcodeToolChangePending, "Invalid gcode ID:40", "G-code command not allowed when tool change is pending." }, + { Status_GcodeSpindleNotRunning, "Invalid gcode ID:41", "Spindle not running when motion commanded in CSS or spindle sync mode." }, + { Status_GcodeIllegalPlane, "Invalid gcode ID:42", "Plane must be ZX for threading." }, + { Status_GcodeMaxFeedRateExceeded, "Invalid gcode ID:43", "Max. feed rate exceeded." }, + { Status_GcodeRPMOutOfRange, "Invalid gcode ID:44", "RPM out of range." }, + { Status_LimitsEngaged, "Limit switch engaged", "Only homing is allowed when a limit switch is engaged." }, + { Status_HomingRequired, "Homing required", "Home machine to continue." }, + { Status_GCodeToolError, "Invalid gcode ID:47", "ATC: current tool is not set. Set current tool with M61." }, + { Status_ValueWordConflict, "Invalid gcode ID:48", "Value word conflict." }, + { Status_SelfTestFailed, "Self test failed", "Power on self test failed. A hard reset is required." }, + { Status_EStop, "E-stop", "Emergency stop active." }, + { Status_MotorFault, "Motor fault", "Motor fault." }, + { Status_SettingValueOutOfRange, "Value out of range.", "Setting value is out of range." }, + { Status_SettingDisabled, "Setting disabled", "Setting is not available, possibly due to limited driver support." }, + { Status_GcodeInvalidRetractPosition, "Invalid gcode ID:54", "Retract position is less than drill depth." } + }; + +static error_details_t details = { + .errors = status_detail, + .n_errors = sizeof(status_detail) / sizeof(status_detail_t) +}; + +error_details_t *errors_get_details (void) +{ + details.on_get_errors = grbl.on_get_errors; + + return &details; +} diff --git a/errors.h b/errors.h index ea7bcb4..79b6543 100644 --- a/errors.h +++ b/errors.h @@ -93,7 +93,8 @@ typedef enum { Status_SDFileEmpty = 64, Status_BTInitError = 70, - Status_Unhandled // For internal use only + Status_Unhandled, // For internal use only + Status_StatusMax = Status_Unhandled } status_code_t; typedef struct { @@ -102,68 +103,15 @@ typedef struct { const char *description; } status_detail_t; -PROGMEM static const status_detail_t status_detail[] = { - { Status_OK, "ok", NULL }, - { Status_ExpectedCommandLetter, "Expected command letter", "G-code words consist of a letter and a value. Letter was not found." }, - { Status_BadNumberFormat, "Bad number format", "Missing the expected G-code word value or numeric value format is not valid." }, - { Status_InvalidStatement, "Invalid statement", "Grbl '$' system command was not recognized or supported." }, - { Status_NegativeValue, "Value < 0", "Negative value received for an expected positive value." }, - { Status_HomingDisabled, "Homing disabled", "Homing cycle failure. Homing is not configured via settings." }, - { Status_SettingStepPulseMin, "Value < 2 microseconds", "Step pulse time must be greater or equal to 2 microseconds." }, - { Status_SettingReadFail, "EEPROM read fail. Using defaults", "An EEPROM read failed. Auto-restoring affected EEPROM to default values." }, - { Status_IdleError, "Not idle", "Grbl '$' command cannot be used unless Grbl is IDLE. Ensures smooth operation during a job." }, - { Status_SystemGClock, "G-code lock", "G-code commands are locked out during alarm or jog state." }, - { Status_SoftLimitError, "Homing not enabled", "Soft limits cannot be enabled without homing also enabled." }, - { Status_Overflow, "Line overflow", "Max characters per line exceeded. Received command line was not executed." }, - { Status_MaxStepRateExceeded, "Step rate > 30kHz", "Grbl '$' setting value cause the step rate to exceed the maximum supported." }, - { Status_CheckDoor, "Check Door", "Safety door detected as opened and door state initiated." }, - { Status_LineLengthExceeded, "Line length exceeded", "Build info or startup line exceeded EEPROM line length limit. Line not stored." }, - { Status_TravelExceeded, "Travel exceeded", "Jog target exceeds machine travel. Jog command has been ignored." }, - { Status_InvalidJogCommand, "Invalid jog command", "Jog command has no '=' or contains prohibited g-code." }, - { Status_SettingDisabledLaser, "Setting disabled", "Laser mode requires PWM output." }, - { Status_Reset, "Reset asserted", "" }, - { Status_NonPositiveValue, "Non positive value", "" }, - { Status_GcodeUnsupportedCommand, "Unsupported command", "Unsupported or invalid g-code command found in block." }, - { Status_GcodeModalGroupViolation, "Modal group violation", "More than one g-code command from same modal group found in block." }, - { Status_GcodeUndefinedFeedRate, "Undefined feed rate", "Feed rate has not yet been set or is undefined." }, - { Status_GcodeCommandValueNotInteger, "Invalid gcode ID:23", "G-code command in block requires an integer value." }, - { Status_GcodeAxisCommandConflict, "Invalid gcode ID:24", "More than one g-code command that requires axis words found in block." }, - { Status_GcodeWordRepeated, "Invalid gcode ID:25", "Repeated g-code word found in block." }, - { Status_GcodeNoAxisWords, "Invalid gcode ID:26", "No axis words found in block for g-code command or current modal state which requires them." }, - { Status_GcodeInvalidLineNumber, "Invalid gcode ID:27", "Line number value is invalid." }, - { Status_GcodeValueWordMissing, "Invalid gcode ID:28", "G-code command is missing a required value word." }, - { Status_GcodeUnsupportedCoordSys, "Invalid gcode ID:29", "G59.x work coordinate systems are not supported." }, - { Status_GcodeG53InvalidMotionMode, "Invalid gcode ID:30", "G53 only allowed with G0 and G1 motion modes." }, - { Status_GcodeAxisWordsExist, "Invalid gcode ID:31", "Axis words found in block when no command or current modal state uses them." }, - { Status_GcodeNoAxisWordsInPlane, "Invalid gcode ID:32", "G2 and G3 arcs require at least one in-plane axis word." }, - { Status_GcodeInvalidTarget, "Invalid gcode ID:33", "Motion command target is invalid." }, - { Status_GcodeArcRadiusError, "Invalid gcode ID:34", "Arc radius value is invalid." }, - { Status_GcodeNoOffsetsInPlane, "Invalid gcode ID:35", "G2 and G3 arcs require at least one in-plane offset word." }, - { Status_GcodeUnusedWords, "Invalid gcode ID:36", "Unused value words found in block." }, - { Status_GcodeG43DynamicAxisError, "Invalid gcode ID:37", "G43.1 dynamic tool length offset is not assigned to configured tool length axis." }, - { Status_GcodeIllegalToolTableEntry, "Invalid gcode ID:38", "Tool number greater than max supported value or undefined tool selected." }, - { Status_GcodeValueOutOfRange, "Invalid gcode ID:39", "Value out of range." }, - { Status_GcodeToolChangePending, "Invalid gcode ID:40", "G-code command not allowed when tool change is pending." }, - { Status_GcodeSpindleNotRunning, "Invalid gcode ID:41", "Spindle not running when motion commanded in CSS or spindle sync mode." }, - { Status_GcodeIllegalPlane, "Invalid gcode ID:42", "Plane must be ZX for threading." }, - { Status_GcodeMaxFeedRateExceeded, "Invalid gcode ID:43", "Max. feed rate exceeded." }, - { Status_GcodeRPMOutOfRange, "Invalid gcode ID:44", "RPM out of range." }, - { Status_LimitsEngaged, "Limit switch engaged", "Only homing is allowed when a limit switch is engaged." }, - { Status_HomingRequired, "Homing required", "Home machine to continue." }, - { Status_GCodeToolError, "Invalid gcode ID:47", "ATC: current tool is not set. Set current tool with M61." }, - { Status_ValueWordConflict, "Invalid gcode ID:48", "Value word conflict." }, - { Status_SelfTestFailed, "Self test failed", "Power on self test failed. A hard reset is required." }, - { Status_EStop, "E-stop", "Emergency stop active." }, - { Status_MotorFault, "Motor fault", "Motor fault." }, - { Status_SettingValueOutOfRange, "Value out of range.", "Setting value is out of range." }, - { Status_SettingDisabled, "Setting disabled", "Setting is not available, possibly due to limited driver support." }, - { Status_GcodeInvalidRetractPosition, "Invalid gcode ID:54", "Retract position is less than drill depth." }, - { Status_SDMountError, "SD Card", "SD Card mount failed." }, - { Status_SDReadError, "SD Card", "SD Card file open/read failed." }, - { Status_SDFailedOpenDir, "SD Card", "SD Card directory listing failed." }, - { Status_SDDirNotFound, "SD Card", "SD Card directory not found." }, - { Status_SDFileEmpty, "SD Card", "SD Card file empty." }, - { Status_BTInitError, "Bluetooth", "Bluetooth initalisation failed." } -}; +typedef struct error_details { + const uint16_t n_errors; + const status_detail_t *errors; + struct error_details *(*on_get_errors)(void); +} error_details_t; + +// NOTE: this must match the signature of on_get_alarms in the on_get_statuses struct above! +typedef error_details_t *(*on_get_errors_ptr)(void); + +error_details_t *errors_get_details (void); #endif diff --git a/grbl.h b/grbl.h index 1d4ab83..be581b7 100644 --- a/grbl.h +++ b/grbl.h @@ -34,7 +34,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_VERSION_BUILD "20210819" +#define GRBL_VERSION_BUILD "20210907" // The following symbols are set here if not already set by the compiler or in config.h // Do NOT change here! diff --git a/grbllib.c b/grbllib.c index 9765f06..565acb6 100644 --- a/grbllib.c +++ b/grbllib.c @@ -103,7 +103,8 @@ int grbl_enter (void) // Clear all and set some core function pointers memset(&grbl, 0, sizeof(grbl_t)); grbl.on_execute_realtime = protocol_execute_noop; - grbl.protocol_enqueue_gcode = protocol_enqueue_gcode; + grbl.enqueue_gcode = protocol_enqueue_gcode; + grbl.enqueue_realtime_command = stream_enqueue_realtime_command; grbl.on_report_options = dummy_bool_handler; // Clear all and set some HAL function pointers @@ -181,7 +182,7 @@ int grbl_enter (void) #endif #ifdef SPINDLE_PWM_DIRECT - driver_ok = driver_ok && hal.spindle.get_pwm != NULL && hal.spindle.update_pwm != NULL; + driver_ok = driver_ok && (!hal.driver_cap.variable_spindle || (hal.spindle.get_pwm != NULL && hal.spindle.update_pwm != NULL)); #endif if(!driver_ok) { diff --git a/nvs_buffer.c b/nvs_buffer.c index 74faa6d..87f0fc6 100644 --- a/nvs_buffer.c +++ b/nvs_buffer.c @@ -68,7 +68,7 @@ static const emap_t target[] = { {TOOL_ADDR(5), NVS_GROUP_TOOLS, 5}, {TOOL_ADDR(6), NVS_GROUP_TOOLS, 6}, {TOOL_ADDR(7), NVS_GROUP_TOOLS, 7}, -#if N_TOOL > 8 +#if N_TOOLS > 8 #error Increase number of tool entries! #endif #endif @@ -373,6 +373,14 @@ void nvs_memmap (void) strcat(buf, uitoa(sizeof(settings_t) + NVS_CRC_BYTES)); report_message(buf, Message_Plain); +#ifdef N_TOOLS + strcpy(buf, "Tool table: "); + strcat(buf, uitoa(NVS_ADDR_TOOL_TABLE)); + strcat(buf, " "); + strcat(buf, uitoa(N_TOOLS * (sizeof(tool_data_t) + NVS_CRC_BYTES))); + report_message(buf, Message_Plain); +#endif + strcpy(buf, "Parameters: "); strcat(buf, uitoa(NVS_ADDR_PARAMETERS)); strcat(buf, " "); diff --git a/planner.c b/planner.c index b3bd33d..9ba9ecd 100644 --- a/planner.c +++ b/planner.c @@ -315,7 +315,7 @@ inline static float plan_compute_profile_parameters (plan_block_t *block, float } // Re-calculates buffered motions profile parameters upon a motion-based override change. -void plan_update_velocity_profile_parameters () +static void plan_update_velocity_profile_parameters () { plan_block_t *block = block_buffer_tail; float prev_nominal_speed = SOME_LARGE_VALUE; // Set high for first block nominal speed calculation. diff --git a/planner.h b/planner.h index c7a1776..2eaceb2 100644 --- a/planner.h +++ b/planner.h @@ -132,9 +132,6 @@ float plan_get_exec_block_exit_speed_sqr(); // Called by main program during planner calculations and step segment buffer during initialization. float plan_compute_profile_nominal_speed(plan_block_t *block); -// Re-calculates buffered motions profile parameters upon a motion-based override change. -void plan_update_velocity_profile_parameters(); - // Reset the planner position vector (in steps) void plan_sync_position(); @@ -147,7 +144,6 @@ uint_fast16_t plan_get_block_buffer_available(); // Returns the status of the block ring buffer. True, if buffer is full. bool plan_check_full_buffer(); -void plan_get_planner_mpos(float *target); void plan_feed_override (uint_fast8_t feed_override, uint_fast8_t rapid_override); #endif diff --git a/plugins_init.h b/plugins_init.h index 3be81c5..bca7c28 100644 --- a/plugins_init.h +++ b/plugins_init.h @@ -48,6 +48,11 @@ openpnp_init(); #endif +#if WEBUI_ENABLE + extern void webui_init (void); + webui_init(); +#endif + my_plugin_init(); #if ODOMETER_ENABLE diff --git a/report.c b/report.c index f02dac2..7f6024d 100644 --- a/report.c +++ b/report.c @@ -1381,6 +1381,15 @@ static void report_bitfield (const char *format, bool bitmap) } } +static void write_quoted (const char *s, const char *sep) +{ + hal.stream.write("\""); + hal.stream.write(s); // TODO: escape double quoutes + hal.stream.write("\""); + if(sep) + hal.stream.write(sep); +} + static void report_settings_detail (settings_format_t format, const setting_detail_t *setting, uint_fast8_t offset) { switch(format) @@ -1474,126 +1483,130 @@ static void report_settings_detail (settings_format_t format, const setting_deta break; case SettingsFormat_Grbl: - hal.stream.write("\""); - hal.stream.write(uitoa(setting->id + offset)); - hal.stream.write("\",\""); - if(setting->group == Group_Axis0) - hal.stream.write(axis_letter[offset]); - hal.stream.write(setting->name[0] == '?' ? &setting->name[1] : setting->name); // temporary hack for ? prefix... - if(setting->unit) { - hal.stream.write("\",\""); - hal.stream.write(setting->unit); - } else // TODO: output sensible unit from datatype - hal.stream.write("\",\""); -#ifndef NO_SETTINGS_DESCRIPTIONS - hal.stream.write("\",\""); - report_setting_description(format, (setting_id_t)(setting->id + offset)); - hal.stream.write("\""); -#else - hal.stream.write("\",\"\""); -#endif + { + write_quoted(uitoa(setting->id + offset), ","); + hal.stream.write("\""); + if(setting->group == Group_Axis0) + hal.stream.write(axis_letter[offset]); + hal.stream.write(setting->name[0] == '?' ? &setting->name[1] : setting->name); // temporary hack for ? prefix... + hal.stream.write("\","); + if(setting->unit) { + write_quoted(setting->unit, ","); + } else // TODO: output sensible unit from datatype + write_quoted("", ","); + + #ifndef NO_SETTINGS_DESCRIPTIONS + const char *description = setting_get_description((setting_id_t)(setting->id + offset)); + write_quoted(description ? description : "", ","); + #else + write_quoted("", NULL); + #endif + } break; case SettingsFormat_grblHAL: - hal.stream.write(uitoa(setting->id + offset)); + { + hal.stream.write(uitoa(setting->id + offset)); - hal.stream.write("\t"); + hal.stream.write("\t"); - if(setting->group == Group_Axis0) - hal.stream.write(axis_letter[offset]); - hal.stream.write(setting->name[0] == '?' ? &setting->name[1] : setting->name); // temporary hack for ? prefix... + if(setting->group == Group_Axis0) + hal.stream.write(axis_letter[offset]); + hal.stream.write(setting->name[0] == '?' ? &setting->name[1] : setting->name); // temporary hack for ? prefix... - hal.stream.write("\t"); + hal.stream.write("\t"); - if(setting->unit) - hal.stream.write(setting->unit); - else if(setting->datatype == Format_AxisMask || setting->datatype == Format_Bitfield || setting->datatype == Format_XBitfield) - hal.stream.write("mask"); - else if(setting->datatype == Format_Bool) - hal.stream.write("boolean"); - else if(setting->datatype == Format_RadioButtons) - hal.stream.write("integer"); - - hal.stream.write("\t"); -/* - Format_Bool = 0, - Format_Bitfield, - Format_XBitfield, - Format_RadioButtons, - Format_AxisMask, - Format_Integer, // 32 bit - , - Format_String, - Format_Password, - Format_IPv4, - // For internal use only - Format_Int8, - Format_Int16, -*/ - switch(setting_datatype_to_external(setting->datatype)) { - - case Format_Integer: + if(setting->unit) + hal.stream.write(setting->unit); + else if(setting->datatype == Format_AxisMask || setting->datatype == Format_Bitfield || setting->datatype == Format_XBitfield) + hal.stream.write("mask"); + else if(setting->datatype == Format_Bool) + hal.stream.write("boolean"); + else if(setting->datatype == Format_RadioButtons) hal.stream.write("integer"); - break; - case Format_Decimal: - hal.stream.write("float"); - break; + hal.stream.write("\t"); + /* + Format_Bool = 0, + Format_Bitfield, + Format_XBitfield, + Format_RadioButtons, + Format_AxisMask, + Format_Integer, // 32 bit + , + Format_String, + Format_Password, + Format_IPv4, + // For internal use only + Format_Int8, + Format_Int16, + */ + switch(setting_datatype_to_external(setting->datatype)) { - case Format_Bool: - hal.stream.write("bool"); - break; + case Format_Integer: + hal.stream.write("integer"); + break; - case Format_AxisMask: - case Format_Bitfield: - hal.stream.write("bitfield"); - break; + case Format_Decimal: + hal.stream.write("float"); + break; - case Format_XBitfield: - hal.stream.write("xbitfield"); - break; + case Format_Bool: + hal.stream.write("bool"); + break; - case Format_RadioButtons: - hal.stream.write("radiobuttons"); - break; + case Format_AxisMask: + case Format_Bitfield: + hal.stream.write("bitfield"); + break; - case Format_IPv4: - hal.stream.write("ipv4"); - break; + case Format_XBitfield: + hal.stream.write("xbitfield"); + break; - case Format_String: - hal.stream.write("string"); - break; + case Format_RadioButtons: + hal.stream.write("radiobuttons"); + break; - case Format_Password: - hal.stream.write("password"); - break; + case Format_IPv4: + hal.stream.write("ipv4"); + break; - default: - break; + case Format_String: + hal.stream.write("string"); + break; + + case Format_Password: + hal.stream.write("password"); + break; + + default: + break; + } + + hal.stream.write("\t"); + + if(setting->format) + hal.stream.write(setting->format); + else if (setting->datatype == Format_AxisMask) + hal.stream.write("axes"); + + hal.stream.write("\t"); + + #ifndef NO_SETTINGS_DESCRIPTIONS + const char *description = setting_get_description((setting_id_t)(setting->id + offset)); + hal.stream.write(description ? description : ""); + #endif + hal.stream.write("\t"); + + if(setting->min_value) + hal.stream.write(setting->min_value); + + hal.stream.write("\t"); + + if(setting->max_value) + hal.stream.write(setting->max_value); } - - hal.stream.write("\t"); - - if(setting->format) - hal.stream.write(setting->format); - else if (setting->datatype == Format_AxisMask) - hal.stream.write("axes"); - - hal.stream.write("\t"); - -#ifndef NO_SETTINGS_DESCRIPTIONS - report_setting_description(format, (setting_id_t)(setting->id + offset)); -#endif - hal.stream.write("\t"); - - if(setting->min_value) - hal.stream.write(setting->min_value); - - hal.stream.write("\t"); - - if(setting->max_value) - hal.stream.write(setting->max_value); break; } @@ -1746,21 +1759,7 @@ status_code_t report_settings_details (settings_format_t format, setting_id_t id status_code_t report_setting_description (settings_format_t format, setting_id_t id) { - uint_fast16_t idx; - const char *description = NULL; - setting_details_t *settings = settings_get_details(); - const setting_detail_t *setting = setting_get_details(id, NULL); - - if(setting) do { - if(settings->descriptions) { - idx = settings->n_descriptions; - do { - if(settings->descriptions[--idx].id == setting->id) - description = settings->descriptions[idx].description; - } while(idx && description == NULL); - } - settings = settings->on_get_settings ? settings->on_get_settings() : NULL; - } while(settings && description == NULL); + const char *description = setting_get_description(id); if(format == SettingsFormat_MachineReadable) { hal.stream.write("[SETTINGDESCR:"); @@ -1778,42 +1777,74 @@ status_code_t report_setting_description (settings_format_t format, setting_id_t #endif -status_code_t report_alarm_details (void) +status_code_t report_alarm_details (bool grbl_format) { - uint_fast16_t idx, n_alarms = sizeof(alarm_detail) / sizeof(alarm_detail_t); + uint_fast16_t idx; + alarm_details_t *list = alarms_get_details(); - for(idx = 0; idx < n_alarms; idx++) { + if(grbl_format) + hal.stream.write("\"Alarm Code in v1.1+\",\" Alarm Message in v1.0-\",\" Alarm Description\"" ASCII_EOL); - hal.stream.write("[ALARMCODE:"); + do { // TODO: add sorting? - hal.stream.write(uitoa(alarm_detail[idx].id)); - hal.stream.write(vbar); - hal.stream.write(alarm_detail[idx].name); - hal.stream.write(vbar); - if(alarm_detail[idx].description) - hal.stream.write(alarm_detail[idx].description); - hal.stream.write("]" ASCII_EOL); - } + for(idx = 0; idx < list->n_alarms; idx++) { + + if(grbl_format) { + write_quoted(uitoa(list->alarms[idx].id), ","); + write_quoted(list->alarms[idx].name, ","); + write_quoted(list->alarms[idx].description ? list->alarms[idx].description : "", NULL); + hal.stream.write(ASCII_EOL); + } else { + hal.stream.write("[ALARMCODE:"); + hal.stream.write(uitoa(list->alarms[idx].id)); + hal.stream.write(vbar); + hal.stream.write(list->alarms[idx].name); + hal.stream.write(vbar); + if(list->alarms[idx].description) + hal.stream.write(list->alarms[idx].description); + hal.stream.write("]" ASCII_EOL); + } + } + + list = list->on_get_alarms ? list->on_get_alarms() : NULL; + + } while(list); return Status_OK; } -status_code_t report_error_details (void) +status_code_t report_error_details (bool grbl_format) { - uint_fast16_t idx, n_alarms = sizeof(status_detail) / sizeof(status_detail_t); + uint_fast16_t idx; + error_details_t *list = errors_get_details(); - for(idx = 0; idx < n_alarms; idx++) { + if(grbl_format) + hal.stream.write("\"Error Code in v1.1+\",\"Error Message in v1.0-\",\"Error Description\"" ASCII_EOL); - hal.stream.write("[ERRORCODE:"); + do { // TODO: add sorting? - hal.stream.write(uitoa(status_detail[idx].id)); - hal.stream.write(vbar); - hal.stream.write(status_detail[idx].name); - hal.stream.write(vbar); - if(status_detail[idx].description) - hal.stream.write(status_detail[idx].description); - hal.stream.write("]" ASCII_EOL); - } + for(idx = 0; idx < list->n_errors; idx++) { + + if(grbl_format) { + write_quoted(uitoa(list->errors[idx].id), ","); + write_quoted(list->errors[idx].name, ","); + write_quoted(list->errors[idx].description ? list->errors[idx].description : "", NULL); + hal.stream.write(ASCII_EOL); + } else { + hal.stream.write("[ERRORCODE:"); + hal.stream.write(uitoa(list->errors[idx].id)); + hal.stream.write(vbar); + hal.stream.write(list->errors[idx].name); + hal.stream.write(vbar); + if(list->errors[idx].description) + hal.stream.write(list->errors[idx].description); + hal.stream.write("]" ASCII_EOL); + } + } + + list = list->on_get_errors ? list->on_get_errors() : NULL; + + } while(list); return Status_OK; } @@ -1943,7 +1974,6 @@ status_code_t report_current_limit_state (sys_state_t state, char *args) return Status_OK; } - // Prints spindle data (encoder pulse and index count, angular position). status_code_t report_spindle_data (sys_state_t state, char *args) { diff --git a/report.h b/report.h index 4025718..7a6fc39 100644 --- a/report.h +++ b/report.h @@ -93,8 +93,8 @@ void report_execute_startup_message (char *line, status_code_t status_code); // Prints build info and user info. void report_build_info (char *line, bool extended); -status_code_t report_alarm_details (void); -status_code_t report_error_details (void); +status_code_t report_alarm_details (bool grbl_format); +status_code_t report_error_details (bool grbl_format); status_code_t report_setting_group_details (bool by_id, char *prefix); status_code_t report_settings_details (settings_format_t format, setting_id_t setting, setting_group_t group); #ifndef NO_SETTINGS_DESCRIPTIONS diff --git a/settings.c b/settings.c index c328a5f..29d7671 100644 --- a/settings.c +++ b/settings.c @@ -1465,17 +1465,21 @@ bool settings_read_tool_data (uint32_t tool, tool_data_t *tool_data) #endif } -// Read Grbl global settings from persistent storage. +// Read global settings from persistent storage. // Checks version-byte of non-volatile storage and global settings copy. bool read_global_settings () { bool ok = hal.nvs.type != NVS_None && SETTINGS_VERSION == hal.nvs.get_byte(0) && hal.nvs.memcpy_from_nvs((uint8_t *)&settings, NVS_ADDR_GLOBAL, sizeof(settings_t), true) == NVS_TransferResult_OK; + // Sanity check of settings, board map could have been changed... + if(settings.mode == Mode_Laser && !hal.driver_cap.variable_spindle) + settings.mode = Mode_Standard; + return ok && settings.version == SETTINGS_VERSION; } -// Write Grbl global settings to persistent storage +// Write global settings to persistent storage void settings_write_global (void) { if(override_backup.valid) @@ -1486,7 +1490,7 @@ void settings_write_global (void) } -// Restore Grbl global settings to defaults and write to persistent storage +// Restore global settings to defaults and write to persistent storage void settings_restore (settings_restore_t restore) { uint_fast8_t idx; @@ -1728,6 +1732,32 @@ const setting_detail_t *setting_get_details (setting_id_t id, setting_details_t return NULL; } +const char *setting_get_description (setting_id_t id) +{ + const char *description = NULL; + +#ifndef NO_SETTINGS_DESCRIPTIONS + + uint_fast16_t idx; + setting_details_t *settings = settings_get_details(); + const setting_detail_t *setting = setting_get_details(id, NULL); + + if(setting) do { + if(settings->descriptions) { + idx = settings->n_descriptions; + do { + if(settings->descriptions[--idx].id == setting->id) + description = settings->descriptions[idx].description; + } while(idx && description == NULL); + } + settings = settings->on_get_settings ? settings->on_get_settings() : NULL; + } while(settings && description == NULL); + +#endif + + return description; +} + static status_code_t validate_value (const setting_detail_t *setting, float value) { float val; diff --git a/settings.h b/settings.h index 98fd5f3..7d866eb 100644 --- a/settings.h +++ b/settings.h @@ -704,6 +704,9 @@ typedef struct setting_details { driver_settings_restore_ptr restore; } setting_details_t; +// NOTE: this must match the signature of on_get_settings in the setting_details_t structure above! +typedef setting_details_t *(*on_get_settings_ptr)(void); + extern settings_t settings; // Initialize the configuration subsystem (load settings from persistent storage) @@ -749,6 +752,7 @@ setting_details_t *settings_get_details (void); bool settings_is_group_available (setting_group_t group); bool settings_iterator (const setting_detail_t *setting, setting_output_ptr callback, void *data); const setting_detail_t *setting_get_details (setting_id_t id, setting_details_t **set); +const char *setting_get_description (setting_id_t id); setting_datatype_t setting_datatype_to_external (setting_datatype_t datatype); setting_group_t settings_normalize_group (setting_group_t group); char *setting_get_value (const setting_detail_t *setting, uint_fast16_t offset); diff --git a/stepper.c b/stepper.c index 67b02e0..bd3cee4 100644 --- a/stepper.c +++ b/stepper.c @@ -550,15 +550,16 @@ void st_reset () // NOTE: buffer indices starts from 1 for simpler driver coding! // Set up stepper block ringbuffer as circular linked list and add id - uint_fast8_t idx; - for(idx = 0 ; idx <= SEGMENT_BUFFER_SIZE - 2 ; idx++) { - st_block_buffer[idx].next = &st_block_buffer[idx == SEGMENT_BUFFER_SIZE - 2 ? 0 : idx + 1]; + uint_fast8_t idx, idx_max = (sizeof(st_block_buffer) / sizeof(st_block_t)) - 1; + for(idx = 0 ; idx <= idx_max ; idx++) { + st_block_buffer[idx].next = &st_block_buffer[idx == idx_max ? 0 : idx + 1]; st_block_buffer[idx].id = idx + 1; } // Set up segments ringbuffer as circular linked list, add id and clear AMASS level - for(idx = 0 ; idx <= SEGMENT_BUFFER_SIZE - 1 ; idx++) { - segment_buffer[idx].next = &segment_buffer[idx == SEGMENT_BUFFER_SIZE - 1 ? 0 : idx + 1]; + idx_max = (sizeof(segment_buffer) / sizeof(segment_t)) - 1; + for(idx = 0 ; idx <= idx_max ; idx++) { + segment_buffer[idx].next = &segment_buffer[idx == idx_max ? 0 : idx + 1]; segment_buffer[idx].id = idx + 1; segment_buffer[idx].amass_level = 0; } diff --git a/stream.c b/stream.c index 5996518..12405c7 100644 --- a/stream.c +++ b/stream.c @@ -91,6 +91,11 @@ ISR_CODE bool stream_buffer_all (char c) return false; } +ISR_CODE bool stream_enqueue_realtime_command (char c) +{ + return hal.stream.enqueue_rt_command ? hal.stream.enqueue_rt_command(c) : protocol_enqueue_realtime_command(c); +} + ISR_CODE bool stream_enable_mpg (const io_stream_t *mpg_stream, bool mpg_mode) { static io_stream_t org_stream = { @@ -138,12 +143,14 @@ ISR_CODE bool stream_enable_mpg (const io_stream_t *mpg_stream, bool mpg_mode) #ifdef DEBUGOUT -static stream_write_ptr dbg_write; +static stream_write_ptr dbg_write = NULL; -static void debug_write (const char *s) +void debug_write (const char *s) { - dbg_write(s); - while(hal.debug.get_tx_buffer_count()); // Wait until message is delivered + if(dbg_write) { + dbg_write(s); + while(hal.debug.get_tx_buffer_count()); // Wait until message is delivered + } } void debug_stream_init (io_stream_t *stream) diff --git a/stream.h b/stream.h index 6332e0a..367abf3 100644 --- a/stream.h +++ b/stream.h @@ -56,7 +56,7 @@ Helper functions for saving away and restoring a stream input buffer. _Not refer #endif #ifndef BLOCK_TX_BUFFER_SIZE -#define BLOCK_TX_BUFFER_SIZE 256 +#define BLOCK_TX_BUFFER_SIZE 1024 #endif // Serial baud rate @@ -124,11 +124,23 @@ This should be called by driver code prior to inserting a character into the inp */ typedef bool (*enqueue_realtime_command_ptr)(char c); + +/*! \brief Optional, but recommended, pointer to function for enqueueing realtime command characters. +\param c character to enqueue. +\returns \a true if sucessfully enqueued, \a false otherwise. + +__NOTE:__ Stream implementations should pass the character over the current handler registered by the set_enqueue_rt_handler(). + +User or plugin code should __not__ enqueue realtime command characters via this handler, it should call \a grbl.enqueue_realtime_command() instead. +*/ +typedef bool (*enqueue_realtime_command2_ptr)(char c); + + /*! \brief Pointer to function for setting the enqueue realtime commands handler. \param enqueue_realtime_command_ptr pointer to the new handler function. \returns \a enqueue_realtime_command_ptr pointer to the replaced function. -__NOTE:__ Stream implementation should hold a pointer to the handler in a local variable and typically +__NOTE:__ Stream implementations should hold a pointer to the handler in a local variable and typically set it to protocol_enqueue_realtime_command() on initialization. */ typedef enqueue_realtime_command_ptr (*set_enqueue_rt_handler_ptr)(enqueue_realtime_command_ptr); @@ -179,7 +191,6 @@ for handing feed-holds, overrides, soft resets etc. \param disable \a true to disable stream, \a false to enable, */ - typedef bool (*disable_stream_ptr)(bool disable); //! Properties and handlers for stream I/O @@ -190,10 +201,11 @@ typedef struct { stream_write_ptr write; //!< Handler for writing string to current output stream only. stream_write_ptr write_all; //!< Handler for writing string to all active output streams. stream_write_char_ptr write_char; //!< Handler for writing a single character to current stream only. + enqueue_realtime_command2_ptr enqueue_rt_command; //!< (Optional) handler for enqueueing a realtime command character. stream_read_ptr read; //!< Handler for reading a single character from the input stream. flush_stream_buffer_ptr reset_read_buffer; //!< Handler for flushing the input buffer. cancel_read_buffer_ptr cancel_read_buffer; //!< Handler for flushing the input buffer and inserting an #ASCII_CAN character. - set_enqueue_rt_handler_ptr set_enqueue_rt_handler; //!< Handler for setting the enqueue realtime commands handler. + set_enqueue_rt_handler_ptr set_enqueue_rt_handler; //!< Handler for setting the enqueue realtime command character handler. suspend_read_ptr suspend_read; //!< Optional handler for saving away and restoring the current input buffer. stream_write_n_ptr write_n; //!< Optional handler for writing n characters to current output stream only. Required for Modbus support. disable_stream_ptr disable; //!< Optional handler for disabling/enabling a stream. Recommended? @@ -257,7 +269,10 @@ bool stream_buffer_all (char c); bool stream_tx_blocking (void); +bool stream_enqueue_realtime_command (char c); + #ifdef DEBUGOUT +void debug_write (const char *s); void debug_stream_init (io_stream_t *stream); #endif diff --git a/system.c b/system.c index e37e68f..c11db1c 100644 --- a/system.c +++ b/system.c @@ -35,7 +35,9 @@ static status_code_t jog (sys_state_t state, char *args); static status_code_t enumerate_alarms (sys_state_t state, char *args); +static status_code_t enumerate_alarms_grblformatted (sys_state_t state, char *args); static status_code_t enumerate_errors (sys_state_t state, char *args); +static status_code_t enumerate_errors_grblformatted (sys_state_t state, char *args); static status_code_t enumerate_groups (sys_state_t state, char *args); static status_code_t enumerate_settings (sys_state_t state, char *args); static status_code_t enumerate_all (sys_state_t state, char *args); @@ -210,7 +212,9 @@ PROGMEM static const sys_command_t sys_commands[] = { { "N0", false, set_startup_line0 }, { "N1", false, set_startup_line1 }, { "EA", true, enumerate_alarms }, + { "EAG", true, enumerate_alarms_grblformatted }, { "EE", true, enumerate_errors }, + { "EEG", true, enumerate_errors_grblformatted }, { "EG", true, enumerate_groups }, { "ES", true, enumerate_settings }, { "ESG", true, enumerate_settings_grblformatted }, @@ -340,12 +344,22 @@ static status_code_t jog (sys_state_t state, char *args) static status_code_t enumerate_alarms (sys_state_t state, char *args) { - return report_alarm_details(); + return report_alarm_details(false); +} + +static status_code_t enumerate_alarms_grblformatted (sys_state_t state, char *args) +{ + return report_alarm_details(true); } static status_code_t enumerate_errors (sys_state_t state, char *args) { - return report_error_details(); + return report_error_details(false); +} + +static status_code_t enumerate_errors_grblformatted (sys_state_t state, char *args) +{ + return report_error_details(true); } static status_code_t enumerate_groups (sys_state_t state, char *args) @@ -370,8 +384,8 @@ static status_code_t enumerate_settings_halformatted (sys_state_t state, char *a static status_code_t enumerate_all (sys_state_t state, char *args) { - report_alarm_details(); - report_error_details(); + report_alarm_details(false); + report_error_details(false); report_setting_group_details(true, NULL); return report_settings_details(SettingsFormat_MachineReadable, Setting_SettingsAll, Group_All); }