Pin state reporting of all pins. Flash optimization.

- New pin state realtime reporting feature. Instead of `Lim:000` for
limit state reports, the new feature shows `Pin:000|0|0000`, or
something similar. The `|` delimited fields indicate xyz limits, probe,
and control pin states, where 0 is always not triggered, and 1 is
triggered. Invert masks ARE accounted for.
  Each field may be enabled or disabled via the `$10` status report
setting. The probe and control pin flags are bits 5 and 6, respectively.

- Remove the now deprecated `REPORT_CONTROL_PIN_STATE` option in
config.h

- The old limit pin reports `Lim:000` may be re-enabled by commenting
out `REPORT_ALL_PIN_STATES` in config.h.

- Incremented the version letter (v1.0c) to indicate the change in
reporting style.

- Replaced all bit_true_atomic and bit_false_atomic macros with
function calls. This saved a couple hundred bytes of flash.
This commit is contained in:
Sonny Jeon
2015-11-09 21:54:26 -07:00
parent b9c3461932
commit 5eee10845b
16 changed files with 182 additions and 63 deletions

View File

@ -164,11 +164,12 @@
// uncomment the config option USE_SPINDLE_DIR_AS_ENABLE_PIN below.
// #define INVERT_SPINDLE_ENABLE_PIN // Default disabled. Uncomment to enable.
// Enable control pin states feedback in status reports. The data is presented as simple binary of
// the control pin port (0 (low) or 1(high)), masked to show only the input pins. Non-control pins on the
// port will always show a 0 value. See cpu_map.h for the pin bitmap. As with the limit pin reporting,
// we do not recommend keeping this option enabled. Try to only use this for setting up a new CNC.
// #define REPORT_CONTROL_PIN_STATE // Default disabled. Uncomment to enable.
// Enable all pin states feedback in status reports. Configurable with Grbl settings to print only
// the desired data, which is presented as simple binary reading of each pin as (0 (low) or 1(high)).
// The fields are printed in a particular order and settings groups are separated by '|' characters.
// NOTE: This option is here for backward compatibility of the old style of pin state reports, i.e.
// `Lim:000`. This new `Pin:` report will be the standard going forward.
#define REPORT_ALL_PIN_STATES // Default enabled. Comment to disable.
// When Grbl powers-cycles or is hard reset with the Arduino reset button, Grbl boots up with no ALARM
// by default. This is to make it as simple as possible for new users to start using Grbl. When homing

View File

