test check in

This commit is contained in:
Terje Io
2021-02-22 12:29:17 +01:00
commit cdca5ad55c
61 changed files with 20794 additions and 0 deletions

18
.gitattributes vendored Normal file
View File

@@ -0,0 +1,18 @@
# Auto detect text files and perform LF normalization
* text=auto eol=lf
# Custom for Visual Studio
*.cs diff=csharp
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

43
.gitignore vendored Normal file
View File

@@ -0,0 +1,43 @@
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# Subversion folders
.svn
# Eclipse folders
.settings
# STM32 .ioc files
*.ioc
# Build folder
build
#
# =========================
# Operating System Files
# =========================
.vscode/settings.json
.vscode/c_cpp_properties.json

76
alarms.h Normal file
View File

@@ -0,0 +1,76 @@
/*
alarms.h -
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _ALARMS_H_
#define _ALARMS_H_
// Alarm executor codes. Valid values (1-255). Zero is reserved.
typedef enum {
Alarm_None = 0,
Alarm_HardLimit = 1,
Alarm_SoftLimit = 2,
Alarm_AbortCycle = 3,
Alarm_ProbeFailInitial = 4,
Alarm_ProbeFailContact = 5,
Alarm_HomingFailReset = 6,
Alarm_HomingFailDoor = 7,
Alarm_FailPulloff = 8,
Alarm_HomingFailApproach = 9,
Alarm_EStop = 10,
Alarm_HomingRequried = 11,
Alarm_LimitsEngaged = 12,
Alarm_ProbeProtect = 13,
Alarm_Spindle = 14,
Alarm_HomingFailAutoSquaringApproach = 15,
Alarm_SelftestFailed = 16,
Alarm_MotorFault = 17
} alarm_code_t;
typedef struct {
alarm_code_t id;
const char *name;
const char *description;
} alarm_detail_t;
PROGMEM static const alarm_detail_t alarm_detail[] = {
{ Alarm_HardLimit, "Hard limit", "Hard limit has been triggered. Machine position is likely lost due to sudden halt. Re-homing is highly recommended." },
{ Alarm_SoftLimit, "Soft limit", "Soft limit alarm. G-code motion target exceeds machine travel. Machine position retained. Alarm may be safely unlocked." },
{ Alarm_AbortCycle, "Abort during cycle", "Reset while in motion. Machine position is likely lost due to sudden halt. Re-homing is highly recommended." },
{ Alarm_ProbeFailInitial, "Probe fail", "Probe fail. Probe is not in the expected initial state before starting probe cycle when G38.2 and G38.3 is not triggered and G38.4 and G38.5 is triggered." },
{ Alarm_ProbeFailContact, "Probe fail", "Probe fail. Probe did not contact the workpiece within the programmed travel for G38.2 and G38.4." },
{ Alarm_HomingFailReset, "Homing fail", "Homing fail. The active homing cycle was reset." },
{ Alarm_HomingFailDoor, "Homing fail", "Homing fail. Safety door was opened during homing cycle." },
{ Alarm_FailPulloff, "Homing fail", "Homing fail. Pull off travel failed to clear limit switch. Try increasing pull-off setting or check wiring." },
{ Alarm_HomingFailApproach, "Homing fail", "Homing fail. Could not find limit switch within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring." },
{ Alarm_EStop, "EStop", "EStop asserted. Clear and reset" },
{ Alarm_HomingRequried, "Homing required", "Homing required. Execute homing command ($H) to continue." },
{ Alarm_LimitsEngaged, "Limit switch engaged", "Limit switch engaged. Clear before continuing." },
{ Alarm_ProbeProtect, "Probe protection triggered", "Probe protection triggered. Clear before continuing." },
{ Alarm_Spindle, "Spindle at speed timeout", "Spindle at speed timeout. Clear before continuing." },
{ Alarm_HomingFailAutoSquaringApproach, "Homing fail", "Homing fail. Could not find second limit switch for auto squared axis within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring." },
{ Alarm_SelftestFailed, "Selftest failed", "Power on selftest (POS) failed." },
{ Alarm_MotorFault, "Motor fault", "Motor fault." }
};
#endif

614
config.h Normal file

File diff suppressed because it is too large Load Diff

55
coolant_control.c Normal file
View File

@@ -0,0 +1,55 @@
/*
coolant_control.c - coolant control methods
Part of grblHAL
Copyright (c) 2016-2021 Terje Io
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdbool.h>
#include "hal.h"
#include "protocol.h"
#include "coolant_control.h"
#include "state_machine.h"
// Main program only. Immediately sets flood coolant running state and also mist coolant,
// if enabled. Also sets a flag to report an update to a coolant state.
// Called by coolant toggle override, parking restore, parking retract, sleep mode, g-code
// parser program end, and g-code parser coolant_sync().
void coolant_set_state (coolant_state_t mode)
{
if (!ABORTED) { // Block during abort.
hal.coolant.set_state(mode);
sys.report.coolant = On; // Set to report change immediately
}
}
// G-code parser entry-point for setting coolant state. Forces a planner buffer sync and bails
// if an abort or check-mode is active.
bool coolant_sync (coolant_state_t mode)
{
bool ok = true;
if (state_get() != STATE_CHECK_MODE) {
if((ok = protocol_buffer_synchronize())) // Ensure coolant changes state when specified in program.
coolant_set_state(mode);
}
return ok;
}

46
coolant_control.h Normal file
View File

@@ -0,0 +1,46 @@
/*
coolant_control.h - spindle control methods
Part of grblHAL
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _COOLANT_CONTROL_H_
#define _COOLANT_CONTROL_H_
typedef union {
uint8_t value;
uint8_t mask;
struct {
uint8_t flood :1,
mist :1,
shower :1,
trough_spindle :1,
reserved4 :1,
reserved5 :1,
reserved6 :1,
reserved7 :1;
};
} coolant_state_t;
// Sets the coolant pins according to state specified.
void coolant_set_state(coolant_state_t mode);
// G-code parser entry-point for setting coolant states. Checks for and executes additional conditions.
bool coolant_sync(coolant_state_t mode);
#endif

166
corexy.c Normal file
View File

@@ -0,0 +1,166 @@
/*
corexy.c - corexy kinematics implementation
Part of grblHAL
Copyright (c) 2019 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include "grbl.h"
#ifdef COREXY
#include "settings.h"
#include "planner.h"
#include "kinematics.h"
// CoreXY motor assignments. DO NOT ALTER.
// NOTE: If the A and B motor axis bindings are changed, this effects the CoreXY equations.
#define A_MOTOR X_AXIS // Must be X_AXIS
#define B_MOTOR Y_AXIS // Must be Y_AXIS
// Returns x or y-axis "steps" based on CoreXY motor steps.
inline static int32_t corexy_convert_to_a_motor_steps (int32_t *steps)
{
return (steps[A_MOTOR] + steps[B_MOTOR]) >> 1;
}
inline static int32_t corexy_convert_to_b_motor_steps (int32_t *steps)
{
return (steps[A_MOTOR] - steps[B_MOTOR]) >> 1;
}
// Returns machine position of axis 'idx'. Must be sent a 'step' array.
static void corexy_convert_array_steps_to_mpos (float *position, int32_t *steps)
{
position[X_AXIS] = corexy_convert_to_a_motor_steps(steps) / settings.axis[X_AXIS].steps_per_mm;
position[Y_AXIS] = corexy_convert_to_b_motor_steps(steps) / settings.axis[Y_AXIS].steps_per_mm;
position[Z_AXIS] = steps[Z_AXIS] / settings.axis[Z_AXIS].steps_per_mm;
}
// Transform absolute position from cartesian coordinate system (mm) to corexy coordinate system (step)
static void corexy_target_to_steps (int32_t *target_steps, float *target)
{
uint_fast8_t idx = N_AXIS;
int32_t a_steps, b_steps;
do {
switch(--idx) {
case X_AXIS:
a_steps = lroundf(target[idx] * settings.axis[idx].steps_per_mm);
break;
case Y_AXIS:
b_steps = lroundf(target[idx] * settings.axis[idx].steps_per_mm);
break;
default:
target_steps[idx] = lroundf(target[idx] * settings.axis[idx].steps_per_mm);
break;
}
} while(idx);
target_steps[A_MOTOR] = a_steps + b_steps;
target_steps[B_MOTOR] = a_steps - b_steps;
}
static uint_fast8_t corexy_limits_get_axis_mask (uint_fast8_t idx)
{
return ((idx == A_MOTOR) || (idx == B_MOTOR)) ? (bit(X_AXIS) | bit(Y_AXIS)) : bit(idx);
}
static void corexy_limits_set_target_pos (uint_fast8_t idx) // fn name?
{
int32_t axis_position;
switch(idx) {
case X_AXIS:
axis_position = corexy_convert_to_b_motor_steps(sys.position);
sys.position[A_MOTOR] = axis_position;
sys.position[B_MOTOR] = -axis_position;
break;
case Y_AXIS:
sys.position[A_MOTOR] = sys.position[B_MOTOR] = corexy_convert_to_a_motor_steps(sys.position);
break;
default:
sys.position[idx] = 0;
break;
}
}
// Set machine positions for homed limit switches. Don't update non-homed axes.
// NOTE: settings.max_travel[] is stored as a negative value.
static void corexy_limits_set_machine_positions (axes_signals_t cycle)
{
uint_fast8_t idx = N_AXIS;
if(settings.homing.flags.force_set_origin) {
if (cycle.mask & bit(--idx)) do {
switch(--idx) {
case X_AXIS:
sys.position[A_MOTOR] = corexy_convert_to_b_motor_steps(sys.position);
sys.position[B_MOTOR] = - sys.position[A_MOTOR];
break;
case Y_AXIS:
sys.position[A_MOTOR] = corexy_convert_to_a_motor_steps(sys.position);
sys.position[B_MOTOR] = sys.position[A_MOTOR];
break;
default:
sys.position[idx] = 0;
break;
}
} while (idx);
} else do {
if (cycle.mask & bit(--idx)) {
int32_t off_axis_position;
int32_t set_axis_position = bit_istrue(settings.homing.dir_mask.value, bit(idx))
? lroundf((settings.axis[idx].max_travel + settings.homing.pulloff) * settings.axis[idx].steps_per_mm)
: lroundf(-settings.homing.pulloff * settings.axis[idx].steps_per_mm);
switch(idx) {
case X_AXIS:
off_axis_position = corexy_convert_to_b_motor_steps(sys.position);
sys.position[A_MOTOR] = set_axis_position + off_axis_position;
sys.position[B_MOTOR] = set_axis_position - off_axis_position;
break;
case Y_AXIS:
off_axis_position = corexy_convert_to_a_motor_steps(sys.position);
sys.position[A_MOTOR] = off_axis_position + set_axis_position;
sys.position[B_MOTOR] = off_axis_position - set_axis_position;
break;
default:
sys.position[idx] = set_axis_position;
break;
}
}
} while(idx);
}
// Initialize API pointers for CoreXY kinematics
void corexy_init (void)
{
kinematics.limits_set_target_pos = corexy_limits_set_target_pos;
kinematics.limits_get_axis_mask = corexy_limits_get_axis_mask;
kinematics.limits_set_machine_positions = corexy_limits_set_machine_positions;
kinematics.plan_target_to_steps = corexy_target_to_steps;
kinematics.convert_array_steps_to_mpos = corexy_convert_array_steps_to_mpos;
}
#endif

29
corexy.h Normal file
View File

@@ -0,0 +1,29 @@
/*
corexy.c - corexy kinematics implementation
Part of grblHAL
Copyright (c) 2019 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _COREXY_H_
#define _COREXY_H_
// Initialize HAL pointers for CoreXY kinematics
void corexy_init (void);
#endif

42
crossbar.h Normal file
View File

@@ -0,0 +1,42 @@
/*
crossbar.h - signal crossbar definitions
Not used by the core.
Part of grblHAL
Copyright (c) 2021 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CROSSBAR_H_
#define _CROSSBAR_H_
typedef bool (*xbar_get_value_ptr)(void);
typedef void (*xbar_set_value_ptr)(bool on);
typedef void (*xbar_event_ptr)(bool on);
typedef void (*xbar_config_ptr)(void *cfg_data);
typedef struct {
uint32_t function;
void *port;
uint8_t bit;
xbar_config_ptr config;
xbar_get_value_ptr get_value;
xbar_set_value_ptr set_value;
xbar_event_ptr on_event;
} xbar_t;
#endif

599
defaults.h Normal file

File diff suppressed because it is too large Load Diff

167
errors.h Normal file
View File

@@ -0,0 +1,167 @@
/*
errors.h -
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _ERRORS_H_
#define _ERRORS_H_
#include <stddef.h>
// Define Grbl status codes. Valid values (0-255)
typedef enum {
Status_OK = 0,
Status_ExpectedCommandLetter = 1,
Status_BadNumberFormat = 2,
Status_InvalidStatement = 3,
Status_NegativeValue = 4,
Status_HomingDisabled = 5,
Status_SettingStepPulseMin = 6,
Status_SettingReadFail = 7,
Status_IdleError = 8,
Status_SystemGClock = 9,
Status_SoftLimitError = 10,
Status_Overflow = 11,
Status_MaxStepRateExceeded = 12,
Status_CheckDoor = 13,
Status_LineLengthExceeded = 14,
Status_TravelExceeded = 15,
Status_InvalidJogCommand = 16,
Status_SettingDisabledLaser = 17,
Status_Reset = 18,
Status_NonPositiveValue = 19,
Status_GcodeUnsupportedCommand = 20,
Status_GcodeModalGroupViolation = 21,
Status_GcodeUndefinedFeedRate = 22,
Status_GcodeCommandValueNotInteger = 23,
Status_GcodeAxisCommandConflict = 24,
Status_GcodeWordRepeated = 25,
Status_GcodeNoAxisWords = 26,
Status_GcodeInvalidLineNumber = 27,
Status_GcodeValueWordMissing = 28,
Status_GcodeUnsupportedCoordSys = 29,
Status_GcodeG53InvalidMotionMode = 30,
Status_GcodeAxisWordsExist = 31,
Status_GcodeNoAxisWordsInPlane = 32,
Status_GcodeInvalidTarget = 33,
Status_GcodeArcRadiusError = 34,
Status_GcodeNoOffsetsInPlane = 35,
Status_GcodeUnusedWords = 36,
Status_GcodeG43DynamicAxisError = 37,
Status_GcodeIllegalToolTableEntry = 38,
Status_GcodeValueOutOfRange = 39,
Status_GcodeToolChangePending = 40,
Status_GcodeSpindleNotRunning = 41,
Status_GcodeIllegalPlane = 42,
Status_GcodeMaxFeedRateExceeded = 43,
Status_GcodeRPMOutOfRange = 44,
Status_LimitsEngaged = 45,
Status_HomingRequired = 46,
Status_GCodeToolError = 47,
Status_ValueWordConflict = 48,
Status_SelfTestFailed = 49,
Status_EStop = 50,
Status_MotorFault = 51,
Status_SettingValueOutOfRange = 52,
Status_SettingDisabled = 53,
// Some error codes as defined in bdring's ESP32 port
Status_SDMountError = 60,
Status_SDReadError = 61,
Status_SDFailedOpenDir = 62,
Status_SDDirNotFound = 63,
Status_SDFileEmpty = 64,
Status_BTInitError = 70,
Status_Unhandled // For internal use only
} status_code_t;
typedef struct {
status_code_t id;
const char *name;
const char *description;
} status_detail_t;
PROGMEM static const status_detail_t status_detail[] = {
{ Status_OK, "ok", NULL },
{ Status_ExpectedCommandLetter, "Expected command letter", "G-code words consist of a letter and a value. Letter was not found." },
{ Status_BadNumberFormat, "Bad number format", "Missing the expected G-code word value or numeric value format is not valid." },
{ Status_InvalidStatement, "Invalid statement", "Grbl '$' system command was not recognized or supported." },
{ Status_NegativeValue, "Value < 0", "Negative value received for an expected positive value." },
{ Status_HomingDisabled, "Homing disabled", "Homing cycle failure. Homing is not configured via settings." },
{ Status_SettingStepPulseMin, "Value < 2 microseconds", "Step pulse time must be greater or equal to 2 microseconds." },
{ Status_SettingReadFail, "EEPROM read fail. Using defaults", "An EEPROM read failed. Auto-restoring affected EEPROM to default values." },
{ Status_IdleError, "Not idle", "Grbl '$' command cannot be used unless Grbl is IDLE. Ensures smooth operation during a job." },
{ Status_SystemGClock, "G-code lock", "G-code commands are locked out during alarm or jog state." },
{ Status_SoftLimitError, "Homing not enabled", "Soft limits cannot be enabled without homing also enabled." },
{ Status_Overflow, "Line overflow", "Max characters per line exceeded. Received command line was not executed." },
{ Status_MaxStepRateExceeded, "Step rate > 30kHz", "Grbl '$' setting value cause the step rate to exceed the maximum supported." },
{ Status_CheckDoor, "Check Door", "Safety door detected as opened and door state initiated." },
{ Status_LineLengthExceeded, "Line length exceeded", "Build info or startup line exceeded EEPROM line length limit. Line not stored." },
{ Status_TravelExceeded, "Travel exceeded", "Jog target exceeds machine travel. Jog command has been ignored." },
{ Status_InvalidJogCommand, "Invalid jog command", "Jog command has no '=' or contains prohibited g-code." },
{ Status_SettingDisabledLaser, "Setting disabled", "Laser mode requires PWM output." },
{ Status_Reset, "Reset asserted", "" },
{ Status_NonPositiveValue, "Non positive value", "" },
{ Status_GcodeUnsupportedCommand, "Unsupported command", "Unsupported or invalid g-code command found in block." },
{ Status_GcodeModalGroupViolation, "Modal group violation", "More than one g-code command from same modal group found in block." },
{ Status_GcodeUndefinedFeedRate, "Undefined feed rate", "Feed rate has not yet been set or is undefined." },
{ Status_GcodeCommandValueNotInteger, "Invalid gcode ID:23", "G-code command in block requires an integer value." },
{ Status_GcodeAxisCommandConflict, "Invalid gcode ID:24", "More than one g-code command that requires axis words found in block." },
{ Status_GcodeWordRepeated, "Invalid gcode ID:25", "Repeated g-code word found in block." },
{ Status_GcodeNoAxisWords, "Invalid gcode ID:26", "No axis words found in block for g-code command or current modal state which requires them." },
{ Status_GcodeInvalidLineNumber, "Invalid gcode ID:27", "Line number value is invalid." },
{ Status_GcodeValueWordMissing, "Invalid gcode ID:28", "G-code command is missing a required value word." },
{ Status_GcodeUnsupportedCoordSys, "Invalid gcode ID:29", "G59.x work coordinate systems are not supported." },
{ Status_GcodeG53InvalidMotionMode, "Invalid gcode ID:30", "G53 only allowed with G0 and G1 motion modes." },
{ Status_GcodeAxisWordsExist, "Invalid gcode ID:31", "Axis words found in block when no command or current modal state uses them." },
{ Status_GcodeNoAxisWordsInPlane, "Invalid gcode ID:32", "G2 and G3 arcs require at least one in-plane axis word." },
{ Status_GcodeInvalidTarget, "Invalid gcode ID:33", "Motion command target is invalid." },
{ Status_GcodeArcRadiusError, "Invalid gcode ID:34", "Arc radius value is invalid." },
{ Status_GcodeNoOffsetsInPlane, "Invalid gcode ID:35", "G2 and G3 arcs require at least one in-plane offset word." },
{ Status_GcodeUnusedWords, "Invalid gcode ID:36", "Unused value words found in block." },
{ Status_GcodeG43DynamicAxisError, "Invalid gcode ID:37", "G43.1 dynamic tool length offset is not assigned to configured tool length axis." },
{ Status_GcodeIllegalToolTableEntry, "Invalid gcode ID:38", "Tool number greater than max supported value or undefined tool selected." },
{ Status_GcodeValueOutOfRange, "Invalid gcode ID:39", "Value out of range." },
{ Status_GcodeToolChangePending, "Invalid gcode ID:40", "G-code command not allowed when tool change is pending." },
{ Status_GcodeSpindleNotRunning, "Invalid gcode ID:41", "Spindle not running when motion commanded in CSS or spindle sync mode." },
{ Status_GcodeIllegalPlane, "Invalid gcode ID:42", "Plane must be ZX for threading." },
{ Status_GcodeMaxFeedRateExceeded, "Invalid gcode ID:43", "Max. feed rate exceeded." },
{ Status_GcodeRPMOutOfRange, "Invalid gcode ID:44", "RPM out of range." },
{ Status_LimitsEngaged, "Limit switch engaged", "Only homing is allowed when a limit switch is engaged." },
{ Status_HomingRequired, "Homing required", "Home machine to continue." },
{ Status_GCodeToolError, "Invalid gcode ID:47", "ATC: current tool is not set. Set current tool with M61." },
{ Status_ValueWordConflict, "Invalid gcode ID:48", "Value word conflict." },
{ Status_SelfTestFailed, "Self test failed", "Power on self test failed. A hard reset is required." },
{ Status_EStop, "E-stop", "Emergency stop active." },
{ Status_MotorFault, "Motor fault", "Motor fault." },
{ Status_SettingValueOutOfRange, "Value out of range.", "Setting value is out of range." },
{ Status_SettingDisabled, "Setting disabled", "Setting is not available, possibly due to limited driver support." },
{ Status_SDMountError, "SD Card", "SD Card mount failed." },
{ Status_SDReadError, "SD Card", "SD Card file open/read failed." },
{ Status_SDFailedOpenDir, "SD Card", "SD Card directory listing failed." },
{ Status_SDDirNotFound, "SD Card", "SD Card directory not found." },
{ Status_SDFileEmpty, "SD Card", "SD Card file empty." },
{ Status_BTInitError, "Bluetooth", "Bluetooth initalisation failed." }
};
#endif

2748
gcode.c Normal file

File diff suppressed because it is too large Load Diff

480
gcode.h Normal file
View File

@@ -0,0 +1,480 @@
/*
gcode.h - rs274/ngc parser.
Part of grblHAL
Copyright (c) 2017-2020 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GCODE_H_
#define _GCODE_H_
#include "nuts_bolts.h"
#include "coolant_control.h"
#include "spindle_control.h"
#include "errors.h"
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
// internally by the parser to know which command to execute.
// NOTE: Some values are assigned specific values to make g-code state reporting and parsing
// compile a litte smaller. Although not
// ideal, just be careful with values that state 'do not alter' and check both report.c and gcode.c
// to see how they are used, if you need to alter them.
// Modal Group G0: Non-modal actions
typedef enum {
NonModal_NoAction = 0, // (Default: Must be zero)
NonModal_Dwell = 4, // G4 (Do not alter value)
NonModal_SetCoordinateData = 10, // G10 (Do not alter value)
NonModal_GoHome_0 = 28, // G28 (Do not alter value)
NonModal_SetHome_0 = 38, // G28.1 (Do not alter value)
NonModal_GoHome_1 = 30, // G30 (Do not alter value)
NonModal_SetHome_1 = 40, // G30.1 (Do not alter value)
NonModal_AbsoluteOverride = 53, // G53 (Do not alter value)
NonModal_SetCoordinateOffset = 92, // G92 (Do not alter value)
NonModal_ResetCoordinateOffset = 102, // G92.1 (Do not alter value)
NonModal_ClearCoordinateOffset = 112, // G92.2 (Do not alter value)
NonModal_RestoreCoordinateOffset = 122 // G92.3 (Do not alter value)
} non_modal_t;
// Modal Group G1: Motion modes
typedef enum {
MotionMode_Seek = 0, // G0 (Default: Must be zero)
MotionMode_Linear = 1, // G1 (Do not alter value)
MotionMode_CwArc = 2, // G2 (Do not alter value)
MotionMode_CcwArc = 3, // G3 (Do not alter value)
MotionMode_CubicSpline = 5, // G5 (Do not alter value)
MotionMode_SpindleSynchronized = 33, // G33 (Do not alter value)
MotionMode_DrillChipBreak = 73, // G73 (Do not alter value)
MotionMode_Threading = 76, // G76 (Do not alter value)
MotionMode_CannedCycle81 = 81, // G81 (Do not alter value)
MotionMode_CannedCycle82 = 82, // G82 (Do not alter value)
MotionMode_CannedCycle83 = 83, // G83 (Do not alter value)
MotionMode_CannedCycle85 = 85, // G85 (Do not alter value)
MotionMode_CannedCycle86 = 86, // G86 (Do not alter value)
MotionMode_CannedCycle89 = 89, // G89 (Do not alter value)
MotionMode_ProbeToward = 140, // G38.2 (Do not alter value)
MotionMode_ProbeTowardNoError = 141, // G38.3 (Do not alter value)
MotionMode_ProbeAway = 142, // G38.4 (Do not alter value)
MotionMode_ProbeAwayNoError = 143, // G38.5 (Do not alter value)
MotionMode_None = 80 // G80 (Do not alter value)
} motion_mode_t;
// Modal Group G2: Plane select
typedef enum {
PlaneSelect_XY = 0, // G17 (Default: Must be zero)
PlaneSelect_ZX = 1, // G18 (Do not alter value)
PlaneSelect_YZ = 2 // G19 (Do not alter value)
} plane_select_t;
// Modal Group G4: Arc IJK distance mode
//#define DISTANCE_ARC_MODE_INCREMENTAL 0 // G91.1 (Default: Must be zero)
// Modal Group M4: Program flow
typedef enum {
ProgramFlow_Running = 0, // (Default: Must be zero)
ProgramFlow_Paused = 3, // M0
ProgramFlow_OptionalStop = 1, // M1
ProgramFlow_CompletedM2 = 2, // M2 (Do not alter value)
ProgramFlow_CompletedM30 = 30, // M30 (Do not alter value)
ProgramFlow_CompletedM60 = 60 // M60 (Do not alter value)
} program_flow_t;
// Modal Group G5: Feed rate mode
typedef enum {
FeedMode_UnitsPerMin = 0, // G94 (Default: Must be zero)
FeedMode_InverseTime = 1, // G93 (Do not alter value)
FeedMode_UnitsPerRev = 2 // G95 (Do not alter value)
} feed_mode_t;
// Modal Group G10: Canned cycle return mode
typedef enum {
CCRetractMode_Previous = 0, // G98 (Default: Must be zero)
CCRetractMode_RPos = 1 // G99 (Do not alter value)
} cc_retract_mode_t;
// Modal Group G7: Cutter radius compensation mode
//#define CUTTER_COMP_DISABLE 0 // G40 (Default: Must be zero)
// Modal Group G13: Control mode
//#define CONTROL_MODE_EXACT_PATH 0 // G61 (Default: Must be zero)
// Modal Group G8: Tool length offset
typedef enum {
ToolLengthOffset_Cancel = 0, // G49 (Default: Must be zero)
ToolLengthOffset_Enable = 1, // G43
ToolLengthOffset_EnableDynamic = 2, // G43.1
ToolLengthOffset_ApplyAdditional = 3 // G43.2
} tool_offset_mode_t;
// Modal Group M9: Override control
typedef enum {
Override_Parking = 56, // M56
Override_FeedHold = 53, // M53
Override_FeedSpeed = 49, // M49
Override_FeedRate = 50, // M50
Override_SpindleSpeed = 51 // M51
} override_mode_t;
// Modal Group G12: Active work coordinate system
// N/A: Stores coordinate system value (54-59) to change to.
// Modal Group G14: Spindle Speed Mode
typedef enum {
SpindleSpeedMode_RPM = 0, // G96 (Default: Must be zero)
SpindleSpeedMode_CSS = 1 // G97 (Do not alter value)
} spindle_rpm_mode_t;
typedef struct output_command {
bool is_digital;
bool is_executed;
uint8_t port;
int32_t value;
struct output_command *next;
} output_command_t;
typedef enum {
WaitMode_Immediate = 0,
WaitMode_Rise,
WaitMode_Fall,
WaitMode_High,
WaitMode_Low,
WaitMode_Max // Used for validation only
} wait_mode_t;
// Modal Group M10: User defined M commands
// NOTE: Not used by core, may be used by driver code
typedef enum {
UserMCode_Ignore = 0,
UserMCode_Generic0 = 100,
UserMCode_Generic1 = 101,
UserMCode_Generic2 = 102,
UserMCode_Generic3 = 103,
UserMCode_Generic4 = 104,
LaserPPI_Enable = 112,
LaserPPI_Rate = 113,
LaserPPI_PulseLength = 114,
Laser_Coolant = 115,
Trinamic_DebugReport = 122,
Trinamic_StepperCurrent = 906,
Trinamic_ModeToggle = 569,
Trinamic_ReportPrewarnFlags = 911,
Trinamic_ClearPrewarnFlags = 912,
Trinamic_HybridThreshold = 913,
Trinamic_HomingSensitivity = 914
} user_mcode_t;
// Define g-code parser position updating flags
typedef enum {
GCUpdatePos_Target = 0,
GCUpdatePos_System,
GCUpdatePos_None
} pos_update_t;
// Define probe cycle exit states and assign proper position updating.
typedef enum {
GCProbe_Found = GCUpdatePos_System,
GCProbe_Abort = GCUpdatePos_None,
GCProbe_FailInit = GCUpdatePos_None,
GCProbe_FailEnd = GCUpdatePos_Target,
#ifdef SET_CHECK_MODE_PROBE_TO_START
GCProbe_CheckMode = GCUpdatePos_None
#else
GCProbe_CheckMode = GCUpdatePos_Target
#endif
} gc_probe_t;
// Define parser words bitfield
typedef union {
uint32_t mask;
uint32_t value;
struct {
uint32_t e :1,
f :1,
h :1,
i :1,
j :1,
k :1,
l :1,
n :1,
p :1,
r :1,
s :1,
t :1,
x :1,
y :1,
z :1,
q :1,
#if N_AXIS > 3
a :1,
b :1,
c :1,
#endif
d :1;
};
} parameter_words_t;
// Define gcode parser flags for handling special cases.
typedef union {
uint16_t value;
struct {
uint16_t jog_motion :1,
canned_cycle_change :1, // Use motion_mode_changed?
arc_is_clockwise :1,
probe_is_away :1,
probe_is_no_error :1,
spindle_force_sync :1,
laser_disable :1,
laser_is_motion :1,
set_coolant :1,
motion_mode_changed :1,
reserved :6;
};
} gc_parser_flags_t;
typedef union {
uint8_t value;
struct {
uint8_t feed_rate_disable :1,
feed_hold_disable :1,
spindle_rpm_disable :1,
parking_disable :1,
reserved :3,
sync :1;
};
} gc_override_flags_t;
typedef union {
float values[N_AXIS];
struct {
float x;
float y;
float z;
#ifdef A_AXIS
float a;
#endif
#ifdef B_AXIS
float b;
#endif
#ifdef C_AXIS
float c;
#endif
};
} coord_data_t;
typedef enum {
CoordinateSystem_G54 = 0,
CoordinateSystem_G55,
CoordinateSystem_G56,
CoordinateSystem_G57,
CoordinateSystem_G58,
CoordinateSystem_G59,
#if COMPATIBILITY_LEVEL <= 1
CoordinateSystem_G59_1,
CoordinateSystem_G59_2,
CoordinateSystem_G59_3,
#endif
N_WorkCoordinateSystems,
CoordinateSystem_G28 = N_WorkCoordinateSystems,
CoordinateSystem_G30,
CoordinateSystem_G92,
N_CoordinateSystems
} coord_system_id_t;
typedef struct {
float xyz[N_AXIS];
coord_system_id_t id;
} coord_system_t;
typedef struct {
uint8_t axis_0;
uint8_t axis_1;
uint8_t axis_linear;
} plane_t;
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
typedef struct {
motion_mode_t motion; // {G0,G1,G2,G3,G38.2,G80}
feed_mode_t feed_mode; // {G93,G94}
bool units_imperial; // {G20,G21}
bool distance_incremental; // {G90,G91}
bool diameter_mode; // {G7,G8} Lathe diameter mode.
// uint8_t distance_arc; // {G91.1} NOTE: Don't track. Only default supported.
plane_select_t plane_select; // {G17,G18,G19}
// uint8_t cutter_comp; // {G40} NOTE: Don't track. Only default supported.
tool_offset_mode_t tool_offset_mode; // {G43,G43.1,G49}
coord_system_t coord_system; // {G54,G55,G56,G57,G58,G59,G59.1,G59.2,G59.3}
// uint8_t control; // {G61} NOTE: Don't track. Only default supported.
program_flow_t program_flow; // {M0,M1,M2,M30,M60}
coolant_state_t coolant; // {M7,M8,M9}
spindle_state_t spindle; // {M3,M4,M5}
gc_override_flags_t override_ctrl; // {M48,M49,M50,M51,M53,M56}
spindle_rpm_mode_t spindle_rpm_mode; // {G96,G97}
cc_retract_mode_t retract_mode; // {G98,G99}
bool scaling_active; // {G50,G51}
bool canned_cycle_active;
float spline_pq[2]; // {G5}
} gc_modal_t;
typedef struct {
float d; // Max spindle RPM in Constant Surface Speed Mode (G96)
float e; // Thread taper length (G76)
float f; // Feed
float ijk[3]; // I,J,K Axis arc offsets
float k; // G33 distance per revolution
float p; // G10 or dwell parameters
float q; // User defined M-code parameter (G82 peck drilling, not supported)
float r; // Arc radius or retract position
float s; // Spindle speed
float xyz[N_AXIS]; // X,Y,Z Translational axes
coord_system_t coord_data; // Coordinate data
int32_t n; // Line number
uint32_t h; // Tool number
uint32_t t; // Tool selection
uint8_t l; // G10 or canned cycles parameters
} gc_values_t;
typedef struct {
float xyz[3];
float delta;
float dwell;
float prev_position;
float retract_position; // Canned cycle retract position
bool rapid_retract;
bool spindle_off;
cc_retract_mode_t retract_mode;
bool change;
} gc_canned_t;
typedef enum {
Taper_None = 0,
Taper_Entry,
Taper_Exit,
Taper_Both
} gc_taper_type;
typedef struct {
float pitch;
float z_final;
float peak;
float initial_depth;
float depth;
float depth_degression;
float main_taper_height;
float end_taper_length;
float infeed_angle;
float cut_direction;
uint_fast16_t spring_passes;
gc_taper_type end_taper_type;
} gc_thread_data;
typedef struct {
float offset[N_AXIS];
float radius;
uint32_t tool;
} tool_data_t;
// Data used for Constant Surface Speed Mode calculations
typedef struct {
float surface_speed; // Surface speed in millimeters/min
float target_rpm; // Target RPM at end of movement
float max_rpm; // Maximum spindle RPM
float tool_offset; // Tool offset
uint_fast8_t axis; // Linear (tool) axis
bool active;
} css_data_t;
typedef struct {
float rpm; // RPM
css_data_t css; // Data used for Constant Surface Speed Mode calculations
} spindle_t;
typedef struct {
gc_modal_t modal;
gc_canned_t canned;
spindle_t spindle; // RPM
float feed_rate; // Millimeters/min
float distance_per_rev; // Millimeters/rev
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
int32_t line_number; // Last line number sent
uint32_t tool_pending; // Tool to be selected on next M6
bool file_run; // Tracks % command
bool is_laser_ppi_mode;
bool is_rpm_rate_adjusted;
bool tool_change;
status_code_t last_error; // last return value from parser
// The following variables are not cleared upon warm restart when COMPATIBILITY_LEVEL <= 1
float g92_coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
// machine zero in mm. Persistent and loaded from non-volatile storage
// on boot when COMPATIBILITY_LEVEL <= 1
float tool_length_offset[N_AXIS]; // Tracks tool length offset when enabled
tool_data_t *tool; // Tracks tool number and tool offset
} parser_state_t;
typedef struct {
float xyz[N_AXIS]; // Center point
float ijk[N_AXIS]; // Scaling factors
} scale_factor_t;
extern parser_state_t gc_state;
#ifdef N_TOOLS
extern tool_data_t tool_table[N_TOOLS + 1];
#else
extern tool_data_t tool_table;
#endif
typedef struct {
non_modal_t non_modal_command;
override_mode_t override_command; // TODO: add to non_modal above?
user_mcode_t user_mcode;
bool user_mcode_sync;
gc_modal_t modal;
gc_values_t values;
output_command_t output_command;
} parser_block_t;
// Initialize the parser
void gc_init (void);
// Execute one block of rs275/ngc/g-code
status_code_t gc_execute_block (char *block, char *message);
// Sets g-code parser position in mm. Input in steps. Called by the system abort and hard
// limit pull-off routines.
#define gc_sync_position() system_convert_array_steps_to_mpos (gc_state.position, sys.position)
// Sets g-code parser and planner position in mm.
#define sync_position() plan_sync_position(); system_convert_array_steps_to_mpos (gc_state.position, sys.position)
// Set dynamic laser power mode to PPI (Pulses Per Inch)
// Driver support for pulsing the laser on signal is required for this to work.
// Returns true if driver uses hardware implementation.
bool gc_laser_ppi_enable (uint_fast16_t ppi, uint_fast16_t pulse_length);
// Gets axes scaling state.
axes_signals_t gc_get_g51_state (void);
float *gc_get_scaling (void);
// Get current axis offset.
float gc_get_offset (uint_fast8_t idx);
void gc_set_tool_offset (tool_offset_mode_t mode, uint_fast8_t idx, int32_t offset);
plane_t *gc_get_plane_data (plane_t *plane, plane_select_t select);
#endif

276
grbl.h Normal file
View File

@@ -0,0 +1,276 @@
/*
grbl.h - main Grbl include file for compile time configuration
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2015-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GRBL_H_
#define _GRBL_H_
#include <stdint.h>
#include <stdbool.h>
#include "config.h"
// Grbl versioning system
#if COMPATIBILITY_LEVEL == 0
#define GRBL_VERSION "1.1f"
#else
#define GRBL_VERSION "1.1f"
#endif
#define GRBL_VERSION_BUILD "20210222"
// The following symbols are set here if not already set by the compiler or in config.h
// Do NOT change here!
#ifdef GRBL_ESP32
#include "esp_attr.h"
#define ISR_CODE IRAM_ATTR
#else
// Used to decorate code run in interrupt context.
// Do not remove or change unless you know what you are doing.
#define ISR_CODE
#endif
#ifdef ARDUINO
#include <Arduino.h>
#endif
#ifndef PROGMEM
#define PROGMEM
#endif
#ifndef N_AXIS
#define N_AXIS 3 // Number of axes
#endif
#ifndef COMPATIBILITY_LEVEL
#define COMPATIBILITY_LEVEL 0
#endif
#if (defined(COREXY) || defined(WALL_PLOTTER) || defined(MASLOW_ROUTER)) && !defined(KINEMATICS_API)
#define KINEMATICS_API
#endif
#ifndef CHECK_MODE_DELAY
#define CHECK_MODE_DELAY 0 // ms
#endif
#ifndef SAFETY_DOOR_SPINDLE_DELAY
#define SAFETY_DOOR_SPINDLE_DELAY 4.0f // Float (seconds)
#endif
#ifndef SAFETY_DOOR_COOLANT_DELAY
#define SAFETY_DOOR_COOLANT_DELAY 1.0f // Float (seconds)
#endif
#ifndef SPINDLE_RPM_CONTROLLED
#define SPINDLE_PWM_DIRECT
#endif
#ifndef SLEEP_DURATION
#define SLEEP_DURATION 5.0f // Number of minutes before sleep mode is entered.
#endif
#ifndef BUFFER_NVSDATA_DISABLE
#define BUFFER_NVSDATA
#endif
// The following symbols are default values that are unlikely to be changed
// Do not change unless you know what you are doing!
// Define realtime command special characters. These characters are 'picked-off' directly from the
// serial read data stream and are not passed to the grbl line execution parser. Select characters
// that do not and must not exist in the streamed g-code program. ASCII control characters may be
// used, if they are available per user setup. Also, extended ASCII codes (>127), which are never in
// g-code programs, maybe selected for interface programs.
// NOTE: If changed, manually update help message in report.c.
#define CMD_EXIT 0x03 // ctrl-C (ETX)
#define CMD_REBOOT 0x14 // ctrl-T (DC4) - only acted upon if preceeded by 0x1B (ESC)
#define CMD_RESET 0x18 // ctrl-X (CAN)
#define CMD_STOP 0x19 // ctrl-Y (EM)
#define CMD_STATUS_REPORT_LEGACY '?'
#define CMD_CYCLE_START_LEGACY '~'
#define CMD_FEED_HOLD_LEGACY '!'
#define CMD_PROGRAM_DEMARCATION '%'
// NOTE: All override realtime commands must be in the extended ASCII character set, starting
// at character value 128 (0x80) and up to 255 (0xFF). If the normal set of realtime commands,
// such as status reports, feed hold, reset, and cycle start, are moved to the extended set
// space, protocol.c's protocol_process_realtime() will need to be modified to accomodate the change.
#define CMD_STATUS_REPORT 0x80 // TODO: use 0x05 ctrl-E ENQ instead?
#define CMD_CYCLE_START 0x81 // TODO: use 0x06 ctrl-F ACK instead? or SYN/DC2/DC3?
#define CMD_FEED_HOLD 0x82 // TODO: use 0x15 ctrl-U NAK instead?
#define CMD_GCODE_REPORT 0x83
#define CMD_SAFETY_DOOR 0x84
#define CMD_JOG_CANCEL 0x85
//#define CMD_DEBUG_REPORT 0x86 // Only when DEBUG enabled, sends debug report in '{}' braces.
#define CMD_STATUS_REPORT_ALL 0x87
#define CMD_OPTIONAL_STOP_TOGGLE 0x88
#define CMD_OVERRIDE_FEED_RESET 0x90 // Restores feed override value to 100%.
#define CMD_OVERRIDE_FEED_COARSE_PLUS 0x91
#define CMD_OVERRIDE_FEED_COARSE_MINUS 0x92
#define CMD_OVERRIDE_FEED_FINE_PLUS 0x93
#define CMD_OVERRIDE_FEED_FINE_MINUS 0x94
#define CMD_OVERRIDE_RAPID_RESET 0x95 // Restores rapid override value to 100%.
#define CMD_OVERRIDE_RAPID_MEDIUM 0x96
#define CMD_OVERRIDE_RAPID_LOW 0x97
// #define CMD_OVERRIDE_RAPID_EXTRA_LOW 0x98 // *NOT SUPPORTED*
#define CMD_OVERRIDE_SPINDLE_RESET 0x99 // Restores spindle override value to 100%.
#define CMD_OVERRIDE_SPINDLE_COARSE_PLUS 0x9A
#define CMD_OVERRIDE_SPINDLE_COARSE_MINUS 0x9B
#define CMD_OVERRIDE_SPINDLE_FINE_PLUS 0x9C
#define CMD_OVERRIDE_SPINDLE_FINE_MINUS 0x9D
#define CMD_OVERRIDE_SPINDLE_STOP 0x9E
#define CMD_OVERRIDE_COOLANT_FLOOD_TOGGLE 0xA0
#define CMD_OVERRIDE_COOLANT_MIST_TOGGLE 0xA1
#define CMD_PID_REPORT 0xA2
#define CMD_TOOL_ACK 0xA3
#define CMD_PROBE_CONNECTED_TOGGLE 0xA4
// System motion line numbers must be zero.
#define JOG_LINE_NUMBER 0
// Number of blocks Grbl executes upon startup. These blocks are stored in non-volatile storage, where the size
// and addresses are defined in settings.h. With the current settings, up to 2 startup blocks may
// be stored and executed in order. These startup blocks would typically be used to set the g-code
// parser state depending on user preferences.
#define N_STARTUP_LINE 2 // Integer (1-2)
// Number of decimal places (scale) output by Grbl for certain value types. These settings
// are determined by realistic and commonly observed values in CNC machines. For example, position
// values cannot be less than 0.001mm or 0.0001in, because machines can not be physically more
// precise this. So, there is likely no need to change these, but you can if you need to here.
// NOTE: Must be an integer value from 0 to ~4. More than 4 may exhibit round-off errors.
#define N_DECIMAL_COORDVALUE_INCH 4 // Coordinate or position value in inches
#define N_DECIMAL_COORDVALUE_MM 3 // Coordinate or position value in mm
#define N_DECIMAL_RATEVALUE_INCH 1 // Rate or velocity value in in/min
#define N_DECIMAL_RATEVALUE_MM 0 // Rate or velocity value in mm/min
#define N_DECIMAL_SETTINGVALUE 3 // Floating point setting values
#define N_DECIMAL_RPMVALUE 0 // RPM value in rotations per min
#define N_DECIMAL_PIDVALUE 3 // PID value
// ---------------------------------------------------------------------------------------
// ADVANCED CONFIGURATION OPTIONS:
// Enables code for debugging purposes. Not for general use and always in constant flux.
// #define DEBUG // Uncomment to enable. Default disabled.
// Configure rapid, feed, and spindle override settings. These values define the max and min
// allowable override values and the coarse and fine increments per command received. Please
// note the allowable values in the descriptions following each define.
#define DEFAULT_FEED_OVERRIDE 100 // 100%. Don't change this value.
#define MAX_FEED_RATE_OVERRIDE 200 // Percent of programmed feed rate (100-255). Usually 120% or 200%
#define MIN_FEED_RATE_OVERRIDE 10 // Percent of programmed feed rate (1-100). Usually 50% or 1%
#define FEED_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
#define FEED_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
#define DEFAULT_RAPID_OVERRIDE 100 // 100%. Don't change this value.
#define RAPID_OVERRIDE_MEDIUM 50 // Percent of rapid (1-99). Usually 50%.
#define RAPID_OVERRIDE_LOW 25 // Percent of rapid (1-99). Usually 25%.
// #define RAPID_OVERRIDE_EXTRA_LOW 5 // *NOT SUPPORTED* Percent of rapid (1-99). Usually 5%.
// #define ENABLE_SPINDLE_LINEARIZATION // Uncomment to enable spindle RPM linearization. Requires compatible driver if enabled.
#define SPINDLE_NPWM_PIECES 4 // Maximum number of pieces for spindle RPM linearization, do not change unless more are needed.
#define DEFAULT_SPINDLE_RPM_OVERRIDE 100 // 100%. Don't change this value.
#define MAX_SPINDLE_RPM_OVERRIDE 200 // Percent of programmed spindle speed (100-255). Usually 200%.
#define MIN_SPINDLE_RPM_OVERRIDE 10 // Percent of programmed spindle speed (1-100). Usually 10%.
#define SPINDLE_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
#define SPINDLE_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
// Some status report data isn't necessary for realtime, only intermittently, because the values don't
// change often. The following macros configures how many times a status report needs to be called before
// the associated data is refreshed and included in the status report. However, if one of these value
// changes, Grbl will automatically include this data in the next status report, regardless of what the
// count is at the time. This helps reduce the communication overhead involved with high frequency reporting
// and agressive streaming. There is also a busy and an idle refresh count, which sets up Grbl to send
// refreshes more often when its not doing anything important. With a good GUI, this data doesn't need
// to be refreshed very often, on the order of a several seconds.
// NOTE: WCO refresh must be 2 or greater. OVERRIDE refresh must be 1 or greater.
//#define REPORT_OVERRIDE_REFRESH_BUSY_COUNT 20 // (1-255)
//#define REPORT_OVERRIDE_REFRESH_IDLE_COUNT 10 // (1-255) Must be less than or equal to the busy count
//#define REPORT_WCO_REFRESH_BUSY_COUNT 30 // (2-255)
//#define REPORT_WCO_REFRESH_IDLE_COUNT 10 // (2-255) Must be less than or equal to the busy count
// The temporal resolution of the acceleration management subsystem. A higher number gives smoother
// acceleration, particularly noticeable on machines that run at very high feedrates, but may negatively
// impact performance. The correct value for this parameter is machine dependent, so it's advised to
// set this only as high as needed. Approximate successful values can widely range from 50 to 200 or more.
// NOTE: Changing this value also changes the execution time of a segment in the step segment buffer.
// When increasing this value, this stores less overall time in the segment buffer and vice versa. Make
// certain the step segment buffer is increased/decreased to account for these changes.
//#define ACCELERATION_TICKS_PER_SECOND 100
// Adaptive Multi-Axis Step Smoothing (AMASS) is an advanced feature that does what its name implies,
// smoothing the stepping of multi-axis motions. This feature smooths motion particularly at low step
// frequencies below 10kHz, where the aliasing between axes of multi-axis motions can cause audible
// noise and shake your machine. At even lower step frequencies, AMASS adapts and provides even better
// step smoothing. See stepper.c for more details on the AMASS system works.
#define ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING // Default enabled. Comment to disable.
// Define Adaptive Multi-Axis Step-Smoothing(AMASS) levels and cutoff frequencies. The highest level
// frequency bin starts at 0Hz and ends at its cutoff frequency. The next lower level frequency bin
// starts at the next higher cutoff frequency, and so on. The cutoff frequencies for each level must
// be considered carefully against how much it over-drives the stepper ISR, the accuracy of the 16-bit
// timer, and the CPU overhead. Level 0 (no AMASS, normal operation) frequency bin starts at the
// Level 1 cutoff frequency and up to as fast as the CPU allows (over 30kHz in limited testing).
// NOTE: AMASS cutoff frequency multiplied by ISR overdrive factor must not exceed maximum step frequency.
// NOTE: Current settings are set to overdrive the ISR to no more than 16kHz, balancing CPU overhead
// and timer accuracy. Do not alter these settings unless you know what you are doing.
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
#ifndef MAX_AMASS_LEVEL
#define MAX_AMASS_LEVEL 3
#endif
#if MAX_AMASS_LEVEL <= 0
error "AMASS must have 1 or more levels to operate correctly."
#endif
#endif
// Sets the maximum step rate allowed to be written as a Grbl setting. This option enables an error
// check in the settings module to prevent settings values that will exceed this limitation. The maximum
// step rate is strictly limited by the CPU speed and will change if something other than an AVR running
// at 16MHz is used.
// NOTE: For now disabled, will enable if flash space permits.
// #define MAX_STEP_RATE_HZ 30000 // Hz
// With this enabled, Grbl sends back an echo of the line it has received, which has been pre-parsed (spaces
// removed, capitalized letters, no comments) and is to be immediately executed by Grbl. Echoes will not be
// sent upon a line buffer overflow, but should for all normal lines sent to Grbl. For example, if a user
// sendss the line 'g1 x1.032 y2.45 (test comment)', Grbl will echo back in the form '[echo: G1X1.032Y2.45]'.
// NOTE: Only use this for debugging purposes!! When echoing, this takes up valuable resources and can effect
// performance. If absolutely needed for normal operation, the serial write buffer should be greatly increased
// to help minimize transmission waiting within the serial write protocol.
// #define REPORT_ECHO_LINE_RECEIVED // Default disabled. Uncomment to enable.
// Sets which axis the tool length offset is applied. Assumes the spindle is always parallel with
// the selected axis with the tool oriented toward the negative direction. In other words, a positive
// tool length offset value is subtracted from the current location.
#if COMPATIBILITY_LEVEL > 2 && defined(TOOL_LENGTH_OFFSET_AXIS) == 0
#define TOOL_LENGTH_OFFSET_AXIS Z_AXIS // Default z-axis. Valid values are X_AXIS, Y_AXIS, or Z_AXIS.
#endif
// Max length of gcode lines (blocks) stored in non-volatile storage
#if N_AXIS == 6 && COMPATIBILITY_LEVEL <= 1
#define MAX_STORED_LINE_LENGTH 60 // do not change!
#else
#define MAX_STORED_LINE_LENGTH 70 // do not set > 70 unless less than 5 axes are enabled or COMPATIBILITY_LEVEL > 1
#endif
#endif

277
grbllib.c Normal file
View File

@@ -0,0 +1,277 @@
/*
grbllib.c - An embedded CNC Controller with rs274/ngc (g-code) support
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2011-2015 Sungeun K. Jeon
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "hal.h"
#include "nuts_bolts.h"
#include "tool_change.h"
#include "override.h"
#include "protocol.h"
#include "limits.h"
#include "report.h"
#include "state_machine.h"
#include "nvs_buffer.h"
#ifdef ENABLE_BACKLASH_COMPENSATION
#include "motion_control.h"
#endif
#ifdef KINEMATICS_API
#include "kinematics.h"
#endif
#ifdef COREXY
#include "corexy.h"
#endif
#ifdef WALL_PLOTTER
#include "wall_plotter.h"
#endif
// Declare system global variable structure
system_t sys = {0};
grbl_t grbl;
grbl_hal_t hal;
// called from stream drivers while tx is blocking, return false to terminate
static bool stream_tx_blocking (void)
{
// TODO: Restructure st_prep_buffer() calls to be executed here during a long print.
grbl.on_execute_realtime(state_get());
return !(sys.rt_exec_state & EXEC_RESET);
}
#ifdef KINEMATICS_API
kinematics_t kinematics;
// called from mc_line() to segment lines if not overridden, default implementation for pass-through
static bool kinematics_segment_line (float *target, plan_line_data_t *pl_data, bool init)
{
static uint_fast8_t iterations;
if(init)
iterations = 2;
else
iterations--;
return iterations != 0;
}
#endif
#ifdef DEBUGOUT
static void debug_out (bool on)
{
// NOOP
}
#endif
void dummy_bool_handler (bool arg)
{
// NOOP
}
// main entry point
int grbl_enter (void)
{
#ifdef N_TOOLS
assert(NVS_ADDR_GLOBAL + sizeof(settings_t) + NVS_CRC_BYTES < NVS_ADDR_TOOL_TABLE);
#else
assert(NVS_ADDR_GLOBAL + sizeof(settings_t) + NVS_CRC_BYTES < NVS_ADDR_PARAMETERS);
#endif
assert(NVS_ADDR_PARAMETERS + N_CoordinateSystems * (sizeof(coord_data_t) + NVS_CRC_BYTES) < NVS_ADDR_STARTUP_BLOCK);
assert(NVS_ADDR_STARTUP_BLOCK + N_STARTUP_LINE * (sizeof(stored_line_t) + NVS_CRC_BYTES) < NVS_ADDR_BUILD_INFO);
bool looping = true, driver_ok;
// Clear all and set some core function pointers
memset(&grbl, 0, sizeof(grbl_t));
grbl.on_execute_realtime = protocol_execute_noop;
grbl.protocol_enqueue_gcode = protocol_enqueue_gcode;
grbl.on_report_options = dummy_bool_handler;
// Clear all and set some HAL function pointers
memset(&hal, 0, sizeof(grbl_hal_t));
hal.version = HAL_VERSION; // Update when signatures and/or contract is changed - driver_init() should fail
hal.driver_reset = dummy_handler;
hal.irq_enable = dummy_handler;
hal.irq_disable = dummy_handler;
hal.nvs.size = GRBL_NVS_SIZE;
hal.stream.enqueue_realtime_command = protocol_enqueue_realtime_command;
hal.limits.interrupt_callback = limit_interrupt_handler;
hal.control.interrupt_callback = control_interrupt_handler;
hal.stepper.interrupt_callback = stepper_driver_interrupt_handler;
hal.stream_blocking_callback = stream_tx_blocking;
hal.signals_cap.reset = hal.signals_cap.feed_hold = hal.signals_cap.cycle_start = On;
sys.cold_start = true;
#ifdef BUFFER_NVSDATA
nvs_buffer_alloc(); // Allocate memory block for NVS buffer
#endif
report_init_fns();
#ifdef KINEMATICS_API
memset(&kinematics, 0, sizeof(kinematics_t));
kinematics.segment_line = kinematics_segment_line; // default to no segmentation
#endif
#ifdef DEBUGOUT
hal.debug_out = debug_out; // must be overridden by driver to have any effect
#endif
driver_ok = driver_init();
#if COMPATIBILITY_LEVEL > 0
hal.stream.suspend_read = NULL;
#endif
#ifndef ENABLE_SAFETY_DOOR_INPUT_PIN
hal.signals_cap.safety_door_ajar = Off;
#else
driver_ok &= hal.signals_cap.safety_door_ajar;
#endif
#ifdef BUFFER_NVSDATA
nvs_buffer_init();
#endif
settings_init(); // Load Grbl settings from non-volatile storage
memset(sys.position, 0, sizeof(sys.position)); // Clear machine position.
// check and configure driver
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
driver_ok = driver_ok && hal.driver_cap.amass_level >= MAX_AMASS_LEVEL;
hal.driver_cap.amass_level = MAX_AMASS_LEVEL;
#else
hal.driver_cap.amass_level = 0;
#endif
#ifdef DEFAULT_STEP_PULSE_DELAY
driver_ok = driver_ok & hal.driver_cap.step_pulse_delay;
#endif
/*
#if AXIS_N_SETTINGS > 4
driver_ok = driver_ok & hal.driver_cap.axes >= AXIS_N_SETTINGS;
#endif
*/
sys.mpg_mode = false;
driver_ok = driver_ok && hal.driver_setup(&settings);
#ifdef ENABLE_SPINDLE_LINEARIZATION
driver_ok = driver_ok && hal.driver_cap.spindle_pwm_linearization;
#endif
#ifdef SPINDLE_PWM_DIRECT
driver_ok = driver_ok && hal.spindle.get_pwm != NULL && hal.spindle.update_pwm != NULL;
#endif
if(!driver_ok) {
hal.stream.write("grblHAL: incompatible driver" ASCII_EOL);
while(true);
}
if(hal.get_position)
hal.get_position(&sys.position); // TODO: restore on abort when returns true?
#ifdef COREXY
corexy_init();
#endif
#ifdef WALL_PLOTTER
wall_plotter_init();
#endif
sys.driver_started = true;
// "Wire" homing switches to limit switches if not provided by the driver.
if(hal.homing.get_state == NULL)
hal.homing.get_state = hal.limits.get_state;
// Grbl initialization loop upon power-up or a system abort. For the latter, all processes
// will return to this loop to be cleanly re-initialized.
while(looping) {
// Reset report entry points
report_init_fns();
if(!sys.position_lost || settings.homing.flags.keep_on_reset)
memset(&sys, 0, offsetof(system_t, homed)); // Clear system variables except alarm & homed status.
else
memset(&sys, 0, offsetof(system_t, alarm)); // Clear system variables except state & alarm.
sys.override.feed_rate = DEFAULT_FEED_OVERRIDE; // Set to 100%
sys.override.rapid_rate = DEFAULT_RAPID_OVERRIDE; // Set to 100%
sys.override.spindle_rpm = DEFAULT_SPINDLE_RPM_OVERRIDE; // Set to 100%
if(settings.parking.flags.enabled)
sys.override.control.parking_disable = settings.parking.flags.deactivate_upon_init;
flush_override_buffers();
// Reset Grbl primary systems.
hal.stream.reset_read_buffer(); // Clear input stream buffer
gc_init(); // Set g-code parser to default state
hal.limits.enable(settings.limits.flags.hard_enabled, false);
plan_reset(); // Clear block buffer and planner variables
st_reset(); // Clear stepper subsystem variables.
limits_set_homing_axes(); // Set axes to be homed from settings.
#ifdef ENABLE_BACKLASH_COMPENSATION
mc_backlash_init(); // Init backlash configuration.
#endif
// Sync cleared gcode and planner positions to current system position.
sync_position();
if(hal.stepper.disable_motors)
hal.stepper.disable_motors((axes_signals_t){0}, SquaringMode_Both);
if(!hal.driver_cap.atc)
tc_init();
// Print welcome message. Indicates an initialization has occured at power-up or with a reset.
report_init_message();
if(state_get() == STATE_ESTOP)
state_set(STATE_ALARM);
if(hal.driver_cap.mpg_mode)
hal.stream.enqueue_realtime_command(sys.mpg_mode ? CMD_STATUS_REPORT_ALL : CMD_STATUS_REPORT);
// Start Grbl main loop. Processes program inputs and executes them.
if(!(looping = protocol_main_loop()))
looping = hal.driver_release == NULL || hal.driver_release();
sys.cold_start = false;
}
return 0;
}

