GRBL V1.1f source code Chinese annotation -- system Chapter

Posted by Myke on Thu, 13 Feb 2020 22:15:07 +0100

Grbl is a free, open-source, high-performance software for controlling the movement of machines, making objects or moving things, and will run directly on the Arduino platform. If the manufacturer movement is an industry, grbl will be the industry standard.

Most open source 3D printers have a grbl controller at their core. It has been used in hundreds of projects, including laser cutting machines, automatic handwriting machines, drilling machines, graffiti artists and eccentric drawing machines. Grbl has developed into a small open source phenomenon due to its performance, simplicity and thrifty requirements for hardware.

For system.h, system level commands and real-time processes are defined.

 

/*
  System.h - Header for system level commands and real-time processes
  Part of Grbl-Advanced

  Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
  Copyright (c)	2017 Patrick F.

  Grbl-Advanced 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-Advanced 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-Advanced.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SYSTEM_H
#define SYSTEM_H

#include <stdint.h>
#include "util.h"


// Define system executor bit map. Used internally by realtime protocol as realtime command flags,
// which notifies the main program to execute the specified realtime command asynchronously.
// NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.) The default
// flags are always false, so the realtime protocol only needs to check for a non-zero value to
// know when there is a realtime command to execute.
/*  Define the system actuator bit mapping. The real-time protocol is used internally as a real-time command flag to inform the main program to execute the specified real-time command asynchronously.
    Note: the system actuator uses an unsigned 8-bit volatile variable (8 flag limits). The default flag is always false,
    Therefore, the real-time protocol only needs to check a non-zero value to know when there is a real-time command to execute.
*/
#define EXEC_STATUS_REPORT  				BIT(0)
#define EXEC_CYCLE_START    				BIT(1)
#define EXEC_CYCLE_STOP     				BIT(2)
#define EXEC_FEED_HOLD      				BIT(3)
#define EXEC_RESET          				BIT(4)
#define EXEC_SAFETY_DOOR    				BIT(5)
#define EXEC_MOTION_CANCEL  				BIT(6)
#define EXEC_SLEEP          				BIT(7)

// Alarm executor codes. Valid values (1-255). Zero is reserved.
//  Alarm actuator variable, valid value (1 -- 255), default value is 0
#Define exec? Alarm? Hard? Limit 1 / / hard limit alarm
#Define exec? Alarm? Soft? Limit 2 / / soft limit alarm
#Define exec? Alarm? Abort? Cycle 3 / / abort cycle alarm
#Define exec? Alarm? Probe? Fail? Initial 4 / / detector initialization failure alarm
#Define exec? Alarm? Probe? Fail? Contact 5 / / failure alarm
#Define exec? Alarm? Holding? Fail? Reset 6 / / reset the alarm in case of zero return failure
#define EXEC_ALARM_HOMING_FAIL_DOOR     	7
#define EXEC_ALARM_HOMING_FAIL_PULLOFF  	8
#define EXEC_ALARM_HOMING_FAIL_APPROACH 	9

// Override bit maps. Realtime bitflags to control feed, rapid, spindle, and coolant overrides.
// Spindle/coolant and feed/rapids are separated into two controlling flag variables.
//  Bit mapping, which is used to control the real-time bit flags of feed, speed, spindle and coolant override.
//  The spindle / coolant and feed / speed are divided into two control flag variables.
#define EXEC_FEED_OVR_RESET         		BIT(0)
#define EXEC_FEED_OVR_COARSE_PLUS   		BIT(1)
#define EXEC_FEED_OVR_COARSE_MINUS  		BIT(2)
#define EXEC_FEED_OVR_FINE_PLUS     		BIT(3)
#define EXEC_FEED_OVR_FINE_MINUS    		BIT(4)
#define EXEC_RAPID_OVR_RESET        		BIT(5)
#define EXEC_RAPID_OVR_MEDIUM       		BIT(6)
#define EXEC_RAPID_OVR_LOW          		BIT(7)
//#define EXEC_RAPID_OVR_EXTRA_LOW			BIT(*) // *NOT SUPPORTED*