@ -1044,7 +1044,7 @@ uint8_t gc_execute_line(char *line)
protocol_buffer_synchronize(); // Sync and finish all remaining buffered motions before moving on.
if (gc_state.modal.program_flow == PROGRAM_FLOW_PAUSED) {
if (sys.state != STATE_CHECK_MODE) {
bit_true_atomic(sys_rt_exec_state, EXEC_FEED_HOLD); // Use feed hold for program pause.
system_set_exec_state_flag(EXEC_FEED_HOLD); // Use feed hold for program pause.
protocol_execute_realtime(); // Execute suspend.
}
} else { // == PROGRAM_FLOW_COMPLETED

View File

@ -22,8 +22,8 @@
#define grbl_h
// Grbl versioning system
#define GRBL_VERSION "1.0b"
#define GRBL_VERSION_BUILD "20150930"
#define GRBL_VERSION "1.0c"
#define GRBL_VERSION_BUILD "20151109"
// Define standard libraries used by Grbl.
#include <avr/io.h>

View File

@ -106,11 +106,11 @@ uint8_t limits_get_state()
// Check limit pin state.
if (limits_get_state()) {
mc_reset(); // Initiate system kill.
bit_true_atomic(sys_rt_exec_alarm, (EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate hard limit critical event
system_set_exec_alarm_flag((EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate hard limit critical event
}
#else
mc_reset(); // Initiate system kill.
bit_true_atomic(sys_rt_exec_alarm, (EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate hard limit critical event
system_set_exec_alarm_flag((EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate hard limit critical event
#endif
}
}
@ -126,7 +126,7 @@ uint8_t limits_get_state()
// Check limit pin state.
if (limits_get_state()) {
mc_reset(); // Initiate system kill.
bit_true_atomic(sys_rt_exec_alarm, (EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate hard limit critical event
system_set_exec_alarm_flag((EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate hard limit critical event
}
}
}
@ -235,7 +235,7 @@ void limits_go_home(uint8_t cycle_mask)
return;
} else {
// Pull-off motion complete. Disable CYCLE_STOP from executing.
bit_false_atomic(sys_rt_exec_state,EXEC_CYCLE_STOP);
system_clear_exec_state_flag(EXEC_CYCLE_STOP);
break;
}
}
@ -335,7 +335,7 @@ void limits_soft_check(float *target)
// workspace volume so just come to a controlled stop so position is not lost. When complete
// enter alarm mode.
if (sys.state == STATE_CYCLE) {
bit_true_atomic(sys_rt_exec_state, EXEC_FEED_HOLD);
system_set_exec_state_flag(EXEC_FEED_HOLD);
do {
protocol_execute_realtime();
if (sys.abort) { return; }
@ -343,7 +343,7 @@ void limits_soft_check(float *target)
}
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
bit_true_atomic(sys_rt_exec_alarm, (EXEC_ALARM_SOFT_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate soft limit critical event
system_set_exec_alarm_flag((EXEC_ALARM_SOFT_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate soft limit critical event
protocol_execute_realtime(); // Execute to enter critical event loop and system abort
return;
}

View File

@ -220,7 +220,7 @@ void mc_homing_cycle()
#ifdef LIMITS_TWO_SWITCHES_ON_AXES
if (limits_get_state()) {
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
bit_true_atomic(sys_rt_exec_alarm, (EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT));
system_set_exec_alarm_flag((EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT));
return;
}
#endif
@ -276,7 +276,7 @@ void mc_homing_cycle()
// After syncing, check if probe is already triggered. If so, halt and issue alarm.
// NOTE: This probe initialization error applies to all probing cycles.
if ( probe_get_state() ) { // Check probe pin state.
bit_true_atomic(sys_rt_exec_alarm, EXEC_ALARM_PROBE_FAIL);
system_set_exec_alarm_flag(EXEC_ALARM_PROBE_FAIL);
protocol_execute_realtime();
}
if (sys.abort) { return; } // Return if system reset has been issued.
@ -292,7 +292,7 @@ void mc_homing_cycle()
sys_probe_state = PROBE_ACTIVE;
// Perform probing cycle. Wait here until probe is triggered or motion completes.
bit_true_atomic(sys_rt_exec_state, EXEC_CYCLE_START);
system_set_exec_state_flag(EXEC_CYCLE_START);
do {
protocol_execute_realtime();
if (sys.abort) { return; } // Check for system abort
@ -303,7 +303,7 @@ void mc_homing_cycle()
// Set state variables and error out, if the probe failed and cycle with error is enabled.
if (sys_probe_state == PROBE_ACTIVE) {
if (is_no_error) { memcpy(sys.probe_position, sys.position, sizeof(sys.position)); }
else { bit_true_atomic(sys_rt_exec_alarm, EXEC_ALARM_PROBE_FAIL); }
else { system_set_exec_alarm_flag(EXEC_ALARM_PROBE_FAIL); }
} else {
sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
}
@ -366,7 +366,7 @@ void mc_reset()
{
// Only this function can set the system reset. Helps prevent multiple kill calls.
if (bit_isfalse(sys_rt_exec_state, EXEC_RESET)) {
bit_true_atomic(sys_rt_exec_state, EXEC_RESET);
system_set_exec_state_flag(EXEC_RESET);
// Kill spindle and coolant.
spindle_stop();
@ -378,8 +378,8 @@ void mc_reset()
// violated, by which, all bets are off.
if ((sys.state & (STATE_CYCLE | STATE_HOMING)) ||
(sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_PARK))) {
if (sys.state == STATE_HOMING) { bit_true_atomic(sys_rt_exec_alarm, EXEC_ALARM_HOMING_FAIL); }
else { bit_true_atomic(sys_rt_exec_alarm, EXEC_ALARM_ABORT_CYCLE); }
if (sys.state == STATE_HOMING) { system_set_exec_alarm_flag(EXEC_ALARM_HOMING_FAIL); }
else { system_set_exec_alarm_flag(EXEC_ALARM_ABORT_CYCLE); }
st_go_idle(); // Force kill steppers. Position has likely been lost.
}
}

View File

@ -56,9 +56,6 @@
// Bit field and masking macros
#define bit(n) (1 << n)
#define bit_true_atomic(x,mask) {uint8_t sreg = SREG; cli(); (x) |= (mask); SREG = sreg; }
#define bit_false_atomic(x,mask) {uint8_t sreg = SREG; cli(); (x) &= ~(mask); SREG = sreg; }
#define bit_toggle_atomic(x,mask) {uint8_t sreg = SREG; cli(); (x) ^= (mask); SREG = sreg; }
#define bit_true(x,mask) (x) |= (mask)
#define bit_false(x,mask) (x) &= ~(mask)
#define bit_istrue(x,mask) ((x & mask) != 0)

View File

@ -34,7 +34,7 @@ void probe_init()
#else
PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation.
#endif
// probe_configure_invert_mask(false); // Initialize invert mask. Not required. Updated when in-use.
probe_configure_invert_mask(false); // Initialize invert mask. Re-updated during use.
}

View File

@ -190,7 +190,7 @@ void protocol_buffer_synchronize()
// when one of these conditions exist respectively: There are no more blocks sent (i.e. streaming
// is finished, single commands), a command that needs to wait for the motions in the buffer to
// execute calls a buffer sync, or the planner buffer is full and ready to go.
void protocol_auto_cycle_start() { bit_true_atomic(sys_rt_exec_state, EXEC_CYCLE_START); }
void protocol_auto_cycle_start() { system_set_exec_state_flag(EXEC_CYCLE_START); }
// This function is the general interface to Grbl's real-time command execution system. It is called
@ -237,7 +237,7 @@ void protocol_exec_rt_system()
// Halt everything upon a critical event flag. Currently hard and soft limits flag this.
if (rt_exec & EXEC_CRITICAL_EVENT) {
report_feedback_message(MESSAGE_CRITICAL_EVENT);
bit_false_atomic(sys_rt_exec_state,EXEC_RESET); // Disable any existing reset
system_clear_exec_state_flag(EXEC_RESET); // Disable any existing reset
do {
// Block everything, except reset and status reports, until user issues reset or power
// cycles. Hard limits typically occur while unattended or not paying attention. Gives
@ -248,12 +248,12 @@ void protocol_exec_rt_system()
// TODO: Allow status reports during a critical alarm. Still need to think about implications of this.
// if (sys_rt_exec_state & EXEC_STATUS_REPORT) {
// report_realtime_status();
// bit_false_atomic(sys_rt_exec_state,EXEC_STATUS_REPORT);
// system_clear_exec_state_flag(EXEC_STATUS_REPORT);
// }
} while (bit_isfalse(sys_rt_exec_state,EXEC_RESET));
}
bit_false_atomic(sys_rt_exec_alarm,0xFF); // Clear all alarm flags
system_clear_exec_alarm_flag(0xFF); // Clear all alarm flags
}
rt_exec = sys_rt_exec_state; // Copy volatile sys_rt_exec_state.
@ -268,7 +268,7 @@ void protocol_exec_rt_system()
// Execute and serial print status
if (rt_exec & EXEC_STATUS_REPORT) {
report_realtime_status();
bit_false_atomic(sys_rt_exec_state,EXEC_STATUS_REPORT);
system_clear_exec_state_flag(EXEC_STATUS_REPORT);
}
// NOTE: The math involved to calculate the hold should be low enough for most, if not all,
@ -340,7 +340,7 @@ void protocol_exec_rt_system()
}
bit_false_atomic(sys_rt_exec_state,(EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR));
system_clear_exec_state_flag((EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR));
}
// Execute a cycle start by starting the stepper interrupt to begin executing the blocks in queue.
@ -380,7 +380,7 @@ void protocol_exec_rt_system()
}
}
}
bit_false_atomic(sys_rt_exec_state,EXEC_CYCLE_START);
system_clear_exec_state_flag(EXEC_CYCLE_START);
}
if (rt_exec & EXEC_CYCLE_STOP) {
@ -399,7 +399,7 @@ void protocol_exec_rt_system()
sys.suspend = SUSPEND_DISABLE;
sys.state = STATE_IDLE;
}
bit_false_atomic(sys_rt_exec_state,EXEC_CYCLE_STOP);
system_clear_exec_state_flag(EXEC_CYCLE_STOP);
}
}
@ -544,7 +544,7 @@ static void protocol_exec_rt_suspend()
if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
sys.suspend |= SUSPEND_RESTORE_COMPLETE;
bit_true_atomic(sys_rt_exec_state,EXEC_CYCLE_START); // Set to resume program.
system_set_exec_state_flag(EXEC_CYCLE_START); // Set to resume program.
}
}