39
grbllib.h Normal file
View File

@@ -0,0 +1,39 @@
/*
grbllib.h - An embedded CNC Controller with rs274/ngc (g-code) support
Part of grblHAL
Copyright (c) 2011-2015 Sungeun K. Jeon
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _GRBLLIB_H_
#define _GRBLLIB_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
int grbl_enter (void);
#ifdef __cplusplus
}
#endif
#endif

375
hal.h Normal file
View File

@@ -0,0 +1,375 @@
/*
hal.h - HAL (Hardware Abstraction Layer) entry points structures and capabilities type
Part of grblHAL
Copyright (c) 2016-2021 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HAL_H_
#define _HAL_H_
#include "grbl.h"
#include "gcode.h"
#include "system.h"
#include "coolant_control.h"
#include "spindle_control.h"
#include "stepper.h"
#include "nvs.h"
#include "stream.h"
#include "probe.h"
#include "plugins.h"
#include "settings.h"
#include "report.h"
#define HAL_VERSION 8
// driver capabilities, to be set by driver in driver_init(), flags may be cleared after to switch off option
typedef union {
uint32_t value;
struct {
uint32_t mist_control :1,
variable_spindle :1,
spindle_dir :1,
software_debounce :1,
step_pulse_delay :1,
limits_pull_up :1,
control_pull_up :1,
probe_pull_up :1,
amass_level :2, // 0...3
spindle_at_speed :1,
laser_ppi_mode :1,
spindle_sync :1,
sd_card :1,
bluetooth :1,
ethernet :1,
wifi :1,
spindle_pwm_invert :1,
spindle_pid :1,
mpg_mode :1,
spindle_pwm_linearization :1,
atc :1,
no_gcode_message_handling :1,
dual_spindle :1,
odometers :1,
unassigned :7;
};
} driver_cap_t;
typedef void (*driver_reset_ptr)(void);
// I/O stream
typedef void (*stream_write_ptr)(const char *s);
typedef bool (*enqueue_realtime_command_ptr)(char data);
typedef struct {
stream_type_t type;
uint16_t (*get_rx_buffer_available)(void);
// bool (*stream_write)(char c);
stream_write_ptr write; // write string to current I/O stream only.
stream_write_ptr write_all; // write string to all active output streams.
int16_t (*read)(void);
void (*reset_read_buffer)(void);
void (*cancel_read_buffer)(void);
bool (*suspend_read)(bool await);
enqueue_realtime_command_ptr enqueue_realtime_command; // NOTE: set by grbl at startup.
} io_stream_t;
typedef struct {
uint8_t num_digital_in;
uint8_t num_digital_out;
uint8_t num_analog_in;
uint8_t num_analog_out;
void (*digital_out)(uint8_t port, bool on);
bool (*analog_out)(uint8_t port, float value);
int32_t (*wait_on_input)(bool digital, uint8_t port, wait_mode_t wait_mode, float timeout);
} io_port_t;
// Spindle
typedef void (*spindle_set_state_ptr)(spindle_state_t state, float rpm);
typedef spindle_state_t (*spindle_get_state_ptr)(void);
#ifdef SPINDLE_PWM_DIRECT
typedef uint_fast16_t (*spindle_get_pwm_ptr)(float rpm);
typedef void (*spindle_update_pwm_ptr)(uint_fast16_t pwm);
#else
typedef void (*spindle_update_rpm_ptr)(float rpm);
#endif
typedef spindle_data_t *(*spindle_get_data_ptr)(spindle_data_request_t request);
typedef void (*spindle_reset_data_ptr)(void);
typedef void (*spindle_pulse_on_ptr)(uint_fast16_t pulse_length);
typedef struct {
spindle_set_state_ptr set_state;
spindle_get_state_ptr get_state;
#ifdef SPINDLE_PWM_DIRECT
spindle_get_pwm_ptr get_pwm;
spindle_update_pwm_ptr update_pwm;
#else
spindle_update_rpm_ptr update_rpm;
#endif
// Optional entry points:
spindle_get_data_ptr get_data;
spindle_reset_data_ptr reset_data;
spindle_pulse_on_ptr pulse_on;
} spindle_ptrs_t;
// Coolant
typedef void (*coolant_set_state_ptr)(coolant_state_t mode);
typedef coolant_state_t (*coolant_get_state_ptr)(void);
typedef struct {
coolant_set_state_ptr set_state;
coolant_get_state_ptr get_state;
} coolant_ptrs_t;
// Limits
typedef void (*limits_enable_ptr)(bool on, bool homing);
typedef limit_signals_t (*limits_get_state_ptr)(void);
typedef void (*limit_interrupt_callback_ptr)(limit_signals_t state);
typedef struct {
limits_enable_ptr enable;
limits_get_state_ptr get_state;
limit_interrupt_callback_ptr interrupt_callback; // set up by core before driver_init() is called.
} limits_ptrs_t;
// Homing
typedef struct {
limits_get_state_ptr get_state;
} homing_ptrs_t;
// Control signals
typedef control_signals_t (*control_signals_get_state_ptr)(void);
typedef void (*control_signals_callback_ptr)(control_signals_t signals);
typedef struct {
control_signals_get_state_ptr get_state;
control_signals_callback_ptr interrupt_callback; // set up by core before driver_init() is called.
} control_signals_ptrs_t;
// Steppers
typedef void (*stepper_wake_up_ptr)(void);
typedef void (*stepper_go_idle_ptr)(bool clear_signals);
typedef void (*stepper_enable_ptr)(axes_signals_t enable);
typedef void (*stepper_disable_motors_ptr)(axes_signals_t axes, squaring_mode_t mode);
typedef void (*stepper_cycles_per_tick_ptr)(uint32_t cycles_per_tick);
typedef void (*stepper_pulse_start_ptr)(stepper_t *stepper);
typedef void (*stepper_output_step_ptr)(axes_signals_t step_outbits, axes_signals_t dir_outbits);
typedef axes_signals_t (*stepper_get_auto_squared_ptr)(void);
typedef void (*stepper_interrupt_callback_ptr)(void);
typedef struct {
stepper_wake_up_ptr wake_up;
stepper_go_idle_ptr go_idle;
stepper_enable_ptr enable;
stepper_disable_motors_ptr disable_motors;
stepper_cycles_per_tick_ptr cycles_per_tick;
stepper_pulse_start_ptr pulse_start;
stepper_interrupt_callback_ptr interrupt_callback; // set up by core before driver_init() is called.
// Optional entry points:
stepper_get_auto_squared_ptr get_auto_squared;
stepper_output_step_ptr output_step;
} stepper_ptrs_t;
// Probe (optional)
typedef probe_state_t (*probe_get_state_ptr)(void);
typedef void (*probe_configure_ptr)(bool is_probe_away, bool probing);
typedef void (*probe_connected_toggle_ptr)(void);
typedef struct {
probe_configure_ptr configure;
probe_get_state_ptr get_state;
probe_connected_toggle_ptr connected_toggle;
} probe_ptrs_t;
typedef void (*tool_select_ptr)(tool_data_t *tool, bool next);
typedef status_code_t (*tool_change_ptr)(parser_state_t *gc_state);
typedef struct {
tool_select_ptr select;
tool_change_ptr change;
} tool_ptrs_t;
// User M-codes (optional)
typedef user_mcode_t (*user_mcode_check_ptr)(user_mcode_t mcode);
typedef status_code_t (*user_mcode_validate_ptr)(parser_block_t *gc_block, parameter_words_t *parameter_words);
typedef void (*user_mcode_execute_ptr)(sys_state_t state, parser_block_t *gc_block);
typedef struct {
user_mcode_check_ptr check;
user_mcode_validate_ptr validate;
user_mcode_execute_ptr execute;
} user_mcode_ptrs_t;
// Encoder (optional)
typedef uint8_t (*encoder_get_n_encoders_ptr)(void);
typedef void (*encoder_on_event_ptr)(encoder_t *encoder, int32_t position);
typedef void (*encoder_reset_ptr)(uint_fast8_t id);
typedef struct {
encoder_get_n_encoders_ptr get_n_encoders;
encoder_on_event_ptr on_event;
encoder_reset_ptr reset;
} encoder_ptrs_t;
//
// main HAL structure
typedef struct {
uint32_t version;
char *info;
char *driver_version;
char *driver_options;
char *board;
uint32_t f_step_timer;
uint32_t rx_buffer_size;
uint32_t max_step_rate;
uint8_t driver_axis_settings;
bool (*driver_setup)(settings_t *settings);
void (*delay_ms)(uint32_t ms, void (*callback)(void));
void (*set_bits_atomic)(volatile uint_fast16_t *value, uint_fast16_t bits);
uint_fast16_t (*clear_bits_atomic)(volatile uint_fast16_t *value, uint_fast16_t bits);
uint_fast16_t (*set_value_atomic)(volatile uint_fast16_t *value, uint_fast16_t bits);
void (*irq_enable)(void);
void (*irq_disable)(void);
limits_ptrs_t limits;
homing_ptrs_t homing;
coolant_ptrs_t coolant;
spindle_ptrs_t spindle;
stepper_ptrs_t stepper;
control_signals_ptrs_t control;
io_stream_t stream;
settings_changed_ptr settings_changed;
//
// optional entry points, may be unassigned (null)
//
bool (*driver_release)(void);
bool (*get_position)(int32_t (*position)[N_AXIS]);
uint32_t (*get_elapsed_ticks)(void);
void (*pallet_shuttle)(void);
void (*reboot)(void);
#ifdef DEBUGOUT
void (*debug_out)(bool on);
#endif
probe_ptrs_t probe;
user_mcode_ptrs_t user_mcode;
driver_reset_ptr driver_reset;
tool_ptrs_t tool;
encoder_ptrs_t encoder;
nvs_io_t nvs;
io_port_t port;
bool (*stream_blocking_callback)(void); // set up by core before driver_init() is called.
// driver capabilities flags
driver_cap_t driver_cap;
control_signals_t signals_cap;
} grbl_hal_t;
// TODO: move the following structs to grbl.h?
/* TODO: add to grbl pointers so that a different formatting (xml, json etc) of reports may be implemented by driver?
typedef struct {
status_code_t (*report_status_message)(status_code_t status_code);
alarm_code_t (*report_alarm_message)(alarm_code_t alarm_code);
message_code_t (*report_feedback_message)(message_code_t message_code);
void (*report_init_message)(void);
void (*report_grbl_help)(void);
void (*report_echo_line_received)(char *line);
void (*report_realtime_status)(void);
void (*report_probe_parameters)(void);
void (*report_ngc_parameters)(void);
void (*report_gcode_modes)(void);
void (*report_startup_line)(uint8_t n, char *line);
void (*report_execute_startup_message)(char *line, status_code_t status_code);
} grbl_report_t;
*/
// Report entry points set by core at reset.
typedef status_code_t (*status_message_ptr)(status_code_t status_code);
typedef message_code_t (*feedback_message_ptr)(message_code_t message_code);
typedef struct {
setting_output_ptr setting;
status_message_ptr status_message;
feedback_message_ptr feedback_message;
} report_t;
// Core event handler and other entry points.
// Most of the event handlers defaults to NULL, a few is set up to call a dummy handler for simpler code.
typedef void (*on_state_change_ptr)(sys_state_t state);
typedef void (*on_probe_completed_ptr)(void);
typedef void (*on_program_completed_ptr)(program_flow_t program_flow);
typedef void (*on_execute_realtime_ptr)(sys_state_t state);
typedef void (*on_unknown_accessory_override_ptr)(uint8_t cmd);
typedef void (*on_report_options_ptr)(bool newopt);
typedef void (*on_report_command_help_ptr)(void);
typedef void (*on_global_settings_restore_ptr)(void);
typedef setting_details_t *(*on_get_settings_ptr)(void); // NOTE: this must match the signature of the same definition in
// the setting_details_t structure in settings.h!
typedef void (*on_realtime_report_ptr)(stream_write_ptr stream_write, report_tracking_flags_t report);
typedef void (*on_unknown_feedback_message_ptr)(stream_write_ptr stream_write);
typedef bool (*on_laser_ppi_enable_ptr)(uint_fast16_t ppi, uint_fast16_t pulse_length);
typedef status_code_t (*on_unknown_sys_command_ptr)(sys_state_t state, char *line); // return Status_Unhandled.
typedef status_code_t (*on_user_command_ptr)(char *line);
typedef sys_commands_t *(*on_get_commands_ptr)(void);
typedef struct {
// report entry points set by core at reset.
report_t report;
// grbl core events - may be subscribed to by drivers or by the core.
on_state_change_ptr on_state_change;
on_probe_completed_ptr on_probe_completed;
on_program_completed_ptr on_program_completed;
on_execute_realtime_ptr on_execute_realtime;
on_unknown_accessory_override_ptr on_unknown_accessory_override;
on_report_options_ptr on_report_options;
on_report_command_help_ptr on_report_command_help;
on_global_settings_restore_ptr on_global_settings_restore;
on_get_settings_ptr on_get_settings;
on_realtime_report_ptr on_realtime_report;
on_unknown_feedback_message_ptr on_unknown_feedback_message;
on_unknown_sys_command_ptr on_unknown_sys_command; // return Status_Unhandled if not handled.
on_get_commands_ptr on_get_commands;
on_user_command_ptr on_user_command;
on_laser_ppi_enable_ptr on_laser_ppi_enable;
// core entry points - set up by core before driver_init() is called.
bool (*protocol_enqueue_gcode)(char *data);
} grbl_t;
extern grbl_t grbl;
extern grbl_hal_t hal;
extern bool driver_init (void);
#endif