#define EXEC_SPINDLE_OVR_RESET         		BIT(0)
#Define exec? Spindle? Ovr? Coarse? Plus BIT(1) / / Coarse+
#define EXEC_SPINDLE_OVR_COARSE_MINUS  		BIT(2)
#Define exec? Spindle? Ovr? Fine? Plus BIT(3) / / fine tuning+
#define EXEC_SPINDLE_OVR_FINE_MINUS    		BIT(4)
#define EXEC_SPINDLE_OVR_STOP          		BIT(5)
#define EXEC_COOLANT_FLOOD_OVR_TOGGLE  		BIT(6)
#define EXEC_COOLANT_MIST_OVR_TOGGLE   		BIT(7)

// Define system state bit map. The state variable primarily tracks the individual functions
// of Grbl to manage each without overlapping. It is also used as a messaging flag for
// critical events.
//  Define system status bit mapping. State variables primarily track the functions of Grbl to manage each function without overlapping.
//  It is also used as a message flag for critical events.
#define STATE_IDLE          				0      // Must be zero. No flags.
#define STATE_ALARM         				BIT(0) // In alarm state. Locks out all g-code processes. Allows settings access.
#define STATE_CHECK_MODE    				BIT(1) // G-code check mode. Locks out planner and motion only.
#define STATE_HOMING        				BIT(2) // Performing homing cycle
#define STATE_CYCLE         				BIT(3) // Cycle is running or motions are being executed.
#define STATE_HOLD          				BIT(4) // Active feed hold
#define STATE_JOG           				BIT(5) // Jogging mode.
#define STATE_SAFETY_DOOR   				BIT(6) // Safety door is ajar. Feed holds and de-energizes system.
#define STATE_SLEEP         				BIT(7) // Sleep state.

// Define system suspend flags. Used in various ways to manage suspend states and procedures.
//  Define the system suspend flag. Used in various ways to manage pending States and processes.
#define SUSPEND_DISABLE           			0      // Must be zero.
#Define suspend? Hold? Complete bit (0) / / indicates the initial feed hold is complete.
//  A sign indicating recovery from recovery parking movement.
#define SUSPEND_RESTART_RETRACT   			BIT(1) // Flag to indicate a retract from a restore parking motion.
//  (safety door only) indicates that retraction and power-off have been completed.
#define SUSPEND_RETRACT_COMPLETE  			BIT(2) // (Safety door only) Indicates retraction and de-energizing is complete.
//  (safety door only) flag to start the recovery procedure from the beginning of the cycle.
#define SUSPEND_INITIATE_RESTORE  			BIT(3) // (Safety door only) Flag to initiate resume procedures from a cycle start.
//  (safety door only) indicates that it is ready to resume normal operation.
#define SUSPEND_RESTORE_COMPLETE  			BIT(4) // (Safety door only) Indicates ready to resume normal operation.
#Define suspend? Safety? Door? Ajar BIT(5) // Tracks safety door state for resuming.
//  Indicates a cancelled recovery action. Currently used by probe routines.
#define SUSPEND_MOTION_CANCEL     			BIT(6) // Indicates a canceled resume motion. Currently used by probing routine.
//  Indicates that a jog cancellation is in progress and the buffer is reset when it is finished.
#define SUSPEND_JOG_CANCEL        			BIT(7) // Indicates a jog cancel in process and to reset buffers when complete.

// Define step segment generator state flags.
//  Define step generator status flag
#define STEP_CONTROL_NORMAL_OP            	0  // Must be zero.
#define STEP_CONTROL_END_MOTION           	BIT(0)
#define STEP_CONTROL_EXECUTE_HOLD         	BIT(1)
#define STEP_CONTROL_EXECUTE_SYS_MOTION   	BIT(2)
#define STEP_CONTROL_UPDATE_SPINDLE_PWM   	BIT(3)

// Define control pin index for Grbl internal use. Pin maps may change, but these values don't.
//Defines the control pin index used internally by Grbl. Pin diagrams may change, but these values do not.
#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)

// Define spindle stop override control states.
//  Define spindle stop override control state
#define SPINDLE_STOP_OVR_DISABLED       	0  // Must be zero.
#define SPINDLE_STOP_OVR_ENABLED        	BIT(0)
#define SPINDLE_STOP_OVR_INITIATE       	BIT(1)
#define SPINDLE_STOP_OVR_RESTORE        	BIT(2)
#define SPINDLE_STOP_OVR_RESTORE_CYCLE  	BIT(3)