View File

@ -502,14 +502,28 @@ void report_realtime_status()
printFloat_RateValue(st_get_realtime_rate());
#endif
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_LIMIT_PINS)) {
printPgmString(PSTR(",Lim:"));
print_unsigned_int8(limits_get_state(),2,N_AXIS);
}
#ifdef REPORT_CONTROL_PIN_STATE
printPgmString(PSTR(",Ctl:"));
print_uint8_base2(CONTROL_PIN & CONTROL_MASK);
#ifdef REPORT_ALL_PIN_STATES
if (bit_istrue(settings.status_report_mask,
( BITFLAG_RT_STATUS_LIMIT_PINS| BITFLAG_RT_STATUS_PROBE_PIN | BITFLAG_RT_STATUS_CONTROL_PINS ))) {
printPgmString(PSTR(",Pin:"));
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_LIMIT_PINS)) {
print_unsigned_int8(limits_get_state(),2,N_AXIS);
}
printPgmString(PSTR("|"));
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_PROBE_PIN)) {
if (probe_get_state()) { printPgmString(PSTR("1")); }
else { printPgmString(PSTR("0")); }
}
printPgmString(PSTR("|"));
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_CONTROL_PINS)) {
print_unsigned_int8(system_control_get_state(),2,N_CONTROL_PIN);
}
}
#else
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_LIMIT_PINS)) {
printPgmString(PSTR(",Lim:"));
print_unsigned_int8(limits_get_state(),2,N_AXIS);
}
#endif
printPgmString(PSTR(">\r\n"));