36
kinematics.h Normal file
View File

@@ -0,0 +1,36 @@
/*
kinematics.h - kinematics interface (API)
Part of grblHAL
Copyright (c) 2019 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KINEMATICS_H_
#define _KINEMATICS_H_
typedef struct {
void (*convert_array_steps_to_mpos)(float *position, int32_t *steps);
void (*plan_target_to_steps) (int32_t *target_steps, float *target);
bool (*segment_line) (float *target, plan_line_data_t *pl_data, bool init);
uint_fast8_t (*limits_get_axis_mask)(uint_fast8_t idx);
void (*limits_set_target_pos)(uint_fast8_t idx);
void (*limits_set_machine_positions)(axes_signals_t cycle);
} kinematics_t;
extern kinematics_t kinematics;
#endif

541
limits.c Normal file

File diff suppressed because it is too large Load Diff

46
limits.h Normal file
View File

@@ -0,0 +1,46 @@
/*
limits.h - code pertaining to limit-switches and performing the homing cycle
Part of grblHAL
Copyright (c) 2017-2018 Terje Io
Copyright (c) 2012-2015 Sungeun K. Jeon
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LIMITS_H_
#define _LIMITS_H_
#include "nuts_bolts.h"
// Perform one portion of the homing cycle based on the input settings.
bool limits_go_home(axes_signals_t cycle);
// Check for soft limit violations
void limits_soft_check(float *target);
// Check if homing is required.
bool limits_homing_required (void);
// Set axes to be homed from settings.
void limits_set_homing_axes (void);
void limits_set_machine_positions (axes_signals_t cycle, bool add_pulloff);
void limit_interrupt_handler (limit_signals_t state);
axes_signals_t limit_signals_merge (limit_signals_t signals);
#endif

676
maslow.c Normal file

File diff suppressed because it is too large Load Diff

161
maslow.h Normal file
View File

@@ -0,0 +1,161 @@
/*
maslow.h - Maslow router kinematics implementation
Part of grblHAL
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
The basis for this code has been pulled from MaslowDue created by Larry D O'Cull.
<https://github.com/ldocull/MaslowDue>
Some portions of that package directly or indirectly has been pulled from from the Maslow CNC
firmware for Aduino Mega. Those parts are Copyright 2014-2017 Bar Smith.
<https://www.maslowcnc.com/>
It has been adapted for grbl by Terje Io.
*** TO BE COMPLETED ***
*/
#include "grbl.h"
#ifndef _MASLOW_H_
#define _MASLOW_H_
#define FP_SCALING 1024.0f
#define SPROCKET_RADIUS_MM (10.1f)
#define MAX_SEG_LENGTH_MM 2.0f /* long lines must be segmented due to circular motion */
// PID position loop factors X: Kp = 25000 Ki = 15000 Kd = 22000 Imax = 5000
// 14.000 fixed point arithmatic S13.10
#ifdef DRIVER_TLE5206
#define MASLOW_A_KP 10.0f
#define MASLOW_A_KI 21.0f
#define MASLOW_A_KD 18.0f
#define MASLOW_A_IMAX 5000
#define MASLOW_B_KP 10.0f
#define MASLOW_B_KI 21.0f
#define MASLOW_B_KD 18.0f
#define MASLOW_B_IMAX 5000
#define MASLOW_Z_KP 10.0f
#define MASLOW_Z_KI 21.0f
#define MASLOW_Z_KD 17.0f
#define MASLOW_Z_IMAX 5000
#else
#define MASLOW_A_KP 22.0f
#define MASLOW_A_KI 17.0f
#define MASLOW_A_KD 20.0f
#define MASLOW_A_IMAX 5000
#define MASLOW_B_KP 22.0f
#define MASLOW_B_KI 17.0f
#define MASLOW_B_KD 20.0f
#define MASLOW_B_IMAX 5000
#define MASLOW_Z_KP 20.0f
#define MASLOW_Z_KI 17.0f
#define MASLOW_Z_KD 18.0f
#define MASLOW_Z_IMAX 5000
#endif
#define MASLOW_MACHINEWIDTH 2400.0f
#define MASLOW_MACHINEHEIGHT 1200.0f
#define MASLOW_DISTBETWEENMOTORS 3000.0f
#define MASLOW_MOTOROFFSETY 600.0f
#define MASLOW_CHAINLENGTH 3000.0f
#define MASLOW_CHAINOVERSPROCKET 0
#define MASLOW_CHAINSAGCORRECTION 59.504839f
#define MASLOW_LEFTCHAINTOLERANCE 0.0f
#define MASLOW_RIGHTCHAINTOLERANCE 0.0f
#define MASLOW_ROTATIONDISKRADIUS 104.3f
#define MASLOW_SLEDHEIGHT 139.0f
#define MASLOW_SLEDWIDTH 310.0f
#define MASLOW_ACORRSCALING 1.003922f
#define MASLOW_BCORRSCALING 1.002611f
typedef enum {
Maslow_ChainOverSprocket = 260,
Maslow_MachineWidth,
Maslow_MachineHeight,
Maslow_DistBetweenMotors,
Maslow_MotorOffsetY,
Maslow_AcorrScaling,
Maslow_BcorrScaling,
Maslow_SettingMax,
} maslow_setting_t;
typedef enum {
AxisSetting_MaslowKP = 10,
AxisSetting_MaslowKI,
AxisSetting_MaslowKD,
AxisSetting_MaslowIMax,
AxisSetting_MaslowMaxSetting
} maslow_axis_setting_t;
typedef struct {
float Kp;
float Ki;
float Kd;
float Imax;
} maslow_pid_coefficients_t;
typedef struct {
maslow_pid_coefficients_t pid[N_AXIS];
uint32_t chainOverSprocket;
float machineWidth; /* Maslow specific settings */
float machineHeight;
float distBetweenMotors;
float motorOffsetY;
float chainSagCorrection;
float leftChainTolerance;
float rightChainTolerance;
float rotationDiskRadius;
float chainLength;
float sledHeight;
float sledWidth;
float XcorrScaling;
float YcorrScaling;
} maslow_settings_t;
typedef struct {
float Error;
float Integral;
float iterm;
float DiffTerm;
float speed;
} maslow_debug_t;
typedef struct {
maslow_settings_t settings;
void (*pid_settings_changed)(uint_fast8_t idx);
void (*move)(uint_fast8_t idx, int_fast16_t distance);
void (*reset_pid)(uint_fast8_t idx);
void (*pos_enable)(bool enable);
void (*tuning_enable)(bool enable);
int32_t (*set_step_size)(uint_fast8_t idx, int32_t step_size);
maslow_debug_t *(*get_debug_data)(uint_fast8_t idx);
} maslow_hal_t;
extern maslow_hal_t maslow_hal;
// Initialize HAL pointers for Maslow Router kinematics
bool maslow_init (void);
static status_code_t maslow_tuning (uint_fast16_t state, char *line);
#endif

