pull/89/head
Patrick Felixberger 2021-01-19 09:45:27 +01:00
rodzic 03926b5a3b
commit e50fcc46d0
48 zmienionych plików z 7047 dodań i 6018 usunięć

Wyświetl plik

@ -1,9 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<EmBitz_layout_file>
<ActiveTarget name="Release" />
<File name="grbl\Config.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="grbl\Config.h" open="1" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1831" topLine="36" />
<Cursor1 position="1922" topLine="21" />
</Cursor>
</File>
<File name="grbl\defaults.h" open="1" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="grbl\Nvm.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
@ -13,7 +18,7 @@
</File>
<File name="grbl\Settings.c" open="0" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="6104" topLine="204" />
<Cursor1 position="2819" topLine="75" />
</Cursor>
</File>
<File name="grbl\SpindleControl.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
@ -53,7 +58,7 @@
</File>
<File name="main.c" open="1" top="1" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1190" topLine="0" />
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="Src\Platform.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">

Wyświetl plik

@ -1,11 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<EmBitz_layout_file>
<ActiveTarget name="Release" />
<File name="grbl\Config.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<File name="grbl\Config.h" open="1" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1842" topLine="12" />
</Cursor>
</File>
<File name="grbl\defaults.h" open="1" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="grbl\Nvm.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1004" topLine="3" />
@ -33,12 +38,12 @@
</File>
<File name="HAL\STM32\stm32f4xx.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="7912" topLine="125" />
<Cursor1 position="7911" topLine="125" />
</Cursor>
</File>
<File name="HAL\STM32\system_stm32f4xx.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="8151" topLine="148" />
<Cursor1 position="8208" topLine="148" />
</Cursor>
</File>
<File name="HAL\TIM\TIM.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
@ -46,39 +51,9 @@
<Cursor1 position="844" topLine="24" />
</Cursor>
</File>
<File name="HAL\USART\USART.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="3724" topLine="78" />
</Cursor>
</File>
<File name="main.c" open="1" top="1" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="2440" topLine="48" />
</Cursor>
</File>
<File name="SPL\inc\stm32f4xx_flash.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1099" topLine="453" />
</Cursor>
</File>
<File name="SPL\src\stm32f4xx_flash.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1049" topLine="669" />
</Cursor>
</File>
<File name="SPL\src\stm32f4xx_pwr.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="42659" topLine="1003" />
</Cursor>
</File>
<File name="SPL\src\stm32f4xx_rcc.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="63062" topLine="1319" />
</Cursor>
</File>
<File name="SPL\src\stm32f4xx_usart.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="12891" topLine="290" />
<Cursor1 position="2685" topLine="12" />
</Cursor>
</File>
<File name="Src\Platform.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">

Wyświetl plik

@ -23,7 +23,11 @@
#include "stm32f4xx.h"
#ifdef USE_EXT_EEPROM
#define EEPROM_SIZE 1
#else
#define EEPROM_SIZE 1024
#endif
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will be done by word */
#define VOLTAGE_RANGE (uint8_t)VoltageRange_3

Wyświetl plik