View File

@ -164,10 +164,10 @@ ISR(SERIAL_RX)
// Pick off realtime command characters directly from the serial stream. These characters are
// not passed into the buffer, but these set system state flag bits for realtime execution.
switch (data) {
case CMD_STATUS_REPORT: bit_true_atomic(sys_rt_exec_state, EXEC_STATUS_REPORT); break; // Set as true
case CMD_CYCLE_START: bit_true_atomic(sys_rt_exec_state, EXEC_CYCLE_START); break; // Set as true
case CMD_FEED_HOLD: bit_true_atomic(sys_rt_exec_state, EXEC_FEED_HOLD); break; // Set as true
case CMD_SAFETY_DOOR: bit_true_atomic(sys_rt_exec_state, EXEC_SAFETY_DOOR); break; // Set as true
case CMD_STATUS_REPORT: system_set_exec_state_flag(EXEC_STATUS_REPORT); break; // Set as true
case CMD_CYCLE_START: system_set_exec_state_flag(EXEC_CYCLE_START); break; // Set as true
case CMD_FEED_HOLD: system_set_exec_state_flag(EXEC_FEED_HOLD); break; // Set as true
case CMD_SAFETY_DOOR: system_set_exec_state_flag(EXEC_SAFETY_DOOR); break; // Set as true
case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
default: // Write character to buffer
next_head = serial_rx_buffer_head + 1;

View File

@ -45,6 +45,8 @@
#define BITFLAG_RT_STATUS_PLANNER_BUFFER bit(2)
#define BITFLAG_RT_STATUS_SERIAL_RX bit(3)
#define BITFLAG_RT_STATUS_LIMIT_PINS bit(4)
#define BITFLAG_RT_STATUS_PROBE_PIN bit(5)
#define BITFLAG_RT_STATUS_CONTROL_PINS bit(6)
// Define settings restore bitflags.
#define SETTINGS_RESTORE_ALL 0xFF // All bitflags

View File

@ -349,7 +349,7 @@ ISR(TIMER1_COMPA_vect)
} else {
// Segment buffer empty. Shutdown.
st_go_idle();
bit_true_atomic(sys_rt_exec_state,EXEC_CYCLE_STOP); // Flag main program for cycle end
system_set_exec_state_flag(EXEC_CYCLE_STOP); // Flag main program for cycle end
return; // Nothing to do but exit.
}
}