// Define global system variables
typedef struct {
	uint8_t state;               // Tracks the current system state of Grbl
	uint8_t abort;               // System abort flag. Forces exit back to main loop for reset.
                                //  System abort flag, force exit to return to main loop for reset
	uint8_t suspend;             // System suspend bitflag variable that manages holds, cancels, and safety door.
                                //  System suspend flag variable to manage hold, cancel, and security doors
	uint8_t soft_limit;          // Tracks soft limit errors for the state machine. (boolean)
                                //  Current machine status soft kickout error status
	uint8_t step_control;        // Governs the step segment generator depending on system state.
                                //  Control step generator according to system state
	uint8_t probe_succeeded;     // Tracks if last probing cycle was successful.
                                //  Tracks the success of the previous probe cycle.
	uint8_t homing_axis_lock;    // Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
                                //  Lock the shaft when the kickout is engaged. Used as an axis motion mask in step ISR.
	uint8_t f_override;          // Feed rate override value in percent
                                //  Feed rate override value (percentage)
	uint8_t r_override;          // Rapids override value in percent
                                //  Speed override value (percentage)
	uint8_t spindle_speed_ovr;   // Spindle speed value in percent
	uint8_t spindle_stop_ovr;    // Tracks spindle stop override states
                                //  Tracking spindle stop override status
	uint8_t report_ovr_counter;  // Tracks when to add override data to status reports.
                                //  Tracks when overlay data is added to the status report.
	uint8_t report_wco_counter;  // Tracks when to add work coordinate offset data to status reports.
                                //  Tracks when work coordinate offset data is added to the status report.
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
	uint8_t override_ctrl;     // Tracks override control states.
#endif
	float spindle_speed;
} System_t;

extern System_t sys;

// NOTE: These position variables may need to be declared as volatiles, if problems arise.
//  If there is a problem, these location variables may need to be declared volatile.
extern int32_t sys_position[N_AXIS];      // Real-time machine (aka home) position vector in steps.
extern int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.

extern volatile uint8_t sys_probe_state;   // Probing state value.  Used to coordinate the probing cycle with stepper ISR.
                                            //  Probe status value. Used to coordinate detection cycle with step ISR.
extern volatile uint8_t sys_rt_exec_state;   // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
                                             //Global real-time actuator bit flag variable for state management. See EXEC bitmask.
extern volatile uint8_t sys_rt_exec_alarm;   // Global realtime executor bitflag variable for setting various alarms.
                                             //It is used to set the global real-time actuator bit flag variable of various alarms.
extern volatile uint8_t sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
                                                    //Global real-time actuator bit flag variable for motion based coverage.
extern volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
                                                        //Global real-time actuator bit flag variable for spindle / coolant coverage.


// Initialize the serial protocol
void System_Init(void);

void System_Clear(void);

void System_ResetPosition(void);

// Returns bitfield of control pin states, organized by CONTROL_PIN_INDEX. (1=triggered, 0=not triggered).
//Returns the bit field of the control pin status organized by control pin index. (1 = triggered, 0 = not triggered).
uint8_t System_GetControlState(void);

// Returns if safety door is open or closed, based on pin state.
//Depending on the pin status, return whether the safety door is open or closed.
uint8_t System_CheckSafetyDoorAjar(void);

// Executes an internal system command, defined as a string starting with a '$'
//Execute internal system commands defined as strings starting with "$"
uint8_t System_ExecuteLine(char *line);

// Execute the startup script lines stored in EEPROM upon initialization
//Execute the startup script line stored in EEPROM during initialization
void System_ExecuteStartup(char *line);

void System_FlagWcoChange(void);

// Returns machine position of axis 'idx'. Must be sent a 'step' array.
//Return to the machine position of the axis "IDX". The 'step' array must be sent.
float System_ConvertAxisSteps2Mpos(int32_t *steps, uint8_t idx);

// Updates a machine 'position' array based on the 'step' array sent.
//Update the computer "position" array based on the sent "step" array.
void System_ConvertArraySteps2Mpos(float *position, int32_t *steps);

// CoreXY calculation only. Returns x or y-axis "steps" based on CoreXY motor steps.
//CoreXY calculation only. Return the X or Y axis of the "step" based on the steps of the motor.
#ifdef COREXY
int32_t system_convert_corexy_to_x_axis_steps(int32_t *steps);
int32_t system_convert_corexy_to_y_axis_steps(int32_t *steps);
#endif