@ -27,13 +27,15 @@ extern "C" {
#endif
typedef struct {
typedef struct
{
uint8_t Hours;
uint8_t Minutes;
uint8_t Seconds;
} Time_t;
typedef struct {
typedef struct
{
uint16_t Year;
uint8_t Month;
uint8_t Day;

Wyświetl plik

@ -97,7 +97,7 @@ void TIM3_Init(void)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Connect TIM pins to AF2 */

Wyświetl plik

@ -54,7 +54,8 @@ int Printf(const char *str, ...)
int8_t Getc(char *c)
{
if(FifoUsart_Get(STDOUT_NUM, USART_DIR_RX, c) == 0) {
if(FifoUsart_Get(STDOUT_NUM, USART_DIR_RX, c) == 0)
{
return 0;
}
@ -103,19 +104,22 @@ void Print_Flush(void)
// techniques are actually just slightly slower. Found this out the hard way.
void PrintFloat(float n, uint8_t decimal_places)
{
if(n < 0) {
if(n < 0)
{
Putc('-');
n = -n;
}
uint8_t decimals = decimal_places;
while(decimals >= 2) { // Quickly convert values expected to be E0 to E-4.
while(decimals >= 2) // Quickly convert values expected to be E0 to E-4.
{
n *= 100;
decimals -= 2;
}
if(decimals) {
if(decimals)
{
n *= 10;
}
n += 0.5; // Add rounding factor. Ensures carryover through entire value.
@ -125,22 +129,27 @@ void PrintFloat(float n, uint8_t decimal_places)
uint8_t i = 0;
uint32_t a = (long)n;
while(a > 0) {
while(a > 0)
{
buf[i++] = (a % 10) + '0'; // Get digit
a /= 10;
}
while(i < decimal_places) {
while(i < decimal_places)
{
buf[i++] = '0'; // Fill in zeros to decimal point for (n < 1)
}
if(i == decimal_places) { // Fill in leading zero, if needed.
if(i == decimal_places) // Fill in leading zero, if needed.
{
buf[i++] = '0';
}
// Print the generated string.
for(; i > 0; i--) {
if(i == decimal_places) {
for(; i > 0; i--)
{
if(i == decimal_places)
{
Putc('.');
} // Insert decimal point in right place.
Putc(buf[i-1]);
@ -154,10 +163,12 @@ void PrintFloat(float n, uint8_t decimal_places)
// - RateValue: Handles feed rate and current velocity in inches or mm reporting.
void PrintFloat_CoordValue(float n)
{
if(BIT_IS_TRUE(settings.flags, BITFLAG_REPORT_INCHES)) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_REPORT_INCHES))
{
PrintFloat(n*INCH_PER_MM,N_DECIMAL_COORDVALUE_INCH);
}
else {
else
{
PrintFloat(n, N_DECIMAL_COORDVALUE_MM);
}
}
@ -165,10 +176,12 @@ void PrintFloat_CoordValue(float n)
void PrintFloat_RateValue(float n)
{
if(BIT_IS_TRUE(settings.flags, BITFLAG_REPORT_INCHES)) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_REPORT_INCHES))
{
PrintFloat(n*INCH_PER_MM,N_DECIMAL_RATEVALUE_INCH);
}
else {
else
{
PrintFloat(n, N_DECIMAL_RATEVALUE_MM);
}
}

Wyświetl plik

@ -28,7 +28,7 @@
#define CONFIG_H
#define GRBL_VERSION "1.1"
#define GRBL_VERSION "1.1i"
#define GRBL_VERSION_BUILD __DATE__
@ -38,7 +38,6 @@
// If doing so, simply comment out these two defines and see instructions below.
#define DEFAULTS_GENERIC
// Serial baud rate
#define BAUD_RATE 115200
//#define BAUD_RATE 230400

Wyświetl plik

@ -57,20 +57,25 @@ void Coolant_Stop(void)
uint8_t Coolant_GetState(void)
{
uint8_t cl_state = COOLANT_STATE_DISABLE;
// TODO: Check if reading works
#ifdef INVERT_COOLANT_FLOOD_PIN
if(!GPIO_ReadInputDataBit(GPIO_COOL_FLOOD_PORT, GPIO_COOL_FLOOD_PIN)) {
if(!GPIO_ReadInputDataBit(GPIO_COOL_FLOOD_PORT, GPIO_COOL_FLOOD_PIN))
{
#else
if(GPIO_ReadInputDataBit(GPIO_COOL_FLOOD_PORT, GPIO_COOL_FLOOD_PIN)) {
if(GPIO_ReadInputDataBit(GPIO_COOL_FLOOD_PORT, GPIO_COOL_FLOOD_PIN))
{
#endif
cl_state |= COOLANT_STATE_FLOOD;
}
#ifdef ENABLE_M7
#ifdef INVERT_COOLANT_MIST_PIN
if(!GPIO_ReadInputDataBit(GPIO_COOL_MIST_PORT, GPIO_COOL_MIST_PIN)) {
if(!GPIO_ReadInputDataBit(GPIO_COOL_MIST_PORT, GPIO_COOL_MIST_PIN))
{
#else
if(GPIO_ReadInputDataBit(GPIO_COOL_MIST_PORT, GPIO_COOL_MIST_PIN)) {
if(GPIO_ReadInputDataBit(GPIO_COOL_MIST_PORT, GPIO_COOL_MIST_PIN))
{
#endif
cl_state |= COOLANT_STATE_MIST;
}
@ -86,19 +91,22 @@ uint8_t Coolant_GetState(void)
// parser program end, and g-code parser coolant_sync().
void Coolant_SetState(uint8_t mode)
{
if(sys.abort) {
if(sys.abort)
{
// Block during abort.
return;
}
if (mode & COOLANT_FLOOD_ENABLE) {
if (mode & COOLANT_FLOOD_ENABLE)
{
#ifdef INVERT_COOLANT_FLOOD_PIN
GPIO_ResetBits(GPIO_COOL_FLOOD_PORT, GPIO_COOL_FLOOD_PIN);
#else
GPIO_SetBits(GPIO_COOL_FLOOD_PORT, GPIO_COOL_FLOOD_PIN);
#endif
}
else {
else
{
#ifdef INVERT_COOLANT_FLOOD_PIN
GPIO_SetBits(GPIO_COOL_FLOOD_PORT, GPIO_COOL_FLOOD_PIN);
#else
@ -107,13 +115,16 @@ void Coolant_SetState(uint8_t mode)
}
#ifdef ENABLE_M7
if (mode & COOLANT_MIST_ENABLE) {
if (mode & COOLANT_MIST_ENABLE)
{
#ifdef INVERT_COOLANT_MIST_PIN
GPIO_ResetBits(GPIO_COOL_MIST_PORT, GPIO_COOL_MIST_PIN);
#else
GPIO_SetBits(GPIO_COOL_MIST_PORT, GPIO_COOL_MIST_PIN);
#endif
} else {
}
else
{
#ifdef INVERT_COOLANT_MIST_PIN
GPIO_SetBits(GPIO_COOL_MIST_PORT, GPIO_COOL_MIST_PIN);
#else
@ -130,7 +141,8 @@ void Coolant_SetState(uint8_t mode)
// if an abort or check-mode is active.
void Coolant_Sync(uint8_t mode)
{
if(sys.state == STATE_CHECK_MODE) {
if(sys.state == STATE_CHECK_MODE)
{
return;
}

Wyświetl plik

@ -20,6 +20,7 @@
along with Grbl-Advanced. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <math.h>
#include "System.h"
#include "Settings.h"
#include "Jog.h"
@ -33,8 +34,6 @@
#include "ToolChange.h"
#include "GCode.h"
#include <math.h>
// Modal Group M9: Override control
#ifdef DEACTIVATE_PARKING_UPON_INIT
@ -115,7 +114,8 @@ uint8_t GC_ExecuteLine(char *line)
memcpy(&gc_block.modal,&gc_state.modal,sizeof(GC_Modal_t)); // Copy current modes
// Determine if the line is a jogging motion or a normal g-code block.
if(line[0] == '$') { // NOTE: `$J=` already parsed when passed to this function.
if(line[0] == '$') // NOTE: `$J=` already parsed when passed to this function.
{
// Set G1 and G94 enforced modes to ensure accurate error checks.
gc_parser_flags |= GC_PARSER_JOG_MOTION;
gc_block.modal.motion = MOTION_MODE_LINEAR;
@ -213,7 +213,10 @@ uint8_t GC_ExecuteLine(char *line)
}
break;
case 10: case 28: case 30: case 92:
case 10:
case 28:
case 30:
case 92:
// Check for G10/28/30/92 being called with G0/1/2/3/38 on same block.
// * G43.1 is also an axis command but is not explicitly defined this way.
if(mantissa == 0) // Ignore G28.1, G30.1, and G92.1
@ -227,7 +230,8 @@ uint8_t GC_ExecuteLine(char *line)
}
// No break. Continues to next line.
case 4: case 53:
case 4:
case 53:
word_bit = MODAL_GROUP_G0;
gc_block.non_modal_command = int_value;
@ -296,7 +300,11 @@ uint8_t GC_ExecuteLine(char *line)
}
break;
case 0: case 1: case 2: case 3: case 38:
case 0:
case 1:
case 2:
case 3:
case 38:
// Check for G0/1/2/3/38 being called with G10/28/30/92 on same block.
// * G43.1 is also an axis command but is not explicitly defined this way.
if(axis_command)
@ -322,24 +330,30 @@ uint8_t GC_ExecuteLine(char *line)
}
break;
case 81: case 82: case 83: // Canned drilling cycles
case 81:
case 82:
case 83: // Canned drilling cycles
word_bit = MODAL_GROUP_G1;
gc_block.modal.motion = int_value;
axis_command = AXIS_COMMAND_MOTION_MODE;
break;
// Set retract mode
case 98: case 99:
case 98:
case 99:
word_bit = MODAL_GROUP_G10;
gc_block.modal.retract = int_value - 98;
break;
case 17: case 18: case 19:
case 17:
case 18:
case 19:
word_bit = MODAL_GROUP_G2;
gc_block.modal.plane_select = int_value - 17;
break;
case 90: case 91:
case 90:
case 91:
if(mantissa == 0)
{
word_bit = MODAL_GROUP_G3;
@ -358,12 +372,14 @@ uint8_t GC_ExecuteLine(char *line)
}
break;
case 93: case 94:
case 93:
case 94:
word_bit = MODAL_GROUP_G5;
gc_block.modal.feed_rate = 94 - int_value;
break;
case 20: case 21:
case 20:
case 21:
word_bit = MODAL_GROUP_G6;
gc_block.modal.units = 21 - int_value;
break;
@ -375,7 +391,8 @@ uint8_t GC_ExecuteLine(char *line)
// gc_block.modal.cutter_comp = CUTTER_COMP_DISABLE; // G40
break;
case 43: case 49:
case 43:
case 49:
word_bit = MODAL_GROUP_G8;
// NOTE: The NIST g-code standard vaguely states that when a tool length offset is changed,
// there cannot be any axis motion or coordinate offsets updated. Meaning G43, G43.1, and G49
@ -405,7 +422,12 @@ uint8_t GC_ExecuteLine(char *line)
mantissa = 0; // Set to zero to indicate valid non-integer G command.
break;
case 54: case 55: case 56: case 57: case 58: case 59:
case 54:
case 55:
case 56:
case 57:
case 58:
case 59:
// NOTE: G59.x are not supported. (But their int_values would be 60, 61, and 62.)
word_bit = MODAL_GROUP_G12;
gc_block.modal.coord_select = int_value - 54; // Shift to array indexing.
@ -450,7 +472,10 @@ uint8_t GC_ExecuteLine(char *line)
switch(int_value)
{
case 0: case 1: case 2: case 30:
case 0:
case 1:
case 2:
case 30:
word_bit = MODAL_GROUP_M4;
switch(int_value)
@ -467,7 +492,9 @@ uint8_t GC_ExecuteLine(char *line)
}
break;
case 3: case 4: case 5:
case 3:
case 4:
case 5:
word_bit = MODAL_GROUP_M7;
switch(int_value)
{
@ -490,9 +517,12 @@ uint8_t GC_ExecuteLine(char *line)
break;
#ifdef ENABLE_M7
case 7: case 8: case 9:
case 7:
case 8:
case 9:
#else
case 8: case 9:
case 8:
case 9:
#endif
word_bit = MODAL_GROUP_M8;
@ -541,25 +571,76 @@ uint8_t GC_ExecuteLine(char *line)
switch(letter)
{
#ifdef USE_MULTI_AXIS
case 'A': word_bit = WORD_A; gc_block.values.xyz[A_AXIS] = value; axis_words |= (1<<A_AXIS); break;
case 'B': word_bit = WORD_B; gc_block.values.xyz[B_AXIS] = value; axis_words |= (1<<B_AXIS); break;
case 'A':
word_bit = WORD_A;
gc_block.values.xyz[A_AXIS] = value;
axis_words |= (1<<A_AXIS);
break;
case 'B':
word_bit = WORD_B;
gc_block.values.xyz[B_AXIS] = value;
axis_words |= (1<<B_AXIS);
break;
#endif
// case 'C': // Not supported
case 'D': word_bit = WORD_D; gc_block.values.d = int_value; break; // Maybe float?
case 'F': word_bit = WORD_F; gc_block.values.f = value; break;
case 'H': word_bit = WORD_H; gc_block.values.h = int_value; break;
case 'E': word_bit = WORD_E; gc_block.values.e = value; break;
case 'I': word_bit = WORD_I; gc_block.values.ijk[X_AXIS] = value; ijk_words |= (1<<X_AXIS); break;
case 'J': word_bit = WORD_J; gc_block.values.ijk[Y_AXIS] = value; ijk_words |= (1<<Y_AXIS); break;
case 'K': word_bit = WORD_K; gc_block.values.ijk[Z_AXIS] = value; ijk_words |= (1<<Z_AXIS); break;
case 'L': word_bit = WORD_L; gc_block.values.l = int_value; break;
case 'N': word_bit = WORD_N; gc_block.values.n = trunc(value); break;
case 'P': word_bit = WORD_P; gc_block.values.p = value; break;
case 'D':
word_bit = WORD_D;
gc_block.values.d = int_value;
break; // Maybe float?
case 'F':
word_bit = WORD_F;
gc_block.values.f = value;
break;
case 'H':
word_bit = WORD_H;
gc_block.values.h = int_value;
break;
case 'E':
word_bit = WORD_E;
gc_block.values.e = value;
break;
case 'I':
word_bit = WORD_I;
gc_block.values.ijk[X_AXIS] = value;
ijk_words |= (1<<X_AXIS);
break;
case 'J':
word_bit = WORD_J;
gc_block.values.ijk[Y_AXIS] = value;
ijk_words |= (1<<Y_AXIS);
break;
case 'K':
word_bit = WORD_K;
gc_block.values.ijk[Z_AXIS] = value;
ijk_words |= (1<<Z_AXIS);
break;
case 'L':
word_bit = WORD_L;
gc_block.values.l = int_value;
break;
case 'N':
word_bit = WORD_N;
gc_block.values.n = trunc(value);
break;
case 'P':
word_bit = WORD_P;
gc_block.values.p = value;
break;
// NOTE: For certain commands, P value must be an integer, but none of these commands are supported.
case 'Q': word_bit = WORD_Q; gc_block.values.q = value; break;
case 'R': word_bit = WORD_R; gc_block.values.r = value; break;
case 'S': word_bit = WORD_S; gc_block.values.s = value; break;
case 'T': word_bit = WORD_T;
case 'Q':
word_bit = WORD_Q;
gc_block.values.q = value;
break;
case 'R':
word_bit = WORD_R;
gc_block.values.r = value;
break;
case 'S':
word_bit = WORD_S;
gc_block.values.s = value;
break;
case 'T':
word_bit = WORD_T;
if(value > MAX_TOOL_NUMBER)
{
return STATUS_GCODE_MAX_VALUE_EXCEEDED;
@ -567,9 +648,21 @@ uint8_t GC_ExecuteLine(char *line)
gc_block.values.t = int_value;
break;
case 'X': word_bit = WORD_X; gc_block.values.xyz[X_AXIS] = value; axis_words |= (1<<X_AXIS); break;
case 'Y': word_bit = WORD_Y; gc_block.values.xyz[Y_AXIS] = value; axis_words |= (1<<Y_AXIS); break;
case 'Z': word_bit = WORD_Z; gc_block.values.xyz[Z_AXIS] = value; axis_words |= (1<<Z_AXIS); break;
case 'X':
word_bit = WORD_X;
gc_block.values.xyz[X_AXIS] = value;
axis_words |= (1<<X_AXIS);
break;
case 'Y':
word_bit = WORD_Y;
gc_block.values.xyz[Y_AXIS] = value;
axis_words |= (1<<Y_AXIS);
break;
case 'Z':
word_bit = WORD_Z;
gc_block.values.xyz[Z_AXIS] = value;
axis_words |= (1<<Z_AXIS);
break;
default:
return STATUS_GCODE_UNSUPPORTED_COMMAND;
}
@ -675,9 +768,11 @@ uint8_t GC_ExecuteLine(char *line)
}
else
{
if(gc_block.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) { // = G93
if(gc_block.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) // = G93
{
// NOTE: G38 can also operate in inverse time, but is undefined as an error. Missing F word check added here.
if(axis_command == AXIS_COMMAND_MOTION_MODE) {
if(axis_command == AXIS_COMMAND_MOTION_MODE)
{
if((gc_block.modal.motion != MOTION_MODE_NONE) && (gc_block.modal.motion != MOTION_MODE_SEEK))
{
if(BIT_IS_FALSE(value_words, BIT(WORD_F)))
@ -700,9 +795,11 @@ uint8_t GC_ExecuteLine(char *line)
// out in the motion modes error-checking. However, if no F word is passed with NO motion command that requires
// a feed rate, we simply move on and the state feed rate value gets updated to zero and remains undefined.
}
else { // = G94
else // = G94
{
// - In units per mm mode: If F word passed, ensure value is in mm/min, otherwise push last state value.
if(gc_state.modal.feed_rate == FEED_RATE_MODE_UNITS_PER_MIN) { // Last state is also G94
if(gc_state.modal.feed_rate == FEED_RATE_MODE_UNITS_PER_MIN) // Last state is also G94
{
if(BIT_IS_TRUE(value_words, BIT(WORD_F)))
{
if(gc_block.modal.units == UNITS_MODE_INCHES)
@ -753,7 +850,8 @@ uint8_t GC_ExecuteLine(char *line)
// [8. Coolant control ]: N/A
// [9. Override control ]: Not supported except for a Grbl-only parking motion override control.
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
if(BIT_IS_TRUE(command_words, BIT(MODAL_GROUP_M9))) { // Already set as enabled in parser.
if(BIT_IS_TRUE(command_words, BIT(MODAL_GROUP_M9))) // Already set as enabled in parser.
{
if(BIT_IS_TRUE(value_words, BIT(WORD_P)))
{
if(gc_block.values.p == 0.0)
@ -806,6 +904,9 @@ uint8_t GC_ExecuteLine(char *line)
// TODO: Check validity of Q
BIT_FALSE(value_words, BIT(WORD_Q));
}
// TODO: Inverse time feed rate not allowed for canned cycles
//if(gc_block.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME)
}
// [11. Set active plane ]: N/A
@ -834,7 +935,8 @@ uint8_t GC_ExecuteLine(char *line)
uint8_t idx;
if(gc_block.modal.units == UNITS_MODE_INCHES)
{
for(idx = 0; idx < N_AXIS; idx++) { // Axes indices are consistent, so loop may be used.
for(idx = 0; idx < N_AXIS; idx++) // Axes indices are consistent, so loop may be used.
{
if(BIT_IS_TRUE(axis_words, BIT(idx)))
{
gc_block.values.xyz[idx] *= MM_PER_INCH;
@ -852,7 +954,8 @@ uint8_t GC_ExecuteLine(char *line)
// NOTE: Although not explicitly stated so, G43.1 should be applied to only one valid
// axis that is configured (in config.h). There should be an error if the configured axis
// is absent or if any of the other axis words are present.
if(axis_command == AXIS_COMMAND_TOOL_LENGTH_OFFSET ) { // Indicates called in block.
if(axis_command == AXIS_COMMAND_TOOL_LENGTH_OFFSET ) // Indicates called in block.
{
if(gc_block.modal.tool_length == TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC)
{
if(axis_words ^ (1<<TOOL_LENGTH_OFFSET_AXIS))
@ -870,7 +973,8 @@ uint8_t GC_ExecuteLine(char *line)
float block_coord_system[N_AXIS];
memcpy(block_coord_system, gc_state.coord_system, sizeof(gc_state.coord_system));
if(BIT_IS_TRUE(command_words,BIT(MODAL_GROUP_G12))) { // Check if called in block
if(BIT_IS_TRUE(command_words,BIT(MODAL_GROUP_G12))) // Check if called in block
{
if(gc_block.modal.coord_select > N_COORDINATE_SYSTEM)
{
// [Greater than N sys]
@ -957,7 +1061,8 @@ uint8_t GC_ExecuteLine(char *line)
}
// Pre-calculate the coordinate data changes.
for(idx = 0; idx < N_AXIS; idx++) { // Axes indices are consistent, so loop may be used.
for(idx = 0; idx < N_AXIS; idx++) // Axes indices are consistent, so loop may be used.
{
// Update axes defined only in block. Always in machine coordinates. Can change non-active system.
if(BIT_IS_TRUE(axis_words, BIT(idx)))
{
@ -990,7 +1095,8 @@ uint8_t GC_ExecuteLine(char *line)
// Update axes defined only in block. Offsets current system to defined value. Does not update when
// active coordinate system is selected, but is still active unless G92.1 disables it.
for(idx = 0; idx < N_AXIS; idx++) { // Axes indices are consistent, so loop may be used.
for(idx = 0; idx < N_AXIS; idx++) // Axes indices are consistent, so loop may be used.
{
if(BIT_IS_TRUE(axis_words, BIT(idx)))
{
// WPos = MPos - WCS - G92 - TLO -> G92 = MPos - WCS - TLO - WPos
@ -1012,10 +1118,12 @@ uint8_t GC_ExecuteLine(char *line)
// target position with the coordinate system offsets, G92 offsets, absolute override, and distance
// modes applied. This includes the motion mode commands. We can now pre-compute the target position.
// NOTE: Tool offsets may be appended to these conversions when/if this feature is added.
if(axis_command != AXIS_COMMAND_TOOL_LENGTH_OFFSET) { // TLO block any axis command.
if(axis_command != AXIS_COMMAND_TOOL_LENGTH_OFFSET) // TLO block any axis command.
{
if(axis_words)
{
for(idx = 0; idx < N_AXIS; idx++) { // Axes indices are consistent, so loop may be used to save flash space.
for(idx = 0; idx < N_AXIS; idx++) // Axes indices are consistent, so loop may be used to save flash space.
{
if(BIT_IS_FALSE(axis_words, BIT(idx)))
{
gc_block.values.xyz[idx] = gc_state.position[idx]; // No axis word in block. Keep same axis position.
@ -1036,7 +1144,8 @@ uint8_t GC_ExecuteLine(char *line)
}
}
else
{ // Incremental mode
{
// Incremental mode
gc_block.values.xyz[idx] += gc_state.position[idx];
}
}
@ -1182,7 +1291,8 @@ uint8_t GC_ExecuteLine(char *line)
x = gc_block.values.xyz[axis_0]-gc_state.position[axis_0]; // Delta x between current position and target
y = gc_block.values.xyz[axis_1]-gc_state.position[axis_1]; // Delta y between current position and target
if(value_words & BIT(WORD_R)) { // Arc Radius Mode
if(value_words & BIT(WORD_R)) // Arc Radius Mode
{
BIT_FALSE(value_words, BIT(WORD_R));
if(isequal_position_vector(gc_state.position, gc_block.values.xyz))
{
@ -1291,17 +1401,22 @@ uint8_t GC_ExecuteLine(char *line)
gc_block.values.ijk[axis_1] = 0.5*(y+(x*h_x2_div_d));
}
else { // Arc Center Format Offset Mode
if(!(ijk_words & (BIT(axis_0)|BIT(axis_1)))) {
else // Arc Center Format Offset Mode
{
if(!(ijk_words & (BIT(axis_0)|BIT(axis_1))))
{
// [No offsets in plane]
return STATUS_GCODE_NO_OFFSETS_IN_PLANE;
}
BIT_FALSE(value_words, (BIT(WORD_I) | BIT(WORD_J) | BIT(WORD_K)));
// Convert IJK values to proper units.
if(gc_block.modal.units == UNITS_MODE_INCHES) {
for(idx = 0; idx < N_LINEAR_AXIS; idx++) { // Axes indices are consistent, so loop may be used to save flash space.
if(ijk_words & BIT(idx)) {
if(gc_block.modal.units == UNITS_MODE_INCHES)
{
for(idx = 0; idx < N_LINEAR_AXIS; idx++) // Axes indices are consistent, so loop may be used to save flash space.
{
if(ijk_words & BIT(idx))
{
gc_block.values.ijk[idx] *= MM_PER_INCH;
}
}
@ -1318,12 +1433,15 @@ uint8_t GC_ExecuteLine(char *line)
// Compute difference between current location and target radii for final error-checks.
float delta_r = fabs(target_r-gc_block.values.r);
if(delta_r > 0.005) {
if(delta_r > 0.5) {
if(delta_r > 0.005)
{
if(delta_r > 0.5)
{
// [Arc definition error] > 0.5mm
return STATUS_GCODE_INVALID_TARGET;
}
if(delta_r > (0.001*gc_block.values.r)) {
if(delta_r > (0.001*gc_block.values.r))
{
// [Arc definition error] > 0.005mm AND 0.1% radius
return STATUS_GCODE_INVALID_TARGET;
}
@ -1331,7 +1449,8 @@ uint8_t GC_ExecuteLine(char *line)
}
break;
case MOTION_MODE_PROBE_TOWARD_NO_ERROR: case MOTION_MODE_PROBE_AWAY_NO_ERROR:
case MOTION_MODE_PROBE_TOWARD_NO_ERROR:
case MOTION_MODE_PROBE_AWAY_NO_ERROR:
gc_parser_flags |= GC_PARSER_PROBE_IS_NO_ERROR; // No break intentional.
case MOTION_MODE_PROBE_TOWARD:
@ -1357,7 +1476,9 @@ uint8_t GC_ExecuteLine(char *line)
}
break;
case MOTION_MODE_DRILL: case MOTION_MODE_DRILL_DWELL: case MOTION_MODE_DRILL_PECK:
case MOTION_MODE_DRILL:
case MOTION_MODE_DRILL_DWELL:
case MOTION_MODE_DRILL_PECK:
if(BIT_TRUE(value_words, (BIT(WORD_L))))
{
}
@ -1650,9 +1771,11 @@ uint8_t GC_ExecuteLine(char *line)
// NOTE: If G43 were supported, its operation wouldn't be any different from G43.1 in terms
// of execution. The error-checking step would simply load the offset value into the correct
// axis of the block XYZ value array.
if(axis_command == AXIS_COMMAND_TOOL_LENGTH_OFFSET) { // Indicates a change.
if(axis_command == AXIS_COMMAND_TOOL_LENGTH_OFFSET) // Indicates a change.
{
gc_state.modal.tool_length = gc_block.modal.tool_length;
if (gc_state.modal.tool_length == TOOL_LENGTH_OFFSET_CANCEL) { // G49
if (gc_state.modal.tool_length == TOOL_LENGTH_OFFSET_CANCEL) // G49
{
gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS] = 0.0;
}
// else G43.1
@ -1693,7 +1816,8 @@ uint8_t GC_ExecuteLine(char *line)
}
break;
case NON_MODAL_GO_HOME_0: case NON_MODAL_GO_HOME_1:
case NON_MODAL_GO_HOME_0:
case NON_MODAL_GO_HOME_1:
// Move to intermediate position before going home. Obeys current coordinate system and offsets
// and absolute and incremental modes.
pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag.
@ -1928,7 +2052,8 @@ uint8_t GC_ExecuteLine(char *line)
Protocol_ExecuteRealtime(); // Execute suspend.
}
}
else { // == PROGRAM_FLOW_COMPLETED
else // == PROGRAM_FLOW_COMPLETED
{
// Upon program complete, only a subset of g-codes reset to certain defaults, according to
// LinuxCNC's program end descriptions and testing. Only modal groups [G-code 1,2,3,5,7,12]
// and [M-code 7,8,9] reset to [G1,G17,G90,G94,G40,G54,M5,M9,M48]. The remaining modal groups

Wyświetl plik

@ -36,16 +36,20 @@ uint8_t Jog_Execute(Planner_LineData_t *pl_data, Parser_Block_t *gc_block)
pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE;
pl_data->line_number = gc_block->values.n;
if(BIT_IS_TRUE(settings.flags, BITFLAG_SOFT_LIMIT_ENABLE)) {
if(System_CheckTravelLimits(gc_block->values.xyz)) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_SOFT_LIMIT_ENABLE))
{
if(System_CheckTravelLimits(gc_block->values.xyz))
{
return STATUS_TRAVEL_EXCEEDED;
}
}
// Valid jog command. Plan, set state, and execute.
MC_Line(gc_block->values.xyz, pl_data);
if(sys.state == STATE_IDLE) {
if (Planner_GetCurrentBlock() != 0) { // Check if there is a block to execute.
if(sys.state == STATE_IDLE)
{
if (Planner_GetCurrentBlock() != 0) // Check if there is a block to execute.
{
sys.state = STATE_JOG;
Stepper_PrepareBuffer();
Stepper_WakeUp(); // NOTE: Manual start. No state machine required.

Wyświetl plik

@ -47,10 +47,12 @@ void Limits_Init(void)
GPIO_InitGPIO(GPIO_LIMIT);
// TODO: Hard limits via interrupt
if(BIT_IS_TRUE(settings.flags, BITFLAG_HARD_LIMIT_ENABLE)) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_HARD_LIMIT_ENABLE))
{
settings.system_flags |= BITFLAG_ENABLE_LIMITS;
}
else {
else
{
Limits_Disable();
}
}
@ -70,11 +72,12 @@ uint8_t Limits_GetState(void)
{
uint8_t limit_state = 0;
limit_state = (GPIO_ReadInputDataBit(GPIO_LIM_X_PORT, GPIO_LIM_X_PIN)<<X_LIMIT_BIT);
limit_state |= (GPIO_ReadInputDataBit(GPIO_LIM_Y_PORT, GPIO_LIM_Y_PIN)<<Y_LIMIT_BIT);
limit_state |= (GPIO_ReadInputDataBit(GPIO_LIM_Z_PORT, GPIO_LIM_Z_PIN)<<Z_LIMIT_BIT);
limit_state = (GPIO_ReadInputDataBit(GPIO_LIM_X_PORT, GPIO_LIM_X_PIN)<<X1_LIMIT_BIT);
limit_state |= (GPIO_ReadInputDataBit(GPIO_LIM_Y_PORT, GPIO_LIM_Y_PIN)<<Y1_LIMIT_BIT);
limit_state |= (GPIO_ReadInputDataBit(GPIO_LIM_Z_PORT, GPIO_LIM_Z_PIN)<<Z1_LIMIT_BIT);
if(BIT_IS_FALSE(settings.flags, BITFLAG_INVERT_LIMIT_PINS)) {
if(BIT_IS_FALSE(settings.flags, BITFLAG_INVERT_LIMIT_PINS))
{
limit_state ^= LIMIT_MASK;
}
@ -100,16 +103,21 @@ void Limit_PinChangeISR(void) // DEFAULT: Limit pin change interrupt process.
// moves in the planner and serial buffers are all cleared and newly sent blocks will be
// locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
// limit setting if their limits are constantly triggering after a reset and move their axes.
if(sys.state != STATE_ALARM) {
if(!(sys_rt_exec_alarm)) {
if(settings.system_flags & BITFLAG_FORCE_HARD_LIMIT_CHECK) {
if(sys.state != STATE_ALARM)
{
if(!(sys_rt_exec_alarm))
{
if(settings.system_flags & BITFLAG_FORCE_HARD_LIMIT_CHECK)
{
// Check limit pin state.
if(Limits_GetState()) {
if(Limits_GetState())
{
MC_Reset(); // Initiate system kill.
System_SetExecAlarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
}
}
else {
else
{
MC_Reset(); // Initiate system kill.
System_SetExecAlarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
}
@ -146,17 +154,20 @@ void Limits_GoHome(uint8_t cycle_mask)
float target[N_AXIS];
float max_travel = 0.0;
uint8_t idx;
for(idx = 0; idx < N_AXIS; idx++) {
for(idx = 0; idx < N_AXIS; idx++)
{
// Initialize step pin masks
step_pin[idx] = Settings_GetStepPinMask(idx);
#ifdef COREXY
if((idx == A_MOTOR) || (idx == B_MOTOR)) {
if((idx == A_MOTOR) || (idx == B_MOTOR))
{
step_pin[idx] = (Settings_GetStepPinMask(X_AXIS) | Settings_GetStepPinMask(Y_AXIS));
}
#endif
if(BIT_IS_TRUE(cycle_mask, BIT(idx))) {
if(BIT_IS_TRUE(cycle_mask, BIT(idx)))
{
// Set target based on max_travel setting. Ensure homing switches engaged with search scalar.
// NOTE: settings.max_travel[] is stored as a negative value.
max_travel = max(max_travel, (-HOMING_AXIS_SEARCH_SCALAR)*settings.max_travel[idx]);
@ -168,27 +179,33 @@ void Limits_GoHome(uint8_t cycle_mask)
float homing_rate = settings.homing_seek_rate;
uint8_t limit_state, axislock, n_active_axis;
do {
do
{
System_ConvertArraySteps2Mpos(target,sys_position);
// Initialize and declare variables needed for homing routine.
axislock = 0;
n_active_axis = 0;
for(idx = 0; idx < N_AXIS; idx++) {
for(idx = 0; idx < N_AXIS; idx++)
{
// Set target location for active axes and setup computation for homing rate.
if(BIT_IS_TRUE(cycle_mask,BIT(idx))) {
if(BIT_IS_TRUE(cycle_mask,BIT(idx)))
{
n_active_axis++;
#ifdef COREXY
if(idx == X_AXIS) {
if(idx == X_AXIS)
{
int32_t axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
sys_position[A_MOTOR] = axis_position;
sys_position[B_MOTOR] = -axis_position;
}
else if (idx == Y_AXIS) {
else if (idx == Y_AXIS)
{
int32_t axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
sys_position[A_MOTOR] = sys_position[B_MOTOR] = axis_position;
}
else {
else
{
sys_position[Z_AXIS] = 0;
}
#else
@ -196,15 +213,25 @@ void Limits_GoHome(uint8_t cycle_mask)
#endif
// Set target direction based on cycle mask and homing cycle approach state.
// NOTE: This happens to compile smaller than any other implementation tried.
if(BIT_IS_TRUE(settings.homing_dir_mask, BIT(idx))) {
if (approach) { target[idx] = -max_travel; }
else { target[idx] = max_travel; }
if(BIT_IS_TRUE(settings.homing_dir_mask, BIT(idx)))
{
if (approach)
{
target[idx] = -max_travel;
}
else {
if(approach) {
else
{
target[idx] = max_travel;
}
else {
}
else
{
if(approach)
{
target[idx] = max_travel;
}
else
{
target[idx] = -max_travel;
}
}
@ -225,18 +252,25 @@ void Limits_GoHome(uint8_t cycle_mask)
Stepper_PrepareBuffer(); // Prep and fill segment buffer from newly planned block.
Stepper_WakeUp(); // Initiate motion
do {
if(approach) {
do
{
if(approach)
{
// Check limit state. Lock out cycle axes when they change.
limit_state = Limits_GetState();
for(idx = 0; idx < N_AXIS; idx++) {
if(axislock & step_pin[idx]) {
if(limit_state & (1 << idx)) {
for(idx = 0; idx < N_AXIS; idx++)
{
if(axislock & step_pin[idx])
{
if(limit_state & (1 << idx))
{
#ifdef COREXY
if(idx == Z_AXIS) {
if(idx == Z_AXIS)
{
axislock &= ~(step_pin[Z_AXIS]);
}
else {
else
{
axislock &= ~(step_pin[A_MOTOR]|step_pin[B_MOTOR]);
}
#else
@ -252,39 +286,47 @@ void Limits_GoHome(uint8_t cycle_mask)
Stepper_PrepareBuffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.
// Exit routines: No time to run protocol_execute_realtime() in this loop.
if(sys_rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET | EXEC_CYCLE_STOP)) {
if(sys_rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET | EXEC_CYCLE_STOP))
{
uint16_t rt_exec = sys_rt_exec_state;
// Homing failure condition: Reset issued during cycle.
if(rt_exec & EXEC_RESET) {
if(rt_exec & EXEC_RESET)
{
System_SetExecAlarm(EXEC_ALARM_HOMING_FAIL_RESET);
}
// Homing failure condition: Safety door was opened.
if(rt_exec & EXEC_SAFETY_DOOR) {
if(rt_exec & EXEC_SAFETY_DOOR)
{
System_SetExecAlarm(EXEC_ALARM_HOMING_FAIL_DOOR);
}
// Homing failure condition: Limit switch still engaged after pull-off motion
if(!approach && (Limits_GetState() & cycle_mask)) {
if(!approach && (Limits_GetState() & cycle_mask))
{
System_SetExecAlarm(EXEC_ALARM_HOMING_FAIL_PULLOFF);
}
// Homing failure condition: Limit switch not found during approach.
if(approach && (rt_exec & EXEC_CYCLE_STOP)) {
if(approach && (rt_exec & EXEC_CYCLE_STOP))
{
System_SetExecAlarm(EXEC_ALARM_HOMING_FAIL_APPROACH);
}
if(sys_rt_exec_alarm) {
if(sys_rt_exec_alarm)
{
MC_Reset(); // Stop motors, if they are running.
Protocol_ExecuteRealtime();
return;
}
else {
else
{
// Pull-off motion complete. Disable CYCLE_STOP from executing.
System_ClearExecStateFlag(EXEC_CYCLE_STOP);
break;
}
}
// TODO:
} while(0x07 & axislock);
}
while(0x3F & axislock);
Stepper_Reset(); // Immediately force kill steppers and reset step segment buffer.
Delay_ms(settings.homing_debounce_delay); // Delay to allow transient dynamics to dissipate.
@ -293,16 +335,19 @@ void Limits_GoHome(uint8_t cycle_mask)
approach = !approach;
// After first cycle, homing enters locating phase. Shorten search to pull-off distance.
if(approach) {
if(approach)
{
max_travel = settings.homing_pulloff*HOMING_AXIS_LOCATE_SCALAR;
homing_rate = settings.homing_feed_rate;
}
else {
else
{
max_travel = settings.homing_pulloff;
homing_rate = settings.homing_seek_rate;
}
} while(n_cycle-- > 0);
}
while(n_cycle-- > 0);
// The active cycle axes should now be homed and machine limits have been located. By
// default, Grbl defines machine space as all negative, as do most CNCs. Since limit switches
@ -312,32 +357,39 @@ void Limits_GoHome(uint8_t cycle_mask)
// triggering when hard limits are enabled or when more than one axes shares a limit pin.
int32_t set_axis_position;
// Set machine positions for homed limit switches. Don't update non-homed axes.
for(idx = 0; idx < N_AXIS; idx++) {
for(idx = 0; idx < N_AXIS; idx++)
{
// NOTE: settings.max_travel[] is stored as a negative value.
if(cycle_mask & BIT(idx)) {
if(cycle_mask & BIT(idx))
{
#ifdef HOMING_FORCE_SET_ORIGIN
set_axis_position = 0;
#else
if(BIT_IS_TRUE(settings.homing_dir_mask, BIT(idx))) {
if(BIT_IS_TRUE(settings.homing_dir_mask, BIT(idx)))
{
set_axis_position = lround((settings.max_travel[idx]+settings.homing_pulloff)*settings.steps_per_mm[idx]);
}
else {
else
{
set_axis_position = lround(-settings.homing_pulloff*settings.steps_per_mm[idx]);
}
#endif
#ifdef COREXY
if(idx == X_AXIS) {
if(idx == X_AXIS)
{
int32_t off_axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
sys_position[A_MOTOR] = set_axis_position + off_axis_position;
sys_position[B_MOTOR] = set_axis_position - off_axis_position;
}
else if(idx == Y_AXIS) {
else if(idx == Y_AXIS)
{
int32_t off_axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
sys_position[A_MOTOR] = off_axis_position + set_axis_position;
sys_position[B_MOTOR] = off_axis_position - set_axis_position;
}
else {
else
{
sys_position[idx] = set_axis_position;
}
#else
@ -360,21 +412,26 @@ void Limits_GoHome(uint8_t cycle_mask)
// NOTE: Used by jogging to limit travel within soft-limit volume.
void Limits_SoftCheck(float *target)
{
if(System_CheckTravelLimits(target)) {
if(System_CheckTravelLimits(target))
{
sys.soft_limit = true;
// Force feed hold if cycle is active. All buffered blocks are guaranteed to be within
// workspace volume so just come to a controlled stop so position is not lost. When complete
// enter alarm mode.
if(sys.state == STATE_CYCLE) {
if(sys.state == STATE_CYCLE)
{
System_SetExecStateFlag(EXEC_FEED_HOLD);
do {
do
{
Protocol_ExecuteRealtime();
if(sys.abort) {
if(sys.abort)
{
return;
}
} while(sys.state != STATE_IDLE);
}
while(sys.state != STATE_IDLE);
}
MC_Reset(); // Issue system reset and ensure spindle and coolant are shutdown.

Wyświetl plik

@ -91,15 +91,18 @@ void MC_Line(float *target, Planner_LineData_t *pl_data)
// If enabled, check for soft limit violations. Placed here all line motions are picked up
// from everywhere in Grbl.
if(BIT_IS_TRUE(settings.flags, BITFLAG_SOFT_LIMIT_ENABLE)) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_SOFT_LIMIT_ENABLE))
{
// NOTE: Block jog state. Jogging is a special case and soft limits are handled independently.
if(sys.state != STATE_JOG) {
if(sys.state != STATE_JOG)
{
Limits_SoftCheck(target);
}
}
// If in check gcode mode, prevent motion by blocking planner. Soft limits still work.
if(sys.state == STATE_CHECK_MODE) {
if(sys.state == STATE_CHECK_MODE)
{
return;
}
@ -120,19 +123,23 @@ void MC_Line(float *target, Planner_LineData_t *pl_data)
// If the buffer is full: good! That means we are well ahead of the robot.
// Remain in this loop until there is room in the buffer.
do {
do
{
Protocol_ExecuteRealtime(); // Check for any run-time commands
if(sys.abort) {
if(sys.abort)
{
// Bail, if system abort.
return;
}
if(Planner_CheckBufferFull()) {
if(Planner_CheckBufferFull())
{
// Auto-cycle start when buffer is full.
Protocol_AutoCycleStart();
}
else {
else
{
break;
}
} while(1);
@ -179,19 +186,23 @@ void MC_Line(float *target, Planner_LineData_t *pl_data)
memcpy(target_prev, target, N_AXIS*sizeof(float));
// Backlash move needs a slot in planner buffer, so we have to check again, if planner is free
do {
do
{
Protocol_ExecuteRealtime(); // Check for any run-time commands
if(sys.abort) {
if(sys.abort)
{
// Bail, if system abort.
return;
}
if(Planner_CheckBufferFull()) {
if(Planner_CheckBufferFull())
{
// Auto-cycle start when buffer is full.
Protocol_AutoCycleStart();
}
else {
else
{
break;
}
} while(1);
@ -201,11 +212,14 @@ void MC_Line(float *target, Planner_LineData_t *pl_data)
#endif
// Plan and queue motion into planner buffer
if(Planner_BufferLine(target, pl_data) == PLAN_EMPTY_BLOCK) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_LASER_MODE)) {
if(Planner_BufferLine(target, pl_data) == PLAN_EMPTY_BLOCK)
{
if(BIT_IS_TRUE(settings.flags, BITFLAG_LASER_MODE))
{
// Correctly set spindle state, if there is a coincident position passed. Forces a buffer
// sync while in M3 laser mode only.
if(pl_data->condition & PL_COND_FLAG_SPINDLE_CW) {
if(pl_data->condition & PL_COND_FLAG_SPINDLE_CW)
{
Spindle_Sync(PL_COND_FLAG_SPINDLE_CW, pl_data->spindle_speed);
}
}
@ -231,13 +245,17 @@ void MC_Arc(float *target, Planner_LineData_t *pl_data, float *position, float *
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
if(is_clockwise_arc) { // Correct atan2 output per direction
if(angular_travel >= -ARC_ANGULAR_TRAVEL_EPSILON) {
if(is_clockwise_arc) // Correct atan2 output per direction
{
if(angular_travel >= -ARC_ANGULAR_TRAVEL_EPSILON)
{
angular_travel -= 2*M_PI;
}
}
else {
if(angular_travel <= ARC_ANGULAR_TRAVEL_EPSILON) {
else
{
if(angular_travel <= ARC_ANGULAR_TRAVEL_EPSILON)
{
angular_travel += 2*M_PI;
}
}
@ -248,11 +266,13 @@ void MC_Arc(float *target, Planner_LineData_t *pl_data, float *position, float *
// For the intended uses of Grbl, this value shouldn't exceed 2000 for the strictest of cases.
uint16_t segments = floor(fabs(0.5*angular_travel*radius) / sqrt(settings.arc_tolerance*(2*radius - settings.arc_tolerance)));
if(segments) {
if(segments)
{
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
// by a number of discrete segments. The inverse feed_rate should be correct for the sum of
// all segments.
if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) {
if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME)
{
pl_data->feed_rate *= segments;
BIT_FALSE(pl_data->condition, PL_COND_FLAG_INVERSE_TIME); // Force as feed absolute mode over arc segments.
}
@ -296,15 +316,18 @@ void MC_Arc(float *target, Planner_LineData_t *pl_data, float *position, float *
uint16_t i;
uint8_t count = 0;
for(i = 1; i < segments; i++) { // Increment (segments-1).
if(count < N_ARC_CORRECTION) {
for(i = 1; i < segments; i++) // Increment (segments-1).
{
if(count < N_ARC_CORRECTION)
{
// Apply vector rotation matrix. ~40 usec
r_axisi = r_axis0*sin_T + r_axis1*cos_T;
r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
r_axis1 = r_axisi;
count++;
}
else {
else
{
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments. ~375 usec
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
cos_Ti = cos(i*theta_per_segment);
@ -322,7 +345,8 @@ void MC_Arc(float *target, Planner_LineData_t *pl_data, float *position, float *
MC_Line(position, pl_data);
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
if(sys.abort) {
if(sys.abort)
{
return;
}
}
@ -336,7 +360,8 @@ void MC_Arc(float *target, Planner_LineData_t *pl_data, float *position, float *
// Execute dwell in seconds.
void MC_Dwell(float seconds)
{
if(sys.state == STATE_CHECK_MODE) {
if(sys.state == STATE_CHECK_MODE)
{
return;
}
@ -357,7 +382,8 @@ void MC_HomigCycle(uint8_t cycle_mask)
// with machines with limits wired on both ends of travel to one limit pin.
// TODO: Move the pin-specific LIMIT_PIN call to limits.c as a function.
#ifdef LIMITS_TWO_SWITCHES_ON_AXES
if(Limits_GetState()) {
if(Limits_GetState())
{
MC_Reset(); // Issue system reset and ensure spindle and coolant are shutdown.
System_SetExecAlarm(EXEC_ALARM_HARD_LIMIT);
@ -371,7 +397,8 @@ void MC_HomigCycle(uint8_t cycle_mask)
// Perform homing routine. NOTE: Special motion case. Only system reset works.
#ifdef HOMING_SINGLE_AXIS_COMMANDS
if(cycle_mask) {
if(cycle_mask)
{
// Perform homing cycle based on mask.
Limits_GoHome(cycle_mask);
}
@ -391,7 +418,8 @@ void MC_HomigCycle(uint8_t cycle_mask)
}
Protocol_ExecuteRealtime(); // Check for reset and set system abort.
if(sys.abort) {
if(sys.abort)
{
// Did not complete. Alarm state set by mc_alarm.
return;
}
@ -413,13 +441,15 @@ void MC_HomigCycle(uint8_t cycle_mask)
uint8_t MC_ProbeCycle(float *target, Planner_LineData_t *pl_data, uint8_t parser_flags)
{
// TODO: Need to update this cycle so it obeys a non-auto cycle start.
if(sys.state == STATE_CHECK_MODE) {
if(sys.state == STATE_CHECK_MODE)
{
return GC_PROBE_CHECK_MODE;
}
// Finish all queued commands and empty planner buffer before starting probe cycle.
Protocol_BufferSynchronize();
if(sys.abort) {
if(sys.abort)
{
// Return if system reset has been issued.
return GC_PROBE_ABORT;
}
@ -433,7 +463,8 @@ uint8_t MC_ProbeCycle(float *target, Planner_LineData_t *pl_data, uint8_t parser
// 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_GetState()) { // Check probe pin state.
if(Probe_GetState()) // Check probe pin state.
{
System_SetExecAlarm(EXEC_ALARM_PROBE_FAIL_INITIAL);
Protocol_ExecuteRealtime();
Probe_ConfigureInvertMask(false); // Re-initialize invert mask before returning.
@ -449,10 +480,12 @@ uint8_t MC_ProbeCycle(float *target, Planner_LineData_t *pl_data, uint8_t parser
// Perform probing cycle. Wait here until probe is triggered or motion completes.
System_SetExecStateFlag(EXEC_CYCLE_START);
do {
do
{
Protocol_ExecuteRealtime();
if(sys.abort) {
if(sys.abort)
{
// Check for system abort
return(GC_PROBE_ABORT);
}
@ -461,15 +494,19 @@ uint8_t MC_ProbeCycle(float *target, Planner_LineData_t *pl_data, uint8_t parser
// Probing cycle complete!
// 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) {
if(sys_probe_state == PROBE_ACTIVE)
{
if(is_no_error)
{
memcpy(sys_probe_position, sys_position, sizeof(sys_position));
}
else {
else
{
System_SetExecAlarm(EXEC_ALARM_PROBE_FAIL_CONTACT);
}
}
else {
else
{
sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
}
@ -488,11 +525,13 @@ uint8_t MC_ProbeCycle(float *target, Planner_LineData_t *pl_data, uint8_t parser
Report_ProbeParams();
#endif
if(sys.probe_succeeded) {
if(sys.probe_succeeded)
{
// Successful probe cycle.
return GC_PROBE_FOUND;
}
else {
else
{
return GC_PROBE_FAIL_END;
} // Failed to trigger probe within travel. With or without error.
}
@ -504,7 +543,8 @@ void MC_OverrideCtrlUpdate(uint8_t override_state)
// Finish all queued commands before altering override control state
Protocol_BufferSynchronize();
if(sys.abort) {
if(sys.abort)
{
return;
}
@ -518,31 +558,37 @@ void MC_OverrideCtrlUpdate(uint8_t override_state)
#ifdef PARKING_ENABLE
void MC_ParkingMotion(float *parking_target, Planner_LineData_t *pl_data)
{
if(sys.abort) {
if(sys.abort)
{
// Block during abort.
return;
}
uint8_t plan_status = Planner_BufferLine(parking_target, pl_data);
if(plan_status) {
if(plan_status)
{
BIT_TRUE(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
BIT_FALSE(sys.step_control, STEP_CONTROL_END_MOTION); // Allow parking motion to execute, if feed hold is active.
Stepper_ParkingSetupBuffer(); // Setup step segment buffer for special parking motion case
Stepper_PrepareBuffer();
Stepper_WakeUp();
do {
do
{
Protocol_ExecRtSystem();
if(sys.abort) {
if(sys.abort)
{
return;
}
} while (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION);
}
while (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION);
Stepper_ParkingRestoreBuffer(); // Restore step segment buffer to normal run state.
}
else {
else
{
BIT_FALSE(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
Protocol_ExecRtSystem();
}
@ -559,7 +605,8 @@ void MC_ParkingMotion(float *parking_target, Planner_LineData_t *pl_data)
void MC_Reset(void)
{
// Only this function can set the system reset. Helps prevent multiple kill calls.
if(BIT_IS_FALSE(sys_rt_exec_state, EXEC_RESET)) {
if(BIT_IS_FALSE(sys_rt_exec_state, EXEC_RESET))
{
System_SetExecStateFlag(EXEC_RESET);
// Kill spindle and coolant.
@ -570,13 +617,17 @@ void MC_Reset(void)
// NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
// the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
// violated, by which, all bets are off.
if((sys.state & (STATE_CYCLE | STATE_HOMING | STATE_JOG)) || (sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION))) {
if(sys.state == STATE_HOMING) {
if(!sys_rt_exec_alarm) {
if((sys.state & (STATE_CYCLE | STATE_HOMING | STATE_JOG)) || (sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION)))
{
if(sys.state == STATE_HOMING)
{
if(!sys_rt_exec_alarm)
{
System_SetExecAlarm(EXEC_ALARM_HOMING_FAIL_RESET);
}
}
else {
else
{
System_SetExecAlarm(EXEC_ALARM_ABORT_CYCLE);
}

Wyświetl plik

@ -41,7 +41,6 @@ void MC_Init(void);
void MC_SyncBacklashPosition(void);
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
// (1 minute)/feed_rate time.

Wyświetl plik

@ -26,6 +26,7 @@
#include <stdint.h>
// EEPROM size in bytes
#define NVM_SIZE 1024

Wyświetl plik

@ -31,7 +31,8 @@
// Define planner variables
typedef struct {
typedef struct
{
int32_t position[N_AXIS]; // The planner position of the tool in absolute steps. Kept separate
// from g-code position for movements requiring multiple line motions,
// i.e. arcs, canned cycles, and backlash compensation.
@ -53,7 +54,6 @@ static uint8_t next_buffer_head; // Index of the next buffer head
static uint8_t block_buffer_planned; // Index of the optimally planned block
void Planner_Init(void)
{
Planner_Reset();
@ -106,7 +106,8 @@ uint8_t Planner_BufferLine(float *target, Planner_LineData_t *pl_data)
uint8_t idx;
// Copy position data based on type of motion being planned.
if(block->condition & PL_COND_FLAG_SYSTEM_MOTION) {
if(block->condition & PL_COND_FLAG_SYSTEM_MOTION)
{
#ifdef COREXY
position_steps[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
position_steps[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
@ -117,7 +118,8 @@ uint8_t Planner_BufferLine(float *target, Planner_LineData_t *pl_data)
memcpy(position_steps, sys_position, sizeof(sys_position));
#endif
}
else {
else
{
memcpy(position_steps, planner.position, sizeof(planner.position));
}
@ -128,25 +130,30 @@ uint8_t Planner_BufferLine(float *target, Planner_LineData_t *pl_data)
block->steps[B_MOTOR] = labs((target_steps[X_AXIS]-position_steps[X_AXIS]) - (target_steps[Y_AXIS]-position_steps[Y_AXIS]));
#endif
for(idx = 0; idx < N_AXIS; idx++) {
for(idx = 0; idx < N_AXIS; idx++)
{
// Calculate target position in absolute steps, number of steps for each axis, and determine max step events.
// Also, compute individual axes distance for move and prep unit vector calculations.
// NOTE: Computes true distance from converted step values.
#ifdef COREXY
if(!(idx == A_MOTOR) && !(idx == B_MOTOR)) {
if(!(idx == A_MOTOR) && !(idx == B_MOTOR))
{
target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
block->steps[idx] = labs(target_steps[idx]-position_steps[idx]);
}
block->step_event_count = max(block->step_event_count, block->steps[idx]);
if(idx == A_MOTOR) {
if(idx == A_MOTOR)
{
delta_mm = (target_steps[X_AXIS]-position_steps[X_AXIS] + target_steps[Y_AXIS]-position_steps[Y_AXIS])/settings.steps_per_mm[idx];
}
else if(idx == B_MOTOR) {
else if(idx == B_MOTOR)
{
delta_mm = (target_steps[X_AXIS]-position_steps[X_AXIS] - target_steps[Y_AXIS]+position_steps[Y_AXIS])/settings.steps_per_mm[idx];
}
else {
else
{
delta_mm = (target_steps[idx] - position_steps[idx])/settings.steps_per_mm[idx];
}
#else
@ -158,13 +165,15 @@ uint8_t Planner_BufferLine(float *target, Planner_LineData_t *pl_data)
unit_vec[idx] = delta_mm; // Store unit vector numerator
// Set direction bits. Bit enabled always means direction is negative.
if(delta_mm < 0.0) {
if(delta_mm < 0.0)
{
block->direction_bits |= Settings_GetDirectionPinMask(idx);
}
}
// Bail if this is a zero-length block. Highly unlikely to occur.
if(block->step_event_count == 0) {
if(block->step_event_count == 0)
{
return PLAN_EMPTY_BLOCK;
}
@ -177,24 +186,29 @@ uint8_t Planner_BufferLine(float *target, Planner_LineData_t *pl_data)
block->rapid_rate = limit_value_by_axis_maximum(settings.max_rate, unit_vec);
// Store programmed rate.
if(block->condition & PL_COND_FLAG_RAPID_MOTION) {
if(block->condition & PL_COND_FLAG_RAPID_MOTION)
{
block->programmed_rate = block->rapid_rate;
}
else {
else
{
block->programmed_rate = pl_data->feed_rate;
if(block->condition & PL_COND_FLAG_INVERSE_TIME) {
if(block->condition & PL_COND_FLAG_INVERSE_TIME)
{
block->programmed_rate *= block->millimeters;
}
}
// TODO: Need to check this method handling zero junction speeds when starting from rest.
if((block_buffer_head == block_buffer_tail) || (block->condition & PL_COND_FLAG_SYSTEM_MOTION)) {
if((block_buffer_head == block_buffer_tail) || (block->condition & PL_COND_FLAG_SYSTEM_MOTION))
{
// Initialize block entry speed as zero. Assume it will be starting from rest. Planner will correct this later.
// If system motion, the system motion block always is assumed to start from rest and end at a complete stop.
block->entry_speed_sqr = 0.0;
block->max_junction_speed_sqr = 0.0; // Starting from rest. Enforce start from zero velocity.
}
else {
else
{
// Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
// Let a circle be tangent to both previous and current path line segments, where the junction
// deviation is defined as the distance from the junction to the closest edge of the circle,
@ -219,21 +233,27 @@ uint8_t Planner_BufferLine(float *target, Planner_LineData_t *pl_data)
float junction_unit_vec[N_AXIS];
float junction_cos_theta = 0.0;
for(idx = 0; idx < N_AXIS; idx++) {
for(idx = 0; idx < N_AXIS; idx++)
{
junction_cos_theta -= planner.previous_unit_vec[idx]*unit_vec[idx];
junction_unit_vec[idx] = unit_vec[idx]-planner.previous_unit_vec[idx];
}
// NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta).
if(junction_cos_theta > 0.999999) {
if(junction_cos_theta > 0.999999)
{
// For a 0 degree acute junction, just set minimum junction speed.
block->max_junction_speed_sqr = MINIMUM_JUNCTION_SPEED*MINIMUM_JUNCTION_SPEED;
}
else {
if(junction_cos_theta < -0.999999) {
else
{
if(junction_cos_theta < -0.999999)
{
// Junction is a straight line or 180 degrees. Junction speed is infinite.
block->max_junction_speed_sqr = SOME_LARGE_VALUE;
} else {
}
else
{
convert_delta_vector_to_unit_vector(junction_unit_vec);
float junction_acceleration = limit_value_by_axis_maximum(settings.acceleration, junction_unit_vec);
float sin_theta_d2 = sqrt(0.5*(1.0-junction_cos_theta)); // Trig half angle identity. Always positive.
@ -244,7 +264,8 @@ uint8_t Planner_BufferLine(float *target, Planner_LineData_t *pl_data)
}
// Block system motion from updating this data to ensure next g-code motion is computed correctly.
if(!(block->condition & PL_COND_FLAG_SYSTEM_MOTION)) {
if(!(block->condition & PL_COND_FLAG_SYSTEM_MOTION))
{
float nominal_speed = Planner_ComputeProfileNominalSpeed(block);
Planner_ComputeProfileParams(block, nominal_speed, planner.previous_nominal_speed);
@ -271,11 +292,13 @@ uint8_t Planner_BufferLine(float *target, Planner_LineData_t *pl_data)
void Planner_DiscardCurrentBlock(void)
{
if(block_buffer_head != block_buffer_tail) { // Discard non-empty buffer.
if(block_buffer_head != block_buffer_tail) // Discard non-empty buffer.
{
uint8_t block_index = Planner_NextBlockIndex(block_buffer_tail);
// Push block_buffer_planned pointer, if encountered.
if(block_buffer_tail == block_buffer_planned) {
if(block_buffer_tail == block_buffer_planned)
{
block_buffer_planned = block_index;
}
block_buffer_tail = block_index;
@ -293,7 +316,8 @@ Planner_Block_t *Planner_GetSystemMotionBlock(void)
// Returns address of first planner block, if available. Called by various main program functions.
Planner_Block_t *Planner_GetCurrentBlock(void)
{
if(block_buffer_head == block_buffer_tail) {
if(block_buffer_head == block_buffer_tail)
{
// Buffer empty
return 0;
}
@ -306,7 +330,8 @@ Planner_Block_t *Planner_GetCurrentBlock(void)
uint8_t Planner_NextBlockIndex(uint8_t block_index)
{
block_index++;
if(block_index == BLOCK_BUFFER_SIZE) {
if(block_index == BLOCK_BUFFER_SIZE)
{
block_index = 0;
}
@ -318,7 +343,8 @@ float Planner_GetExecBlockExitSpeedSqr(void)
{
uint8_t block_index = Planner_NextBlockIndex(block_buffer_tail);
if(block_index == block_buffer_head) {
if(block_index == block_buffer_head)
{
return (0.0);
}
@ -332,18 +358,23 @@ float Planner_ComputeProfileNominalSpeed(Planner_Block_t *block)
{
float nominal_speed = block->programmed_rate;
if(block->condition & PL_COND_FLAG_RAPID_MOTION) {
if(block->condition & PL_COND_FLAG_RAPID_MOTION)
{
nominal_speed *= (0.01*sys.r_override);
}
else {
if(!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE)) {
else
{
if(!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE))
{
nominal_speed *= (0.01*sys.f_override);
}
if(nominal_speed > block->rapid_rate) {
if(nominal_speed > block->rapid_rate)
{
nominal_speed = block->rapid_rate;
}
}
if(nominal_speed > MINIMUM_FEED_RATE) {
if(nominal_speed > MINIMUM_FEED_RATE)
{
return nominal_speed;
}
@ -359,7 +390,8 @@ void Planner_UpdateVelocityProfileParams(void)
float nominal_speed;
float prev_nominal_speed = SOME_LARGE_VALUE; // Set high for first block nominal speed calculation.
while(block_index != block_buffer_head) {
while(block_index != block_buffer_head)
{
block = &block_buffer[block_index];
nominal_speed = Planner_ComputeProfileNominalSpeed(block);
Planner_ComputeProfileParams(block, nominal_speed, prev_nominal_speed);
@ -377,15 +409,19 @@ void Planner_SyncPosition(void)
// TODO: For motor configurations not in the same coordinate frame as the machine position,
// this function needs to be updated to accomodate the difference.
uint8_t idx;
for(idx = 0; idx < N_AXIS; idx++) {
for(idx = 0; idx < N_AXIS; idx++)
{
#ifdef COREXY
if(idx==X_AXIS) {
if(idx==X_AXIS)
{
planner.position[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
}
else if(idx==Y_AXIS) {
else if(idx==Y_AXIS)
{
planner.position[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
}
else {
else
{
planner.position[idx] = sys_position[idx];
}
#else
@ -409,7 +445,8 @@ void Planner_CycleReinitialize(void)
// Returns the number of available blocks are in the planner buffer.
uint8_t Planner_GetBlockBufferAvailable(void)
{
if(block_buffer_head >= block_buffer_tail) {
if(block_buffer_head >= block_buffer_tail)
{
return (BLOCK_BUFFER_SIZE-1)-(block_buffer_head-block_buffer_tail);
}
@ -421,7 +458,8 @@ uint8_t Planner_GetBlockBufferAvailable(void)
// NOTE: Deprecated. Not used unless classic status reports are enabled in config.h
uint8_t Planner_GetBlockBufferCount(void)
{
if(block_buffer_head >= block_buffer_tail) {
if(block_buffer_head >= block_buffer_tail)
{
return block_buffer_head-block_buffer_tail;
}
@ -432,7 +470,8 @@ uint8_t Planner_GetBlockBufferCount(void)
// Returns the availability status of the block ring buffer. True, if full.
uint8_t Planner_CheckBufferFull(void)
{
if(block_buffer_tail == next_buffer_head) {
if(block_buffer_tail == next_buffer_head)
{
return true;
}
@ -443,7 +482,8 @@ uint8_t Planner_CheckBufferFull(void)
// Returns the index of the previous block in the ring buffer
static uint8_t Planner_PrevBlockIndex(uint8_t block_index)
{
if(block_index == 0) {
if(block_index == 0)
{
block_index = BLOCK_BUFFER_SIZE;
}
block_index--;
@ -523,7 +563,8 @@ static void Planner_Recalculate(void)
uint8_t block_index = Planner_PrevBlockIndex(block_buffer_head);
// Bail. Can't do anything with only one plan-able block.
if(block_index == block_buffer_planned) {
if(block_index == block_buffer_planned)
{
return;
}
@ -538,28 +579,38 @@ static void Planner_Recalculate(void)
current->entry_speed_sqr = min( current->max_entry_speed_sqr, 2*current->acceleration*current->millimeters);
block_index = Planner_PrevBlockIndex(block_index);
if(block_index == block_buffer_planned) { // Only two plannable blocks in buffer. Reverse pass complete.
if(block_index == block_buffer_planned) // Only two plannable blocks in buffer. Reverse pass complete.
{
// Check if the first block is the tail. If so, notify stepper to update its current parameters.
if (block_index == block_buffer_tail) { Stepper_UpdatePlannerBlockParams(); }
if (block_index == block_buffer_tail)
{
Stepper_UpdatePlannerBlockParams();
}
else { // Three or more plan-able blocks
while (block_index != block_buffer_planned) {
}
else // Three or more plan-able blocks
{
while (block_index != block_buffer_planned)
{
next = current;
current = &block_buffer[block_index];
block_index = Planner_PrevBlockIndex(block_index);
// Check if next block is the tail block(=planned block). If so, update current stepper parameters.
if(block_index == block_buffer_tail) {
if(block_index == block_buffer_tail)
{
Stepper_UpdatePlannerBlockParams();
}
// Compute maximum entry speed decelerating over the current block from its exit speed.
if(current->entry_speed_sqr != current->max_entry_speed_sqr) {
if(current->entry_speed_sqr != current->max_entry_speed_sqr)
{
entry_speed_sqr = next->entry_speed_sqr + 2*current->acceleration*current->millimeters;
if(entry_speed_sqr < current->max_entry_speed_sqr) {
if(entry_speed_sqr < current->max_entry_speed_sqr)
{
current->entry_speed_sqr = entry_speed_sqr;
}
else {
else
{
current->entry_speed_sqr = current->max_entry_speed_sqr;
}
}
@ -570,18 +621,21 @@ static void Planner_Recalculate(void)
// Also scans for optimal plan breakpoints and appropriately updates the planned pointer.
next = &block_buffer[block_buffer_planned]; // Begin at buffer planned pointer
block_index = Planner_NextBlockIndex(block_buffer_planned);
while(block_index != block_buffer_head) {
while(block_index != block_buffer_head)
{
current = next;
next = &block_buffer[block_index];
// Any acceleration detected in the forward pass automatically moves the optimal planned
// pointer forward, since everything before this is all optimal. In other words, nothing
// can improve the plan from the buffer tail to the planned pointer by logic.
if (current->entry_speed_sqr < next->entry_speed_sqr) {
if (current->entry_speed_sqr < next->entry_speed_sqr)
{
entry_speed_sqr = current->entry_speed_sqr + 2*current->acceleration*current->millimeters;
// If true, current block is full-acceleration and we can move the planned pointer forward.
if(entry_speed_sqr < next->entry_speed_sqr) {
if(entry_speed_sqr < next->entry_speed_sqr)
{
next->entry_speed_sqr = entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
block_buffer_planned = block_index; // Set optimal plan pointer.
}
@ -591,7 +645,8 @@ static void Planner_Recalculate(void)
// point in the buffer. When the plan is bracketed by either the beginning of the
// buffer and a maximum entry speed or two maximum entry speeds, every block in between
// cannot logically be further improved. Hence, we don't have to recompute them anymore.
if(next->entry_speed_sqr == next->max_entry_speed_sqr) {
if(next->entry_speed_sqr == next->max_entry_speed_sqr)
{
block_buffer_planned = block_index;
}
block_index = Planner_NextBlockIndex( block_index );
@ -604,14 +659,17 @@ static void Planner_Recalculate(void)
static void Planner_ComputeProfileParams(Planner_Block_t *block, float nominal_speed, float prev_nominal_speed)
{
// Compute the junction maximum entry based on the minimum of the junction speed and neighboring nominal speeds.
if(nominal_speed > prev_nominal_speed) {
if(nominal_speed > prev_nominal_speed)
{
block->max_entry_speed_sqr = prev_nominal_speed*prev_nominal_speed;
}
else {
else
{
block->max_entry_speed_sqr = nominal_speed*nominal_speed;
}
if(block->max_entry_speed_sqr > block->max_junction_speed_sqr) {
if(block->max_entry_speed_sqr > block->max_junction_speed_sqr)
{
block->max_entry_speed_sqr = block->max_junction_speed_sqr;
}
}

Wyświetl plik

@ -46,7 +46,8 @@
// This struct stores a linear movement of a g-code block motion with its critical "nominal" values
// are as specified in the source g-code.
typedef struct {
typedef struct
{
// Fields used by the bresenham algorithm for tracing the line
// NOTE: Used by stepper algorithm to execute the block correctly. Do not alter these values.
uint32_t steps[N_AXIS]; // Step count along each axis
@ -79,7 +80,8 @@ typedef struct {
// Planner data prototype. Must be used when passing new motions to the planner.
typedef struct {
typedef struct
{
float feed_rate; // Desired feed rate for line motion. Value is ignored, if rapid motion.
float spindle_speed; // Desired spindle speed through line motion.
uint8_t condition; // Bitflag variable to indicate planner conditions. See defines above.

Wyświetl plik

@ -52,17 +52,20 @@ void Probe_ConfigureInvertMask(uint8_t is_probe_away)
{
probe_invert_mask = 0; // Initialize as zero.
if(BIT_IS_FALSE(settings.flags, BITFLAG_INVERT_PROBE_PIN)) {
if(BIT_IS_FALSE(settings.flags, BITFLAG_INVERT_PROBE_PIN))
{
probe_invert_mask ^= 1;
}
if(is_probe_away) {
if(is_probe_away)
{
probe_invert_mask ^= 1;
}
}
// Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
uint8_t Probe_GetState(void) {
uint8_t Probe_GetState(void)
{
return (GPIO_ReadInputDataBit(GPIO_PROBE_PORT, GPIO_PROBE_PIN) ^ probe_invert_mask);
}
@ -72,7 +75,8 @@ uint8_t Probe_GetState(void) {
// NOTE: This function must be extremely efficient as to not bog down the stepper ISR.
void Probe_StateMonitor(void)
{
if(Probe_GetState()) {
if(Probe_GetState())
{
sys_probe_state = PROBE_OFF;
memcpy(sys_probe_position, sys_position, sizeof(sys_position));
BIT_TRUE(sys_rt_exec_state, EXEC_MOTION_CANCEL);

Wyświetl plik

@ -66,8 +66,10 @@ void Protocol_MainLoop(void)
{
// Perform some machine checks to make sure everything is good to go.
#ifdef CHECK_LIMITS_AT_INIT
if(BIT_IS_TRUE(settings.flags, BITFLAG_HARD_LIMIT_ENABLE)) {
if(Limits_GetState()) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_HARD_LIMIT_ENABLE))
{
if(Limits_GetState())
{
sys.state = STATE_ALARM; // Ensure alarm state is active.
Report_FeedbackMessage(MESSAGE_CHECK_LIMITS);
}
@ -77,14 +79,17 @@ void Protocol_MainLoop(void)
// Check for and report alarm state after a reset, error, or an initial power up.
// NOTE: Sleep mode disables the stepper drivers and position can't be guaranteed.
// Re-initialize the sleep state as an ALARM mode to ensure user homes or acknowledges.
if(sys.state & (STATE_ALARM | STATE_SLEEP)) {
if(sys.state & (STATE_ALARM | STATE_SLEEP))
{
Report_FeedbackMessage(MESSAGE_ALARM_LOCK);
sys.state = STATE_ALARM; // Ensure alarm state is set.
}
else {
else
{
// Check if the safety door is open.
sys.state = STATE_IDLE;
if(System_CheckSafetyDoorAjar()) {
if(System_CheckSafetyDoorAjar())
{
BIT_TRUE(sys_rt_exec_state, EXEC_SAFETY_DOOR);
Protocol_ExecuteRealtime(); // Enter safety door mode. Should return as IDLE state.
}
@ -102,14 +107,18 @@ void Protocol_MainLoop(void)
char c;
for(;;) {
for(;;)
{
// Process one line of incoming serial data, as the data becomes available. Performs an
// initial filtering by removing spaces and comments and capitalizing all letters.
while(Getc(&c) == 0) {
if((c == '\n') || (c == '\r')) { // End of line reached
while(Getc(&c) == 0)
{
if((c == '\n') || (c == '\r')) // End of line reached
{
Protocol_ExecuteRealtime(); // Runtime command check point.
if(sys.abort) {
if(sys.abort)
{
// Bail to calling function upon system abort
return;
}
@ -121,23 +130,28 @@ void Protocol_MainLoop(void)
#endif
// Direct and execute one line of formatted input, and report status of execution.
if(line_flags & LINE_FLAG_OVERFLOW) {
if(line_flags & LINE_FLAG_OVERFLOW)
{
// Report line overflow error.
Report_StatusMessage(STATUS_OVERFLOW);
}
else if(line[0] == 0) {
else if(line[0] == 0)
{
// Empty or comment line. For syncing purposes.
Report_StatusMessage(STATUS_OK);
}
else if(line[0] == '$') {
else if(line[0] == '$')
{
// Grbl '$' system command
Report_StatusMessage(System_ExecuteLine(line));
}
else if(sys.state & (STATE_ALARM | STATE_JOG | STATE_TOOL_CHANGE)) {
else if(sys.state & (STATE_ALARM | STATE_JOG | STATE_TOOL_CHANGE))
{
// Everything else is gcode. Block if in alarm or jog mode.
Report_StatusMessage(STATUS_SYSTEM_GC_LOCK);
}
else {
else
{
// Parse and execute g-code block.
Report_StatusMessage(GC_ExecuteLine(line));
}
@ -147,32 +161,41 @@ void Protocol_MainLoop(void)
char_counter = 0;
}
else {
if(line_flags) {
else
{
if(line_flags)
{
// Throw away all (except EOL) comment characters and overflow characters.
if(c == ')') {
if(c == ')')
{
// End of '()' comment. Resume line allowed.
if (line_flags & LINE_FLAG_COMMENT_PARENTHESES) {
if (line_flags & LINE_FLAG_COMMENT_PARENTHESES)
{
line_flags &= ~(LINE_FLAG_COMMENT_PARENTHESES);
}
}
}
else {
if(c <= ' ') {
else
{
if(c <= ' ')
{
// Throw away whitepace and control characters
}
else if(c == '/') {
else if(c == '/')
{
// Block delete NOT SUPPORTED. Ignore character.
// NOTE: If supported, would simply need to check the system if block delete is enabled.
}
else if(c == '(') {
else if(c == '(')
{
// Enable comments flag and ignore all characters until ')' or EOL.
// NOTE: This doesn't follow the NIST definition exactly, but is good enough for now.
// In the future, we could simply remove the items within the comments, but retain the
// comment control characters, so that the g-code parser can error-check it.
line_flags |= LINE_FLAG_COMMENT_PARENTHESES;
}
else if(c == ';') {
else if(c == ';')
{
// NOTE: ';' comment to EOL is a LinuxCNC definition. Not NIST.
line_flags |= LINE_FLAG_COMMENT_SEMICOLON;
// TODO: Install '%' feature
@ -183,14 +206,17 @@ void Protocol_MainLoop(void)
// everything until the next '%' sign. This will help fix resuming issues with certain
// functions that empty the planner buffer to execute its task on-time.
}
else if(char_counter >= (LINE_BUFFER_SIZE-1)) {
else if(char_counter >= (LINE_BUFFER_SIZE-1))
{
// Detect line buffer overflow and set flag.
line_flags |= LINE_FLAG_OVERFLOW;
}
else if(c >= 'a' && c <= 'z') { // Upcase lowercase
else if(c >= 'a' && c <= 'z') // Upcase lowercase
{
line[char_counter++] = c-'a'+'A';
}
else {
else
{
line[char_counter++] = c;
}
}
@ -204,7 +230,8 @@ void Protocol_MainLoop(void)
Protocol_ExecuteRealtime(); // Runtime command check point.
if(sys.abort) {
if(sys.abort)
{
// Bail to main() program loop to reset system.
return;
}
@ -220,14 +247,17 @@ void Protocol_BufferSynchronize(void)
{
// If system is queued, ensure cycle resumes if the auto start flag is present.
Protocol_AutoCycleStart();
do {
do
{
Protocol_ExecuteRealtime(); // Check and execute run-time commands
if(sys.abort) {
if(sys.abort)
{
// Check for system abort
return;
}
} while(Planner_GetCurrentBlock() || (sys.state == STATE_CYCLE));
}
while(Planner_GetCurrentBlock() || (sys.state == STATE_CYCLE));
}
@ -239,7 +269,8 @@ void Protocol_BufferSynchronize(void)
// execute calls a buffer sync, or the planner buffer is full and ready to go.
void Protocol_AutoCycleStart(void)
{
if(Planner_GetCurrentBlock() != 0) { // Check if there are any blocks in the buffer.
if(Planner_GetCurrentBlock() != 0) // Check if there are any blocks in the buffer.
{
System_SetExecStateFlag(EXEC_CYCLE_START); // If so, execute them!
}
}
@ -276,7 +307,8 @@ void Protocol_ExecuteRealtime(void)
(void)packet;
#endif
if(sys.suspend) {
if(sys.suspend)
{
Protocol_ExecRtSuspend();
}
}
@ -290,7 +322,8 @@ void Protocol_ExecRtSystem(void)
uint8_t rt_exec; // Temp variable to avoid calling volatile multiple times.
rt_exec = sys_rt_exec_alarm; // Copy volatile sys_rt_exec_alarm.
if(rt_exec) { // Enter only if any bit flag is true
if(rt_exec) // Enter only if any bit flag is true
{
// System alarm. Everything has shutdown by something that has gone severely wrong. Report
// the source of the error to the user. If critical, Grbl disables by entering an infinite
// loop until system reset/abort.
@ -298,50 +331,62 @@ void Protocol_ExecRtSystem(void)
Report_AlarmMessage(rt_exec);
// Halt everything upon a critical event flag. Currently hard and soft limits flag this.
if((rt_exec == EXEC_ALARM_HARD_LIMIT) || (rt_exec == EXEC_ALARM_SOFT_LIMIT)) {
if((rt_exec == EXEC_ALARM_HARD_LIMIT) || (rt_exec == EXEC_ALARM_SOFT_LIMIT))
{
Report_FeedbackMessage(MESSAGE_CRITICAL_EVENT);
System_ClearExecStateFlag(EXEC_RESET); // Disable any existing reset
do {
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
// the user and a GUI time to do what is needed before resetting, like killing the
// incoming stream. The same could be said about soft limits. While the position is not
// lost, continued streaming could cause a serious crash if by chance it gets executed.
} while(BIT_IS_FALSE(sys_rt_exec_state, EXEC_RESET));
}
while(BIT_IS_FALSE(sys_rt_exec_state, EXEC_RESET));
}
System_ClearExecAlarm(); // Clear alarm
}
rt_exec = sys_rt_exec_state; // Copy volatile sys_rt_exec_state.
if(rt_exec) {
if(rt_exec)
{
// Execute system abort.
if(rt_exec & EXEC_RESET) {
if(rt_exec & EXEC_RESET)
{
sys.abort = true; // Only place this is set true.
return; // Nothing else to do but exit.
}
// Execute and serial print status
if(rt_exec & EXEC_STATUS_REPORT) {
if(rt_exec & EXEC_STATUS_REPORT)
{
Report_RealtimeStatus();
System_ClearExecStateFlag(EXEC_STATUS_REPORT);
}
// NOTE: Once hold is initiated, the system immediately enters a suspend state to block all
// main program processes until either reset or resumed. This ensures a hold completes safely.
if(rt_exec & (EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR | EXEC_SLEEP)) {
if(rt_exec & (EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR | EXEC_SLEEP))
{
// State check for allowable states for hold methods.
if(!(sys.state & (STATE_ALARM | STATE_CHECK_MODE))) {
if(!(sys.state & (STATE_ALARM | STATE_CHECK_MODE)))
{
// If in CYCLE or JOG states, immediately initiate a motion HOLD.
if(sys.state & (STATE_CYCLE | STATE_JOG)) {
if(!(sys.suspend & (SUSPEND_MOTION_CANCEL | SUSPEND_JOG_CANCEL))) { // Block, if already holding.
if(sys.state & (STATE_CYCLE | STATE_JOG))
{
if(!(sys.suspend & (SUSPEND_MOTION_CANCEL | SUSPEND_JOG_CANCEL))) // Block, if already holding.
{
Stepper_UpdatePlannerBlockParams(); // Notify stepper module to recompute for hold deceleration.
sys.step_control = STEP_CONTROL_EXECUTE_HOLD; // Initiate suspend state with active flag.
if(sys.state == STATE_JOG) { // Jog cancelled upon any hold event, except for sleeping.
if (!(rt_exec & EXEC_SLEEP)) {
if(sys.state == STATE_JOG) // Jog cancelled upon any hold event, except for sleeping.
{
if (!(rt_exec & EXEC_SLEEP))
{
sys.suspend |= SUSPEND_JOG_CANCEL;
}
}
@ -349,25 +394,30 @@ void Protocol_ExecRtSystem(void)
}
// If IDLE, Grbl is not in motion. Simply indicate suspend state and hold is complete.
if(sys.state == STATE_IDLE) {
if(sys.state == STATE_IDLE)
{
sys.suspend = SUSPEND_HOLD_COMPLETE;
}
// Execute and flag a motion cancel with deceleration and return to idle. Used primarily by probing cycle
// to halt and cancel the remainder of the motion.
if(rt_exec & EXEC_MOTION_CANCEL) {
if(rt_exec & EXEC_MOTION_CANCEL)
{
// MOTION_CANCEL only occurs during a CYCLE, but a HOLD and SAFETY_DOOR may been initiated beforehand
// to hold the CYCLE. Motion cancel is valid for a single planner block motion only, while jog cancel
// will handle and clear multiple planner block motions.
if(!(sys.state & STATE_JOG)) {
if(!(sys.state & STATE_JOG))
{
sys.suspend |= SUSPEND_MOTION_CANCEL;
} // NOTE: State is STATE_CYCLE.
}
// Execute a feed hold with deceleration, if required. Then, suspend system.
if(rt_exec & EXEC_FEED_HOLD) {
if(rt_exec & EXEC_FEED_HOLD)
{
// Block SAFETY_DOOR, JOG, and SLEEP states from changing to HOLD state.
if(!(sys.state & (STATE_SAFETY_DOOR | STATE_JOG | STATE_SLEEP))) {
if(!(sys.state & (STATE_SAFETY_DOOR | STATE_JOG | STATE_SLEEP)))
{
sys.state = STATE_HOLD;
}
}
@ -375,18 +425,23 @@ void Protocol_ExecRtSystem(void)
// Execute a safety door stop with a feed hold and disable spindle/coolant.
// NOTE: Safety door differs from feed holds by stopping everything no matter state, disables powered
// devices (spindle/coolant), and blocks resuming until switch is re-engaged.
if(rt_exec & EXEC_SAFETY_DOOR) {
if(rt_exec & EXEC_SAFETY_DOOR)
{
Report_FeedbackMessage(MESSAGE_SAFETY_DOOR_AJAR);
// If jogging, block safety door methods until jog cancel is complete. Just flag that it happened.
if(!(sys.suspend & SUSPEND_JOG_CANCEL)) {
if(!(sys.suspend & SUSPEND_JOG_CANCEL))
{
// Check if the safety re-opened during a restore parking motion only. Ignore if
// already retracting, parked or in sleep state.
if(sys.state == STATE_SAFETY_DOOR) {
if(sys.suspend & SUSPEND_INITIATE_RESTORE) { // Actively restoring
if(sys.state == STATE_SAFETY_DOOR)
{
if(sys.suspend & SUSPEND_INITIATE_RESTORE) // Actively restoring
{
#ifdef PARKING_ENABLE
// Set hold and reset appropriate control flags to restart parking sequence.
if(sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) {
if(sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION)
{
Stepper_UpdatePlannerBlockParams(); // Notify stepper module to recompute for hold deceleration.
sys.step_control = (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION);
sys.suspend &= ~(SUSPEND_HOLD_COMPLETE);
@ -397,7 +452,8 @@ void Protocol_ExecRtSystem(void)
}
}
if(sys.state != STATE_SLEEP) {
if(sys.state != STATE_SLEEP)
{
sys.state = STATE_SAFETY_DOOR;
}
}
@ -407,8 +463,10 @@ void Protocol_ExecRtSystem(void)
}
}
if(rt_exec & EXEC_SLEEP) {
if(sys.state == STATE_ALARM) {
if(rt_exec & EXEC_SLEEP)
{
if(sys.state == STATE_ALARM)
{
sys.suspend |= (SUSPEND_RETRACT_COMPLETE | SUSPEND_HOLD_COMPLETE);
}
@ -419,16 +477,21 @@ void Protocol_ExecRtSystem(void)
}
// Execute a cycle start by starting the stepper interrupt to begin executing the blocks in queue.
if(rt_exec & EXEC_CYCLE_START) {
if(rt_exec & EXEC_CYCLE_START)
{
// Block if called at same time as the hold commands: feed hold, motion cancel, and safety door.
// Ensures auto-cycle-start doesn't resume a hold without an explicit user-input.
if(!(rt_exec & (EXEC_FEED_HOLD | EXEC_MOTION_CANCEL | EXEC_SAFETY_DOOR))) {
if(!(rt_exec & (EXEC_FEED_HOLD | EXEC_MOTION_CANCEL | EXEC_SAFETY_DOOR)))
{
// Resume door state when parking motion has retracted and door has been closed.
if((sys.state == STATE_SAFETY_DOOR) && !(sys.suspend & SUSPEND_SAFETY_DOOR_AJAR)) {
if(sys.suspend & SUSPEND_RESTORE_COMPLETE) {
if((sys.state == STATE_SAFETY_DOOR) && !(sys.suspend & SUSPEND_SAFETY_DOOR_AJAR))
{
if(sys.suspend & SUSPEND_RESTORE_COMPLETE)
{
sys.state = STATE_IDLE; // Set to IDLE to immediately resume the cycle.
}
else if(sys.suspend & SUSPEND_RETRACT_COMPLETE) {
else if(sys.suspend & SUSPEND_RETRACT_COMPLETE)
{
// Flag to re-energize powered components and restore original position, if disabled by SAFETY_DOOR.
// NOTE: For a safety door to resume, the switch must be closed, as indicated by HOLD state, and
// the retraction execution is complete, which implies the initial feed hold is not active. To
@ -439,21 +502,26 @@ void Protocol_ExecRtSystem(void)
}
// Cycle start only when IDLE or when a hold is complete and ready to resume.
if((sys.state == STATE_IDLE) || ((sys.state & STATE_HOLD) && (sys.suspend & SUSPEND_HOLD_COMPLETE))) {
if (sys.state == STATE_HOLD && sys.spindle_stop_ovr) {
if((sys.state == STATE_IDLE) || ((sys.state & STATE_HOLD) && (sys.suspend & SUSPEND_HOLD_COMPLETE)))
{
if (sys.state == STATE_HOLD && sys.spindle_stop_ovr)
{
sys.spindle_stop_ovr |= SPINDLE_STOP_OVR_RESTORE_CYCLE; // Set to restore in suspend routine and cycle start after.
}
else {
else
{
// Start cycle only if queued motions exist in planner buffer and the motion is not canceled.
sys.step_control = STEP_CONTROL_NORMAL_OP; // Restore step control to normal operation
if(Planner_GetCurrentBlock() && BIT_IS_FALSE(sys.suspend, SUSPEND_MOTION_CANCEL)) {
if(Planner_GetCurrentBlock() && BIT_IS_FALSE(sys.suspend, SUSPEND_MOTION_CANCEL))
{
sys.suspend = SUSPEND_DISABLE; // Break suspend state.
sys.state = STATE_CYCLE;
Stepper_PrepareBuffer(); // Initialize step segment buffer before beginning cycle.
Stepper_WakeUp();
}
else { // Otherwise, do nothing. Set and resume IDLE state.
else // Otherwise, do nothing. Set and resume IDLE state.
{
sys.suspend = SUSPEND_DISABLE; // Break suspend state.
sys.state = STATE_IDLE;
}
@ -464,24 +532,31 @@ void Protocol_ExecRtSystem(void)
System_ClearExecStateFlag(EXEC_CYCLE_START);
}
if(rt_exec & EXEC_CYCLE_STOP) {
if(rt_exec & EXEC_CYCLE_STOP)
{
// Reinitializes the cycle plan and stepper system after a feed hold for a resume. Called by
// realtime command execution in the main program, ensuring that the planner re-plans safely.
// NOTE: Bresenham algorithm variables are still maintained through both the planner and stepper
// cycle reinitializations. The stepper path should continue exactly as if nothing has happened.
// NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
if((sys.state & (STATE_HOLD|STATE_SAFETY_DOOR|STATE_SLEEP)) && !(sys.soft_limit) && !(sys.suspend & SUSPEND_JOG_CANCEL)) {
if((sys.state & (STATE_HOLD|STATE_SAFETY_DOOR|STATE_SLEEP)) && !(sys.soft_limit) && !(sys.suspend & SUSPEND_JOG_CANCEL))
{
// Hold complete. Set to indicate ready to resume. Remain in HOLD or DOOR states until user
// has issued a resume command or reset.
Planner_CycleReinitialize();
if(sys.step_control & STEP_CONTROL_EXECUTE_HOLD) { sys.suspend |= SUSPEND_HOLD_COMPLETE; }
if(sys.step_control & STEP_CONTROL_EXECUTE_HOLD)
{
sys.suspend |= SUSPEND_HOLD_COMPLETE;
}
BIT_FALSE(sys.step_control,(STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION));
}
else {
else
{
// Motion complete. Includes CYCLE/JOG/HOMING states and jog cancel/motion cancel/soft limit events.
// NOTE: Motion and jog cancel both immediately return to idle after the hold completes.
if(sys.suspend & SUSPEND_JOG_CANCEL) { // For jog cancel, flush buffers and sync positions.
if(sys.suspend & SUSPEND_JOG_CANCEL) // For jog cancel, flush buffers and sync positions.
{
sys.step_control = STEP_CONTROL_NORMAL_OP;
Planner_Reset();
Stepper_Reset();
@ -490,12 +565,14 @@ void Protocol_ExecRtSystem(void)
MC_SyncBacklashPosition();
}
if(sys.suspend & SUSPEND_SAFETY_DOOR_AJAR) { // Only occurs when safety door opens during jog.
if(sys.suspend & SUSPEND_SAFETY_DOOR_AJAR) // Only occurs when safety door opens during jog.
{
sys.suspend &= ~(SUSPEND_JOG_CANCEL);
sys.suspend |= SUSPEND_HOLD_COMPLETE;
sys.state = STATE_SAFETY_DOOR;
}
else {
else
{
sys.suspend = SUSPEND_DISABLE;
sys.state = STATE_IDLE;
}
@ -507,24 +584,30 @@ void Protocol_ExecRtSystem(void)
// Execute overrides.
rt_exec = sys_rt_exec_motion_override; // Copy volatile sys_rt_exec_motion_override
if(rt_exec) {
if(rt_exec)
{
System_ClearExecMotionOverride(); // Clear all motion override flags.
uint8_t new_f_override = sys.f_override;
if(rt_exec & EXEC_FEED_OVR_RESET) {
if(rt_exec & EXEC_FEED_OVR_RESET)
{
new_f_override = DEFAULT_FEED_OVERRIDE;
}
if(rt_exec & EXEC_FEED_OVR_COARSE_PLUS) {
if(rt_exec & EXEC_FEED_OVR_COARSE_PLUS)
{
new_f_override += FEED_OVERRIDE_COARSE_INCREMENT;
}
if(rt_exec & EXEC_FEED_OVR_COARSE_MINUS) {
if(rt_exec & EXEC_FEED_OVR_COARSE_MINUS)
{
new_f_override -= FEED_OVERRIDE_COARSE_INCREMENT;
}
if(rt_exec & EXEC_FEED_OVR_FINE_PLUS) {
if(rt_exec & EXEC_FEED_OVR_FINE_PLUS)
{
new_f_override += FEED_OVERRIDE_FINE_INCREMENT;
}
if(rt_exec & EXEC_FEED_OVR_FINE_MINUS) {
if(rt_exec & EXEC_FEED_OVR_FINE_MINUS)
{
new_f_override -= FEED_OVERRIDE_FINE_INCREMENT;
}
@ -533,17 +616,21 @@ void Protocol_ExecRtSystem(void)
uint8_t new_r_override = sys.r_override;
if(rt_exec & EXEC_RAPID_OVR_RESET) {
if(rt_exec & EXEC_RAPID_OVR_RESET)
{
new_r_override = DEFAULT_RAPID_OVERRIDE;
}
if(rt_exec & EXEC_RAPID_OVR_MEDIUM) {
if(rt_exec & EXEC_RAPID_OVR_MEDIUM)
{
new_r_override = RAPID_OVERRIDE_MEDIUM;
}
if(rt_exec & EXEC_RAPID_OVR_LOW) {
if(rt_exec & EXEC_RAPID_OVR_LOW)
{
new_r_override = RAPID_OVERRIDE_LOW;
}
if((new_f_override != sys.f_override) || (new_r_override != sys.r_override)) {
if((new_f_override != sys.f_override) || (new_r_override != sys.r_override))
{
sys.f_override = new_f_override;
sys.r_override = new_r_override;
sys.report_ovr_counter = 0; // Set to report change immediately
@ -554,51 +641,64 @@ void Protocol_ExecRtSystem(void)
}
rt_exec = sys_rt_exec_accessory_override;
if(rt_exec) {
if(rt_exec)
{
System_ClearExecAccessoryOverrides(); // Clear all accessory override flags.
// NOTE: Unlike motion overrides, spindle overrides do not require a planner reinitialization.
uint8_t last_s_override = sys.spindle_speed_ovr;
if(rt_exec & EXEC_SPINDLE_OVR_RESET) {
if(rt_exec & EXEC_SPINDLE_OVR_RESET)
{
last_s_override = DEFAULT_SPINDLE_SPEED_OVERRIDE;
}
if(rt_exec & EXEC_SPINDLE_OVR_COARSE_PLUS) {
if(rt_exec & EXEC_SPINDLE_OVR_COARSE_PLUS)
{
last_s_override += SPINDLE_OVERRIDE_COARSE_INCREMENT;
}
if(rt_exec & EXEC_SPINDLE_OVR_COARSE_MINUS) {
if(rt_exec & EXEC_SPINDLE_OVR_COARSE_MINUS)
{
last_s_override -= SPINDLE_OVERRIDE_COARSE_INCREMENT;
}
if(rt_exec & EXEC_SPINDLE_OVR_FINE_PLUS) {
if(rt_exec & EXEC_SPINDLE_OVR_FINE_PLUS)
{
last_s_override += SPINDLE_OVERRIDE_FINE_INCREMENT;
}
if(rt_exec & EXEC_SPINDLE_OVR_FINE_MINUS) {
if(rt_exec & EXEC_SPINDLE_OVR_FINE_MINUS)
{
last_s_override -= SPINDLE_OVERRIDE_FINE_INCREMENT;
}
last_s_override = min(last_s_override,MAX_SPINDLE_SPEED_OVERRIDE);
last_s_override = max(last_s_override,MIN_SPINDLE_SPEED_OVERRIDE);
if(last_s_override != sys.spindle_speed_ovr) {
if(last_s_override != sys.spindle_speed_ovr)
{
sys.spindle_speed_ovr = last_s_override;
// NOTE: Spindle speed overrides during HOLD state are taken care of by suspend function.
if (sys.state == STATE_IDLE) {
if (sys.state == STATE_IDLE)
{
Spindle_SetState(gc_state.modal.spindle, gc_state.spindle_speed);
}
else {
else
{
BIT_TRUE(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
}
sys.report_ovr_counter = 0; // Set to report change immediately
}
if(rt_exec & EXEC_SPINDLE_OVR_STOP) {
if(rt_exec & EXEC_SPINDLE_OVR_STOP)
{
// Spindle stop override allowed only while in HOLD state.
// NOTE: Report counters are set in spindle_set_state() when spindle stop is executed.
if(sys.state == STATE_HOLD) {
if(!(sys.spindle_stop_ovr)) {
if(sys.state == STATE_HOLD)
{
if(!(sys.spindle_stop_ovr))
{
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_INITIATE;
}
else if(sys.spindle_stop_ovr & SPINDLE_STOP_OVR_ENABLED) {
else if(sys.spindle_stop_ovr & SPINDLE_STOP_OVR_ENABLED)
{
sys.spindle_stop_ovr |= SPINDLE_STOP_OVR_RESTORE;
}
}
@ -607,32 +707,42 @@ void Protocol_ExecRtSystem(void)
// NOTE: Since coolant state always performs a planner sync whenever it changes, the current
// run state can be determined by checking the parser state.
// NOTE: Coolant overrides only operate during IDLE, CYCLE, HOLD, and JOG states. Ignored otherwise.
if(rt_exec & (EXEC_COOLANT_FLOOD_OVR_TOGGLE | EXEC_COOLANT_MIST_OVR_TOGGLE)) {
if((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_JOG))) {
if(rt_exec & (EXEC_COOLANT_FLOOD_OVR_TOGGLE | EXEC_COOLANT_MIST_OVR_TOGGLE))
{
if((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_JOG)))
{
uint8_t coolant_state = gc_state.modal.coolant;
#ifdef ENABLE_M7
if(rt_exec & EXEC_COOLANT_MIST_OVR_TOGGLE) {
if(coolant_state & COOLANT_MIST_ENABLE) {
if(rt_exec & EXEC_COOLANT_MIST_OVR_TOGGLE)
{
if(coolant_state & COOLANT_MIST_ENABLE)
{
BIT_FALSE(coolant_state,COOLANT_MIST_ENABLE);
}
else {
else
{
coolant_state |= COOLANT_MIST_ENABLE;
}
}
if(rt_exec & EXEC_COOLANT_FLOOD_OVR_TOGGLE) {
if(coolant_state & COOLANT_FLOOD_ENABLE) {
if(rt_exec & EXEC_COOLANT_FLOOD_OVR_TOGGLE)
{
if(coolant_state & COOLANT_FLOOD_ENABLE)
{
BIT_FALSE(coolant_state,COOLANT_FLOOD_ENABLE);
}
else {
else
{
coolant_state |= COOLANT_FLOOD_ENABLE;
}
}
#else
if(coolant_state & COOLANT_FLOOD_ENABLE) {
if(coolant_state & COOLANT_FLOOD_ENABLE)
{
BIT_FALSE(coolant_state,COOLANT_FLOOD_ENABLE);
}
else {
else
{
coolant_state |= COOLANT_FLOOD_ENABLE;
}
#endif
@ -643,14 +753,16 @@ void Protocol_ExecRtSystem(void)
}
#ifdef DEBUG
if(sys_rt_exec_debug) {
if(sys_rt_exec_debug)
{
Report_RealtimeDebug();
sys_rt_exec_debug = 0;
}
#endif
// Reload step segment buffer
if(sys.state & (STATE_CYCLE | STATE_HOLD | STATE_SAFETY_DOOR | STATE_HOMING | STATE_SLEEP| STATE_JOG)) {
if(sys.state & (STATE_CYCLE | STATE_HOLD | STATE_SAFETY_DOOR | STATE_HOMING | STATE_SLEEP| STATE_JOG))
{
Stepper_PrepareBuffer();
}
}
@ -681,22 +793,27 @@ static void Protocol_ExecRtSuspend(void)
RX_Packet_t packet;
float restore_spindle_speed;
if(block == 0) {
if(block == 0)
{
restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant);
restore_spindle_speed = gc_state.spindle_speed;
}
else {
else
{
restore_condition = (block->condition & PL_COND_SPINDLE_MASK) | Coolant_GetState();
restore_spindle_speed = block->spindle_speed;
}
#ifdef DISABLE_LASER_DURING_HOLD
if(BIT_IS_TRUE(settings.flags, BITFLAG_LASER_MODE)) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_LASER_MODE))
{
System_SetExecAccessoryOverrideFlag(EXEC_SPINDLE_OVR_STOP);
}
#endif
while(sys.suspend) {
if(sys.abort) {
while(sys.suspend)
{
if(sys.abort)
{
return;
}
@ -715,12 +832,15 @@ static void Protocol_ExecRtSuspend(void)
#endif
// Block until initial hold is complete and the machine has stopped motion.
if(sys.suspend & SUSPEND_HOLD_COMPLETE) {
if(sys.suspend & SUSPEND_HOLD_COMPLETE)
{
// Parking manager. Handles de/re-energizing, switch state checks, and parking motions for
// the safety door and sleep states.
if(sys.state & (STATE_SAFETY_DOOR | STATE_SLEEP)) {
if(sys.state & (STATE_SAFETY_DOOR | STATE_SLEEP))
{
// Handles retraction motions and de-energizing.
if(BIT_IS_FALSE(sys.suspend,SUSPEND_RETRACT_COMPLETE)) {
if(BIT_IS_FALSE(sys.suspend,SUSPEND_RETRACT_COMPLETE))
{
// Ensure any prior spindle stop override is disabled at start of safety door routine.
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED;
@ -732,7 +852,8 @@ static void Protocol_ExecRtSuspend(void)
// Get current position and store restore location and spindle retract waypoint.
System_ConvertArraySteps2Mpos(parking_target,sys_position);
if(BIT_IS_FALSE(sys.suspend,SUSPEND_RESTART_RETRACT)) {
if(BIT_IS_FALSE(sys.suspend,SUSPEND_RESTART_RETRACT))
{
memcpy(restore_target,parking_target,sizeof(parking_target));
retract_waypoint += restore_target[PARKING_AXIS];
@ -746,15 +867,18 @@ static void Protocol_ExecRtSuspend(void)
if((BIT_IS_TRUE(settings.flags, BITFLAG_HOMING_ENABLE)) &&
(parking_target[PARKING_AXIS] < PARKING_TARGET) &&
BIT_IS_FALSE(settings.flags,BITFLAG_LASER_MODE) &&
(sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
(sys.override_ctrl == OVERRIDE_PARKING_MOTION))
{
#else
if((BIT_IS_TRUE(settings.flags, BITFLAG_HOMING_ENABLE)) &&
(parking_target[PARKING_AXIS] < PARKING_TARGET) &&
BIT_IS_FALSE(settings.flags,BITFLAG_LASER_MODE)) {
BIT_IS_FALSE(settings.flags,BITFLAG_LASER_MODE))
{
#endif
// Retract spindle by pullout distance. Ensure retraction motion moves away from
// the workpiece and waypoint motion doesn't exceed the parking target location.
if(parking_target[PARKING_AXIS] < retract_waypoint) {
if(parking_target[PARKING_AXIS] < retract_waypoint)
{
parking_target[PARKING_AXIS] = retract_waypoint;
pl_data->feed_rate = PARKING_PULLOUT_RATE;
pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Retain accessory state
@ -770,13 +894,15 @@ static void Protocol_ExecRtSuspend(void)
Coolant_SetState(COOLANT_DISABLE); // De-energize
// Execute fast parking retract motion to parking target location.
if(parking_target[PARKING_AXIS] < PARKING_TARGET) {
if(parking_target[PARKING_AXIS] < PARKING_TARGET)
{
parking_target[PARKING_AXIS] = PARKING_TARGET;
pl_data->feed_rate = PARKING_RATE;
MC_ParkingMotion(parking_target, pl_data);
}
}
else {
else
{
// Parking motion not possible. Just disable the spindle and coolant.
// NOTE: Laser mode does not start a parking motion to ensure the laser stops immediately.
Spindle_SetState(SPINDLE_DISABLE, 0.0); // De-energize
@ -790,8 +916,10 @@ static void Protocol_ExecRtSuspend(void)
sys.suspend |= SUSPEND_RETRACT_COMPLETE;
}
else {
if(sys.state == STATE_SLEEP) {
else
{
if(sys.state == STATE_SLEEP)
{
Report_FeedbackMessage(MESSAGE_SLEEP_MODE);
// Spindle and coolant should already be stopped, but do it again just to be sure.
@ -799,7 +927,8 @@ static void Protocol_ExecRtSuspend(void)
Coolant_SetState(COOLANT_DISABLE); // De-energize
Stepper_Disable(0); // Disable steppers
while(!(sys.abort)) {
while(!(sys.abort))
{
Protocol_ExecRtSystem();
} // Do nothing until reset.
@ -807,26 +936,32 @@ static void Protocol_ExecRtSuspend(void)
}
// Allows resuming from parking/safety door. Actively checks if safety door is closed and ready to resume.
if(sys.state == STATE_SAFETY_DOOR) {
if(!(System_CheckSafetyDoorAjar())) {
if(sys.state == STATE_SAFETY_DOOR)
{
if(!(System_CheckSafetyDoorAjar()))
{
sys.suspend &= ~(SUSPEND_SAFETY_DOOR_AJAR); // Reset door ajar flag to denote ready to resume.
}
}
// Handles parking restore and safety door resume.
if(sys.suspend & SUSPEND_INITIATE_RESTORE) {
if(sys.suspend & SUSPEND_INITIATE_RESTORE)
{
#ifdef PARKING_ENABLE
// Execute fast restore motion to the pull-out position. Parking requires homing enabled.
// NOTE: State is will remain DOOR, until the de-energizing and retract is complete.
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
if(((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
(sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
(sys.override_ctrl == OVERRIDE_PARKING_MOTION))
{
#else
if((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
if((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE)
{
#endif
// Check to ensure the motion doesn't move below pull-out position.
if(parking_target[PARKING_AXIS] <= PARKING_TARGET) {
if(parking_target[PARKING_AXIS] <= PARKING_TARGET)
{
parking_target[PARKING_AXIS] = retract_waypoint;
pl_data->feed_rate = PARKING_RATE;
@ -836,23 +971,29 @@ static void Protocol_ExecRtSuspend(void)
#endif
// Delayed Tasks: Restart spindle and coolant, delay to power-up, then resume cycle.
if(gc_state.modal.spindle != SPINDLE_DISABLE) {
if(gc_state.modal.spindle != SPINDLE_DISABLE)
{
// Block if safety door re-opened during prior restore actions.
if(BIT_IS_FALSE(sys.suspend,SUSPEND_RESTART_RETRACT)) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_LASER_MODE)) {
if(BIT_IS_FALSE(sys.suspend,SUSPEND_RESTART_RETRACT))
{
if(BIT_IS_TRUE(settings.flags, BITFLAG_LASER_MODE))
{
// When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
BIT_TRUE(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
}
else {
else
{
Spindle_SetState((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
Delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DELAY_MODE_SYS_SUSPEND);
}
}
}
if(gc_state.modal.coolant != COOLANT_DISABLE) {
if(gc_state.modal.coolant != COOLANT_DISABLE)
{
// Block if safety door re-opened during prior restore actions.
if(BIT_IS_FALSE(sys.suspend, SUSPEND_RESTART_RETRACT)) {
if(BIT_IS_FALSE(sys.suspend, SUSPEND_RESTART_RETRACT))
{
// NOTE: Laser mode will honor this delay. An exhaust system is often controlled by this pin.
Coolant_SetState((restore_condition & (PL_COND_FLAG_COOLANT_FLOOD | PL_COND_FLAG_COOLANT_MIST)));
Delay_sec(SAFETY_DOOR_COOLANT_DELAY, DELAY_MODE_SYS_SUSPEND);
@ -863,12 +1004,15 @@ static void Protocol_ExecRtSuspend(void)
// Execute slow plunge motion from pull-out position to resume position.
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
if(((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
(sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
(sys.override_ctrl == OVERRIDE_PARKING_MOTION))
{
#else
if((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
if((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE)
{
#endif
// Block if safety door re-opened during prior restore actions.
if(BIT_IS_FALSE(sys.suspend,SUSPEND_RESTART_RETRACT)) {
if(BIT_IS_FALSE(sys.suspend,SUSPEND_RESTART_RETRACT))
{
// Regardless if the retract parking motion was a valid/safe motion or not, the
// restore parking motion should logically be valid, either by returning to the
// original position through valid machine space or by not moving at all.
@ -881,7 +1025,8 @@ static void Protocol_ExecRtSuspend(void)
}
#endif
if(BIT_IS_FALSE(sys.suspend, SUSPEND_RESTART_RETRACT)) {
if(BIT_IS_FALSE(sys.suspend, SUSPEND_RESTART_RETRACT))
{
sys.suspend |= SUSPEND_RESTORE_COMPLETE;
System_SetExecStateFlag(EXEC_CYCLE_START); // Set to resume program.
}
@ -889,43 +1034,55 @@ static void Protocol_ExecRtSuspend(void)
}
}
else {
else
{
// Feed hold manager. Controls spindle stop override states.
// NOTE: Hold ensured as completed by condition check at the beginning of suspend routine.
if(sys.spindle_stop_ovr) {
if(sys.spindle_stop_ovr)
{
// Handles beginning of spindle stop
if(sys.spindle_stop_ovr & SPINDLE_STOP_OVR_INITIATE) {
if(gc_state.modal.spindle != SPINDLE_DISABLE) {
if(sys.spindle_stop_ovr & SPINDLE_STOP_OVR_INITIATE)
{
if(gc_state.modal.spindle != SPINDLE_DISABLE)
{
Spindle_SetState(SPINDLE_DISABLE,0.0); // De-energize
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_ENABLED; // Set stop override state to enabled, if de-energized.
}
else {
else
{
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
}
// Handles restoring of spindle state
}
else if(sys.spindle_stop_ovr & (SPINDLE_STOP_OVR_RESTORE | SPINDLE_STOP_OVR_RESTORE_CYCLE)) {
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
else if(sys.spindle_stop_ovr & (SPINDLE_STOP_OVR_RESTORE | SPINDLE_STOP_OVR_RESTORE_CYCLE))
{
if (gc_state.modal.spindle != SPINDLE_DISABLE)
{
Report_FeedbackMessage(MESSAGE_SPINDLE_RESTORE);
if(BIT_IS_TRUE(settings.flags, BITFLAG_LASER_MODE)) {
if(BIT_IS_TRUE(settings.flags, BITFLAG_LASER_MODE))
{
// When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
BIT_TRUE(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
}
else {
else
{
Spindle_SetState((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
}
}
if(sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE) {
if(sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE)
{
System_SetExecStateFlag(EXEC_CYCLE_START); // Set to resume program.
}
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
}
}
else {
else
{
// Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state.
// NOTE: STEP_CONTROL_UPDATE_SPINDLE_PWM is automatically reset upon resume in step generator.
if(BIT_IS_TRUE(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
if(BIT_IS_TRUE(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM))
{
Spindle_SetState((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
BIT_FALSE(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
}

Wyświetl plik

@ -89,10 +89,12 @@ static void Report_AxisValue(float *axis_value)
axis_num = N_AXIS;
#endif
for(idx = 0; idx < axis_num; idx++) {
for(idx = 0; idx < axis_num; idx++)
{
PrintFloat_CoordValue(axis_value[idx]);
if(idx < (axis_num-1)) {
if(idx < (axis_num-1))
{
Putc(',');
}
}
@ -217,13 +219,14 @@ void Report_FeedbackMessage(uint8_t message_code)
void Report_InitMessage(void)
{
//Printf("\r\nGRBL-Advanced %s ['$' for help]\r\n", GRBL_VERSION);
Printf("\r\nGrbl 1.1f [Advanced Edition | '$' for help]\r\n");
Printf("\r\nGrbl %s [Advanced Edition | '$' for help]\r\n", GRBL_VERSION);
Print_Flush();
}
// Grbl help message
void Report_GrblHelp(void) {
void Report_GrblHelp(void)
{
Printf("[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H ~ ! ? ctrl-x]\r\n");
Printf("[GRBL-Advanced by Schildkroet]\r\n");
Print_Flush();
@ -232,7 +235,8 @@ void Report_GrblHelp(void) {
// Grbl global settings print out.
// NOTE: The numbering scheme here must correlate to storing in settings.c
void Report_GrblSettings(void) {
void Report_GrblSettings(void)
{
// Print Grbl settings.
report_util_uint8_setting(0, settings.system_flags);
report_util_uint8_setting(1, settings.stepper_idle_lock_time);
@ -329,10 +333,12 @@ void Report_TLSParams(void)
Printf("[TLS:");
System_ConvertArraySteps2Mpos(print_position, settings.tls_position);
for(idx = 0; idx < 3; idx++) {
for(idx = 0; idx < 3; idx++)
{
PrintFloat_CoordValue(print_position[idx]);
if(idx < (3-1)) {
if(idx < (3-1))
{
Putc(',');
}
}
@ -349,9 +355,12 @@ void Report_ToolParams(uint8_t tool_nr)
ToolParams_t params = {};
TT_GetToolParams(tool_nr, &params);
PrintFloat_CoordValue(params.x_offset);Putc(':');
PrintFloat_CoordValue(params.y_offset);Putc(':');
PrintFloat_CoordValue(params.z_offset);Putc(':');
PrintFloat_CoordValue(params.x_offset);
Putc(':');
PrintFloat_CoordValue(params.y_offset);
Putc(':');
PrintFloat_CoordValue(params.z_offset);
Putc(':');
PrintFloat_CoordValue(params.reserved);
report_util_feedback_line_feed();
}
@ -364,8 +373,10 @@ void Report_NgcParams(void)
uint8_t coord_select;
for(coord_select = 0; coord_select <= SETTING_INDEX_NCOORD; coord_select++) {
if(!(Settings_ReadCoordData(coord_select,coord_data))) {
for(coord_select = 0; coord_select <= SETTING_INDEX_NCOORD; coord_select++)
{
if(!(Settings_ReadCoordData(coord_select,coord_data)))
{
Report_StatusMessage(STATUS_SETTING_READ_FAIL);
return;
@ -411,11 +422,13 @@ void Report_GCodeModes(void)
{
Printf("[GC:G");
if(gc_state.modal.motion >= MOTION_MODE_PROBE_TOWARD) {
if(gc_state.modal.motion >= MOTION_MODE_PROBE_TOWARD)
{
Printf("38.");
Printf("%d", gc_state.modal.motion - (MOTION_MODE_PROBE_TOWARD-2));
}
else {
else
{
Printf("%d", gc_state.modal.motion);
}
@ -437,7 +450,8 @@ void Report_GCodeModes(void)
report_util_gcode_modes_G();
Printf("%d", 98+gc_state.modal.retract);
if(gc_state.modal.program_flow) {
if(gc_state.modal.program_flow)
{
report_util_gcode_modes_M();
switch(gc_state.modal.program_flow)
@ -475,26 +489,40 @@ void Report_GCodeModes(void)
}
#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(); Putc('7'); }
if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_FLOOD) { report_util_gcode_modes_M(); Putc('8'); }
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();
Putc('7');
}
else {
report_util_gcode_modes_M(); Putc('9');
if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_FLOOD)
{
report_util_gcode_modes_M();
Putc('8');
}
}
else
{
report_util_gcode_modes_M();
Putc('9');
}
#else
report_util_gcode_modes_M();
if(gc_state.modal.coolant) {
if(gc_state.modal.coolant)
{
Putc('8');
}
else {
else
{
Putc('9');
}
#endif
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
if(sys.override_ctrl == OVERRIDE_PARKING_MOTION) {
if(sys.override_ctrl == OVERRIDE_PARKING_MOTION)
{
report_util_gcode_modes_M();
Printf("%d", 56);
}
@ -536,7 +564,7 @@ void Report_ExecuteStartupMessage(char *line, uint8_t status_code)
// Prints build info line
void Report_BuildInfo(char *line)
{
Printf("[VER: %s %s:", GRBL_VERSION, GRBL_VERSION_BUILD);
Printf("[VER: %s, %s:", GRBL_VERSION, GRBL_VERSION_BUILD);
Printf("%s", line);
report_util_feedback_line_feed();
Printf("[OPT:"); // Generate compile-time build option list
@ -638,7 +666,6 @@ void Report_RealtimeStatus(void)
System_ConvertArraySteps2Mpos(print_position, current_position);
// Report current machine state and sub-states
//Putc('\n');
Putc('<');
switch(sys.state)
@ -652,37 +679,54 @@ void Report_RealtimeStatus(void)
break;
case STATE_HOLD:
if(!(sys.suspend & SUSPEND_JOG_CANCEL)) {
if(!(sys.suspend & SUSPEND_JOG_CANCEL))
{
Printf("Hold:");
if(sys.suspend & SUSPEND_HOLD_COMPLETE) {
if(sys.suspend & SUSPEND_HOLD_COMPLETE)
{
Putc('0');
} // Ready to resume
else {
else
{
Putc('1');
} // Actively holding
break;
} // Continues to print jog state during jog cancel.
case STATE_JOG: Printf("Jog"); break;
case STATE_HOMING: Printf("Home"); break;
case STATE_ALARM: Printf("Alarm"); break;
case STATE_CHECK_MODE: Printf("Check"); break;
case STATE_JOG:
Printf("Jog");
break;
case STATE_HOMING:
Printf("Home");
break;
case STATE_ALARM:
Printf("Alarm");
break;
case STATE_CHECK_MODE:
Printf("Check");
break;
case STATE_SAFETY_DOOR:
Printf("Door:");
if (sys.suspend & SUSPEND_INITIATE_RESTORE) {
if (sys.suspend & SUSPEND_INITIATE_RESTORE)
{
Putc('3'); // Restoring
}
else {
if(sys.suspend & SUSPEND_RETRACT_COMPLETE) {
if(sys.suspend & SUSPEND_SAFETY_DOOR_AJAR) {
else
{
if(sys.suspend & SUSPEND_RETRACT_COMPLETE)
{
if(sys.suspend & SUSPEND_SAFETY_DOOR_AJAR)
{
Putc('1'); // Door ajar
}
else {
else
{
Putc('0');
} // Door closed and ready to resume
}
else {
else
{
Putc('2'); // Retracting
}
}
@ -705,25 +749,32 @@ void Report_RealtimeStatus(void)
}
float wco[N_AXIS];
if(BIT_IS_FALSE(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE) || (sys.report_wco_counter == 0) ) {
for (idx = 0; idx < N_AXIS; idx++) {
if(BIT_IS_FALSE(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) {
if(idx == TOOL_LENGTH_OFFSET_AXIS)
{
wco[idx] += gc_state.tool_length_offset;
}
if(BIT_IS_FALSE(settings.status_report_mask, BITFLAG_RT_STATUS_POSITION_TYPE)) {
if(BIT_IS_FALSE(settings.status_report_mask, BITFLAG_RT_STATUS_POSITION_TYPE))
{
print_position[idx] -= wco[idx];
}
}
}
// Report machine position
if(BIT_IS_TRUE(settings.status_report_mask, BITFLAG_RT_STATUS_POSITION_TYPE)) {
if(BIT_IS_TRUE(settings.status_report_mask, BITFLAG_RT_STATUS_POSITION_TYPE))
{
Printf("|MPos:");
} else {
}
else
{
Printf("|WPos:");
}
@ -731,7 +782,8 @@ void Report_RealtimeStatus(void)
// Returns planner and serial read buffer states.
#ifdef REPORT_FIELD_BUFFER_STATE
if(BIT_IS_TRUE(settings.status_report_mask, BITFLAG_RT_STATUS_BUFFER_STATE)) {
if(BIT_IS_TRUE(settings.status_report_mask, BITFLAG_RT_STATUS_BUFFER_STATE))
{
Printf("|Bf:");
Printf("%d", Planner_GetBlockBufferAvailable());
Putc(',');
@ -742,10 +794,12 @@ void Report_RealtimeStatus(void)
#ifdef REPORT_FIELD_LINE_NUMBERS
// Report current line number
Planner_Block_t * cur_block = Planner_GetCurrentBlock();
if(cur_block != NULL) {
if(cur_block != NULL)
{
uint32_t ln = cur_block->line_number;
if(ln > 0) {
if(ln > 0)
{
Printf("|Ln:");
Printf("%d", ln);
}
@ -765,42 +819,70 @@ void Report_RealtimeStatus(void)
uint8_t ctrl_pin_state = System_GetControlState();
uint8_t prb_pin_state = Probe_GetState();
if(lim_pin_state | ctrl_pin_state | prb_pin_state) {
if(lim_pin_state | ctrl_pin_state | prb_pin_state)
{
Printf("|Pn:");
if(prb_pin_state) {
if(prb_pin_state)
{
Putc('P');
}
if(lim_pin_state) {
if (BIT_IS_TRUE(lim_pin_state, BIT(X_AXIS))) { Putc('X'); }
if (BIT_IS_TRUE(lim_pin_state, BIT(Y_AXIS))) { Putc('Y'); }
if (BIT_IS_TRUE(lim_pin_state, BIT(Z_AXIS))) { Putc('Z'); }
if (BIT_IS_TRUE(lim_pin_state, BIT(A_AXIS))) { Putc('A'); }
if (BIT_IS_TRUE(lim_pin_state, BIT(B_AXIS))) { Putc('B'); }
if(lim_pin_state)
{
if (BIT_IS_TRUE(lim_pin_state, BIT(X_AXIS)))
{
Putc('X');
}
if (BIT_IS_TRUE(lim_pin_state, BIT(Y_AXIS)))
{
Putc('Y');
}
if (BIT_IS_TRUE(lim_pin_state, BIT(Z_AXIS)))
{
Putc('Z');
}
}
if(ctrl_pin_state) {
if (BIT_IS_TRUE(ctrl_pin_state, CONTROL_PIN_INDEX_SAFETY_DOOR)) { Putc('D'); }
if (BIT_IS_TRUE(ctrl_pin_state, CONTROL_PIN_INDEX_RESET)) { Putc('R'); }
if (BIT_IS_TRUE(ctrl_pin_state, CONTROL_PIN_INDEX_FEED_HOLD)) { Putc('H'); }
if (BIT_IS_TRUE(ctrl_pin_state, CONTROL_PIN_INDEX_CYCLE_START)) { Putc('S'); }
if(ctrl_pin_state)
{
if (BIT_IS_TRUE(ctrl_pin_state, CONTROL_PIN_INDEX_SAFETY_DOOR))
{
Putc('D');
}
if (BIT_IS_TRUE(ctrl_pin_state, CONTROL_PIN_INDEX_RESET))
{
Putc('R');
}
if (BIT_IS_TRUE(ctrl_pin_state, CONTROL_PIN_INDEX_FEED_HOLD))
{
Putc('H');
}
if (BIT_IS_TRUE(ctrl_pin_state, CONTROL_PIN_INDEX_CYCLE_START))
{
Putc('S');
}
}
}
#endif
#ifdef REPORT_FIELD_WORK_COORD_OFFSET
if(sys.report_wco_counter > 0) {
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)) {
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 {
else
{
sys.report_wco_counter = (REPORT_WCO_REFRESH_IDLE_COUNT-1);
}
if(sys.report_ovr_counter == 0) {
if(sys.report_ovr_counter == 0)
{
sys.report_ovr_counter = 1;
} // Set override on next report.
@ -810,14 +892,18 @@ void Report_RealtimeStatus(void)
#endif
#ifdef REPORT_FIELD_OVERRIDES
if(sys.report_ovr_counter > 0) {
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)) {
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 {
else
{
sys.report_ovr_counter = (REPORT_OVR_REFRESH_IDLE_COUNT-1);
}
@ -831,23 +917,29 @@ void Report_RealtimeStatus(void)
uint8_t sp_state = Spindle_GetState();
uint8_t cl_state = Coolant_GetState();
if(sp_state || cl_state) {
if(sp_state || cl_state)
{
Printf("|A:");
if(sp_state) { // != SPINDLE_STATE_DISABLE
if(sp_state == SPINDLE_STATE_CW) {
if(sp_state) // != SPINDLE_STATE_DISABLE
{
if(sp_state == SPINDLE_STATE_CW)
{
Putc('S');
} // CW
else {
else
{
Putc('C');
} // CCW
}
if(cl_state & COOLANT_STATE_FLOOD) {
if(cl_state & COOLANT_STATE_FLOOD)
{
Putc('F');
}
#ifdef ENABLE_M7
if(cl_state & COOLANT_STATE_MIST) {
if(cl_state & COOLANT_STATE_MIST)
{
Putc('M');
}
#endif

Wyświetl plik

@ -87,8 +87,10 @@ void WriteGlobalSettings(void)
// Method to restore EEPROM-saved Grbl global settings back to defaults.
void Settings_Restore(uint8_t restore_flag) {
if(restore_flag & SETTINGS_RESTORE_DEFAULTS) {
void Settings_Restore(uint8_t restore_flag)
{
if(restore_flag & SETTINGS_RESTORE_DEFAULTS)
{
settings.system_flags = DEFAULT_SYSTEM_INVERT_MASK;
settings.flags2 = DEFAULT_LATHE_MODE;
settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
@ -108,14 +110,38 @@ void Settings_Restore(uint8_t restore_flag) {
settings.homing_pulloff = DEFAULT_HOMING_PULLOFF;
settings.flags = 0;
if(DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
if(DEFAULT_LASER_MODE) { settings.flags |= BITFLAG_LASER_MODE; }
if(DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
if(DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
if(DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; }
if(DEFAULT_SOFT_LIMIT_ENABLE) { settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; }
if(DEFAULT_INVERT_LIMIT_PINS) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
if(DEFAULT_INVERT_PROBE_PIN) { settings.flags |= BITFLAG_INVERT_PROBE_PIN; }
if(DEFAULT_REPORT_INCHES)
{
settings.flags |= BITFLAG_REPORT_INCHES;
}
if(DEFAULT_LASER_MODE)
{
settings.flags |= BITFLAG_LASER_MODE;
}
if(DEFAULT_INVERT_ST_ENABLE)
{
settings.flags |= BITFLAG_INVERT_ST_ENABLE;
}
if(DEFAULT_HARD_LIMIT_ENABLE)
{
settings.flags |= BITFLAG_HARD_LIMIT_ENABLE;
}
if(DEFAULT_HOMING_ENABLE)
{
settings.flags |= BITFLAG_HOMING_ENABLE;
}
if(DEFAULT_SOFT_LIMIT_ENABLE)
{
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
}
if(DEFAULT_INVERT_LIMIT_PINS)
{
settings.flags |= BITFLAG_INVERT_LIMIT_PINS;
}
if(DEFAULT_INVERT_PROBE_PIN)
{
settings.flags |= BITFLAG_INVERT_PROBE_PIN;
}
settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
@ -154,18 +180,21 @@ void Settings_Restore(uint8_t restore_flag) {
WriteGlobalSettings();
}
if(restore_flag & SETTINGS_RESTORE_PARAMETERS) {
if(restore_flag & SETTINGS_RESTORE_PARAMETERS)
{
uint8_t idx;
float coord_data[N_AXIS];
memset(&coord_data, 0, sizeof(coord_data));
for(idx = 0; idx <= SETTING_INDEX_NCOORD; idx++) {
for(idx = 0; idx <= SETTING_INDEX_NCOORD; idx++)
{
Settings_WriteCoordData(idx, coord_data);
}
}
if(restore_flag & SETTINGS_RESTORE_STARTUP_LINES) {
if(restore_flag & SETTINGS_RESTORE_STARTUP_LINES)
{
#if N_STARTUP_LINE > 0
Nvm_WriteByte(EEPROM_ADDR_STARTUP_BLOCK, 0);
Nvm_WriteByte(EEPROM_ADDR_STARTUP_BLOCK+1, 0); // Checksum
@ -177,7 +206,8 @@ void Settings_Restore(uint8_t restore_flag) {
Nvm_Update();
}
if(restore_flag & SETTINGS_RESTORE_BUILD_INFO) {
if(restore_flag & SETTINGS_RESTORE_BUILD_INFO)
{
Nvm_WriteByte(EEPROM_ADDR_BUILD_INFO , 0);
Nvm_WriteByte(EEPROM_ADDR_BUILD_INFO+1 , 0); // Checksum
Nvm_Update();
@ -194,7 +224,8 @@ void Settings_Restore(uint8_t restore_flag) {
uint8_t Settings_ReadStartupLine(uint8_t n, char *line)
{
uint32_t addr = n*(STARTUP_LINE_LEN+1)+EEPROM_ADDR_STARTUP_BLOCK;
if (!(Nvm_Read((uint8_t*)line, addr, STARTUP_LINE_LEN))) {
if(!(Nvm_Read((uint8_t*)line, addr, STARTUP_LINE_LEN)))
{
// Reset line with default value
line[0] = 0; // Empty line
Settings_StoreStartupLine(n, line);
@ -220,7 +251,8 @@ void Settings_StoreToolParams(uint8_t tool_nr, ToolParams_t *params)
uint8_t Settings_ReadToolTable(ToolTable_t *table)
{
if(!(Nvm_Read((uint8_t*)table, EEPROM_ADDR_TOOLTABLE, sizeof(ToolTable_t)))) {
if(!(Nvm_Read((uint8_t*)table, EEPROM_ADDR_TOOLTABLE, sizeof(ToolTable_t))))
{
return false;
}
@ -231,7 +263,8 @@ uint8_t Settings_ReadToolTable(ToolTable_t *table)
// Reads startup line from EEPROM. Updated pointed line string data.
uint8_t Settings_ReadBuildInfo(char *line)
{
if(!(Nvm_Read((uint8_t*)line, EEPROM_ADDR_BUILD_INFO, STARTUP_LINE_LEN))) {
if(!(Nvm_Read((uint8_t*)line, EEPROM_ADDR_BUILD_INFO, STARTUP_LINE_LEN)))
{
// Reset line with default value
line[0] = 0; // Empty line
Settings_StoreBuildInfo(line);
@ -247,7 +280,8 @@ uint8_t Settings_ReadBuildInfo(char *line)
uint8_t Settings_ReadCoordData(uint8_t coord_select, float *coord_data)
{
uint32_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
if(!(Nvm_Read((uint8_t*)coord_data, addr, sizeof(float)*N_AXIS))) {
if(!(Nvm_Read((uint8_t*)coord_data, addr, sizeof(float)*N_AXIS)))
{
// Reset with default zero vector
memset(&coord_data, 0.0, sizeof(coord_data));
Settings_WriteCoordData(coord_select, coord_data);
@ -260,17 +294,21 @@ uint8_t Settings_ReadCoordData(uint8_t coord_select, float *coord_data)
// Reads Grbl global settings struct from EEPROM.
uint8_t ReadGlobalSettings() {
uint8_t ReadGlobalSettings()
{
// Check version-byte of eeprom
uint8_t version = Nvm_ReadByte(0);
if(version == SETTINGS_VERSION) {
if(version == SETTINGS_VERSION)
{
// Read settings-record and check checksum
if(!(Nvm_Read((uint8_t*)&settings, EEPROM_ADDR_GLOBAL, sizeof(Settings_t)))) {
if(!(Nvm_Read((uint8_t*)&settings, EEPROM_ADDR_GLOBAL, sizeof(Settings_t))))
{
return false;
}
}
else {
else
{
return false;
}
@ -279,50 +317,73 @@ uint8_t ReadGlobalSettings() {
// A helper method to set settings from command line
uint8_t Settings_StoreGlobalSetting(uint8_t parameter, float value) {
if(value < 0.0) {
uint8_t Settings_StoreGlobalSetting(uint8_t parameter, float value)
{
if(value < 0.0)
{
return STATUS_NEGATIVE_VALUE;
}
if(parameter >= AXIS_SETTINGS_START_VAL) {
if(parameter >= AXIS_SETTINGS_START_VAL)
{
// Store axis configuration. Axis numbering sequence set by AXIS_SETTING defines.
// NOTE: Ensure the setting index corresponds to the report.c settings printout.
parameter -= AXIS_SETTINGS_START_VAL;
uint8_t set_idx = 0;
while(set_idx < AXIS_N_SETTINGS) {
if(parameter < N_AXIS) {
while(set_idx < AXIS_N_SETTINGS)
{
if(parameter < N_AXIS)
{
// Valid axis setting found.
switch (set_idx) {
switch (set_idx)
{
case 0:
#ifdef MAX_STEP_RATE_HZ
if (value*settings.max_rate[parameter] > (MAX_STEP_RATE_HZ*60.0)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
if (value*settings.max_rate[parameter] > (MAX_STEP_RATE_HZ*60.0))
{
return(STATUS_MAX_STEP_RATE_EXCEEDED);
}
#endif
settings.steps_per_mm[parameter] = value;
break;
case 1:
#ifdef MAX_STEP_RATE_HZ
if (value*settings.steps_per_mm[parameter] > (MAX_STEP_RATE_HZ*60.0)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
if (value*settings.steps_per_mm[parameter] > (MAX_STEP_RATE_HZ*60.0))
{
return(STATUS_MAX_STEP_RATE_EXCEEDED);
}
#endif
settings.max_rate[parameter] = value;
break;
case 2: settings.acceleration[parameter] = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
case 3: settings.max_travel[parameter] = -value; break; // Store as negative for grbl internal use.
case 4: settings.backlash[parameter] = value; break;
case 2:
settings.acceleration[parameter] = value*60*60;
break; // Convert to mm/min^2 for grbl internal use.
case 3:
settings.max_travel[parameter] = -value;
break; // Store as negative for grbl internal use.
case 4:
settings.backlash[parameter] = value;
break;
}
break; // Exit while-loop after setting has been configured and proceed to the EEPROM write call.
}
else {
else
{
set_idx++;
// If axis index greater than N_AXIS or setting index greater than number of axis settings, error out.
if ((parameter < AXIS_SETTINGS_INCREMENT) || (set_idx == AXIS_N_SETTINGS)) { return(STATUS_INVALID_STATEMENT); }
if ((parameter < AXIS_SETTINGS_INCREMENT) || (set_idx == AXIS_N_SETTINGS))
{
return(STATUS_INVALID_STATEMENT);
}
parameter -= AXIS_SETTINGS_INCREMENT;
}
}
}
else {
else
{
// Store non-axis Grbl settings
uint8_t int_value = trunc(value);
@ -347,68 +408,149 @@ uint8_t Settings_StoreGlobalSetting(uint8_t parameter, float value) {
break;
case 4: // Reset to ensure change. Immediate re-init may cause problems.
if (int_value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
if (int_value)
{
settings.flags |= BITFLAG_INVERT_ST_ENABLE;
}
else
{
settings.flags &= ~BITFLAG_INVERT_ST_ENABLE;
}
break;
case 5: // Reset to ensure change. Immediate re-init may cause problems.
if (int_value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; }
if (int_value)
{
settings.flags |= BITFLAG_INVERT_LIMIT_PINS;
}
else
{
settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS;
}
break;
case 6: // Reset to ensure change. Immediate re-init may cause problems.
if (int_value) { settings.flags |= BITFLAG_INVERT_PROBE_PIN; }
else { settings.flags &= ~BITFLAG_INVERT_PROBE_PIN; }
if (int_value)
{
settings.flags |= BITFLAG_INVERT_PROBE_PIN;
}
else
{
settings.flags &= ~BITFLAG_INVERT_PROBE_PIN;
}
Probe_ConfigureInvertMask(false);
break;
case 10: settings.status_report_mask = int_value; break;
case 11: settings.junction_deviation = value; break;
case 12: settings.arc_tolerance = value; break;
case 10:
settings.status_report_mask = int_value;
break;
case 11:
settings.junction_deviation = value;
break;
case 12:
settings.arc_tolerance = value;
break;
case 13:
if (int_value) { settings.flags |= BITFLAG_REPORT_INCHES; }
else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
if (int_value)
{
settings.flags |= BITFLAG_REPORT_INCHES;
}
else
{
settings.flags &= ~BITFLAG_REPORT_INCHES;
}
System_FlagWcoChange(); // Make sure WCO is immediately updated.
break;
case 14: settings.tool_change = int_value; break; // Check for range?
case 14:
settings.tool_change = int_value;
break; // Check for range?
case 20:
if (int_value) {
if (BIT_IS_FALSE(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); }
if (int_value)
{
if (BIT_IS_FALSE(settings.flags, BITFLAG_HOMING_ENABLE))
{
return(STATUS_SOFT_LIMIT_ERROR);
}
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
} else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; }
}
else
{
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE;
}
break;
case 21:
if (int_value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
if (int_value)
{
settings.flags |= BITFLAG_HARD_LIMIT_ENABLE;
}
else
{
settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE;
}
Limits_Init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later.
break;
case 22:
if (int_value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
else {
if (int_value)
{
settings.flags |= BITFLAG_HOMING_ENABLE;
}
else
{
settings.flags &= ~BITFLAG_HOMING_ENABLE;
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits.
}
break;
case 23: settings.homing_dir_mask = int_value; break;
case 24: settings.homing_feed_rate = value; break;
case 25: settings.homing_seek_rate = value; break;
case 26: settings.homing_debounce_delay = int_value; break;
case 27: settings.homing_pulloff = value; break;
case 30: settings.rpm_max = value; Spindle_Init(); break; // Re-initialize spindle rpm calibration
case 31: settings.rpm_min = value; Spindle_Init(); break; // Re-initialize spindle rpm calibration
case 23:
settings.homing_dir_mask = int_value;
break;
case 24:
settings.homing_feed_rate = value;
break;
case 25:
settings.homing_seek_rate = value;
break;
case 26:
settings.homing_debounce_delay = int_value;
break;
case 27:
settings.homing_pulloff = value;
break;
case 30:
settings.rpm_max = value;
Spindle_Init();
break; // Re-initialize spindle rpm calibration
case 31:
settings.rpm_min = value;
Spindle_Init();
break; // Re-initialize spindle rpm calibration
case 32:
if (int_value) { settings.flags |= BITFLAG_LASER_MODE; }
else { settings.flags &= ~BITFLAG_LASER_MODE; }
if (int_value)
{
settings.flags |= BITFLAG_LASER_MODE;
}
else
{
settings.flags &= ~BITFLAG_LASER_MODE;
}
break;
case 33:
if (int_value) { settings.flags2 |= BITFLAG_LATHE_MODE; }
else { settings.flags2 &= ~BITFLAG_LATHE_MODE; }
if (int_value)
{
settings.flags2 |= BITFLAG_LATHE_MODE;
}
else
{
settings.flags2 &= ~BITFLAG_LATHE_MODE;
}
break;
default:
@ -436,7 +578,8 @@ void Settings_Init(void)
{
Nvm_Init();
if(!ReadGlobalSettings()) {
if(!ReadGlobalSettings())
{
Report_StatusMessage(STATUS_SETTING_READ_FAIL);
Settings_Restore(SETTINGS_RESTORE_ALL); // Force restore all EEPROM data.
Report_GrblSettings();
@ -450,10 +593,22 @@ void Settings_Init(void)
// Returns step pin mask according to Grbl internal axis indexing.
uint8_t Settings_GetStepPinMask(uint8_t axis_idx)
{
if(axis_idx == X_AXIS) { return (1<<X_STEP_BIT); }
if(axis_idx == Y_AXIS) { return (1<<Y_STEP_BIT); }
if(axis_idx == Z_AXIS) { return (1<<Z_STEP_BIT); }
if(axis_idx == A_AXIS) { return (1<<A_STEP_BIT); }
if(axis_idx == X_AXIS)
{
return (1<<X_STEP_BIT);
}
if(axis_idx == Y_AXIS)
{
return (1<<Y_STEP_BIT);
}
if(axis_idx == Z_AXIS)
{
return (1<<Z_STEP_BIT);
}
if(axis_idx == A_AXIS)
{
return (1<<A_STEP_BIT);
}
return (1<<B_STEP_BIT);
}
@ -462,10 +617,22 @@ uint8_t Settings_GetStepPinMask(uint8_t axis_idx)
// Returns direction pin mask according to Grbl internal axis indexing.
uint8_t Settings_GetDirectionPinMask(uint8_t axis_idx)
{
if(axis_idx == X_AXIS) { return (1<<X_DIRECTION_BIT); }
if(axis_idx == Y_AXIS) { return (1<<Y_DIRECTION_BIT); }
if(axis_idx == Z_AXIS) { return (1<<Z_DIRECTION_BIT); }
if(axis_idx == A_AXIS) { return (1<<A_DIRECTION_BIT); }
if(axis_idx == X_AXIS)
{
return (1<<X_DIRECTION_BIT);
}
if(axis_idx == Y_AXIS)
{
return (1<<Y_DIRECTION_BIT);
}
if(axis_idx == Z_AXIS)
{
return (1<<Z_DIRECTION_BIT);
}
if(axis_idx == A_AXIS)
{
return (1<<A_DIRECTION_BIT);
}
return (1<<B_DIRECTION_BIT);
}
@ -474,10 +641,22 @@ uint8_t Settings_GetDirectionPinMask(uint8_t axis_idx)
// Returns limit pin mask according to Grbl internal axis indexing.
uint8_t Settings_GetLimitPinMask(uint8_t axis_idx)
{
if(axis_idx == X_AXIS) { return (1<<X_STEP_BIT); }
if(axis_idx == Y_AXIS) { return (1<<Y_STEP_BIT); }
if(axis_idx == Z_AXIS) { return (1<<Z_STEP_BIT); }
if(axis_idx == A_AXIS) { return (1<<A_STEP_BIT); }
if(axis_idx == X_AXIS)
{
return (1<<X_STEP_BIT);
}
if(axis_idx == Y_AXIS)
{
return (1<<Y_STEP_BIT);
}
if(axis_idx == Z_AXIS)
{
return (1<<Z_STEP_BIT);
}
if(axis_idx == A_AXIS)
{
return (1<<A_STEP_BIT);
}
return (1<<B_STEP_BIT);
}

Wyświetl plik

@ -33,6 +33,8 @@ static float pwm_gradient; // Precalulated value to speed up rpm to PWM conversi
static uint8_t spindle_enabled = 0;
static uint8_t spindle_dir_cw = 1;
extern uint32_t uwTIM3Freq;
void Spindle_Init(void)
{
@ -120,6 +122,13 @@ void Spindle_SetSpeed(uint8_t pwm_value)
}
uint16_t Spindle_GetRPM(void)
{
// 4 impulses per revolution
return (uint16_t)(uwTIM3Freq / 4);
}
// Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
uint8_t Spindle_ComputePwmValue(float rpm) // 328p PWM register is 8-bit.
{
@ -128,22 +137,27 @@ uint8_t Spindle_ComputePwmValue(float rpm) // 328p PWM register is 8-bit.
rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value.
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
if((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max)) {
if((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max))
{
// No PWM range possible. Set simple on/off spindle control pin state.
sys.spindle_speed = settings.rpm_max;
pwm_value = SPINDLE_PWM_MAX_VALUE;
}
else if(rpm <= settings.rpm_min) {
if(rpm == 0.0) { // S0 disables spindle
else if(rpm <= settings.rpm_min)
{
if(rpm == 0.0) // S0 disables spindle
{
sys.spindle_speed = 0.0;
pwm_value = SPINDLE_PWM_OFF_VALUE;
}
else { // Set minimum PWM output
else // Set minimum PWM output
{
sys.spindle_speed = settings.rpm_min;
pwm_value = SPINDLE_PWM_MIN_VALUE;
}
}
else {
else
{
// Compute intermediate PWM value with linear spindle speed model.
// NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
sys.spindle_speed = rpm;
@ -159,21 +173,26 @@ uint8_t Spindle_ComputePwmValue(float rpm) // 328p PWM register is 8-bit.
// sleep, and spindle stop override.
void Spindle_SetState(uint8_t state, float rpm)
{
if(sys.abort) {
if(sys.abort)
{
// Block during abort.
return;
}
if(state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
if(state == SPINDLE_DISABLE) // Halt or set spindle direction and rpm.
{
sys.spindle_speed = 0.0;
Spindle_Stop();
}
else {
if(state == SPINDLE_ENABLE_CW) {
else
{
if(state == SPINDLE_ENABLE_CW)
{
GPIO_ResetBits(GPIO_SPINDLE_DIR_PORT, GPIO_SPINDLE_DIR_PIN);
spindle_dir_cw = 1;
}
else {
else
{
GPIO_SetBits(GPIO_SPINDLE_DIR_PORT, GPIO_SPINDLE_DIR_PIN);
spindle_dir_cw = 0;
}
@ -185,8 +204,10 @@ void Spindle_SetState(uint8_t state, float rpm)
#endif
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
if(settings.flags & BITFLAG_LASER_MODE) {
if(state == SPINDLE_ENABLE_CCW) {
if(settings.flags & BITFLAG_LASER_MODE)
{
if(state == SPINDLE_ENABLE_CCW)
{
// TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
rpm = 0.0;
}
@ -203,7 +224,8 @@ void Spindle_SetState(uint8_t state, float rpm)
// if an abort or check-mode is active.
void Spindle_Sync(uint8_t state, float rpm)
{
if(sys.state == STATE_CHECK_MODE) {
if(sys.state == STATE_CHECK_MODE)
{
return;
}

Plik diff jest za duży Load Diff

Wyświetl plik

@ -72,17 +72,21 @@ uint8_t System_GetControlState(void)
// Invert control pins if necessary
pin ^= CONTROL_MASK & settings.system_flags;
if(pin) {
if(BIT_IS_FALSE(pin, (1<<CONTROL_RESET_BIT))) {
if(pin)
{
if(BIT_IS_TRUE(pin, (1<<CONTROL_RESET_BIT)))
{
control_state |= CONTROL_PIN_INDEX_RESET;
}
if(BIT_IS_FALSE(pin, (1<<CONTROL_FEED_HOLD_BIT))) {
if(BIT_IS_TRUE(pin, (1<<CONTROL_FEED_HOLD_BIT)))
{
control_state |= CONTROL_PIN_INDEX_FEED_HOLD;
}
if(BIT_IS_FALSE(pin, (1<<CONTROL_CYCLE_START_BIT))) {
if(BIT_IS_TRUE(pin, (1<<CONTROL_CYCLE_START_BIT)))
{
control_state |= CONTROL_PIN_INDEX_CYCLE_START;
}
/*if(BIT_IS_FALSE(pin, (1<<CONTROL_SAFETY_DOOR_BIT))) {
/*if(BIT_IS_TRUE(pin, (1<<CONTROL_SAFETY_DOOR_BIT))) {
control_state |= CONTROL_PIN_INDEX_SAFETY_DOOR;
}*/
}
@ -99,17 +103,22 @@ void System_PinChangeISR(void)
{
uint8_t pin = System_GetControlState();
if(pin) {
if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_RESET)) {
if(pin)
{
if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_RESET))
{
MC_Reset();
}
else if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_CYCLE_START)) {
else if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_CYCLE_START))
{
BIT_TRUE(sys_rt_exec_state, EXEC_CYCLE_START);
}
if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_FEED_HOLD)) {
if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_FEED_HOLD))
{
BIT_TRUE(sys_rt_exec_state, EXEC_FEED_HOLD);
}
if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_SAFETY_DOOR)) {
if(BIT_IS_TRUE(pin, CONTROL_PIN_INDEX_SAFETY_DOOR))
{
BIT_TRUE(sys_rt_exec_state, EXEC_SAFETY_DOOR);
}
}
@ -129,13 +138,17 @@ 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))) {
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) {
else
{
if(line[0] != 0)
{
uint8_t status_code = GC_ExecuteLine(line);
Report_ExecuteStartupMessage(line,status_code);
@ -170,10 +183,12 @@ uint8_t System_ExecuteLine(char *line)
case 'J': // Jogging
// Execute only if in IDLE or JOG states.
if(sys.state != STATE_IDLE && sys.state != STATE_JOG) {
if(sys.state != STATE_IDLE && sys.state != STATE_JOG)
{
return STATUS_IDLE_ERROR;
}
if(line[2] != '=') {
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.
@ -183,17 +198,20 @@ uint8_t System_ExecuteLine(char *line)
case 'G':
case 'C':
case 'X':
if(line[2] != 0) {
if(line[2] != 0)
{
return(STATUS_INVALID_STATEMENT);
}
switch(line[1])
{
case '$': // Prints Grbl settings
if(sys.state & (STATE_CYCLE | STATE_HOLD)) {
if(sys.state & (STATE_CYCLE | STATE_HOLD))
{
return(STATUS_IDLE_ERROR);
} // Block during cycle. Takes too long to print.
else {
else
{
Report_GrblSettings();
}
break;
@ -207,12 +225,15 @@ uint8_t System_ExecuteLine(char *line)
// 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.
if(sys.state == STATE_CHECK_MODE ) {
if(sys.state == STATE_CHECK_MODE )
{
MC_Reset();
Report_FeedbackMessage(MESSAGE_DISABLED);
}
else {
if(sys.state) {
else
{
if(sys.state)
{
// Requires no alarm mode.
return STATUS_IDLE_ERROR;
}
@ -223,14 +244,17 @@ uint8_t System_ExecuteLine(char *line)
break;
case 'X': // Disable alarm lock [ALARM]
if(sys.state == STATE_ALARM) {
if(sys.state == STATE_ALARM)
{
// Block if safety door is ajar.
if(System_CheckSafetyDoorAjar()) {
if(System_CheckSafetyDoorAjar())
{
return(STATUS_CHECK_DOOR);
}
Report_FeedbackMessage(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE;
Stepper_WakeUp();
// Don't run startup script. Prevents stored moves in startup from causing accidents.
} // Otherwise, no effect.
break;
@ -288,7 +312,8 @@ uint8_t System_ExecuteLine(char *line)
{
c = line[char_counter++];
num[idx++] = c;
} while(isdigit(c) && idx < 3);
}
while(isdigit(c) && idx < 3);
num[idx] = '\0';
if(c == '=')
@ -346,37 +371,44 @@ uint8_t System_ExecuteLine(char *line)
default:
// Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
if(!(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) {
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) {
if(line[2] != 0)
{
return STATUS_INVALID_STATEMENT;
}
else {
else
{
Report_NgcParams();
}
break;
case 'H': // Perform homing cycle [IDLE/ALARM]
if(BIT_IS_FALSE(settings.flags, BITFLAG_HOMING_ENABLE)) {
if(BIT_IS_FALSE(settings.flags, BITFLAG_HOMING_ENABLE))
{
return(STATUS_SETTING_DISABLED);
}
if(System_CheckSafetyDoorAjar()) {
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) {
if(line[2] == 0)
{
MC_HomigCycle(HOMING_CYCLE_ALL);
#ifdef HOMING_SINGLE_AXIS_COMMANDS
}
else if(line[3] == 0) {
else if(line[3] == 0)
{
switch(line[2])
{
case 'X':
@ -404,43 +436,52 @@ uint8_t System_ExecuteLine(char *line)
}
#endif
}
else {
else
{
return STATUS_INVALID_STATEMENT;
}
if(!sys.abort) { // Execute startup scripts after successful homing.
if(!sys.abort) // Execute startup scripts after successful homing.
{
sys.state = STATE_IDLE; // Set to IDLE when complete.
Stepper_Disable(0); // Set steppers to the settings idle state before returning.
if(line[2] == 0) {
if(line[2] == 0)
{
System_ExecuteStartup(line);
}
}
break;
case 'S': // Puts Grbl to sleep [IDLE/ALARM]
if((line[2] != 'L') || (line[3] != 'P') || (line[4] != 0)) {
if((line[2] != 'L') || (line[3] != 'P') || (line[4] != 0))
{
return(STATUS_INVALID_STATEMENT);
}
System_SetExecStateFlag(EXEC_SLEEP); // Set to execute sleep mode immediately
break;
case 'I': // Print or store build info. [IDLE/ALARM]
if(line[++char_counter] == 0 ) {
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++] != '=') {
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.
do {
do
{
line[char_counter-helper_var] = line[char_counter];
} while(line[char_counter++] != 0);
}
while(line[char_counter++] != 0);
Settings_StoreBuildInfo(line);
#endif
@ -448,7 +489,8 @@ uint8_t System_ExecuteLine(char *line)
break;
case 'R': // Restore defaults [IDLE/ALARM]
if((line[2] != 'S') || (line[3] != 'T') || (line[4] != '=') || (line[6] != 0)) {
if((line[2] != 'S') || (line[3] != 'T') || (line[4] != '=') || (line[6] != 0))
{
return(STATUS_INVALID_STATEMENT);
}
switch(line[5])
@ -482,19 +524,25 @@ uint8_t System_ExecuteLine(char *line)
case 'N': // Startup lines. [IDLE/ALARM]
#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))) {
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 {
else
{
Report_StartupLine(helper_var,line);
}
}
break;
}
else { // Store startup line [IDLE Only] Prevents motion during ALARM.
if(sys.state != STATE_IDLE) {
else // Store startup line [IDLE Only] Prevents motion during ALARM.
{
if(sys.state != STATE_IDLE)
{
// Store only when idle.
return STATUS_IDLE_ERROR;
}
@ -504,36 +552,46 @@ uint8_t System_ExecuteLine(char *line)
#endif
default: // Storing setting methods [IDLE/ALARM]
if(!Read_Float(line, &char_counter, &parameter)) {
if(!Read_Float(line, &char_counter, &parameter))
{
return(STATUS_BAD_NUMBER_FORMAT);
}
if(line[char_counter++] != '=') {
if(line[char_counter++] != '=')
{
return(STATUS_INVALID_STATEMENT);
}
if(helper_var) { // Store startup line
if(helper_var) // Store startup line
{
// Prepare sending gcode block to gcode parser by shifting all characters
helper_var = char_counter; // Set helper variable as counter to start of gcode block
do {
do
{
line[char_counter-helper_var] = line[char_counter];
} while(line[char_counter++] != 0);
}
while(line[char_counter++] != 0);
// Execute gcode block to ensure block is valid.
helper_var = GC_ExecuteLine(line); // Set helper_var to returned status code.
if(helper_var) {
if(helper_var)
{
return(helper_var);
}
else {
else
{
helper_var = trunc(parameter); // Set helper_var to int value of parameter
Settings_StoreStartupLine(helper_var, line);
}
}
else { // Store global setting.
if(!Read_Float(line, &char_counter, &value)) {
else // Store global setting.
{
if(!Read_Float(line, &char_counter, &value))
{
return STATUS_BAD_NUMBER_FORMAT;
}
if((line[char_counter] != 0) || (parameter > 255)) {
if((line[char_counter] != 0) || (parameter > 255))
{
return STATUS_INVALID_STATEMENT;
}
@ -564,13 +622,16 @@ float System_ConvertAxisSteps2Mpos(const int32_t *steps, const uint8_t idx)
float pos = 0.0;
#ifdef COREXY
if(idx == X_AXIS) {
if(idx == X_AXIS)
{
pos = (float)system_convert_corexy_to_x_axis_steps(steps) / settings.steps_per_mm[idx];
}
else if (idx == Y_AXIS) {
else if (idx == Y_AXIS)
{
pos = (float)system_convert_corexy_to_y_axis_steps(steps) / settings.steps_per_mm[idx];
}
else {
else
{
pos = steps[idx]/settings.steps_per_mm[idx];
}
#else
@ -589,7 +650,8 @@ void System_ConvertArraySteps2Mpos(float *position, const int32_t *steps)
{
uint8_t idx;
for(idx = 0; idx < N_AXIS; idx++) {
for(idx = 0; idx < N_AXIS; idx++)
{
position[idx] = System_ConvertAxisSteps2Mpos(steps, idx);
}
@ -616,23 +678,29 @@ uint8_t System_CheckTravelLimits(float *target)
{
uint8_t idx;
for(idx = 0; idx < N_AXIS; 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.
// NOTE: max_travel is stored as negative
if(BIT_IS_TRUE(settings.homing_dir_mask, BIT(idx))) {
if(target[idx] < 0 || target[idx] > -settings.max_travel[idx]) {
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]) {
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]) {
if(target[idx] > 0 || target[idx] < settings.max_travel[idx])
{
return true;
}
#endif

Wyświetl plik

@ -53,6 +53,13 @@
#define EXEC_ALARM_HOMING_FAIL_PULLOFF 8
#define EXEC_ALARM_HOMING_FAIL_APPROACH 9
#define EXEC_ALARM_HARD_LIMIT_X1 21
#define EXEC_ALARM_HARD_LIMIT_X2 22
#define EXEC_ALARM_HARD_LIMIT_Y1 23
#define EXEC_ALARM_HARD_LIMIT_Y2 24
#define EXEC_ALARM_HARD_LIMIT_Z1 25
#define EXEC_ALARM_HARD_LIMIT_Z2 26
// 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.
#define EXEC_FEED_OVR_RESET BIT(0)
@ -125,7 +132,8 @@
// Define global system variables
typedef struct {
typedef struct
{
uint16_t state; // Tracks the current system state of Grbl.
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t suspend; // System suspend bitflag variable that manages holds, cancels, and safety door.

Wyświetl plik

@ -3,6 +3,7 @@
Part of Grbl-Advanced
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2017-2020 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

Wyświetl plik

@ -48,11 +48,13 @@ uint8_t Read_Float(char *line, uint8_t *char_counter, float *float_ptr)
// Capture initial positive/minus character
bool isnegative = false;
if(c == '-') {
if(c == '-')
{
isnegative = true;
c = *ptr++;
}
else if(c == '+') {
else if(c == '+')
{
c = *ptr++;
}
@ -62,30 +64,45 @@ uint8_t Read_Float(char *line, uint8_t *char_counter, float *float_ptr)
uint8_t ndigit = 0;
bool isdecimal = false;
while(1) {
while(1)
{
c -= '0';
if(c <= 9) {
if(c <= 9)
{
ndigit++;
if(ndigit <= MAX_INT_DIGITS) {
if(isdecimal) { exp--; }
if(ndigit <= MAX_INT_DIGITS)
{
if(isdecimal)
{
exp--;
}
intval = (((intval << 2) + intval) << 1) + c; // intval*10 + c
}
else {
if (!(isdecimal)) { exp++; } // Drop overflow digits
else
{
if (!(isdecimal))
{
exp++; // Drop overflow digits
}
}
else if(c == (('.'-'0') & 0xff) && !(isdecimal)) {
}
else if(c == (('.'-'0') & 0xff) && !(isdecimal))
{
isdecimal = true;
}
else {
else
{
break;
}
c = *ptr++;
}
// Return if no digits have been read.
if(!ndigit) { return(false); };
if(!ndigit)
{
return(false);
};
// Convert integer into floating point.
float fval;
@ -93,26 +110,34 @@ uint8_t Read_Float(char *line, uint8_t *char_counter, float *float_ptr)
// Apply decimal. Should perform no more than two floating point multiplications for the
// expected range of E0 to E-4.
if(fval != 0) {
while(exp <= -2) {
if(fval != 0)
{
while(exp <= -2)
{
fval *= 0.01;
exp += 2;
}
if(exp < 0) {
if(exp < 0)
{
fval *= 0.1;
}
else if(exp > 0) {
do {
else if(exp > 0)
{
do
{
fval *= 10.0;
} while(--exp > 0);
}
while(--exp > 0);
}
}
// Assign floating point value with correct sign.
if(isnegative) {
if(isnegative)
{
*float_ptr = -fval;
}
else {
else
{
*float_ptr = fval;
}
@ -141,7 +166,8 @@ uint8_t ExtractFloat(char *line, int start_idx, char *float_char)
do
{
float_char[j++] = line[i++];
} while(isdigit((unsigned char)line[i]) || line[i] == '.'); // Read float
}
while(isdigit((unsigned char)line[i]) || line[i] == '.'); // Read float
float_char[j] = '\0';
@ -158,19 +184,24 @@ void Delay_sec(float seconds, uint8_t mode)
{
uint16_t i = ceil(1000/DWELL_TIME_STEP*seconds);
while(i-- > 0) {
if(sys.abort) {
while(i-- > 0)
{
if(sys.abort)
{
return;
}
if(mode == DELAY_MODE_DWELL) {
if(mode == DELAY_MODE_DWELL)
{
Protocol_ExecuteRealtime();
}
else { // DELAY_MODE_SYS_SUSPEND
else // DELAY_MODE_SYS_SUSPEND
{
// Execute rt_system() only to avoid nesting suspend loops.
Protocol_ExecRtSystem();
if(sys.suspend & SUSPEND_RESTART_RETRACT) {
if(sys.suspend & SUSPEND_RESTART_RETRACT)
{
// Bail, if safety door reopens.
return;
}
@ -188,7 +219,8 @@ float hypot_f(float x, float y)
bool isEqual_f(float a, float b)
{
if(fabs(a-b) < 0.00001) {
if(fabs(a-b) < 0.00001)
{
return true;
}
@ -200,8 +232,10 @@ float convert_delta_vector_to_unit_vector(float *vector)
uint8_t idx;
float magnitude = 0.0;
for(idx = 0; idx < N_AXIS; idx++) {
if(vector[idx] != 0.0) {
for(idx = 0; idx < N_AXIS; idx++)
{
if(vector[idx] != 0.0)
{
magnitude += vector[idx]*vector[idx];
}
}
@ -209,7 +243,8 @@ float convert_delta_vector_to_unit_vector(float *vector)
magnitude = sqrt(magnitude);
float inv_magnitude = 1.0/magnitude;
for(idx = 0; idx < N_AXIS; idx++) {
for(idx = 0; idx < N_AXIS; idx++)
{
vector[idx] *= inv_magnitude;
}
@ -221,8 +256,10 @@ float limit_value_by_axis_maximum(float *max_value, float *unit_vec)
uint8_t idx;
float limit_value = SOME_LARGE_VALUE;
for(idx = 0; idx < N_AXIS; idx++) {
if(unit_vec[idx] != 0) { // Avoid divide by zero.
for(idx = 0; idx < N_AXIS; idx++)
{
if(unit_vec[idx] != 0) // Avoid divide by zero.
{
limit_value = min(limit_value,fabs(max_value[idx]/unit_vec[idx]));
}
}

Wyświetl plik

@ -66,10 +66,13 @@
#define A_DIRECTION_BIT 3
#define B_DIRECTION_BIT 4
#define X_LIMIT_BIT 0
#define Y_LIMIT_BIT 1
#define Z_LIMIT_BIT 2
#define LIMIT_MASK ((1<<X_LIMIT_BIT) | (1<<Y_LIMIT_BIT) | (1<<Z_LIMIT_BIT))
#define X1_LIMIT_BIT 0
#define Y1_LIMIT_BIT 1
#define Z1_LIMIT_BIT 2
#define X2_LIMIT_BIT 3
#define Y2_LIMIT_BIT 4
#define Z2_LIMIT_BIT 5
#define LIMIT_MASK ((1<<X1_LIMIT_BIT) | (1<<Y1_LIMIT_BIT) | (1<<Z1_LIMIT_BIT) | (1<<X2_LIMIT_BIT) | (1<<Y2_LIMIT_BIT) | (1<<Z2_LIMIT_BIT))
#define SPINDLE_ENABLE_BIT 0
#define SPINDLE_DIRECTION_BIT 1