View File

@ -34,27 +34,45 @@ void system_init()
}
// Returns control pin state as a uint8 bitfield. Each bit indicates the input pin state, where
// triggered is 1 and not triggered is 0. Invert mask is applied. Bitfield organization is
// defined by the CONTROL_PIN_INDEX in the header file.
uint8_t system_control_get_state()
{
uint8_t control_state = 0;
uint8_t pin = (CONTROL_PIN & CONTROL_MASK);
#ifndef INVERT_ALL_CONTROL_PINS
pin ^= CONTROL_INVERT_MASK;
#endif
if (pin) {
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
if (bit_istrue(pin,(1<<SAFETY_DOOR_BIT))) { control_state |= CONTROL_PIN_INDEX_SAFETY_DOOR; }
#endif
if (bit_istrue(pin,(1<<RESET_BIT))) { control_state |= CONTROL_PIN_INDEX_RESET; }
if (bit_istrue(pin,(1<<FEED_HOLD_BIT))) { control_state |= CONTROL_PIN_INDEX_FEED_HOLD; }
if (bit_istrue(pin,(1<<CYCLE_START_BIT))) { control_state |= CONTROL_PIN_INDEX_CYCLE_START; }
}
return(control_state);
}
// Pin change interrupt for pin-out commands, i.e. cycle start, feed hold, and reset. Sets
// only the realtime command execute variable to have the main program execute these when
// its ready. This works exactly like the character-based realtime commands when picked off
// directly from the incoming serial data stream.
ISR(CONTROL_INT_vect)
{
uint8_t pin = (CONTROL_PIN & CONTROL_MASK);
#ifndef INVERT_ALL_CONTROL_PINS
pin ^= CONTROL_INVERT_MASK;
#endif
// Enter only if any CONTROL pin is detected as active.
uint8_t pin = system_control_get_state();
if (pin) {
if (bit_istrue(pin,bit(RESET_BIT))) {
if (bit_istrue(pin,CONTROL_PIN_INDEX_RESET)) {
mc_reset();
} else if (bit_istrue(pin,bit(CYCLE_START_BIT))) {
} else if (bit_istrue(pin,CONTROL_PIN_INDEX_CYCLE_START)) {
bit_true(sys_rt_exec_state, EXEC_CYCLE_START);
#ifndef ENABLE_SAFETY_DOOR_INPUT_PIN
} else if (bit_istrue(pin,bit(FEED_HOLD_BIT))) {
} else if (bit_istrue(pin,CONTROL_PIN_INDEX_FEED_HOLD)) {
bit_true(sys_rt_exec_state, EXEC_FEED_HOLD);
#else
} else if (bit_istrue(pin,bit(SAFETY_DOOR_BIT))) {
} else if (bit_istrue(pin,CONTROL_PIN_INDEX_SAFETY_DOOR)) {
bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
#endif
}
@ -66,11 +84,7 @@ ISR(CONTROL_INT_vect)
uint8_t system_check_safety_door_ajar()
{
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
#ifdef INVERT_CONTROL_PIN
return(bit_istrue(CONTROL_PIN,bit(SAFETY_DOOR_BIT)));
#else
return(bit_isfalse(CONTROL_PIN,bit(SAFETY_DOOR_BIT)));
#endif
return(system_control_get_state() & CONTROL_PIN_INDEX_SAFETY_DOOR);
#else
return(false); // Input pin not enabled, so just return that it's closed.
#endif
@ -275,3 +289,33 @@ void system_convert_array_steps_to_mpos(float *position, int32_t *steps)
}
return;
}
// Special handlers for setting and clearing Grbl's real-time execution flags.
void system_set_exec_state_flag(uint8_t mask) {
uint8_t sreg = SREG;
cli();
sys_rt_exec_state |= (mask);
SREG = sreg;
}
void system_clear_exec_state_flag(uint8_t mask) {
uint8_t sreg = SREG;
cli();
sys_rt_exec_state &= ~(mask);
SREG = sreg;
}
void system_set_exec_alarm_flag(uint8_t mask) {
uint8_t sreg = SREG;
cli();
sys_rt_exec_alarm |= (mask);
SREG = sreg;
}
void system_clear_exec_alarm_flag(uint8_t mask) {
uint8_t sreg = SREG;
cli();
sys_rt_exec_alarm &= ~(mask);
SREG = sreg;
}

View File

@ -69,13 +69,26 @@
#define SUSPEND_SAFETY_DOOR_AJAR bit(5) // Indicates suspend was initiated by a safety door state.
#define SUSPEND_MOTION_CANCEL bit(6) // Indicates a canceled resume motion. Currently used by probing routine.
// Define step segment generator state flags.
#define STEP_CONTROL_NORMAL_OP 0
// #define STEP_CONTROL_RECOMPUTE_ACTIVE_BLOCK bit(0)
#define STEP_CONTROL_END_MOTION bit(1)
#define STEP_CONTROL_EXECUTE_HOLD bit(2)
#define STEP_CONTROL_EXECUTE_PARK bit(3)
// Define control pin index for Grbl internal use. Pin maps may change, but these values don't.
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
#define N_CONTROL_PIN 4
#define CONTROL_PIN_INDEX_SAFETY_DOOR bit(0)
#define CONTROL_PIN_INDEX_RESET bit(1)
#define CONTROL_PIN_INDEX_FEED_HOLD bit(2)
#define CONTROL_PIN_INDEX_CYCLE_START bit(3)
#else
#define N_CONTROL_PIN 3
#define CONTROL_PIN_INDEX_RESET bit(0)
#define CONTROL_PIN_INDEX_FEED_HOLD bit(1)
#define CONTROL_PIN_INDEX_CYCLE_START bit(2)
#endif
// Define global system variables
@ -102,6 +115,9 @@ volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variabl
// Initialize the serial protocol
void system_init();
// Returns bitfield of control pin states, organized by CONTROL_PIN_INDEX. (1=triggered, 0=not triggered).
uint8_t system_control_get_state();
// Returns if safety door is open or closed, based on pin state.
uint8_t system_check_safety_door_ajar();
@ -117,4 +133,11 @@ float system_convert_axis_steps_to_mpos(int32_t *steps, uint8_t idx);
// Updates a machine 'position' array based on the 'step' array sent.
void system_convert_array_steps_to_mpos(float *position, int32_t *steps);
// Special handlers for setting and clearing Grbl's real-time execution flags.
void system_set_exec_state_flag(uint8_t mask);
void system_clear_exec_state_flag(uint8_t mask);
void system_set_exec_alarm_flag(uint8_t mask);
void system_clear_exec_alarm_flag(uint8_t mask);
#endif