989
motion_control.c Normal file

File diff suppressed because it is too large Load Diff

82
motion_control.h Normal file
View File

@@ -0,0 +1,82 @@
/*
motion_control.h - high level interface for issuing motion commands
Part of grblHAL
Copyright (c) 2017-2019 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MOTION_CONTROL_H_
#define _MOTION_CONTROL_H_
// System motion commands must have a line number of zero.
#define HOMING_CYCLE_LINE_NUMBER 0
#define PARKING_MOTION_LINE_NUMBER 0
#define HOMING_CYCLE_ALL 0 // Must be zero.
#define HOMING_CYCLE_X bit(X_AXIS)
#define HOMING_CYCLE_Y bit(Y_AXIS)
#define HOMING_CYCLE_Z bit(Z_AXIS)
// 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.
bool mc_line(float *target, plan_line_data_t *pl_data);
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
// the direction of helical travel, radius == circle radius, is_clockwise_arc boolean. Used
// for vector transformation direction.
void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius,
plane_t plane, bool is_clockwise_arc);
// Execute canned cycle (drill)
void mc_canned_drill (motion_mode_t motion, float *target, plan_line_data_t *pl_data, float *position, plane_t plane, uint32_t repeats, gc_canned_t *canned);
// Execute canned cycle (threading)
void mc_thread (plan_line_data_t *pl_data, float *position, gc_thread_data *thread, bool feed_hold_disabled);
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
status_code_t mc_jog_execute(plan_line_data_t *pl_data, parser_block_t *gc_block);
// Dwell for a specific number of seconds
void mc_dwell(float seconds);
// Perform homing cycle to locate machine zero. Requires limit switches.
status_code_t mc_homing_cycle(axes_signals_t cycle);
// Perform tool length probe cycle. Requires probe switch.
gc_probe_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, gc_parser_flags_t parser_flags);
// Handles updating the override control state.
void mc_override_ctrl_update(gc_override_flags_t override_state);
// Plans and executes the single special motion case for parking. Independent of main planner buffer.
bool mc_parking_motion(float *parking_target, plan_line_data_t *pl_data);
void mc_cubic_b_spline(float *target, plan_line_data_t *pl_data, float *position, float *offset1, float *offset2);
// Performs system reset. If in motion state, kills all motion and sets system alarm.
void mc_reset();
#ifdef ENABLE_BACKLASH_COMPENSATION
void mc_backlash_init (void);
void mc_sync_backlash_position (void);
#endif
#endif

27
my_plugin.c Normal file
View File

@@ -0,0 +1,27 @@
/*
my_plugin.c - An embedded CNC Controller with rs274/ngc (g-code) support
"Dummy" user plugin init, called if no user plugin is provided.
Part of grblHAL
Copyright (c) 2020 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
__attribute__((weak)) void my_plugin_init (void)
{
// NOOP
}

293
nuts_bolts.c Normal file
View File

@@ -0,0 +1,293 @@
/*
nuts_bolts.c - Shared functions
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include <stdint.h>
#include <stdbool.h>
#include "hal.h"
#include "protocol.h"
#include "state_machine.h"
#include "nuts_bolts.h"
#ifndef DWELL_TIME_STEP
#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds)
#endif
#define MAX_PRECISION 10
static char buf[STRLEN_COORDVALUE + 1];
static const float froundvalues[MAX_PRECISION + 1] =
{
0.5, // 0
0.05, // 1
0.005, // 2
0.0005, // 3
0.00005, // 4
0.000005, // 5
0.0000005, // 6
0.00000005, // 7
0.000000005, // 8
0.0000000005, // 9
0.00000000005 // 10
};
char const *const axis_letter[N_AXIS] = {
"X",
"Y",
"Z"
#if N_AXIS > 3
,"A"
#endif
#if N_AXIS > 4
,"B"
#endif
#if N_AXIS > 5
,"C"
#endif
};
// Converts an uint32 variable to string.
char *uitoa (uint32_t n)
{
char *bptr = buf + sizeof(buf);
*--bptr = '\0';
if (n == 0)
*--bptr = '0';
else while (n) {
*--bptr = '0' + (n % 10);
n /= 10;
}
return bptr;
}
// Convert float to string by immediately converting to integers.
// Number of decimal places, which are tracked by a counter, must be set by the user.
// The integers is then efficiently converted to a string.
char *ftoa (float n, uint8_t decimal_places)
{
bool isNegative;
char *bptr = buf + sizeof(buf);
*--bptr = '\0';
if ((isNegative = n < 0.0f))
n = -n;
n += froundvalues[decimal_places];
uint32_t a = (uint32_t)n;
if (decimal_places) {
n -= (float)a;
uint_fast8_t decimals = decimal_places;
while (decimals >= 2) { // Quickly convert values expected to be E0 to E-4.
n *= 100.0f;
decimals -= 2;
}
if (decimals)
n *= 10.0f;
uint32_t b = (uint32_t)n;
while(decimal_places--) {
if(b) {
*--bptr = (b % 10) + '0'; // Get digit
b /= 10;
} else
*--bptr = '0';
}
}
*--bptr = '.'; // Always add decimal point (TODO: is this really needed?)
if(a == 0)
*--bptr = '0';
else while(a) {
*--bptr = (a % 10) + '0'; // Get digit
a /= 10;
}
if(isNegative)
*--bptr = '-';
return bptr;
}
// Extracts a floating point value from a string. The following code is based loosely on
// the avr-libc strtod() function by Michael Stumpf and Dmitry Xmelkov and many freely
// available conversion method examples, but has been highly optimized for Grbl. For known
// CNC applications, the typical decimal value is expected to be in the range of E0 to E-4.
// Scientific notation is officially not supported by g-code, and the 'E' character may
// be a g-code word on some CNC systems. So, 'E' notation will not be recognized.
// NOTE: Thanks to Radu-Eosif Mihailescu for identifying the issues with using strtod().
bool read_float (char *line, uint_fast8_t *char_counter, float *float_ptr)
{
char *ptr = line + *char_counter;
int_fast8_t exp = 0;
uint_fast8_t ndigit = 0, c;
uint32_t intval = 0;
bool isnegative, isdecimal = false;
// Grab first character and increment pointer. No spaces assumed in line.
c = *ptr++;
// Capture initial positive/minus character
if ((isnegative = (c == '-')) || c == '+')
c = *ptr++;
// Extract number into fast integer. Track decimal in terms of exponent value.
while(c) {
c -= '0';
if (c <= 9) {
ndigit++;
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 (c == (uint_fast8_t)('.' - '0') && !isdecimal)
isdecimal = true;
else
break;
c = *ptr++;
}
// Return if no digits have been read.
if (!ndigit)
return false;
// Convert integer into floating point.
float fval = (float)intval;
// Apply decimal. Should perform no more than two floating point multiplications for the
// expected range of E0 to E-4.
if (fval != 0.0f) {
while (exp <= -2) {
fval *= 0.01f;
exp += 2;
}
if (exp < 0)
fval *= 0.1f;
else if (exp > 0) do {
fval *= 10.0f;
} while (--exp > 0);
}
// Assign floating point value with correct sign.
*float_ptr = isnegative ? - fval : fval;
*char_counter = ptr - line - 1; // Set char_counter to next statement
return true;
}
// Returns true if float value is a whole number (integer)
bool isintf (float value)
{
return value != NAN && fabsf(value - truncf(value)) < 0.001f;
}
// Non-blocking delay function used for general operation and suspend features.
void delay_sec (float seconds, delaymode_t mode)
{
uint_fast16_t i = (uint_fast16_t)ceilf((1000.0f / DWELL_TIME_STEP) * seconds) + 1;
while (--i && !sys.abort) {
if (mode == DelayMode_Dwell) {
protocol_execute_realtime();
} else { // DelayMode_SysSuspend
// Execute rt_system() only to avoid nesting suspend loops.
protocol_exec_rt_system();
if (state_door_reopened()) // Bail, if safety door reopens.
return;
}
hal.delay_ms(DWELL_TIME_STEP, 0); // Delay DWELL_TIME_STEP increment
}
}
float convert_delta_vector_to_unit_vector (float *vector)
{
uint_fast8_t idx = N_AXIS;
float magnitude = 0.0f, inv_magnitude;
do {
if (vector[--idx] != 0.0f)
magnitude += vector[idx] * vector[idx];
} while(idx);
idx = N_AXIS;
magnitude = sqrtf(magnitude);
inv_magnitude = 1.0f / magnitude;
do {
vector[--idx] *= inv_magnitude;
} while(idx);
return magnitude;
}
// calculate checksum byte for data
uint8_t calc_checksum (uint8_t *data, uint32_t size) {
uint8_t checksum = 0;
while(size--) {
checksum = (checksum << 1) | (checksum >> 7);
checksum += *(data++);
}
return checksum;
}
// Remove spaces from and convert string to uppercase (in situ)
char *strcaps (char *s)
{
char c, *s1 = s, *s2 = s;
do {
c = *s1++;
if(c != ' ')
*s2++ = CAPS(c);
} while(c);
*s2 = '\0';
return s;
}
void dummy_handler (void)
{
// NOOP
}

176
nuts_bolts.h Normal file
View File

@@ -0,0 +1,176 @@
/*
nuts_bolts.h - Header file for shared definitions, variables, and functions
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NUTS_BOLTS_H_
#define _NUTS_BOLTS_H_
#include "grbl.h"
#ifndef true
#define false 0
#define true 1
#endif
#define Off 0
#define On 1
#define SOME_LARGE_VALUE 1.0E+38f
#ifndef M_PI
#define M_PI 3.14159265358979323846f
#endif
#define TAN_30 0.57735f // Used for threading calculations (60 degree inserts)
#define RADDEG 0.0174532925f // Radians per degree
#define ABORTED (sys.abort || sys.cancel)
// Convert character to uppercase
#define CAPS(c) ((c >= 'a' && c <= 'z') ? c & 0x5F : c)
#ifndef STM32F103xB
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#endif
// Axis array index values. Must start with 0 and be continuous.
#define X_AXIS 0 // Axis indexing value.
#define Y_AXIS 1
#define Z_AXIS 2
#define X_AXIS_BIT bit(X_AXIS)
#define Y_AXIS_BIT bit(Y_AXIS)
#define Z_AXIS_BIT bit(Z_AXIS)
#if N_AXIS > 3
#define A_AXIS 3
#define A_AXIS_BIT bit(A_AXIS)
#endif
#if N_AXIS > 4
#define B_AXIS 4
#define B_AXIS_BIT bit(B_AXIS)
#endif
#if N_AXIS == 6
#define C_AXIS 5
#define C_AXIS_BIT bit(C_AXIS)
#define AXES_BITMASK (X_AXIS_BIT|Y_AXIS_BIT|Z_AXIS_BIT|A_AXIS_BIT|B_AXIS_BIT|C_AXIS_BIT)
#endif
#if N_AXIS == 3
#define AXES_BITMASK (X_AXIS_BIT|Y_AXIS_BIT|Z_AXIS_BIT)
#elif N_AXIS == 4
#define AXES_BITMASK (X_AXIS_BIT|Y_AXIS_BIT|Z_AXIS_BIT|A_AXIS_BIT)
#elif N_AXIS == 5
#define AXES_BITMASK (X_AXIS_BIT|Y_AXIS_BIT|Z_AXIS_BIT|A_AXIS_BIT|B_AXIS_BIT)
#endif
extern char const *const axis_letter[];
typedef union {
uint8_t mask;
uint8_t value;
struct {
uint8_t x :1,
y :1,
z :1,
a :1,
b :1,
c :1;
};
} axes_signals_t;
#pragma pack(push, 1)
typedef struct {
axes_signals_t min;
axes_signals_t max;
axes_signals_t min2;
axes_signals_t max2;
} limit_signals_t;
#pragma pack(pop)
typedef enum {
DelayMode_Dwell = 0,
DelayMode_SysSuspend
} delaymode_t;
// Delay struct, currently not used by core - may be used by drivers
typedef struct {
volatile uint32_t ms;
void (*callback)(void);
} delay_t;
// Conversions
#define MM_PER_INCH (25.40f)
#define INCH_PER_MM (0.0393701f)
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)
#define STRLEN_COORDVALUE (MAX_INT_DIGITS + N_DECIMAL_COORDVALUE_INCH + 1) // 8.4 format - excluding terminating null
// Useful macros
#define clear_vector(a) memset(a, 0, sizeof(a))
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#define isequal_position_vector(a,b) !memcmp(a, b, sizeof(coord_data_t))
// Bit field and masking macros
#ifndef bit
#define bit(n) (1UL << n)
#endif
#define bit_true(x,mask) (x) |= (mask)
#define bit_false(x,mask) (x) &= ~(mask)
#define BIT_SET(x, bit, v) { if (v) { x |= (bit); } else { x &= ~(bit); } }
#define bit_istrue(x, mask) ((x & (mask)) != 0)
#define bit_isfalse(x, mask) ((x & (mask)) == 0)
// Converts an uint32 variable to string.
char *uitoa (uint32_t n);
// Converts a float variable to string with the specified number of decimal places.
char *ftoa (float n, uint8_t decimal_places);
// Returns true if float value is a whole number (integer)
bool isintf (float value);
// Read a floating point value from a string. Line points to the input buffer, char_counter
// is the indexer pointing to the current character of the line, while float_ptr is
// a pointer to the result variable. Returns true when it succeeds
bool read_float(char *line, uint_fast8_t *char_counter, float *float_ptr);
// Non-blocking delay function used for general operation and suspend features.
void delay_sec(float seconds, delaymode_t mode);
float convert_delta_vector_to_unit_vector(float *vector);
// calculate checksum byte for data
uint8_t calc_checksum (uint8_t *data, uint32_t size);
char *strcaps (char *s);
void dummy_handler (void);
#endif

77
nvs.h Normal file
View File

@@ -0,0 +1,77 @@
/*
nvs.h - non-volative storage data structures
Part of grblHAL
Copyright (c) 2017-2020 Terje Io
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NVS_H_
#define _NVS_H_
#ifndef NVS_SIZE
#define NVS_SIZE 2048
#endif
#define GRBL_NVS_SIZE 1024
#define NVS_CRC_BYTES 1
// Define persistent storage memory address location values for Grbl settings and parameters
// NOTE: 1KB persistent storage is the minimum required. The upper half is reserved for parameters and
// the startup script. The lower half contains the global settings and space for future
// developments.
#define NVS_ADDR_GLOBAL 1U
#define NVS_ADDR_PARAMETERS 512U
#define NVS_ADDR_BUILD_INFO 942U
#define NVS_ADDR_STARTUP_BLOCK (NVS_ADDR_BUILD_INFO - 1 - N_STARTUP_LINE * (sizeof(stored_line_t) + NVS_CRC_BYTES))
#ifdef N_TOOLS
#define NVS_ADDR_TOOL_TABLE (NVS_ADDR_PARAMETERS - 1 - N_TOOLS * (sizeof(tool_data_t) + NVS_CRC_BYTES))
#endif
typedef enum {
NVS_None = 0,
NVS_EEPROM,
NVS_FRAM,
NVS_Flash,
NVS_Emulated
} nvs_type;
typedef struct {
uint8_t *mem_address;
uint16_t address;
uint16_t size;
} nvs_driver_area_t;
typedef enum {
NVS_TransferResult_Failed = 0,
NVS_TransferResult_Busy,
NVS_TransferResult_OK,
} nvs_transfer_result_t;
typedef struct {
nvs_type type;
uint16_t size;
nvs_driver_area_t driver_area;
uint8_t (*get_byte)(uint32_t addr);
void (*put_byte)(uint32_t addr, uint8_t new_value);
nvs_transfer_result_t (*memcpy_to_nvs)(uint32_t destination, uint8_t *source, uint32_t size, bool with_checksum);
nvs_transfer_result_t (*memcpy_from_nvs)(uint8_t *destination, uint32_t source, uint32_t size, bool with_checksum);
bool (*memcpy_from_flash)(uint8_t *dest);
bool (*memcpy_to_flash)(uint8_t *source);
} nvs_io_t;
#endif

387
nvs_buffer.c Normal file
View File

@@ -0,0 +1,387 @@
/*
nvs_buffer.c - RAM based non-volatile storage buffer/emulation
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License.
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
//
// Can be used by MCUs with no nonvolatile storage options, be sure to allocate enough heap memory before use
//
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "hal.h"
#include "nvs_buffer.h"
#include "protocol.h"
static uint8_t *nvsbuffer = NULL;
static nvs_io_t physical_nvs;
static bool dirty;
settings_dirty_t settings_dirty;
typedef struct {
uint16_t addr;
uint8_t type;
uint8_t offset;
} emap_t;
#define NVS_GROUP_GLOBAL 0
#define NVS_GROUP_TOOLS 1
#define NVS_GROUP_PARAMETERS 2
#define NVS_GROUP_STARTUP 3
#define NVS_GROUP_BUILD 4
#define PARAMETER_ADDR(n) (NVS_ADDR_PARAMETERS + n * (sizeof(coord_data_t) + NVS_CRC_BYTES))
#define STARTLINE_ADDR(n) (NVS_ADDR_STARTUP_BLOCK + n * (sizeof(stored_line_t) + NVS_CRC_BYTES))
#ifdef N_TOOLS
#define TOOL_ADDR(n) (NVS_ADDR_TOOL_TABLE + n * (sizeof(tool_data_t) + NVS_CRC_BYTES))
#endif
static const emap_t target[] = {
{NVS_ADDR_GLOBAL, NVS_GROUP_GLOBAL, 0},
#ifdef N_TOOLS
{TOOL_ADDR(0), NVS_GROUP_TOOLS, 0},
{TOOL_ADDR(1), NVS_GROUP_TOOLS, 1},
{TOOL_ADDR(2), NVS_GROUP_TOOLS, 2},
{TOOL_ADDR(3), NVS_GROUP_TOOLS, 3},
{TOOL_ADDR(4), NVS_GROUP_TOOLS, 4},
{TOOL_ADDR(5), NVS_GROUP_TOOLS, 5},
{TOOL_ADDR(6), NVS_GROUP_TOOLS, 6},
{TOOL_ADDR(7), NVS_GROUP_TOOLS, 7},
#if N_TOOL > 8
#error Increase number of tool entries!
#endif
#endif
{PARAMETER_ADDR(0), NVS_GROUP_PARAMETERS, 0},
{PARAMETER_ADDR(1), NVS_GROUP_PARAMETERS, 1},
{PARAMETER_ADDR(2), NVS_GROUP_PARAMETERS, 2},
{PARAMETER_ADDR(3), NVS_GROUP_PARAMETERS, 3},
{PARAMETER_ADDR(4), NVS_GROUP_PARAMETERS, 4},
{PARAMETER_ADDR(5), NVS_GROUP_PARAMETERS, 5},
{PARAMETER_ADDR(6), NVS_GROUP_PARAMETERS, 6},
{PARAMETER_ADDR(7), NVS_GROUP_PARAMETERS, 7},
{PARAMETER_ADDR(8), NVS_GROUP_PARAMETERS, 8},
{PARAMETER_ADDR(9), NVS_GROUP_PARAMETERS, 9},
{PARAMETER_ADDR(10), NVS_GROUP_PARAMETERS, 10},
{PARAMETER_ADDR(11), NVS_GROUP_PARAMETERS, 11},
{STARTLINE_ADDR(0), NVS_GROUP_STARTUP, 0},
{STARTLINE_ADDR(1), NVS_GROUP_STARTUP, 1},
#if N_STARTUP_LINE > 2
#error Increase number of startup line entries!
#endif
{NVS_ADDR_BUILD_INFO, NVS_GROUP_BUILD, 0},
{0, 0, 0} // list termination - do not remove
};
inline static uint8_t ram_get_byte (uint32_t addr)
{
return nvsbuffer[addr];
}
inline static void ram_put_byte (uint32_t addr, uint8_t new_value)
{
dirty = dirty || nvsbuffer[addr] != new_value;
nvsbuffer[addr] = new_value;
}
// Extensions added as part of Grbl
static nvs_transfer_result_t memcpy_to_ram (uint32_t destination, uint8_t *source, uint32_t size, bool with_checksum)
{
if(hal.nvs.driver_area.address && destination > hal.nvs.driver_area.address + hal.nvs.driver_area.size)
return physical_nvs.memcpy_to_nvs(destination, source, size, with_checksum);
uint32_t dest = destination;
uint8_t checksum = with_checksum ? calc_checksum(source, size) : 0;
dirty = false;
for(; size > 0; size--)
ram_put_byte(dest++, *(source++));
if(with_checksum)
ram_put_byte(dest, checksum);
if(source == hal.nvs.driver_area.mem_address)
dirty = true;
if(dirty && physical_nvs.type != NVS_None) {
uint8_t idx = 0;
settings_dirty.is_dirty = true;
if(hal.nvs.driver_area.address && destination >= hal.nvs.driver_area.address)
settings_dirty.driver_settings = true;
else {
do {
if(target[idx].addr == destination)
break;
} while(target[++idx].addr);
if(target[idx].addr) switch(target[idx].type) {
case NVS_GROUP_GLOBAL:
settings_dirty.global_settings = true;
break;
#ifdef N_TOOLS
case NVS_GROUP_TOOLS:
settings_dirty.tool_data |= (1 << target[idx].offset);
break;
#endif
case NVS_GROUP_PARAMETERS:
settings_dirty.coord_data |= (1 << target[idx].offset);
break;
case NVS_GROUP_STARTUP:
settings_dirty.startup_lines |= (1 << target[idx].offset);
break;
case NVS_GROUP_BUILD:
settings_dirty.build_info = true;
break;
}
}
}
return NVS_TransferResult_OK;
}
static nvs_transfer_result_t memcpy_from_ram (uint8_t *destination, uint32_t source, uint32_t size, bool with_checksum)
{
if(hal.nvs.driver_area.address && source > hal.nvs.driver_area.address + hal.nvs.driver_area.size)
return physical_nvs.memcpy_from_nvs(destination, source, size, with_checksum);
uint8_t checksum = with_checksum ? calc_checksum(&nvsbuffer[source], size) : 0;
for(; size > 0; size--)
*(destination++) = ram_get_byte(source++);
return with_checksum ? (checksum == ram_get_byte(source) ? NVS_TransferResult_OK : NVS_TransferResult_Failed) : NVS_TransferResult_OK;
}
static void nvs_warning (sys_state_t state)
{
report_message("Not enough heap for NVS buffer!", Message_Warning);
}
// Try to allocate RAM from heap for buffer/emulation.
bool nvs_buffer_alloc (void)
{
assert(NVS_SIZE >= GRBL_NVS_SIZE);
nvsbuffer = malloc(NVS_SIZE);
return nvsbuffer != NULL;
}
//
// Switch over to RAM based copy.
// Changes to RAM based copy will be written to physical storage when Grbl is in IDLE state.
bool nvs_buffer_init (void)
{
if(nvsbuffer) {
memcpy(&physical_nvs, &hal.nvs, sizeof(nvs_io_t)); // save pointers to physical storage handler functions
// Copy physical storage content to RAM when available
if(physical_nvs.type == NVS_Flash)
physical_nvs.memcpy_from_flash(nvsbuffer);
else if(physical_nvs.type != NVS_None)
physical_nvs.memcpy_from_nvs(nvsbuffer, 0, GRBL_NVS_SIZE + hal.nvs.driver_area.size, false);
// Switch hal to use RAM version of non-volatile storage data
hal.nvs.type = NVS_Emulated;
hal.nvs.get_byte = &ram_get_byte;
hal.nvs.put_byte = &ram_put_byte;
hal.nvs.memcpy_to_nvs = &memcpy_to_ram;
hal.nvs.memcpy_from_nvs = &memcpy_from_ram;
hal.nvs.memcpy_from_flash = NULL;
hal.nvs.memcpy_to_flash = NULL;
// If no physical storage available or if NVS import fails copy default settings to RAM
// and write out to physical storage when available.
if(physical_nvs.type == NVS_None || ram_get_byte(0) != SETTINGS_VERSION) {
settings_restore(settings_all);
if(physical_nvs.type == NVS_Flash)
physical_nvs.memcpy_to_flash(nvsbuffer);
else if(physical_nvs.memcpy_to_nvs)
physical_nvs.memcpy_to_nvs(0, nvsbuffer, GRBL_NVS_SIZE + hal.nvs.driver_area.size, false);
if(physical_nvs.type != NVS_None)
grbl.report.status_message(Status_SettingReadFail);
}
} else
protocol_enqueue_rt_command(nvs_warning);
// Clear settings dirty flags
memset(&settings_dirty, 0, sizeof(settings_dirty_t));
return nvsbuffer != NULL;
}
// Allocate NVS block for driver settings.
// NOTE: allocation has to be done before content is copied from physical storage.
nvs_address_t nvs_alloc (size_t size)
{
static uint8_t *mem_address;
nvs_address_t addr = 0;
// Check if already switched to emulation or buffer allocation failed, return NULL if so.
if(hal.nvs.type == NVS_Emulated || nvsbuffer == NULL)
return 0;
if(hal.nvs.driver_area.address == 0) {
hal.nvs.driver_area.address = GRBL_NVS_SIZE;
hal.nvs.driver_area.mem_address = mem_address = nvsbuffer + GRBL_NVS_SIZE;
}
size += NVS_CRC_BYTES; // add room for checksum.
if(hal.nvs.driver_area.size + size < (NVS_SIZE - GRBL_NVS_SIZE)) {
mem_address = (uint8_t *)((uint32_t)(mem_address - 1) | 0x03) + 1; // Align to word boundary
addr = mem_address - nvsbuffer;
mem_address += size;
hal.nvs.driver_area.size = mem_address - hal.nvs.driver_area.mem_address;
hal.nvs.size = GRBL_NVS_SIZE + hal.nvs.driver_area.size + 1;
}
return addr;
}
// Write RAM changes to physical storage
void nvs_buffer_sync_physical (void)
{
if(!settings_dirty.is_dirty)
return;
if(physical_nvs.memcpy_to_nvs) {
if(settings_dirty.build_info)
settings_dirty.build_info = physical_nvs.memcpy_to_nvs(NVS_ADDR_BUILD_INFO, (uint8_t *)(nvsbuffer + NVS_ADDR_BUILD_INFO), sizeof(stored_line_t) + NVS_CRC_BYTES, false) != NVS_TransferResult_OK;
if(settings_dirty.global_settings)
settings_dirty.global_settings = physical_nvs.memcpy_to_nvs(NVS_ADDR_GLOBAL, (uint8_t *)(nvsbuffer + NVS_ADDR_GLOBAL), sizeof(settings_t) + NVS_CRC_BYTES, false) != NVS_TransferResult_OK;
uint_fast8_t idx = N_STARTUP_LINE, offset;
if(settings_dirty.startup_lines) do {
idx--;
if(bit_istrue(settings_dirty.startup_lines, bit(idx))) {
bit_false(settings_dirty.startup_lines, bit(idx));
offset = NVS_ADDR_STARTUP_BLOCK + idx * (sizeof(stored_line_t) + NVS_CRC_BYTES);
if(physical_nvs.memcpy_to_nvs(offset, (uint8_t *)(nvsbuffer + offset), sizeof(stored_line_t) + NVS_CRC_BYTES, false) == NVS_TransferResult_OK)
bit_false(settings_dirty.startup_lines, bit(idx));
}
} while(idx);
idx = N_CoordinateSystems;
if(settings_dirty.coord_data) do {
if(bit_istrue(settings_dirty.coord_data, bit(idx))) {
offset = NVS_ADDR_PARAMETERS + idx * (sizeof(coord_data_t) + NVS_CRC_BYTES);
if(physical_nvs.memcpy_to_nvs(offset, (uint8_t *)(nvsbuffer + offset), sizeof(coord_data_t) + NVS_CRC_BYTES, false) == NVS_TransferResult_OK)
bit_false(settings_dirty.coord_data, bit(idx));
}
} while(idx--);
if(settings_dirty.driver_settings) {
if(hal.nvs.driver_area.size > 0)
settings_dirty.driver_settings = physical_nvs.memcpy_to_nvs(hal.nvs.driver_area.address, (uint8_t *)(nvsbuffer + hal.nvs.driver_area.address), hal.nvs.driver_area.size, false) != NVS_TransferResult_OK;
else
settings_dirty.driver_settings = false;
}
#ifdef N_TOOLS
idx = N_TOOLS;
if(settings_dirty.tool_data) do {
idx--;
if(bit_istrue(settings_dirty.tool_data, bit(idx))) {
offset = NVS_ADDR_TOOL_TABLE + idx * (sizeof(tool_data_t) + NVS_CRC_BYTES);
if(physical_nvs.memcpy_to_nvs(offset, (uint8_t *)(nvsbuffer + offset), sizeof(tool_data_t) + NVS_CRC_BYTES, false) == NVS_TransferResult_OK)
bit_false(settings_dirty.tool_data, bit(idx));
}
} while(idx);
#endif
settings_dirty.is_dirty = settings_dirty.coord_data ||
settings_dirty.global_settings ||
settings_dirty.driver_settings ||
settings_dirty.startup_lines ||
#ifdef N_TOOLS
settings_dirty.tool_data ||
#endif
settings_dirty.build_info;
} else if(physical_nvs.memcpy_to_flash) {
physical_nvs.memcpy_to_flash(nvsbuffer);
settings_dirty.is_dirty = false;
}
}
nvs_io_t *nvs_buffer_get_physical (void)
{
return hal.nvs.type == NVS_Emulated ? &physical_nvs : &hal.nvs;
}
#ifndef DEBUGOUT
#include "report.h"
void nvs_memmap (void)
{
char buf[30];
report_message("NVS Area: addr size", Message_Plain);
strcpy(buf, "Global: ");
strcat(buf, uitoa(NVS_ADDR_GLOBAL));
strcat(buf, " ");
strcat(buf, uitoa(sizeof(settings_t) + NVS_CRC_BYTES));
report_message(buf, Message_Plain);
strcpy(buf, "Parameters: ");
strcat(buf, uitoa(NVS_ADDR_PARAMETERS));
strcat(buf, " ");
strcat(buf, uitoa(N_CoordinateSystems * (sizeof(coord_data_t) + NVS_CRC_BYTES)));
report_message(buf, Message_Plain);
strcpy(buf, "Startup block: ");
strcat(buf, uitoa(NVS_ADDR_STARTUP_BLOCK));
strcat(buf, " ");
strcat(buf, uitoa(N_STARTUP_LINE * (sizeof(stored_line_t) + NVS_CRC_BYTES)));
report_message(buf, Message_Plain);
strcpy(buf, "Build info: ");
strcat(buf, uitoa(NVS_ADDR_BUILD_INFO));
strcat(buf, " ");
strcat(buf, uitoa(sizeof(stored_line_t) + NVS_CRC_BYTES));
report_message(buf, Message_Plain);
strcpy(buf, "Driver: ");
strcat(buf, uitoa(hal.nvs.driver_area.address));
strcat(buf, " ");
strcat(buf, uitoa(hal.nvs.driver_area.size));
report_message(buf, Message_Plain);
}
#endif

49
nvs_buffer.h Normal file
View File

@@ -0,0 +1,49 @@
/*
nvs_buffer.h - RAM based non-volatile storage buffer/emulation
Part of grblHAL
Copyright (c) 2017-2020 Terje Io
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NVS_BUFFER_H_
#define _NVS_BUFFER_H_
typedef uint32_t nvs_address_t;
typedef struct {
bool is_dirty;
bool global_settings;
bool build_info;
bool driver_settings;
uint8_t startup_lines;
uint16_t coord_data;
#ifdef N_TOOLS
uint16_t tool_data;
#endif
} settings_dirty_t;
extern settings_dirty_t settings_dirty;
bool nvs_buffer_init (void);
bool nvs_buffer_alloc (void);
nvs_address_t nvs_alloc (size_t size);
void nvs_buffer_sync_physical (void);
nvs_io_t *nvs_buffer_get_physical (void);
void nvs_memmap (void);
#endif

85
override.c Normal file
View File

@@ -0,0 +1,85 @@
/*
override.c - An embedded CNC Controller with rs274/ngc (g-code) support
Buffer handlers for real-time override commands
Part of grblHAL
Copyright (c) 2017-2019 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include "grbl.h"
#include "override.h"
typedef struct {
volatile uint_fast8_t head;
volatile uint_fast8_t tail;
uint8_t buf[OVERRIDE_BUFSIZE];
} override_queue_t;
static override_queue_t feed = {0}, accessory = {0};
ISR_CODE void enqueue_feed_override (uint8_t cmd)
{
uint_fast8_t bptr = (feed.head + 1) & (OVERRIDE_BUFSIZE - 1); // Get next head pointer
if(bptr != feed.tail) { // If not buffer full
feed.buf[feed.head] = cmd; // add data to buffer
feed.head = bptr; // and update pointer
}
}
// Returns 0 if no commands enqueued
uint8_t get_feed_override (void)
{
uint8_t data = 0;
uint_fast8_t bptr = feed.tail;
if(bptr != feed.head) {
data = feed.buf[bptr++]; // Get next character, increment tmp pointer
feed.tail = bptr & (OVERRIDE_BUFSIZE - 1); // and update pointer
}
return data;
}
ISR_CODE void enqueue_accessory_override (uint8_t cmd)
{
uint_fast8_t bptr = (accessory.head + 1) & (OVERRIDE_BUFSIZE - 1); // Get next head pointer
if(bptr != accessory.tail) { // If not buffer full
accessory.buf[accessory.head] = cmd; // add data to buffer
accessory.head = bptr; // and update pointer
}
}
// Returns 0 if no commands enqueued
uint8_t get_accessory_override (void)
{
uint8_t data = 0;
uint_fast8_t bptr = accessory.tail;
if(bptr != accessory.head) {
data = accessory.buf[bptr++]; // Get next character, increment tmp pointer
accessory.tail = bptr & (OVERRIDE_BUFSIZE - 1); // and update pointer
}
return data;
}
void flush_override_buffers () {
feed.head = feed.tail = accessory.head = accessory.tail = 0;
}

37
override.h Normal file
View File

@@ -0,0 +1,37 @@
/*
override.h - An embedded CNC Controller with rs274/ngc (g-code) support
Buffer handlers for real-time override commands
Part of grblHAL
Copyright (c) 2016-2019 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _OVERRIDE_H_
#define _OVERRIDE_H_
#ifndef OVERRIDE_BUFSIZE
#define OVERRIDE_BUFSIZE 16 // must be a power of 2
#endif
void flush_override_buffers ();
void enqueue_feed_override (uint8_t cmd);
uint8_t get_feed_override (void);
void enqueue_accessory_override (uint8_t cmd);
uint8_t get_accessory_override (void);
#endif

105
pid.c Normal file
View File

@@ -0,0 +1,105 @@
/*
pid.c - An embedded CNC Controller with rs274/ngc (g-code) support
PID algorithm for closed loop control
NOTE: not referenced in the core grbl code
Part of grblHAL
Copyright (c) 2020-2021 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "pid.h"
// Fixed point version: TODO
// Float version
void pidf_init (pidf_t *pid, pid_values_t *config)
{
pidf_reset(pid);
memcpy(&pid->cfg, config, sizeof(pid_values_t));
}
bool pidf_config_changed (pidf_t *pid, pid_values_t *config)
{
return memcmp(&pid->cfg, config, sizeof(pid_values_t));
}
void pidf_reset (pidf_t *pid)
{
pid->error = 0.0f;
pid->i_error = 0.0f;
pid->d_error = 0.0f;
pid->sample_rate_prev = 1.0f;
}
float pidf (pidf_t *pid, float command, float actual, float sample_rate)
{
float error = command - actual;
/*
if(error > pid->deadband)
error -= pid->deadband;
else if (error < pid->deadband)
error += pid->deadband;
else
error = 0.0f;
*/
// calculate the proportional term
float pidres = pid->cfg.p_gain * error;
// calculate and add the integral term
pid->i_error += error * (pid->sample_rate_prev / sample_rate);
if(pid->cfg.i_max_error != 0.0f) {
if (pid->i_error > pid->cfg.i_max_error)
pid->i_error = pid->cfg.i_max_error;
else if (pid->i_error < -pid->cfg.i_max_error)
pid->i_error = -pid->cfg.i_max_error;
}
pidres += pid->cfg.i_gain * pid->i_error;
// calculate and add the derivative term
if(pid->cfg.d_gain != 0.0f) {
float p_error = (error - pid->d_error) * (sample_rate / pid->sample_rate_prev);
if(pid->cfg.d_max_error != 0.0f) {
if (p_error > pid->cfg.d_max_error)
p_error = pid->cfg.d_max_error;
else if (p_error < -pid->cfg.d_max_error)
p_error = -pid->cfg.d_max_error;
}
pidres += pid->cfg.d_gain * p_error;
pid->d_error = error;
}
pid->sample_rate_prev = sample_rate;
// limit error output
if(pid->cfg.max_error != 0.0f) {
if(pidres > pid->cfg.max_error)
pidres = pid->cfg.max_error;
else if(pidres < -pid->cfg.max_error)
pidres = -pid->cfg.max_error;
}
pid->error = pidres;
return pidres;
}