// Checks and reports if target array exceeds machine travel limits.
//Check and report if the target array exceeds the machine travel limit.
uint8_t System_CheckTravelLimits(float *target);

// Special handlers for setting and clearing Grbl's real-time execution flags.
//Special handler for setting and clearing the Grbl real time execution flag.
void System_SetExecStateFlag(uint8_t mask);
void System_ClearExecStateFlag(uint8_t mask);
void System_SetExecAlarm(uint8_t code);
void System_ClearExecAlarm(void);
void System_SetExecMotionOverrideFlag(uint8_t mask);
void System_SetExecAccessoryOverrideFlag(uint8_t mask);
void System_ClearExecMotionOverride(void);
void System_ClearExecAccessoryOverrides(void);


#endif // SYSTEM_H

system.c file

/*
  System.c - Handles system level commands and real-time processes
  Part of Grbl-Advanced

  Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
  Copyright (c)	2017 Patrick F.

  Grbl-Advanced 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-Advanced 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-Advanced.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "Config.h"
#include "GCode.h"
#include "GPIO.h"
#include "MotionControl.h"
#include "Protocol.h"
#include "Report.h"
#include "Settings.h"
#include "Stepper.h"
#include "System.h"
#include "System32.h"


void System_Init(void)
{
	GPIO_InitGPIO(GPIO_SYSTEM);
}


void System_Clear(void)
{
	memset(&sys, 0, sizeof(System_t)); // Clear system structure variable

	sys.f_override = DEFAULT_FEED_OVERRIDE;  // Set to 100%
	sys.r_override = DEFAULT_RAPID_OVERRIDE; // Set to 100%
	sys.spindle_speed_ovr = DEFAULT_SPINDLE_SPEED_OVERRIDE; // Set to 100%
}


void System_ResetPosition(void)
{
	// Clear machine position.
	memset(sys_position, 0 , sizeof(sys_position));
}


// 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.
//Returns the bit field of the control pin status organized by control pin index. (1 = triggered, 0 = not triggered).
uint8_t System_GetControlState(void)
{
	uint8_t control_state = 0;
	uint8_t pin = ((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)<<CONTROL_RESET_BIT) |
					(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)<<CONTROL_FEED_HOLD_BIT) |
					(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4)<<CONTROL_CYCLE_START_BIT) |
					(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_8)<<CONTROL_SAFETY_DOOR_BIT));

	// Invert control pin s if necessary
	//pin ^= CONTROL_MASK & settings.system_flags;
	pin ^= CONTROL_MASK;

	if(pin) {
		if(BIT_IS_FALSE(pin, (1<<CONTROL_RESET_BIT))) {
			control_state |= CONTROL_PIN_INDEX_RESET;
		}
		if(BIT_IS_FALSE(pin, (1<<CONTROL_FEED_HOLD_BIT))) {
			control_state |= CONTROL_PIN_INDEX_FEED_HOLD;
		}
		if(BIT_IS_FALSE(pin, (1<<CONTROL_CYCLE_START_BIT))) {
			control_state |= CONTROL_PIN_INDEX_CYCLE_START;
		}
		if(BIT_IS_FALSE(pin, (1<<CONTROL_SAFETY_DOOR_BIT))) {
			control_state |= CONTROL_PIN_INDEX_SAFETY_DOOR;
		}
	}

	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.
//Pin change interrupt of pin out command, i.e. cycle start, feed hold and reset. Set only the realtime command execute variable,
//Causes the main program to execute these commands when it is ready. This is exactly the same as character based real-time commands that are extracted directly from the incoming serial data stream.
void System_PinChangeISR(void)
{
	uint8_t pin = System_GetControlState();

	if(pin) {
		if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_RESET)) {
			MC_Reset();
		}
		else if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_CYCLE_START)) {
			BIT_TRUE(sys_rt_exec_state, EXEC_CYCLE_START);
		}
		else if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_FEED_HOLD)) {
			BIT_TRUE(sys_rt_exec_state, EXEC_FEED_HOLD);
		}
		else if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_SAFETY_DOOR)) {
			BIT_TRUE(sys_rt_exec_state, EXEC_SAFETY_DOOR);
		}
	}
}


// Returns if safety door is ajar(T) or closed(F), based on pin state.
//If the safety door is slightly open (T) or closed (F), it will return according to the pin status.
uint8_t System_CheckSafetyDoorAjar(void)
{
    return (System_GetControlState() & CONTROL_PIN_INDEX_SAFETY_DOOR);
}


// Executes user startup script, if stored.
//Execute the user startup script, if stored.
void System_ExecuteStartup(char *line)
{
#if (N_STARTUP_LINE > 0)
	uint8_t n;

	for(n = 0; n < N_STARTUP_LINE; n++) {
		if(!(Settings_ReadStartupLine(n, line))) {
			line[0] = 0;
			Report_ExecuteStartupMessage(line, STATUS_SETTING_READ_FAIL);
		}
		else {
			if(line[0] != 0) {
				uint8_t status_code = GC_ExecuteLine(line);

				Report_ExecuteStartupMessage(line,status_code);
			}
		}
	}
#else
	(void)line;
#endif
}


// Directs and executes one line of formatted input from protocol_process. While mostly
// incoming streaming g-code blocks, this also executes Grbl internal commands, such as
// settings, initiating the homing cycle, and toggling switch states. This differs from
// the realtime command module by being susceptible to when Grbl is ready to execute the
// next line during a cycle, so for switches like block delete, the switch only effects
// the lines that are processed afterward, not necessarily real-time during a cycle,
// since there are motions already stored in the buffer. However, this 'lag' should not
// be an issue, since these commands are not typically used during a cycle.
//Direct and execute one line of formatted input from protocol "process. Although it is mainly the incoming stream g code block,
//However, it also performs internal commands of Grbl, such as setting, starting homing cycle and switching state. This is different from the real-time command module
//This is because it is vulnerable to the effect that Grbl is ready to execute the next line in one cycle, so for switches such as block deletion, the switch only shadows
//Respond to subsequent rows, not necessarily in real time in a cycle, because the motion is already stored in the buffer. But this "delay"
//It shouldn't be a problem because these commands are usually not used in one cycle.
uint8_t System_ExecuteLine(char *line)
{
	uint8_t char_counter = 1;
	uint8_t helper_var = 0; // Helper variable
	float parameter, value;

	switch(line[char_counter])
	{
	case 0:
		Report_GrblHelp();
		break;

	case 'J': // Jogging
		// Execute only if in IDLE or JOG states
		if(sys.state != STATE_IDLE && sys.state != STATE_JOG) {
			return STATUS_IDLE_ERROR;
		}
		if(line[2] != '=') {
			return STATUS_INVALID_STATEMENT;
		}
		return GC_ExecuteLine(line); // NOTE: $J= is ignored inside g-code parser and used to detect jog motions.
		break;

	case '$':
	case 'G':
	case 'C':
	case 'X':
		if(line[2] != 0) {
			return(STATUS_INVALID_STATEMENT);
		}

		switch(line[1])
		{
		case '$': // Print Grbl settings print Grbl settings
			if(sys.state & (STATE_CYCLE | STATE_HOLD)) {
				return(STATUS_IDLE_ERROR);
			} // Block during cycle. Takes too long to print.
            //Blocked in loop. Printing time is too long.
			else {
				Report_GrblSettings();
			}
			break;

		case 'G': // Prints gcode parser state output G-code parser state
			// TODO: Move this to realtime commands for GUIs to request this data during suspend-state.
            // TODO: move this to a real-time command so that the GUI requests this data during a suspended state.
			Report_GCodeModes();
			break;

		case 'C': // Set check g-code mode [IDLE/CHECK]
            //Set check g code mode [IDLE/CHECK]
			// Perform reset when toggling off. Check g-code mode should only work if Grbl
			// is idle and ready, regardless of alarm locks. This is mainly to keep things
			// simple and consistent.
            //Perform a reset on shutdown. Check g code mode should only work when Grbl is idle and ready, regardless of alarm lock.
            //This is mainly to keep things simple and consistent.
			if(sys.state == STATE_CHECK_MODE ) {
				MC_Reset();
				Report_FeedbackMessage(MESSAGE_DISABLED);
			}
			else {
				if(sys.state) {
					// Requires no alarm mode.
					return STATUS_IDLE_ERROR;
				}

				sys.state = STATE_CHECK_MODE;
				Report_FeedbackMessage(MESSAGE_ENABLED);
			}
			break;

		case 'X': // Disable alarm lock [ALARM] Disable alarm lock [ALARM]
			if(sys.state == STATE_ALARM) {
				// Block if safety door is ajar.
				if(System_CheckSafetyDoorAjar()) {
					return(STATUS_CHECK_DOOR);
				}

				Report_FeedbackMessage(MESSAGE_ALARM_UNLOCK);
				sys.state = STATE_IDLE;
				// Don't run startup script. Prevents stored moves in startup from causing accidents.
                //Do not run the startup script. Prevent accidents caused by the movement of storage at startup.
			} // Otherwise, no effect
			break;
		}
		break;

	default:
		// Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
        //Block any system command that requires the status to be IDLE/ALARM. (i.e. EEPROM, homing)
		if(!(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) {
			return(STATUS_IDLE_ERROR);
		}

		switch(line[1])
		{
		case '#': / / Print Grbl NGC parameters
			if(line[2] != 0) {
				return STATUS_INVALID_STATEMENT;
			}
			else {
				Report_NgcParams();
			}
			break;

		case 'H': // Perform homing cycle [IDLE/ALARM]
			if(BIT_IS_FALSE(settings.flags, BITFLAG_HOMING_ENABLE)) {
				return(STATUS_SETTING_DISABLED);
			}
			if(System_CheckSafetyDoorAjar()) {
				// Block if safety door is ajar
				return STATUS_CHECK_DOOR;
			}

			sys.state = STATE_HOMING; // Set system state variable

			if(line[2] == 0) {
				MC_HomigCycle(HOMING_CYCLE_ALL);
#ifdef HOMING_SINGLE_AXIS_COMMANDS
			}
			else if(line[3] == 0) {
				switch(line[2])
				{
				case 'X':
					MC_HomigCycle(HOMING_CYCLE_X);
					break;

				case 'Y':
					MC_HomigCycle(HOMING_CYCLE_Y);
					break;

				case 'Z':
					MC_HomigCycle(HOMING_CYCLE_Z);
					break;

				default:
					return STATUS_INVALID_STATEMENT;
				}
#endif
			}
			else {
				return STATUS_INVALID_STATEMENT;
			}

			if(!sys.abort) {  // Execute startup scripts after successful homing.
                //Execute startup script after successful homing.
				sys.state = STATE_IDLE; // Set to IDLE when complete
				Stepper_Disable(); // Set steppers to the settings idle state before returning.
                                    //Set the stepper motor to idle before returning.

				if(line[2] == 0) {
					System_ExecuteStartup(line);
				}
			}
			break;

		case 'S': // Put grbl to sleep [idle / alarm] grbl set to sleep mode
			if((line[2] != 'L') || (line[3] != 'P') || (line[4] != 0)) {
				return(STATUS_INVALID_STATEMENT);
			}
			System_SetExecStateFlag(EXEC_SLEEP); // Set to execute sleep mode immediately
                                                 //Set to immediate sleep mode
			break;

		case 'I': // Print or store build info. [IDLE/ALARM] print or store build information
			if(line[++char_counter] == 0 ) {
				Settings_ReadBuildInfo(line);
				Report_BuildInfo(line);
#ifdef ENABLE_BUILD_INFO_WRITE_COMMAND
			}
			else { // Store startup line [IDLE/ALARM]
				if(line[char_counter++] != '=') {
					return STATUS_INVALID_STATEMENT;
				}

				helper_var = char_counter; // Set helper variable as counter to start of user info line.
                                            //Set the helper variable to a counter to start the user information line.

				do {
					line[char_counter-helper_var] = line[char_counter];
				} while(line[char_counter++] != 0);

				Settings_StoreBuildInfo(line);
#endif
			}
			break;

		case 'R': // Restore defaults [IDLE/ALARM] restore defaults
			if((line[2] != 'S') || (line[3] != 'T') || (line[4] != '=') || (line[6] != 0)) {
				return(STATUS_INVALID_STATEMENT);
			}
			switch(line[5])
			{
#ifdef ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS
			case '$':
				Settings_Restore(SETTINGS_RESTORE_DEFAULTS);
				break;
#endif
#ifdef ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS
			case '#':
				Settings_Restore(SETTINGS_RESTORE_PARAMETERS);
			break;
#endif
#ifdef ENABLE_RESTORE_EEPROM_WIPE_ALL
			case '*':
				Settings_Restore(SETTINGS_RESTORE_ALL);
			break;
#endif
			default:
				return STATUS_INVALID_STATEMENT;
			}

			Report_FeedbackMessage(MESSAGE_RESTORE_DEFAULTS);
			MC_Reset(); // Force reset to ensure settings are initialized correctly.
                        //Force a reset to ensure the settings are initialized correctly.
			break;

		case 'N': // Startup lines. [IDLE/ALARM] startup lines
#if (N_STARTUP_LINE > 0)
			if(line[++char_counter] == 0 ) { // Print startup lines
				for(helper_var = 0; helper_var < N_STARTUP_LINE; helper_var++) {
					if (!(Settings_ReadStartupLine(helper_var, line))) {
						Report_StatusMessage(STATUS_SETTING_READ_FAIL);
					}
					else {
						Report_StartupLine(helper_var,line);
					}
				}
				break;
			}
			else { // Store startup line [IDLE Only] Prevents motion during ALARM.
                //The store start line [IDLE only] prevents movement during an alarm.
				if(sys.state != STATE_IDLE) {
					// Store only when idle.
					return STATUS_IDLE_ERROR;
				}
				helper_var = true;  // Set helper_var to flag storing method.
                                    //Set helper? VaR as the tag store method.
				// No break. Continues into default: to read remaining command characters.
                //No suspension. Continue with default: read the remaining command characters.
			}
#endif

		default:  // Storage setting methods [idle / alarm] storage setting methods
			if(!Read_Float(line, &char_counter, &parameter)) {
				return(STATUS_BAD_NUMBER_FORMAT);
			}
			if(line[char_counter++] != '=') {
				return(STATUS_INVALID_STATEMENT);
			}
			if(helper_var) { // Store startup line store startup line
				// Prepare sending gcode block to gcode parser by shifting all characters
                //Prepare to send gcode blocks to the gcode parser by moving all characters
				helper_var = char_counter; // Set helper variable as counter to start of gcode block

				do {
					line[char_counter-helper_var] = line[char_counter];
				} while(line[char_counter++] != 0);

				// Execute gcode block to ensure block is valid.
                //Execute gcode blocks to make sure the blocks are valid.
				helper_var = GC_ExecuteLine(line); // Set helper_var to returned status code.
                                                    //  Set helper? VaR as the returned status code

				if(helper_var) {
					return(helper_var);
				}
				else {
					helper_var = trunc(parameter); // Set helper_var to int value of parameter
                                                    //  Set helper? VaR as the integer value of the parameter
					Settings_StoreStartupLine(helper_var, line);
				}
			}
			else { // Store global setting
				if(!Read_Float(line, &char_counter, &value)) {
					return STATUS_BAD_NUMBER_FORMAT;
				}
				if((line[char_counter] != 0) || (parameter > 255)) {
					return STATUS_INVALID_STATEMENT;
				}

				return Settings_StoreGlobalSetting((uint8_t)parameter, value);
			}
		}
	}

	return STATUS_OK; // If '$' command makes it to here, then everything's ok.
                      //If the "$" command gets here, everything is OK.
}



void System_FlagWcoChange(void)
{
#ifdef FORCE_BUFFER_SYNC_DURING_WCO_CHANGE
    Protocol_BufferSynchronize();
#endif
	sys.report_wco_counter = 0;
}


// Returns machine position of axis 'idx'. Must be sent a 'step' array.
// NOTE: If motor steps and machine position are not in the same coordinate frame, this function
//   serves as a central place to compute the transformation.
//Return to the machine position of the axis "IDX". The 'step' array must be sent.
//Note: if the motor step distance and the machine position are not in the same coordinate system, this function is used as the center position of calculation transformation.
float System_ConvertAxisSteps2Mpos(int32_t *steps, uint8_t idx)
{
	float pos;

#ifdef COREXY
	if(idx == X_AXIS) {
		pos = (float)system_convert_corexy_to_x_axis_steps(steps) / settings.steps_per_mm[idx];
	}
	else if (idx == Y_AXIS) {
		pos = (float)system_convert_corexy_to_y_axis_steps(steps) / settings.steps_per_mm[idx];
	}
	else {
		pos = steps[idx]/settings.steps_per_mm[idx];
	}
#else
	pos = steps[idx]/settings.steps_per_mm[idx];
#endif

	return pos;
}


void System_ConvertArraySteps2Mpos(float *position, int32_t *steps)
{
	uint8_t idx;

	for(idx = 0; idx < N_AXIS; idx++) {
		position[idx] = System_ConvertAxisSteps2Mpos(steps, idx);
	}

	return;
}


// CoreXY calculation only. Returns x or y-axis "steps" based on CoreXY motor steps.
//CoreXY calculation only. Return X or Y axis "steps" based on the steps of the motor.
#ifdef COREXY
int32_t system_convert_corexy_to_x_axis_steps(int32_t *steps)
{
    return ((steps[A_MOTOR] + steps[B_MOTOR])/2);
}

int32_t system_convert_corexy_to_y_axis_steps(int32_t *steps)
{
    return ((steps[A_MOTOR] - steps[B_MOTOR])/2);
}
#endif


// Checks and reports if target array exceeds machine travel limits.
//Check and report if the target array exceeds the machine travel limit.
uint8_t System_CheckTravelLimits(float *target)
{
	uint8_t idx;

	for(idx = 0; idx < N_AXIS; idx++) {
#ifdef HOMING_FORCE_SET_ORIGIN
		// When homing forced set origin is enabled, soft limits checks need to account for directionality.
        //When force origin is on, the soft limit check needs to consider directionality.
		// NOTE: max_travel is stored as negative 
        //  Note: Max? Travel is stored as a negative value
		if(BIT_IS_TRUE(settings.homing_dir_mask, BIT(idx))) {
			if(target[idx] < 0 || target[idx] > -settings.max_travel[idx]) {
				return true;
			}
		}
		else {
			if(target[idx] > 0 || target[idx] < settings.max_travel[idx]) {
				return true;
			}
		}
#else
		// NOTE: max_travel is stored as negative
		if(target[idx] > 0 || target[idx] < settings.max_travel[idx]) {
			return true;
		}
#endif
	}

	return false;
}


// Special handlers for setting and clearing Grbl's real-time execution flags.
//Special handler for setting and clearing the Grbl real time execution flag.
void System_SetExecStateFlag(uint8_t mask)
{
	uint32_t primask = __get_PRIMASK();
	__disable_irq();

	sys_rt_exec_state |= (mask);

	__set_PRIMASK(primask);
}


void System_ClearExecStateFlag(uint8_t mask)
{
	uint32_t primask = __get_PRIMASK();
	__disable_irq();

	sys_rt_exec_state &= ~(mask);

	__set_PRIMASK(primask);
}


void System_SetExecAlarm(uint8_t code)
{
	uint32_t primask = __get_PRIMASK();
	__disable_irq();

	sys_rt_exec_alarm = code;

	__set_PRIMASK(primask);
}


void System_ClearExecAlarm(void)
{
	uint32_t primask = __get_PRIMASK();
	__disable_irq();

	sys_rt_exec_alarm = 0;

	__set_PRIMASK(primask);
}


void System_SetExecMotionOverrideFlag(uint8_t mask)
{
	uint32_t primask = __get_PRIMASK();
	__disable_irq();

	sys_rt_exec_motion_override |= (mask);

	__set_PRIMASK(primask);
}


void System_SetExecAccessoryOverrideFlag(uint8_t mask)
{
	uint32_t primask = __get_PRIMASK();
	__disable_irq();

	sys_rt_exec_accessory_override |= (mask);

	__set_PRIMASK(primask);
}


void System_ClearExecMotionOverride(void)
{
	uint32_t primask = __get_PRIMASK();
	__disable_irq();

	sys_rt_exec_motion_override = 0;

	__set_PRIMASK(primask);
}


void System_ClearExecAccessoryOverrides(void)
{
	uint32_t primask = __get_PRIMASK();
	__disable_irq();

	sys_rt_exec_accessory_override = 0;

	__set_PRIMASK(primask);
}

 

Published 7 original articles, won praise 1, visited 3219
Private letter follow