Import grbl v1.1h
diff --git a/grbl/report.c b/grbl/report.c
new file mode 100644
index 0000000..666608a
--- /dev/null
+++ b/grbl/report.c
@@ -0,0 +1,662 @@
+/*
+ report.c - reporting and messaging methods
+ Part of Grbl
+
+ Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ This file functions as the primary feedback interface for Grbl. Any outgoing data, such
+ as the protocol status messages, feedback messages, and status reports, are stored here.
+ For the most part, these functions primarily are called from protocol.c methods. If a
+ different style feedback is desired (i.e. JSON), then a user can change these following
+ methods to accomodate their needs.
+*/
+
+#include "grbl.h"
+
+
+// Internal report utilities to reduce flash with repetitive tasks turned into functions.
+void report_util_setting_prefix(uint8_t n) { serial_write('$'); print_uint8_base10(n); serial_write('='); }
+static void report_util_line_feed() { printPgmString(PSTR("\r\n")); }
+static void report_util_feedback_line_feed() { serial_write(']'); report_util_line_feed(); }
+static void report_util_gcode_modes_G() { printPgmString(PSTR(" G")); }
+static void report_util_gcode_modes_M() { printPgmString(PSTR(" M")); }
+// static void report_util_comment_line_feed() { serial_write(')'); report_util_line_feed(); }
+static void report_util_axis_values(float *axis_value) {
+ uint8_t idx;
+ for (idx=0; idx<N_AXIS; idx++) {
+ printFloat_CoordValue(axis_value[idx]);
+ if (idx < (N_AXIS-1)) { serial_write(','); }
+ }
+}
+
+/*
+static void report_util_setting_string(uint8_t n) {
+ serial_write(' ');
+ serial_write('(');
+ switch(n) {
+ case 0: printPgmString(PSTR("stp pulse")); break;
+ case 1: printPgmString(PSTR("idl delay")); break;
+ case 2: printPgmString(PSTR("stp inv")); break;
+ case 3: printPgmString(PSTR("dir inv")); break;
+ case 4: printPgmString(PSTR("stp en inv")); break;
+ case 5: printPgmString(PSTR("lim inv")); break;
+ case 6: printPgmString(PSTR("prb inv")); break;
+ case 10: printPgmString(PSTR("rpt")); break;
+ case 11: printPgmString(PSTR("jnc dev")); break;
+ case 12: printPgmString(PSTR("arc tol")); break;
+ case 13: printPgmString(PSTR("rpt inch")); break;
+ case 20: printPgmString(PSTR("sft lim")); break;
+ case 21: printPgmString(PSTR("hrd lim")); break;
+ case 22: printPgmString(PSTR("hm cyc")); break;
+ case 23: printPgmString(PSTR("hm dir inv")); break;
+ case 24: printPgmString(PSTR("hm feed")); break;
+ case 25: printPgmString(PSTR("hm seek")); break;
+ case 26: printPgmString(PSTR("hm delay")); break;
+ case 27: printPgmString(PSTR("hm pulloff")); break;
+ case 30: printPgmString(PSTR("rpm max")); break;
+ case 31: printPgmString(PSTR("rpm min")); break;
+ case 32: printPgmString(PSTR("laser")); break;
+ default:
+ n -= AXIS_SETTINGS_START_VAL;
+ uint8_t idx = 0;
+ while (n >= AXIS_SETTINGS_INCREMENT) {
+ n -= AXIS_SETTINGS_INCREMENT;
+ idx++;
+ }
+ serial_write(n+'x');
+ switch (idx) {
+ case 0: printPgmString(PSTR(":stp/mm")); break;
+ case 1: printPgmString(PSTR(":mm/min")); break;
+ case 2: printPgmString(PSTR(":mm/s^2")); break;
+ case 3: printPgmString(PSTR(":mm max")); break;
+ }
+ break;
+ }
+ report_util_comment_line_feed();
+}
+*/
+
+static void report_util_uint8_setting(uint8_t n, int val) {
+ report_util_setting_prefix(n);
+ print_uint8_base10(val);
+ report_util_line_feed(); // report_util_setting_string(n);
+}
+static void report_util_float_setting(uint8_t n, float val, uint8_t n_decimal) {
+ report_util_setting_prefix(n);
+ printFloat(val,n_decimal);
+ report_util_line_feed(); // report_util_setting_string(n);
+}
+
+
+// Handles the primary confirmation protocol response for streaming interfaces and human-feedback.
+// For every incoming line, this method responds with an 'ok' for a successful command or an
+// 'error:' to indicate some error event with the line or some critical system error during
+// operation. Errors events can originate from the g-code parser, settings module, or asynchronously
+// from a critical error, such as a triggered hard limit. Interface should always monitor for these
+// responses.
+void report_status_message(uint8_t status_code)
+{
+ switch(status_code) {
+ case STATUS_OK: // STATUS_OK
+ printPgmString(PSTR("ok\r\n")); break;
+ default:
+ printPgmString(PSTR("error:"));
+ print_uint8_base10(status_code);
+ report_util_line_feed();
+ }
+}
+
+// Prints alarm messages.
+void report_alarm_message(uint8_t alarm_code)
+{
+ printPgmString(PSTR("ALARM:"));
+ print_uint8_base10(alarm_code);
+ report_util_line_feed();
+ delay_ms(500); // Force delay to ensure message clears serial write buffer.
+}
+
+// Prints feedback messages. This serves as a centralized method to provide additional
+// user feedback for things that are not of the status/alarm message protocol. These are
+// messages such as setup warnings, switch toggling, and how to exit alarms.
+// NOTE: For interfaces, messages are always placed within brackets. And if silent mode
+// is installed, the message number codes are less than zero.
+void report_feedback_message(uint8_t message_code)
+{
+ printPgmString(PSTR("[MSG:"));
+ switch(message_code) {
+ case MESSAGE_CRITICAL_EVENT:
+ printPgmString(PSTR("Reset to continue")); break;
+ case MESSAGE_ALARM_LOCK:
+ printPgmString(PSTR("'$H'|'$X' to unlock")); break;
+ case MESSAGE_ALARM_UNLOCK:
+ printPgmString(PSTR("Caution: Unlocked")); break;
+ case MESSAGE_ENABLED:
+ printPgmString(PSTR("Enabled")); break;
+ case MESSAGE_DISABLED:
+ printPgmString(PSTR("Disabled")); break;
+ case MESSAGE_SAFETY_DOOR_AJAR:
+ printPgmString(PSTR("Check Door")); break;
+ case MESSAGE_CHECK_LIMITS:
+ printPgmString(PSTR("Check Limits")); break;
+ case MESSAGE_PROGRAM_END:
+ printPgmString(PSTR("Pgm End")); break;
+ case MESSAGE_RESTORE_DEFAULTS:
+ printPgmString(PSTR("Restoring defaults")); break;
+ case MESSAGE_SPINDLE_RESTORE:
+ printPgmString(PSTR("Restoring spindle")); break;
+ case MESSAGE_SLEEP_MODE:
+ printPgmString(PSTR("Sleeping")); break;
+ }
+ report_util_feedback_line_feed();
+}
+
+
+// Welcome message
+void report_init_message()
+{
+ printPgmString(PSTR("\r\nGrbl " GRBL_VERSION " ['$' for help]\r\n"));
+}
+
+// Grbl help message
+void report_grbl_help() {
+ printPgmString(PSTR("[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H ~ ! ? ctrl-x]\r\n"));
+}
+
+
+// Grbl global settings print out.
+// NOTE: The numbering scheme here must correlate to storing in settings.c
+void report_grbl_settings() {
+ // Print Grbl settings.
+ report_util_uint8_setting(0,settings.pulse_microseconds);
+ report_util_uint8_setting(1,settings.stepper_idle_lock_time);
+ report_util_uint8_setting(2,settings.step_invert_mask);
+ report_util_uint8_setting(3,settings.dir_invert_mask);
+ report_util_uint8_setting(4,bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
+ report_util_uint8_setting(5,bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS));
+ report_util_uint8_setting(6,bit_istrue(settings.flags,BITFLAG_INVERT_PROBE_PIN));
+ report_util_uint8_setting(10,settings.status_report_mask);
+ report_util_float_setting(11,settings.junction_deviation,N_DECIMAL_SETTINGVALUE);
+ report_util_float_setting(12,settings.arc_tolerance,N_DECIMAL_SETTINGVALUE);
+ report_util_uint8_setting(13,bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
+ report_util_uint8_setting(20,bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE));
+ report_util_uint8_setting(21,bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
+ report_util_uint8_setting(22,bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
+ report_util_uint8_setting(23,settings.homing_dir_mask);
+ report_util_float_setting(24,settings.homing_feed_rate,N_DECIMAL_SETTINGVALUE);
+ report_util_float_setting(25,settings.homing_seek_rate,N_DECIMAL_SETTINGVALUE);
+ report_util_uint8_setting(26,settings.homing_debounce_delay);
+ report_util_float_setting(27,settings.homing_pulloff,N_DECIMAL_SETTINGVALUE);
+ report_util_float_setting(30,settings.rpm_max,N_DECIMAL_RPMVALUE);
+ report_util_float_setting(31,settings.rpm_min,N_DECIMAL_RPMVALUE);
+ #ifdef VARIABLE_SPINDLE
+ report_util_uint8_setting(32,bit_istrue(settings.flags,BITFLAG_LASER_MODE));
+ #else
+ report_util_uint8_setting(32,0);
+ #endif
+ // Print axis settings
+ uint8_t idx, set_idx;
+ uint8_t val = AXIS_SETTINGS_START_VAL;
+ for (set_idx=0; set_idx<AXIS_N_SETTINGS; set_idx++) {
+ for (idx=0; idx<N_AXIS; idx++) {
+ switch (set_idx) {
+ case 0: report_util_float_setting(val+idx,settings.steps_per_mm[idx],N_DECIMAL_SETTINGVALUE); break;
+ case 1: report_util_float_setting(val+idx,settings.max_rate[idx],N_DECIMAL_SETTINGVALUE); break;
+ case 2: report_util_float_setting(val+idx,settings.acceleration[idx]/(60*60),N_DECIMAL_SETTINGVALUE); break;
+ case 3: report_util_float_setting(val+idx,-settings.max_travel[idx],N_DECIMAL_SETTINGVALUE); break;
+ }
+ }
+ val += AXIS_SETTINGS_INCREMENT;
+ }
+}
+
+
+// Prints current probe parameters. Upon a probe command, these parameters are updated upon a
+// successful probe or upon a failed probe with the G38.3 without errors command (if supported).
+// These values are retained until Grbl is power-cycled, whereby they will be re-zeroed.
+void report_probe_parameters()
+{
+ // Report in terms of machine position.
+ printPgmString(PSTR("[PRB:"));
+ float print_position[N_AXIS];
+ system_convert_array_steps_to_mpos(print_position,sys_probe_position);
+ report_util_axis_values(print_position);
+ serial_write(':');
+ print_uint8_base10(sys.probe_succeeded);
+ report_util_feedback_line_feed();
+}
+
+
+// Prints Grbl NGC parameters (coordinate offsets, probing)
+void report_ngc_parameters()
+{
+ float coord_data[N_AXIS];
+ uint8_t coord_select;
+ for (coord_select = 0; coord_select <= SETTING_INDEX_NCOORD; coord_select++) {
+ if (!(settings_read_coord_data(coord_select,coord_data))) {
+ report_status_message(STATUS_SETTING_READ_FAIL);
+ return;
+ }
+ printPgmString(PSTR("[G"));
+ switch (coord_select) {
+ case 6: printPgmString(PSTR("28")); break;
+ case 7: printPgmString(PSTR("30")); break;
+ default: print_uint8_base10(coord_select+54); break; // G54-G59
+ }
+ serial_write(':');
+ report_util_axis_values(coord_data);
+ report_util_feedback_line_feed();
+ }
+ printPgmString(PSTR("[G92:")); // Print G92,G92.1 which are not persistent in memory
+ report_util_axis_values(gc_state.coord_offset);
+ report_util_feedback_line_feed();
+ printPgmString(PSTR("[TLO:")); // Print tool length offset value
+ printFloat_CoordValue(gc_state.tool_length_offset);
+ report_util_feedback_line_feed();
+ report_probe_parameters(); // Print probe parameters. Not persistent in memory.
+}
+
+
+// Print current gcode parser mode state
+void report_gcode_modes()
+{
+ printPgmString(PSTR("[GC:G"));
+ if (gc_state.modal.motion >= MOTION_MODE_PROBE_TOWARD) {
+ printPgmString(PSTR("38."));
+ print_uint8_base10(gc_state.modal.motion - (MOTION_MODE_PROBE_TOWARD-2));
+ } else {
+ print_uint8_base10(gc_state.modal.motion);
+ }
+
+ report_util_gcode_modes_G();
+ print_uint8_base10(gc_state.modal.coord_select+54);
+
+ report_util_gcode_modes_G();
+ print_uint8_base10(gc_state.modal.plane_select+17);
+
+ report_util_gcode_modes_G();
+ print_uint8_base10(21-gc_state.modal.units);
+
+ report_util_gcode_modes_G();
+ print_uint8_base10(gc_state.modal.distance+90);
+
+ report_util_gcode_modes_G();
+ print_uint8_base10(94-gc_state.modal.feed_rate);
+
+ if (gc_state.modal.program_flow) {
+ report_util_gcode_modes_M();
+ switch (gc_state.modal.program_flow) {
+ case PROGRAM_FLOW_PAUSED : serial_write('0'); break;
+ // case PROGRAM_FLOW_OPTIONAL_STOP : serial_write('1'); break; // M1 is ignored and not supported.
+ case PROGRAM_FLOW_COMPLETED_M2 :
+ case PROGRAM_FLOW_COMPLETED_M30 :
+ print_uint8_base10(gc_state.modal.program_flow);
+ break;
+ }
+ }
+
+ report_util_gcode_modes_M();
+ switch (gc_state.modal.spindle) {
+ case SPINDLE_ENABLE_CW : serial_write('3'); break;
+ case SPINDLE_ENABLE_CCW : serial_write('4'); break;
+ case SPINDLE_DISABLE : serial_write('5'); break;
+ }
+
+ #ifdef ENABLE_M7
+ if (gc_state.modal.coolant) { // Note: Multiple coolant states may be active at the same time.
+ if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_MIST) { report_util_gcode_modes_M(); serial_write('7'); }
+ if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_FLOOD) { report_util_gcode_modes_M(); serial_write('8'); }
+ } else { report_util_gcode_modes_M(); serial_write('9'); }
+ #else
+ report_util_gcode_modes_M();
+ if (gc_state.modal.coolant) { serial_write('8'); }
+ else { serial_write('9'); }
+ #endif
+
+ #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ if (sys.override_ctrl == OVERRIDE_PARKING_MOTION) {
+ report_util_gcode_modes_M();
+ print_uint8_base10(56);
+ }
+ #endif
+
+ printPgmString(PSTR(" T"));
+ print_uint8_base10(gc_state.tool);
+
+ printPgmString(PSTR(" F"));
+ printFloat_RateValue(gc_state.feed_rate);
+
+ #ifdef VARIABLE_SPINDLE
+ printPgmString(PSTR(" S"));
+ printFloat(gc_state.spindle_speed,N_DECIMAL_RPMVALUE);
+ #endif
+
+ report_util_feedback_line_feed();
+}
+
+// Prints specified startup line
+void report_startup_line(uint8_t n, char *line)
+{
+ printPgmString(PSTR("$N"));
+ print_uint8_base10(n);
+ serial_write('=');
+ printString(line);
+ report_util_line_feed();
+}
+
+void report_execute_startup_message(char *line, uint8_t status_code)
+{
+ serial_write('>');
+ printString(line);
+ serial_write(':');
+ report_status_message(status_code);
+}
+
+// Prints build info line
+void report_build_info(char *line)
+{
+ printPgmString(PSTR("[VER:" GRBL_VERSION "." GRBL_VERSION_BUILD ":"));
+ printString(line);
+ report_util_feedback_line_feed();
+ printPgmString(PSTR("[OPT:")); // Generate compile-time build option list
+ #ifdef VARIABLE_SPINDLE
+ serial_write('V');
+ #endif
+ #ifdef USE_LINE_NUMBERS
+ serial_write('N');
+ #endif
+ #ifdef ENABLE_M7
+ serial_write('M');
+ #endif
+ #ifdef COREXY
+ serial_write('C');
+ #endif
+ #ifdef PARKING_ENABLE
+ serial_write('P');
+ #endif
+ #ifdef HOMING_FORCE_SET_ORIGIN
+ serial_write('Z');
+ #endif
+ #ifdef HOMING_SINGLE_AXIS_COMMANDS
+ serial_write('H');
+ #endif
+ #ifdef LIMITS_TWO_SWITCHES_ON_AXES
+ serial_write('T');
+ #endif
+ #ifdef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES
+ serial_write('A');
+ #endif
+ #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
+ serial_write('D');
+ #endif
+ #ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
+ serial_write('0');
+ #endif
+ #ifdef ENABLE_SOFTWARE_DEBOUNCE
+ serial_write('S');
+ #endif
+ #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ serial_write('R');
+ #endif
+ #ifndef HOMING_INIT_LOCK
+ serial_write('L');
+ #endif
+ #ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
+ serial_write('+');
+ #endif
+ #ifndef ENABLE_RESTORE_EEPROM_WIPE_ALL // NOTE: Shown when disabled.
+ serial_write('*');
+ #endif
+ #ifndef ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS // NOTE: Shown when disabled.
+ serial_write('$');
+ #endif
+ #ifndef ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS // NOTE: Shown when disabled.
+ serial_write('#');
+ #endif
+ #ifndef ENABLE_BUILD_INFO_WRITE_COMMAND // NOTE: Shown when disabled.
+ serial_write('I');
+ #endif
+ #ifndef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE // NOTE: Shown when disabled.
+ serial_write('E');
+ #endif
+ #ifndef FORCE_BUFFER_SYNC_DURING_WCO_CHANGE // NOTE: Shown when disabled.
+ serial_write('W');
+ #endif
+ #ifdef ENABLE_DUAL_AXIS
+ serial_write('2');
+ #endif
+ // NOTE: Compiled values, like override increments/max/min values, may be added at some point later.
+ serial_write(',');
+ print_uint8_base10(BLOCK_BUFFER_SIZE-1);
+ serial_write(',');
+ print_uint8_base10(RX_BUFFER_SIZE);
+
+ report_util_feedback_line_feed();
+}
+
+
+// Prints the character string line Grbl has received from the user, which has been pre-parsed,
+// and has been sent into protocol_execute_line() routine to be executed by Grbl.
+void report_echo_line_received(char *line)
+{
+ printPgmString(PSTR("[echo: ")); printString(line);
+ report_util_feedback_line_feed();
+}
+
+
+ // Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram
+ // and the actual location of the CNC machine. Users may change the following function to their
+ // specific needs, but the desired real-time data report must be as short as possible. This is
+ // requires as it minimizes the computational overhead and allows grbl to keep running smoothly,
+ // especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
+void report_realtime_status()
+{
+ uint8_t idx;
+ int32_t current_position[N_AXIS]; // Copy current state of the system position variable
+ memcpy(current_position,sys_position,sizeof(sys_position));
+ float print_position[N_AXIS];
+ system_convert_array_steps_to_mpos(print_position,current_position);
+
+ // Report current machine state and sub-states
+ serial_write('<');
+ switch (sys.state) {
+ case STATE_IDLE: printPgmString(PSTR("Idle")); break;
+ case STATE_CYCLE: printPgmString(PSTR("Run")); break;
+ case STATE_HOLD:
+ if (!(sys.suspend & SUSPEND_JOG_CANCEL)) {
+ printPgmString(PSTR("Hold:"));
+ if (sys.suspend & SUSPEND_HOLD_COMPLETE) { serial_write('0'); } // Ready to resume
+ else { serial_write('1'); } // Actively holding
+ break;
+ } // Continues to print jog state during jog cancel.
+ case STATE_JOG: printPgmString(PSTR("Jog")); break;
+ case STATE_HOMING: printPgmString(PSTR("Home")); break;
+ case STATE_ALARM: printPgmString(PSTR("Alarm")); break;
+ case STATE_CHECK_MODE: printPgmString(PSTR("Check")); break;
+ case STATE_SAFETY_DOOR:
+ printPgmString(PSTR("Door:"));
+ if (sys.suspend & SUSPEND_INITIATE_RESTORE) {
+ serial_write('3'); // Restoring
+ } else {
+ if (sys.suspend & SUSPEND_RETRACT_COMPLETE) {
+ if (sys.suspend & SUSPEND_SAFETY_DOOR_AJAR) {
+ serial_write('1'); // Door ajar
+ } else {
+ serial_write('0');
+ } // Door closed and ready to resume
+ } else {
+ serial_write('2'); // Retracting
+ }
+ }
+ break;
+ case STATE_SLEEP: printPgmString(PSTR("Sleep")); break;
+ }
+
+ float wco[N_AXIS];
+ if (bit_isfalse(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE) ||
+ (sys.report_wco_counter == 0) ) {
+ for (idx=0; idx< N_AXIS; idx++) {
+ // Apply work coordinate offsets and tool length offset to current position.
+ wco[idx] = gc_state.coord_system[idx]+gc_state.coord_offset[idx];
+ if (idx == TOOL_LENGTH_OFFSET_AXIS) { wco[idx] += gc_state.tool_length_offset; }
+ if (bit_isfalse(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE)) {
+ print_position[idx] -= wco[idx];
+ }
+ }
+ }
+
+ // Report machine position
+ if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE)) {
+ printPgmString(PSTR("|MPos:"));
+ } else {
+ printPgmString(PSTR("|WPos:"));
+ }
+ report_util_axis_values(print_position);
+
+ // Returns planner and serial read buffer states.
+ #ifdef REPORT_FIELD_BUFFER_STATE
+ if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_BUFFER_STATE)) {
+ printPgmString(PSTR("|Bf:"));
+ print_uint8_base10(plan_get_block_buffer_available());
+ serial_write(',');
+ print_uint8_base10(serial_get_rx_buffer_available());
+ }
+ #endif
+
+ #ifdef USE_LINE_NUMBERS
+ #ifdef REPORT_FIELD_LINE_NUMBERS
+ // Report current line number
+ plan_block_t * cur_block = plan_get_current_block();
+ if (cur_block != NULL) {
+ uint32_t ln = cur_block->line_number;
+ if (ln > 0) {
+ printPgmString(PSTR("|Ln:"));
+ printInteger(ln);
+ }
+ }
+ #endif
+ #endif
+
+ // Report realtime feed speed
+ #ifdef REPORT_FIELD_CURRENT_FEED_SPEED
+ #ifdef VARIABLE_SPINDLE
+ printPgmString(PSTR("|FS:"));
+ printFloat_RateValue(st_get_realtime_rate());
+ serial_write(',');
+ printFloat(sys.spindle_speed,N_DECIMAL_RPMVALUE);
+ #else
+ printPgmString(PSTR("|F:"));
+ printFloat_RateValue(st_get_realtime_rate());
+ #endif
+ #endif
+
+ #ifdef REPORT_FIELD_PIN_STATE
+ uint8_t lim_pin_state = limits_get_state();
+ uint8_t ctrl_pin_state = system_control_get_state();
+ uint8_t prb_pin_state = probe_get_state();
+ if (lim_pin_state | ctrl_pin_state | prb_pin_state) {
+ printPgmString(PSTR("|Pn:"));
+ if (prb_pin_state) { serial_write('P'); }
+ if (lim_pin_state) {
+ #ifdef ENABLE_DUAL_AXIS
+ #if (DUAL_AXIS_SELECT == X_AXIS)
+ if (bit_istrue(lim_pin_state,(bit(X_AXIS)|bit(N_AXIS)))) { serial_write('X'); }
+ if (bit_istrue(lim_pin_state,bit(Y_AXIS))) { serial_write('Y'); }
+ #endif
+ #if (DUAL_AXIS_SELECT == Y_AXIS)
+ if (bit_istrue(lim_pin_state,bit(X_AXIS))) { serial_write('X');
+ if (bit_istrue(lim_pin_state,(bit(Y_AXIS)|bit(N_AXIS)))) { serial_write('Y'); }
+ #endif
+ if (bit_istrue(lim_pin_state,bit(Z_AXIS))) { serial_write('Z'); }
+ #else
+ if (bit_istrue(lim_pin_state,bit(X_AXIS))) { serial_write('X'); }
+ if (bit_istrue(lim_pin_state,bit(Y_AXIS))) { serial_write('Y'); }
+ if (bit_istrue(lim_pin_state,bit(Z_AXIS))) { serial_write('Z'); }
+ #endif
+ }
+ if (ctrl_pin_state) {
+ #ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
+ if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_SAFETY_DOOR)) { serial_write('D'); }
+ #endif
+ if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_RESET)) { serial_write('R'); }
+ if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_FEED_HOLD)) { serial_write('H'); }
+ if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_CYCLE_START)) { serial_write('S'); }
+ }
+ }
+ #endif
+
+ #ifdef REPORT_FIELD_WORK_COORD_OFFSET
+ if (sys.report_wco_counter > 0) { sys.report_wco_counter--; }
+ else {
+ if (sys.state & (STATE_HOMING | STATE_CYCLE | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
+ sys.report_wco_counter = (REPORT_WCO_REFRESH_BUSY_COUNT-1); // Reset counter for slow refresh
+ } else { sys.report_wco_counter = (REPORT_WCO_REFRESH_IDLE_COUNT-1); }
+ if (sys.report_ovr_counter == 0) { sys.report_ovr_counter = 1; } // Set override on next report.
+ printPgmString(PSTR("|WCO:"));
+ report_util_axis_values(wco);
+ }
+ #endif
+
+ #ifdef REPORT_FIELD_OVERRIDES
+ if (sys.report_ovr_counter > 0) { sys.report_ovr_counter--; }
+ else {
+ if (sys.state & (STATE_HOMING | STATE_CYCLE | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
+ sys.report_ovr_counter = (REPORT_OVR_REFRESH_BUSY_COUNT-1); // Reset counter for slow refresh
+ } else { sys.report_ovr_counter = (REPORT_OVR_REFRESH_IDLE_COUNT-1); }
+ printPgmString(PSTR("|Ov:"));
+ print_uint8_base10(sys.f_override);
+ serial_write(',');
+ print_uint8_base10(sys.r_override);
+ serial_write(',');
+ print_uint8_base10(sys.spindle_speed_ovr);
+
+ uint8_t sp_state = spindle_get_state();
+ uint8_t cl_state = coolant_get_state();
+ if (sp_state || cl_state) {
+ printPgmString(PSTR("|A:"));
+ if (sp_state) { // != SPINDLE_STATE_DISABLE
+ #ifdef VARIABLE_SPINDLE
+ #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
+ serial_write('S'); // CW
+ #else
+ if (sp_state == SPINDLE_STATE_CW) { serial_write('S'); } // CW
+ else { serial_write('C'); } // CCW
+ #endif
+ #else
+ if (sp_state & SPINDLE_STATE_CW) { serial_write('S'); } // CW
+ else { serial_write('C'); } // CCW
+ #endif
+ }
+ if (cl_state & COOLANT_STATE_FLOOD) { serial_write('F'); }
+ #ifdef ENABLE_M7
+ if (cl_state & COOLANT_STATE_MIST) { serial_write('M'); }
+ #endif
+ }
+ }
+ #endif
+
+ serial_write('>');
+ report_util_line_feed();
+}
+
+
+#ifdef DEBUG
+ void report_realtime_debug()
+ {
+
+ }
+#endif