48
pid.h Normal file
View File

@@ -0,0 +1,48 @@
/*
pid.h - An embedded CNC Controller with rs274/ngc (g-code) support
PID algorithm for closed loop control
NOTE: not referenced in the core grbl code
Part of grblHAL
Copyright (c) 2020-2021 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PID_H_
#define _PID_H_
#include <stdbool.h>
#include "settings.h"
typedef struct {
pid_values_t cfg;
float deadband;
float i_error;
float d_error;
float sample_rate_prev;
float error;
float max_error;
} pidf_t;
void pidf_reset (pidf_t *pid);
void pidf_init(pidf_t *pid, pid_values_t *config);
bool pidf_config_changed (pidf_t *pid, pid_values_t *config);
float pidf (pidf_t *pid, float command, float actual, float sample_rate);
#endif

576
planner.c Normal file

File diff suppressed because it is too large Load Diff

152
planner.h Normal file
View File

@@ -0,0 +1,152 @@
/*
planner.h - buffers movement commands and manages the acceleration profile plan
Part of grblHAL
Copyright (c) 2019-2021 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PLANNER_H_
#define _PLANNER_H_
// The number of linear motions that can be in the plan at any give time
#ifndef BLOCK_BUFFER_SIZE
#define BLOCK_BUFFER_SIZE 36
#endif
typedef union {
uint32_t value;
struct {
uint16_t rapid_motion :1,
system_motion :1,
jog_motion :1,
backlash_motion :1,
no_feed_override :1,
inverse_time :1,
is_rpm_rate_adjusted :1,
is_rpm_pos_adjusted :1,
is_laser_ppi_mode :1,
unassigned :7;
spindle_state_t spindle;
coolant_state_t coolant;
};
} planner_cond_t;
// 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 plan_block {
// 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
uint32_t step_event_count; // The maximum step axis count and number of steps required to complete this block.
axes_signals_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
// Block condition data to ensure correct execution depending on states and overrides.
planner_cond_t condition; // Block bitfield variable defining block run conditions. Copied from pl_line_data.
gc_override_flags_t overrides; // Block bitfield variable for overrides
int32_t line_number; // Block line number for real-time reporting. Copied from pl_line_data.
// Fields used by the motion planner to manage acceleration. Some of these values may be updated
// by the stepper module during execution of special motion cases for replanning purposes.
float entry_speed_sqr; // The current planned entry speed at block junction in (mm/min)^2
float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and
// neighboring nominal speeds with overrides in (mm/min)^2
float acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change.
float millimeters; // The remaining distance for this block to be executed in (mm).
// NOTE: This value may be altered by stepper algorithm during execution.
// Stored rate limiting data used by planner when changes occur.
float max_junction_speed_sqr; // Junction entry speed limit based on direction vectors in (mm/min)^2
float rapid_rate; // Axis-limit adjusted maximum rate for this block direction in (mm/min)
float programmed_rate; // Programmed rate of this block (mm/min).
// Stored spindle speed data used by spindle overrides and resuming methods.
spindle_t spindle; // Block spindle speed. Copied from pl_line_data.
char *message; // Message to be displayed when block is executed.
output_command_t *output_commands;
struct plan_block *prev, *next; // Linked list pointers, DO NOT MOVE - these MUST be the last elements in the struct!
} plan_block_t;
// Planner data prototype. Must be used when passing new motions to the planner.
typedef struct {
float feed_rate; // Desired feed rate for line motion. Value is ignored, if rapid motion.
spindle_t spindle; // Desired spindle speed through line motion.
planner_cond_t condition; // Bitfield variable to indicate planner conditions. See defines above.
gc_override_flags_t overrides; // Block bitfield variable for overrides
int32_t line_number; // Desired line number to report when executing.
// void *parameters; // TODO: pointer to extra parameters, for canned cycles and threading?
char *message; // Message to be displayed when block is executed.
output_command_t *output_commands;
} plan_line_data_t;
// Define planner variables
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.
float previous_unit_vec[N_AXIS]; // Unit vector of previous path line segment
float previous_nominal_speed; // Nominal speed of previous path line segment
} planner_t;
// Initialize and reset the motion plan subsystem
void plan_reset(); // Reset all
//void plan_reset_buffer(); // Reset buffer only.
// Add a new linear movement to the buffer. target[N_AXIS] is the signed, absolute target position
// in millimeters. Feed rate specifies the speed of the motion. If feed rate is inverted, the feed
// rate is taken to mean "frequency" and would complete the operation in 1/feed_rate minutes.
bool plan_buffer_line(float *target, plan_line_data_t *pl_data);
// Called when the current block is no longer needed. Discards the block and makes the memory
// availible for new blocks.
void plan_discard_current_block();
// Gets the planner block for the special system motion cases. (Parking/Homing)
plan_block_t *plan_get_system_motion_block();
// Gets the current block. Returns NULL if buffer empty
plan_block_t *plan_get_current_block();
// Called by step segment buffer when computing executing block velocity profile.
float plan_get_exec_block_exit_speed_sqr();
// Called by main program during planner calculations and step segment buffer during initialization.
float plan_compute_profile_nominal_speed(plan_block_t *block);
// Re-calculates buffered motions profile parameters upon a motion-based override change.
void plan_update_velocity_profile_parameters();
// Reset the planner position vector (in steps)
void plan_sync_position();
// Reinitialize plan with a partially completed block
void plan_cycle_reinitialize();
// Returns the number of available blocks in the planner buffer.
uint_fast16_t plan_get_block_buffer_available();
// Returns the status of the block ring buffer. True, if buffer is full.
bool plan_check_full_buffer();
void plan_get_planner_mpos(float *target);
void plan_feed_override (uint_fast8_t feed_override, uint_fast8_t rapid_override);
#endif

32
platform.h Normal file
View File

@@ -0,0 +1,32 @@
/*
platform.h - platform specific definitions
Part of grblHAL
Copyright (c) 2021 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if defined(STM32F103xB) || defined(STM32F401xC) || defined(STM32F407xx) || defined(STM32F411xE) || defined(STM32F446xx)
#define STM32_PLATFORM
#endif
#if defined(STM32_PLATFORM) || defined(__LPC17XX__) || defined(__IMXRT1062__)
#define UINT32FMT "lu"
#else
#define UINT32FMT "u"
#endif

190
plugins.h Normal file
View File

@@ -0,0 +1,190 @@
/*
plugins.h - An embedded CNC Controller with rs274/ngc (g-code) support
Some data structures and function declarations for plugins that require driver code
These are NOT referenced in the core grbl code
Part of grblHAL
Copyright (c) 2020-2021 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PLUGINS_H_
#define _PLUGINS_H_
#include <stdint.h>
#include <stdbool.h>
#include "nvs.h"
// Jogging
typedef struct {
float fast_speed;
float slow_speed;
float step_speed;
float fast_distance;
float slow_distance;
float step_distance;
} jog_settings_t;
// Networking
typedef enum {
IpMode_Static = 0,
IpMode_DHCP,
IpMode_AutoIP
} ip_mode_t;
typedef union {
uint8_t mask;
struct {
uint8_t telnet :1,
websocket :1,
http :1,
dns :1,
mdns :1,
ssdp :1,
webdav :1,
unassigned :1;
};
} network_services_t;
typedef char ssid_t[65];
typedef char password_t[33];
typedef char hostname_t[33];
typedef struct {
char ip[16];
char gateway[16];
char mask[16];
hostname_t hostname;
uint16_t telnet_port;
uint16_t websocket_port;
uint16_t http_port;
ip_mode_t ip_mode;
network_services_t services;
} network_settings_t;
typedef enum {
WiFiMode_NULL = 0,
WiFiMode_STA,
WiFiMode_AP,
WiFiMode_APSTA
} grbl_wifi_mode_t;
typedef struct {
ssid_t ssid;
password_t password;
char country[4];
uint8_t channel;
network_settings_t network;
} wifi_ap_settings_t;
typedef struct {
ssid_t ssid;
password_t password;
network_settings_t network;
} wifi_sta_settings_t;
typedef struct {
char device_name[33];
char service_name[33];
} bluetooth_settings_t;
typedef struct {
uint32_t baud_rate;
uint32_t rx_timeout;
} modbus_settings_t;
// Quadrature encoder interface
typedef enum {
Encoder_Universal = 0,
Encoder_FeedRate,
Encoder_RapidRate,
Encoder_Spindle_RPM,
Encoder_MPG,
Encoder_MPG_X,
Encoder_MPG_Y,
Encoder_MPG_Z,
Encoder_MPG_A,
Encoder_MPG_B,
Encoder_MPG_C,
Encoder_Spindle_Position
} encoder_mode_t;
typedef enum {
Setting_EncoderMode = 0,
Setting_EncoderCPR = 1, // Count Per Revolution
Setting_EncoderCPD = 2, // Count Per Detent
Setting_EncoderDblClickWindow = 3 // ms
} encoder_setting_id_t;
typedef union {
uint8_t events;
struct {
uint8_t position_changed :1,
click :1,
dbl_click :1,
long_click :1,
index_pulse :1;
};
} encoder_event_t;
typedef union {
uint8_t flags;
uint8_t value;
struct {
uint8_t single_count_per_detent :1;
};
} encoder_flags_t;
typedef struct {
encoder_mode_t mode;
uint32_t cpr; // count per revolution
uint32_t cpd; // count per detent
uint32_t dbl_click_window; // ms
encoder_flags_t flags;
} encoder_settings_t;
typedef struct {
encoder_mode_t mode;
uint_fast8_t id;
uint_fast8_t axis; // axis index for MPG encoders, 0xFF for others
int32_t position;
uint32_t velocity;
encoder_event_t event;
encoder_settings_t *settings;
} encoder_t;
// EEPROM/FRAM interface
typedef struct {
uint8_t address;
uint8_t word_addr_bytes;
uint16_t word_addr;
volatile uint_fast16_t count;
bool add_checksum;
uint8_t checksum;
uint8_t *data;
} nvs_transfer_t;
extern nvs_transfer_result_t i2c_nvs_transfer (nvs_transfer_t *i2c, bool read);
extern void my_plugin_init (void) __attribute__((weak));
#endif

43
probe.h Normal file
View File

@@ -0,0 +1,43 @@
/*
probe.h - An embedded CNC Controller with rs274/ngc (g-code) support
Part of grblHAL
Copyright (c) 2020 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PROBE_H_
#define _PROBE_H_
// Values that define the probing state machine.
typedef enum {
Probing_Off = 0,
Probing_Active
} probing_state_t;
typedef union {
uint8_t value;
struct {
uint8_t triggered :1,
connected :1,
inverted :1, // For driver use
is_probing :1, // For driver use
unassigned :4;
};
} probe_state_t;
#endif

930
protocol.c Normal file

File diff suppressed because it is too large Load Diff

56
protocol.h Normal file
View File

@@ -0,0 +1,56 @@
/*
protocol.h - controls Grbl execution protocol and procedures
Part of grblHAL
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PROTOCOL_H_
#define _PROTOCOL_H_
// Line buffer size from the input stream to be executed.
// NOTE: Not a problem except for extreme cases, but the line buffer size can be too small
// and g-code blocks can get truncated. Officially, the g-code standards support up to 256
// characters. In future versions, this will be increased, when we know how much extra
// memory space we can invest into here or we re-write the g-code parser not to have this
// buffer.
#ifndef LINE_BUFFER_SIZE
#define LINE_BUFFER_SIZE 257 // 256 characters plus terminator
#endif
// Starts Grbl main loop. It handles all incoming characters from the input stream and executes
// them as they complete. It is also responsible for finishing the initialization procedures.
bool protocol_main_loop (void);
// Checks and executes a realtime command at various stop points in main program
bool protocol_execute_realtime (void);
bool protocol_exec_rt_system (void);
void protocol_execute_noop (uint_fast16_t state);
bool protocol_enqueue_rt_command (on_execute_realtime_ptr fn);
// Executes the auto cycle feature, if enabled.
void protocol_auto_cycle_start (void);
// Block until all buffered steps are executed
bool protocol_buffer_synchronize (void);
bool protocol_enqueue_realtime_command (char c);
bool protocol_enqueue_gcode (char *data);
void protocol_message (char *message);
#endif

1869
report.c Normal file

File diff suppressed because it is too large Load Diff

103
report.h Normal file
View File

@@ -0,0 +1,103 @@
/*
report.h - reporting and messaging methods
Part of grblHAL
Copyright (c) 2018-2021 Terje Io
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _REPORT_H_
#define _REPORT_H_
#include "system.h"
// Message types for uncoded messages
typedef enum {
Message_Plain = 0,
Message_Info,
Message_Warning
} message_type_t;
// Initialize reporting subsystem
void report_init (void);
void report_init_fns (void);
// Prints system status messages.
status_code_t report_status_message (status_code_t status_code);
// Prints system alarm messages.
alarm_code_t report_alarm_message (alarm_code_t alarm_code);
// Prints feedback message, typically from gcode.
void report_message (const char *msg, message_type_t type);
// Prints miscellaneous feedback messages.
message_code_t report_feedback_message (message_code_t message_code);
// Prints welcome message.
void report_init_message (void);
// Prints Grbl help.
status_code_t report_help (char *args, char *lcargs);
void report_grbl_help();
// Prints Grbl settings
void report_grbl_settings (bool all, void *data);
// Prints Grbl setting
status_code_t report_grbl_setting (setting_id_t id, void *data);
// Prints an echo of the pre-parsed line received right before execution.
void report_echo_line_received (char *line);
// Prints realtime status report.
void report_realtime_status (void);
// Prints recorded probe position.
void report_probe_parameters (void);
// Prints current tool offsets.
void report_tool_offsets (void);
// Prints Grbl NGC parameters (coordinate offsets, probe).
void report_ngc_parameters (void);
// Prints current g-code parser mode state.
void report_gcode_modes (void);
// Prints startup line when requested and executed.
void report_startup_line (uint8_t n, char *line);
void report_execute_startup_message (char *line, status_code_t status_code);
// Prints build info and user info.
void report_build_info (char *line, bool extended);
status_code_t report_alarm_details (void);
status_code_t report_error_details (void);
status_code_t report_setting_group_details (bool by_id, char *prefix);
status_code_t report_settings_details (bool human_readable, setting_id_t setting, setting_group_t group);
status_code_t report_last_signals_event (sys_state_t state, char *args);
status_code_t report_current_limit_state (sys_state_t state, char *args);
// Prints spindle data (encoder pulse and index count, angular position).
status_code_t report_spindle_data (sys_state_t state, char *args);
// Prints current PID log.
void report_pid_log (void);
#endif

1807
settings.c Normal file

File diff suppressed because it is too large Load Diff

721
settings.h Normal file

File diff suppressed because it is too large Load Diff

88
sleep.c Normal file
View File

@@ -0,0 +1,88 @@
/*
sleep.c - determines and executes sleep procedures
Part of grblHAL
Copyright (c) 2018-2021 Terje Io
Copyright (c) 2016 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hal.h"
#include "state_machine.h"
volatile bool slumber;
static void fall_asleep()
{
slumber = false;
}
// Starts sleep timer if running conditions are satified. When elapsed, sleep mode is executed.
static void sleep_execute()
{
// Enable sleep timeout
slumber = true;
hal.delay_ms((uint32_t)(SLEEP_DURATION * 1000.0f * 60.0f), fall_asleep);
// Fetch current number of buffered characters in input stream buffer.
uint16_t rx_initial = hal.stream.get_rx_buffer_available();
do {
// Monitor for any new input stream data or external events (queries, buttons, alarms) to exit.
if ((hal.stream.get_rx_buffer_available() != rx_initial) || sys.rt_exec_state || sys.rt_exec_alarm ) {
// Disable sleep timeout and return to normal operation.
hal.delay_ms(0, NULL);
return;
}
} while(slumber);
// If reached, sleep counter has expired. Execute sleep procedures.
// Notify user that Grbl has timed out and will be parking.
// To exit sleep, resume or reset. Either way, the job will not be recoverable.
grbl.report.feedback_message(Message_SleepMode);
system_set_exec_state_flag(EXEC_SLEEP);
}
// Checks running conditions for sleep. If satisfied, enables sleep timeout and executes
// sleep mode upon elapse.
// NOTE: Sleep procedures can be blocking, since Grbl isn't receiving any commands, nor moving.
// Hence, make sure any valid running state that executes the sleep timer is not one that is moving.
void sleep_check()
{
// The sleep execution feature will continue only if the machine is in an IDLE or HOLD state and
// has any powered components enabled.
// NOTE: With overrides or in laser mode, modal spindle and coolant state are not guaranteed. Need
// to directly monitor and record running state during parking to ensure proper function.
if (!sys.steppers_deenergize && (gc_state.modal.spindle.value || gc_state.modal.coolant.value)) {
switch(state_get()) {
case STATE_IDLE:
sleep_execute();
break;
case STATE_HOLD:
if(sys.holding_state == Hold_Complete)
sleep_execute();
break;
case STATE_SAFETY_DOOR:
if(sys.parking_state == Parking_DoorAjar)
sleep_execute();
break;
}
}
}

29
sleep.h Normal file
View File

@@ -0,0 +1,29 @@
/*
sleep.h - Sleep methods header file
Part of grblHAL
Copyright (c) 2016 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SLEEP_H_
#define _SLEEP_H_
// Checks running conditions for sleep. If satisfied, enables sleep countdown and executes
// sleep mode upon elapse.
void sleep_check();
#endif

225
spindle_control.c Normal file
View File

@@ -0,0 +1,225 @@
/*
spindle_control.c - spindle control methods
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2012-2015 Sungeun K. Jeon
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include "hal.h"
#include "protocol.h"
#include "state_machine.h"
// Set spindle speed override
// NOTE: Unlike motion overrides, spindle overrides do not require a planner reinitialization.
void spindle_set_override (uint_fast8_t speed_override)
{
if(sys.override.control.spindle_rpm_disable)
return;
speed_override = max(min(speed_override, MAX_SPINDLE_RPM_OVERRIDE), MIN_SPINDLE_RPM_OVERRIDE);
if ((uint8_t)speed_override != sys.override.spindle_rpm) {
sys.override.spindle_rpm = (uint8_t)speed_override;
if(state_get() == STATE_IDLE)
spindle_set_state(gc_state.modal.spindle, gc_state.spindle.rpm);
else
sys.step_control.update_spindle_rpm = On;
sys.report.overrides = On; // Set to report change immediately
}
}
// Immediately sets spindle running state with direction and spindle rpm, if enabled.
// Called by g-code parser spindle_sync(), parking retract and restore, g-code program end,
// sleep, and spindle stop override.
bool spindle_set_state (spindle_state_t state, float rpm)
{
if (!ABORTED) { // Block during abort.
if (!state.on) { // Halt or set spindle direction and rpm.
sys.spindle_rpm = rpm = 0.0f;
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
} else {
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
// TODO: alarm/interlock if going from CW to CCW directly in non-laser mode?
if (settings.mode == Mode_Laser && state.ccw)
rpm = 0.0f; // TODO: May need to be rpm_min*(100/MAX_SPINDLE_RPM_OVERRIDE);
hal.spindle.set_state(state, spindle_set_rpm(rpm, sys.override.spindle_rpm));
}
sys.report.spindle = On; // Set to report change immediately
st_rpm_changed(rpm);
}
return !ABORTED;
}
// G-code parser entry-point for setting spindle state. Forces a planner buffer sync and bails
// if an abort or check-mode is active.
bool spindle_sync (spindle_state_t state, float rpm)
{
bool ok = true;
bool at_speed = state_get() == STATE_CHECK_MODE || !state.on || !hal.driver_cap.spindle_at_speed || settings.spindle.at_speed_tolerance <= 0.0f;
if (state_get() != STATE_CHECK_MODE) {
// Empty planner buffer to ensure spindle is set when programmed.
if((ok = protocol_buffer_synchronize()) && spindle_set_state(state, rpm) && !at_speed) {
float delay = 0.0f;
while(!(at_speed = hal.spindle.get_state().at_speed)) {
delay_sec(0.1f, DelayMode_Dwell);
delay += 0.1f;
if(ABORTED)
break;
if(delay >= SAFETY_DOOR_SPINDLE_DELAY) {
system_raise_alarm(Alarm_Spindle);
break;
}
}
}
}
return ok && at_speed;
}
// Restore spindle running state with direction, enable, spindle RPM and appropriate delay.
bool spindle_restore (spindle_state_t state, float rpm)
{
bool ok = true;
if(settings.mode == Mode_Laser) // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
sys.step_control.update_spindle_rpm = On;
else { // TODO: add check for current spindle state matches restore state?
spindle_set_state(state, rpm);
if(state.on) {
if((ok = !hal.driver_cap.spindle_at_speed))
delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DelayMode_SysSuspend);
else if((ok == (settings.spindle.at_speed_tolerance <= 0.0f))) {
float delay = 0.0f;
while(!(ok = hal.spindle.get_state().at_speed)) {
delay_sec(0.1f, DelayMode_SysSuspend);
delay += 0.1f;
if(ABORTED)
break;
if(delay >= SAFETY_DOOR_SPINDLE_DELAY) {
system_raise_alarm(Alarm_Spindle);
break;
}
}
}
}
}
return ok;
}
// Calculate and set programmed RPM according to override and max/min limits
float spindle_set_rpm (float rpm, uint8_t override_pct)
{
if(override_pct != 100)
rpm *= 0.01f * (float)override_pct; // Scale RPM by override value.
// Apply RPM limits
if (rpm <= 0.0f)
rpm = 0.0f;
else if (rpm > settings.spindle.rpm_max)
rpm = settings.spindle.rpm_max;
else if (rpm < settings.spindle.rpm_min)
rpm = settings.spindle.rpm_min;
sys.spindle_rpm = rpm;
return rpm;
}
//
// The following functions are not called by the core, may be called by driver code.
//
// calculate inverted pwm value if configured
static inline uint_fast16_t invert_pwm (spindle_pwm_t *pwm_data, uint_fast16_t pwm_value)
{
return pwm_data->invert_pwm ? pwm_data->period - pwm_value - 1 : pwm_value;
}
// Precompute PWM values for faster conversion.
// Returns false if no PWM range possible, driver should revert to simple on/off spindle control if so.
bool spindle_precompute_pwm_values (spindle_pwm_t *pwm_data, uint32_t clock_hz)
{
if(settings.spindle.rpm_max > settings.spindle.rpm_min) {
pwm_data->period = (uint_fast16_t)((float)clock_hz / settings.spindle.pwm_freq);
if(settings.spindle.pwm_off_value == 0.0f)
pwm_data->off_value = pwm_data->invert_pwm ? pwm_data->period : 0;
else
pwm_data->off_value = invert_pwm(pwm_data, (uint_fast16_t)(pwm_data->period * settings.spindle.pwm_off_value / 100.0f));
pwm_data->min_value = (uint_fast16_t)(pwm_data->period * settings.spindle.pwm_min_value / 100.0f);
pwm_data->max_value = (uint_fast16_t)(pwm_data->period * settings.spindle.pwm_max_value / 100.0f) + pwm_data->offset;
pwm_data->pwm_gradient = (float)(pwm_data->max_value - pwm_data->min_value) / (settings.spindle.rpm_max - settings.spindle.rpm_min);
pwm_data->always_on = settings.spindle.pwm_off_value != 0.0f;
}
#ifdef ENABLE_SPINDLE_LINEARIZATION
uint_fast8_t idx;
pwm_data->n_pieces = 0;
for(idx = 0; idx < SPINDLE_NPWM_PIECES; idx++) {
if(!isnan(settings.spindle.pwm_piece[idx].rpm) && settings.spindle.pwm_piece[idx].start != 0.0f)
memcpy(&pwm_data->piece[pwm_data->n_pieces++], &settings.spindle.pwm_piece[idx], sizeof(pwm_piece_t));
}
#endif
return settings.spindle.rpm_max > settings.spindle.rpm_min;
}
// Spindle RPM to PWM conversion.
uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, bool pid_limit)
{
uint_fast16_t pwm_value;
if(rpm > settings.spindle.rpm_min) {
#ifdef ENABLE_SPINDLE_LINEARIZATION
// Compute intermediate PWM value with linear spindle speed model via piecewise linear fit model.
uint_fast8_t idx = pwm_data->n_pieces;
if(idx) {
do {
idx--;
if(idx == 0 || rpm > pwm_data->piece[idx].rpm) {
pwm_value = floorf(pwm_data->piece[idx].start * rpm - pwm_data->piece[idx].end);
break;
}
} while(idx);
} else
#endif
// Compute intermediate PWM value with linear spindle speed model.
pwm_value = (uint_fast16_t)floorf((rpm - settings.spindle.rpm_min) * pwm_data->pwm_gradient) + pwm_data->min_value;
if(pwm_value >= (pid_limit ? pwm_data->period : pwm_data->max_value))
pwm_value = pid_limit ? pwm_data->period - 1 : pwm_data->max_value;
else if(pwm_value < pwm_data->min_value)
pwm_value = pwm_data->min_value;
pwm_value = invert_pwm(pwm_data, pwm_value);
} else
pwm_value = rpm == 0.0f ? pwm_data->off_value : invert_pwm(pwm_data, pwm_data->min_value);
return pwm_value;
}

109
spindle_control.h Normal file
View File

@@ -0,0 +1,109 @@
/*
spindle_control.h - spindle control methods
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2012-2015 Sungeun K. Jeon
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SPINDLE_CONTROL_H_
#define _SPINDLE_CONTROL_H_
typedef union {
uint8_t value;
uint8_t mask;
struct {
uint8_t on :1,
ccw :1,
pwm :1, // NOTE: only used for PWM inversion setting
reserved3 :1,
reserved4 :1,
encoder_error :1,
at_speed :1,
synchronized :1;
};
} spindle_state_t;
typedef struct {
float rpm;
float start;
float end;
} pwm_piece_t;
// Precalculated values that may be set/used by HAL driver to speed up RPM to PWM conversions if variable spindle is supported
typedef struct {
uint_fast16_t period;
uint_fast16_t off_value; // NOTE: this value holds the inverted version if software PWM inversion is enabled by the driver.
uint_fast16_t min_value;
uint_fast16_t max_value;
float pwm_gradient;
bool invert_pwm; // NOTE: set (by driver) when inversion is done in code
bool always_on;
int_fast16_t offset;
uint_fast16_t n_pieces;
pwm_piece_t piece[SPINDLE_NPWM_PIECES];
} spindle_pwm_t;
// Used when HAL driver supports spindle synchronization
typedef struct {
float rpm;
float rpm_low_limit;
float rpm_high_limit;
float angular_position; // Number of revolutions since last reset
float rpm_programmed;
uint32_t index_count;
uint32_t pulse_count;
uint32_t error_count;
spindle_state_t state_programmed;
} spindle_data_t;
typedef enum {
SpindleData_Counters,
SpindleData_RPM,
SpindleData_AngularPosition
} spindle_data_request_t;
void spindle_set_override (uint_fast8_t speed_override);
// Called by g-code parser when setting spindle state and requires a buffer sync.
// Immediately sets spindle running state with direction and spindle RPM, if enabled.
// Called by spindle_sync() after sync and parking motion/spindle stop override during restore.
// Called by g-code parser when setting spindle state and requires a buffer sync.
bool spindle_sync (spindle_state_t state, float rpm);
// Sets spindle running state with direction, enable, and spindle RPM.
bool spindle_set_state (spindle_state_t state, float rpm);
// Spindle speed calculation and limit handling
float spindle_set_rpm (float rpm, uint8_t speed_override);
// Restore spindle running state with direction, enable, spindle RPM and appropriate delay.
bool spindle_restore (spindle_state_t state, float rpm);
//
// The following functions are not called by the core, may be called by driver code.
//
// Precompute PWM values for faster conversion.
bool spindle_precompute_pwm_values (spindle_pwm_t *pwm_data, uint32_t clock_hz);
// Spindle speed to PWM conversion.
uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, bool pid_limit);
#endif

78
spindle_sync.h Normal file
View File

@@ -0,0 +1,78 @@
/*
spindle_sync.h - An embedded CNC Controller with rs274/ngc (g-code) support
Spindle sync data strucures
NOTE: not referenced in the core grbl code
Part of grblHAL
Copyright (c) 2020-2021 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SPINDLE_SYNC_H_
#define _SPINDLE_SYNC_H_
#include "pid.h"
// Free running timer log data.
// The free running timer is used to timestamp pulse events from the encoder.
typedef struct {
volatile uint32_t last_index; // Timer value at last encoder index pulse
volatile uint32_t last_pulse; // Timer value at last encoder pulse
volatile uint32_t pulse_length; // Last timer tics between spindle encoder pulse interrupts.
} spindle_encoder_timer_t;
// Pulse counter timer log data.
// This counter is used to "prescale" the encoder pulses in order to
// reduce pulse interrupt frequency. This allows the use of high PPR encoders
// without overloading the MCU while still making use of the better resolution.
// NOTE: if a 16bit counter is used then it is important than proper casting
// is performed in order to handle counter overflow correctly.
typedef struct {
volatile uint32_t last_count; // Counter value at last encoder pulse interrupt
volatile uint32_t last_index; // Counter value at last encoder index interrupt
volatile uint32_t index_count;
volatile uint32_t pulse_count;
} spindle_encoder_counter_t;
typedef struct {
uint32_t ppr; // Encoder pulses per revolution
float rpm_factor; // Inverse of event timer tics per RPM
float pulse_distance; // Encoder pulse distance in fraction of one revolution
uint32_t maximum_tt; // Maximum timer tics since last spindle encoder pulse before RPM = 0 is returned
spindle_encoder_timer_t timer; // Event timestamps
spindle_encoder_counter_t counter; // Encoder event counts
uint32_t error_count; // Incremented when actual PPR count differs from ppr setting
uint32_t tics_per_irq; // Counts per interrupt generated (prescaler value)
volatile bool spin_lock;
} spindle_encoder_t;
typedef struct {
float prev_pos; // Target position of previous segment
float steps_per_mm; // Steps per mm for current block
float programmed_rate; // Programmed feed in mm/rev for current block
int32_t min_cycles_per_tick; // Minimum cycles per tick for PID loop
uint_fast8_t segment_id; // Used for detecing start of new segment
pidf_t pid; // PID data for position
stepper_pulse_start_ptr stepper_pulse_start_normal; // Driver pulse function to restore after spindle sync move is completed
#ifdef PID_LOG
int32_t log[PID_LOG];
int32_t pos[PID_LOG];
#endif
} spindle_sync_t;
#endif

Some files were not shown because too many files have changed in this diff Show More