mirror of
https://github.com/grblHAL/core.git
synced 2026-02-05 16:50:16 +08:00
Spindle handling refactoring for improved management and configuration of multiple spindles.
NOTE: this is a relatively large change and may have introduced bugs and/or unintended side-effects. Please report any issues! Added setting $519 for binding spindle encoder to given spindle in multi spindle configurations. Added machine readable spindle enumeration report, $SPINDLESH. Increased default value for setting $398 (number of planner blocs) from 35 to 100 for faster laser engraving. NOTE: the $398 setting value will not change on an upgrade! NOTE: STM32F103 builds for the 128K flash variants does not have enough free RAM and will keep 35 as the default value. Increased allowed number of decimal places from 3 to 5 for $10x stepper step/mm settings. Ref. ioSender issue 346. Added setting $650 for filing system options. Ref. issue 397. Currently the following bits are available (depending on the configuration): 0 - Auto mount SD card on startup (1). 1 - Do not add littlefs files when listing the root directory (2). Added build option for lathe UVW mode. When enabled UVW words can be used to command relative moves for XYZ without switching to relative mode with G91. NOTE: This permanently sets lathe mode and disables the $32 mode setting. There are signature changes to some spindle, ioports enumeration and VFS filing system mount functions. Added events to allow plugin code to handle tool table data, possibly stored on a SD card.
This commit is contained in:
@@ -13,11 +13,8 @@ It has been written to complement grblHAL and has features such as proper keyboa
|
||||
|
||||
---
|
||||
|
||||
Latest build date is 20231005, see the [changelog](changelog.md) for details.
|
||||
Latest build date is 20231210, see the [changelog](changelog.md) for details.
|
||||
__NOTE:__ A settings reset will be performed on an update of builds earlier than 20230125. Backup and restore of settings is recommended.
|
||||
__IMPORTANT!__ A new setting has been introduced for ganged axes motors in build 20211121.
|
||||
I have only bench tested this for a couple of drivers, correct function should be verified after updating by those who have more than three motors configured.
|
||||
More details in the [changelog](changelog.md).
|
||||
|
||||
---
|
||||
|
||||
@@ -80,7 +77,7 @@ This is a port/rewrite of [grbl 1.1f](https://github.com/gnea/grbl) and should b
|
||||
- Return from macro*****: M99
|
||||
- Valid Non-Command Words: A*, B*, C*, D, E*, F, H*, I, J, K, L, N, P, Q*, R, S, T, U*, V*, W*, X, Y, Z
|
||||
|
||||
* driver/configuration dependent. W axis only available when ABC axes are remapped to UVW.
|
||||
* driver/configuration dependent. W axis only available when ABC axes are remapped to UVW or when lathe UVW mode is enabled.
|
||||
** requires compatible GCode sender due to protocol extensions, new state and RT command.
|
||||
*** number of inputs and outputs supported dependent on driver implementation.
|
||||
**** supports multi turn arcs from build 20220718.
|
||||
@@ -92,4 +89,4 @@ G/M-codes not supported by [legacy Grbl](https://github.com/gnea/grbl/wiki) are
|
||||
Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes.
|
||||
|
||||
---
|
||||
2023-09-05
|
||||
2023-12-10
|
||||
|
||||
64
changelog.md
64
changelog.md
@@ -1,5 +1,69 @@
|
||||
## grblHAL changelog
|
||||
|
||||
<a name="20231210"/>Build 20231210
|
||||
|
||||
Core:
|
||||
|
||||
* Spindle handling refactoring for improved management and configuration of multiple spindles.
|
||||
__NOTE:__ this is a relatively large change and may have introduced bugs and/or unintended side-effects. Please report any issues!
|
||||
|
||||
* Added setting `$519` for binding spindle encoder to given spindle in multi spindle configurations.
|
||||
|
||||
* Added machine readable spindle enumeration report, `$SPINDLESH`.
|
||||
|
||||
* Increased _default_ value for setting `$398` \(number of planner blocs\) from 35 to 100 for faster laser engraving.
|
||||
Ref. [this discussion](https://github.com/grblHAL/core/discussions/402).
|
||||
__NOTE:__ the `$398` setting value will _not_ change on an upgrade!
|
||||
__NOTE:__ STM32F103 builds for the 128K flash variants does not have enough free RAM and will keep 35 as the default value.
|
||||
|
||||
* Increased allowed number of decimal places from 3 to 5 for `$10x` stepper step/mm settings.
|
||||
Ref. [ioSender issue 346](https://github.com/terjeio/ioSender/issues/346).
|
||||
|
||||
* Added setting `$650` for filing system options. Ref. [issue 397](https://github.com/grblHAL/core/issues/397).
|
||||
Currently the following bits are available \(depending on the configuration\):
|
||||
0 - Auto mount SD card on startup \(1\).
|
||||
1 - Do not add littlefs files when listing the root directory \(2\).
|
||||
|
||||
* Added build option for [lathe UVW mode](https://www.cnctrainingcentre.com/haas-turn/u-and-w-on-a-cnc-lathe-incremental-programming/).
|
||||
Ref [this discussion](https://github.com/grblHAL/core/discussions/398).
|
||||
When enabled `UVW` words can be used to command relative moves for `XYZ` without switching to relative mode with `G91`. `U` -> `X`, `V` -> `Y`, `W` -> `Z`.
|
||||
__NOTE:__ This permanently sets lathe mode and disables the `$32` mode setting.
|
||||
|
||||
For developers:
|
||||
|
||||
* There are signature changes to some spindle, ioports enumeration and VFS filing system mount functions.
|
||||
|
||||
* Added events to allow plugin code to handle tool table data, possibly stored on a SD card. Ref. [this discussion](https://github.com/grblHAL/core/discussions/392).
|
||||
|
||||
Drivers:
|
||||
|
||||
* Most: updated for refactored spindle handling and configuration.
|
||||
|
||||
* ESP32: fix for spindle at speed failure. Ref. [ioSender issue 345](https://github.com/terjeio/ioSender/issues/345).
|
||||
Initial changes for ESP32-S3 support and some code refactoring.
|
||||
|
||||
* STM32F7xx: fix to reduce stepper current surge on startup. Ref. [issue 400](https://github.com/grblHAL/core/issues/400).
|
||||
|
||||
* iMRX1062: fix for hardfault when enabling aux input IRQ early in startup sequence. Ref. [issue 395](https://github.com/grblHAL/core/issues/395).
|
||||
|
||||
Plugins:
|
||||
|
||||
* Spindle: updated for core changes. Added several spindles:
|
||||
_Nowforever VFD._ \(untested\).
|
||||
_Stepper spindle._ This claims the stepper driver from the last configured axis.
|
||||
_PWM clone._ This clones the default driver implemented PWM spindle and changes it to use the direction signal for on/off control.
|
||||
Settings `$730`, `$731` and `$734` - `$736` will be used to configure the clone. These has the same function as the `$30` - `$36` counterparts.
|
||||
The driver spindle is suitable for controlling a laser when `$32` = `1` and the clone is suitable for controlling a spindle motor.
|
||||
Switching between the spindles is typically done with `M104Q<n>` where `<n>` is the spindle number.
|
||||
_Basic spindle._ Needs and claims 1 or 2 auxillary digital output ports depending on the configuration.
|
||||
_Additional PWM spindle._ Needs and claims 1 or 2 auxillary digital output ports and one analog PWM capable port.
|
||||
|
||||
* Motors: fixed default Trinamic motor current - was incorrectly set to 0, changed to 500 mA RMS. Ref. [issue 400](https://github.com/grblHAL/core/issues/400).
|
||||
|
||||
* Various: updated for core call signature changes.
|
||||
|
||||
---
|
||||
|
||||
<a name="20231005"/>Build 20231005
|
||||
|
||||
Core:
|
||||
|
||||
38
config.h
38
config.h
@@ -493,7 +493,7 @@ by a driver or a plugin.
|
||||
#if COMPATIBILITY_LEVEL == 0 || defined __DOXYGEN__
|
||||
/*! \def N_TOOLS
|
||||
\brief
|
||||
Number of tools in tool table, edit to enable (max. 16 allowed)
|
||||
Number of tools in tool table, edit to enable (max. 32 allowed)
|
||||
*/
|
||||
#if !defined N_TOOLS || defined __DOXYGEN__
|
||||
#define N_TOOLS 0
|
||||
@@ -518,6 +518,14 @@ Maximum number of parameters allowed in a block.
|
||||
#define NGC_N_ASSIGN_PARAMETERS_PER_BLOCK 10
|
||||
#endif
|
||||
|
||||
/*! \def LATHE_UVW_OPTION
|
||||
\brief
|
||||
Allow use of UVW axis words for non-modal relative lathe motion.
|
||||
*/
|
||||
#if !defined LATHE_UVW_OPTION || defined __DOXYGEN__
|
||||
#define LATHE_UVW_OPTION Off
|
||||
#endif
|
||||
|
||||
// Max number of entries in log for PID data reporting, to be used for tuning
|
||||
//#define PID_LOG 1000 // Default disabled. Uncomment to enable.
|
||||
|
||||
@@ -811,7 +819,7 @@ having trouble keeping up with planning new incoming motions as they are execute
|
||||
*/
|
||||
///@{
|
||||
#if !defined DEFAULT_PLANNER_BUFFER_BLOCKS || defined __DOXYGEN__
|
||||
#define DEFAULT_PLANNER_BUFFER_BLOCKS 35
|
||||
#define DEFAULT_PLANNER_BUFFER_BLOCKS 100
|
||||
#endif
|
||||
///@}
|
||||
|
||||
@@ -1858,28 +1866,28 @@ __NOTE:__ Must be a positive values.
|
||||
*/
|
||||
///@{
|
||||
#if !defined DEFAULT_X_CURRENT || defined __DOXYGEN__
|
||||
#define DEFAULT_X_CURRENT 0.0 // mA
|
||||
#define DEFAULT_X_CURRENT 500.0f // mA RMS
|
||||
#endif
|
||||
#if !defined DEFAULT_Y_CURRENT || defined __DOXYGEN__
|
||||
#define DEFAULT_Y_CURRENT 0.0 // mA
|
||||
#define DEFAULT_Y_CURRENT 500.0f // mA RMS
|
||||
#endif
|
||||
#if !defined DEFAULT_Z_CURRENT || defined __DOXYGEN__
|
||||
#define DEFAULT_Z_CURRENT 0.0 // mA
|
||||
#define DEFAULT_Z_CURRENT 500.0f // mA RMS
|
||||
#endif
|
||||
#if (defined A_AXIS && !defined DEFAULT_A_CURRENT) || defined __DOXYGEN__
|
||||
#define DEFAULT_A_CURRENT 0.0 // mA
|
||||
#define DEFAULT_A_CURRENT 500.0f // mA RMS
|
||||
#endif
|
||||
#if (defined B_AXIS && !defined DEFAULT_B_CURRENT) || defined __DOXYGEN__
|
||||
#define DEFAULT_B_CURRENT 0.0 // mA
|
||||
#define DEFAULT_B_CURRENT 500.0f // mA RMS
|
||||
#endif
|
||||
#if (defined C_AXIS && !defined DEFAULT_C_CURRENT) || defined __DOXYGEN__
|
||||
#define DEFAULT_C_CURRENT 0.0 // mA
|
||||
#define DEFAULT_C_CURRENT 500.0f // mA RMS
|
||||
#endif
|
||||
#if (defined U_AXIS && !defined DEFAULT_U_CURRENT) || defined __DOXYGEN__
|
||||
#define DEFAULT_U_CURRENT 0.0 // mA
|
||||
#define DEFAULT_U_CURRENT 500.0f // mA RMS
|
||||
#endif
|
||||
#if (defined V_AXIS && !defined DEFAULT_V_CURRENT) || defined __DOXYGEN__
|
||||
#define DEFAULT_V_CURRENT 0.0 // mA
|
||||
#define DEFAULT_V_CURRENT 500.0f // mA RMS
|
||||
#endif
|
||||
///@}
|
||||
|
||||
@@ -1890,9 +1898,9 @@ __NOTE:__ Must be a positive values.
|
||||
#undef N_TOOLS
|
||||
#endif
|
||||
|
||||
#if defined(N_TOOLS) && N_TOOLS > 16
|
||||
#if defined(N_TOOLS) && N_TOOLS > 32
|
||||
#undef N_TOOLS
|
||||
#define N_TOOLS 16
|
||||
#define N_TOOLS 32
|
||||
#endif
|
||||
|
||||
#if N_SYS_SPINDLE > N_SPINDLE
|
||||
@@ -1927,6 +1935,12 @@ __NOTE:__ Must be a positive values.
|
||||
#error "Cannot enable laser and lathe mode at the same time!"
|
||||
#endif
|
||||
|
||||
#if LATHE_UVW_OPTION && (N_AXIS > 6 || AXIS_REMAP_ABC2UVW)
|
||||
#warning "Cannot enable lathe UVW option when N_AXIS > 6 or ABC words are remapped!"
|
||||
#undef LATHE_UVW_OPTION
|
||||
#define LATHE_UVW_OPTION Off
|
||||
#endif
|
||||
|
||||
#if DEFAULT_CONTROL_SIGNALS_INVERT_MASK < 0
|
||||
#undef DEFAULT_CONTROL_SIGNALS_INVERT_MASK
|
||||
#define DEFAULT_CONTROL_SIGNALS_INVERT_MASK SIGNALS_BITMASK
|
||||
|
||||
@@ -126,9 +126,23 @@ typedef sys_commands_t *(*on_get_commands_ptr)(void);
|
||||
typedef status_code_t (*on_macro_execute_ptr)(macro_id_t macro); // macro implementations _must_ claim hal.stream.read to stream macros!
|
||||
typedef void (*on_macro_return_ptr)(void);
|
||||
|
||||
typedef bool (*write_tool_data_ptr)(tool_data_t *tool_data);
|
||||
typedef bool (*read_tool_data_ptr)(tool_id_t tool_id, tool_data_t *tool_data);
|
||||
typedef bool (*clear_tool_data_ptr)(void);
|
||||
|
||||
typedef struct {
|
||||
uint32_t n_tools;
|
||||
tool_data_t *tool; //!< Array of tool data, size _must_ be n_tools + 1
|
||||
read_tool_data_ptr read;
|
||||
write_tool_data_ptr write;
|
||||
clear_tool_data_ptr clear;
|
||||
} tool_table_t;
|
||||
|
||||
typedef struct {
|
||||
// report entry points set by core at reset.
|
||||
report_t report;
|
||||
//
|
||||
tool_table_t tool_table;
|
||||
// grbl core events - may be subscribed to by drivers or by the core.
|
||||
on_parser_init_ptr on_parser_init;
|
||||
on_state_change_ptr on_state_change;
|
||||
|
||||
@@ -466,7 +466,7 @@ struct xbar;
|
||||
typedef float (*xbar_get_value_ptr)(struct xbar *pin);
|
||||
typedef void (*xbar_set_value_ptr)(struct xbar *pin, float value);
|
||||
typedef void (*xbar_event_ptr)(bool on);
|
||||
typedef void (*xbar_config_ptr)(struct xbar *pin, void *cfg_data);
|
||||
typedef bool (*xbar_config_ptr)(struct xbar *pin, void *cfg_data);
|
||||
|
||||
typedef struct xbar {
|
||||
pin_function_t function;
|
||||
|
||||
110
driver_opts.h
110
driver_opts.h
@@ -162,6 +162,14 @@
|
||||
#define SPINDLE_SYNC_ENABLE 0
|
||||
#endif
|
||||
|
||||
#ifndef SPINDLE_ENCODER_ENABLE
|
||||
#if SPINDLE_SYNC_ENABLE
|
||||
#define SPINDLE_ENCODER_ENABLE 1
|
||||
#else
|
||||
#define SPINDLE_ENCODER_ENABLE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TRINAMIC_ENABLE
|
||||
#define TRINAMIC_ENABLE 0
|
||||
#endif
|
||||
@@ -213,10 +221,6 @@
|
||||
#define PPI_ENABLE 0
|
||||
#endif
|
||||
|
||||
#ifndef STEP_INJECT_ENABLE
|
||||
#define STEP_INJECT_ENABLE 0
|
||||
#endif
|
||||
|
||||
#if EMBROIDERY_ENABLE
|
||||
#if defined(SDCARD_ENABLE) && SDCARD_ENABLE == 0
|
||||
#undef SDCARD_ENABLE
|
||||
@@ -226,6 +230,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// TODO: remove?
|
||||
#ifndef VFD_SPINDLE
|
||||
#if VFD_ENABLE
|
||||
#define VFD_SPINDLE 1
|
||||
@@ -234,6 +239,93 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SPINDLE0_ENABLE
|
||||
#if VFD_ENABLE
|
||||
#define SPINDLE0_ENABLE VFD_ENABLE
|
||||
#if N_SPINDLE > 1 && !defined(SPINDLE1_ENABLE)
|
||||
#define SPINDLE1_ENABLE SPINDLE_PWM0
|
||||
#endif
|
||||
#else
|
||||
#define SPINDLE0_ENABLE SPINDLE_PWM0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SPINDLE1_ENABLE
|
||||
#define SPINDLE1_ENABLE 0
|
||||
#endif
|
||||
|
||||
#ifndef SPINDLE2_ENABLE
|
||||
#define SPINDLE2_ENABLE 0
|
||||
#endif
|
||||
|
||||
#ifndef SPINDLE3_ENABLE
|
||||
#define SPINDLE3_ENABLE 0
|
||||
#endif
|
||||
|
||||
#if SPINDLE0_ENABLE == SPINDLE_ALL
|
||||
#define SPINDLE_ENABLE SPINDLE_ALL
|
||||
#else
|
||||
#define SPINDLE_ENABLE ((1<<SPINDLE0_ENABLE)|(1<<SPINDLE1_ENABLE)|(1<<SPINDLE2_ENABLE)|(1<<SPINDLE3_ENABLE))
|
||||
#endif
|
||||
|
||||
// Driver spindle 0
|
||||
|
||||
#if SPINDLE_ENABLE & ((1<<SPINDLE_PWM0)|(1<<SPINDLE_PWM0_NODIR)|(1<<SPINDLE_ONOFF0)|(1<<SPINDLE_ONOFF0_DIR))
|
||||
#define DRIVER_SPINDLE_ENABLE 1
|
||||
#else
|
||||
#define DRIVER_SPINDLE_ENABLE 0
|
||||
#endif
|
||||
|
||||
#if SPINDLE_ENABLE & ((1<<SPINDLE_PWM0)|(1<<SPINDLE_ONOFF0_DIR))
|
||||
#define DRIVER_SPINDLE_DIR_ENABLE 1
|
||||
#else
|
||||
#define DRIVER_SPINDLE_DIR_ENABLE 0
|
||||
#endif
|
||||
|
||||
#if SPINDLE_ENABLE & ((1<<SPINDLE_PWM0)|(1<<SPINDLE_PWM0_NODIR))
|
||||
#define DRIVER_SPINDLE_PWM_ENABLE 1
|
||||
#define DRIVER_SPINDLE_NAME "PWM"
|
||||
#else
|
||||
#define DRIVER_SPINDLE_PWM_ENABLE 0
|
||||
#if DRIVER_SPINDLE_ENABLE
|
||||
#define DRIVER_SPINDLE_NAME "Basic"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Driver spindle 1
|
||||
|
||||
#if SPINDLE_ENABLE & ((1<<SPINDLE_PWM1)|(1<<SPINDLE_PWM1_NODIR)|(1<<SPINDLE_ONOFF1)|(1<<SPINDLE_ONOFF1_DIR))
|
||||
#define DRIVER_SPINDLE1_ENABLE 1
|
||||
#else
|
||||
#define DRIVER_SPINDLE1_ENABLE 0
|
||||
#endif
|
||||
|
||||
#if SPINDLE_ENABLE & ((1<<SPINDLE_PWM1)|(1<<SPINDLE_ONOFF1_DIR))
|
||||
#define DRIVER_SPINDLE1_DIR_ENABLE 1
|
||||
#else
|
||||
#define DRIVER_SPINDLE1_DIR_ENABLE 0
|
||||
#endif
|
||||
|
||||
#if SPINDLE_ENABLE & ((1<<SPINDLE_PWM1)|(1<<SPINDLE_PWM1_NODIR))
|
||||
#define DRIVER_SPINDLE1_PWM_ENABLE 1
|
||||
#define DRIVER_SPINDLE1_NAME "PWM"
|
||||
#else
|
||||
#define DRIVER_SPINDLE1_PWM_ENABLE 0
|
||||
#if DRIVER_SPINDLE1_ENABLE
|
||||
#define DRIVER_SPINDLE1_NAME "Basic"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
#ifndef VFD_ENABLE
|
||||
#if SPINDLE_ENABLE & ((1<<SPINDLE_HUANYANG1)|(1<<SPINDLE_HUANYANG2)|(1<<SPINDLE_GS20)|(1<<SPINDLE_YL620A)|(1<<SPINDLE_MODVFD)|(1<<SPINDLE_H100)|(1<<SPINDLE_NOWFOREVER))
|
||||
#define VFD_ENABLE 1
|
||||
#else
|
||||
#define VFD_ENABLE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MODBUS_RTU_ENABLED 0b001
|
||||
#define MODBUS_RTU_DIR_ENABLED 0b010
|
||||
#define MODBUS_TCP_ENABLED 0b100
|
||||
@@ -251,10 +343,12 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !VFD_SPINDLE || N_SPINDLE > 1
|
||||
#define DRIVER_SPINDLE_ENABLE 1
|
||||
#else
|
||||
#define DRIVER_SPINDLE_ENABLE 0
|
||||
#ifndef STEP_INJECT_ENABLE
|
||||
#if SPINDLE_ENABLE & (1<<SPINDLE_STEPPER)
|
||||
#define STEP_INJECT_ENABLE 1
|
||||
#else
|
||||
#define STEP_INJECT_ENABLE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef QEI_ENABLE
|
||||
|
||||
214
gcode.c
214
gcode.c
@@ -40,11 +40,7 @@
|
||||
// arbitrary value, and some GUIs may require more. So we increased it based on a max safe
|
||||
// value when converting a float (7.2 digit precision)s to an integer.
|
||||
#define MAX_LINE_NUMBER 10000000
|
||||
#if N_TOOLS
|
||||
#define MAX_TOOL_NUMBER N_TOOLS // Limited by max unsigned 8-bit value
|
||||
#else
|
||||
#define MAX_TOOL_NUMBER 4294967294 // Limited by max unsigned 32-bit value - 1
|
||||
#endif
|
||||
|
||||
#define MACH3_SCALING
|
||||
|
||||
@@ -110,11 +106,6 @@ typedef union {
|
||||
|
||||
// Declare gc extern struct
|
||||
parser_state_t gc_state, *saved_state = NULL;
|
||||
#if N_TOOLS
|
||||
tool_data_t tool_table[N_TOOLS + 1];
|
||||
#else
|
||||
tool_data_t tool_table;
|
||||
#endif
|
||||
|
||||
#define FAIL(status) return(status);
|
||||
|
||||
@@ -217,9 +208,8 @@ void gc_set_tool_offset (tool_offset_mode_t mode, uint_fast8_t idx, int32_t offs
|
||||
idx--;
|
||||
tlo_changed |= gc_state.tool_length_offset[idx] != 0.0f;
|
||||
gc_state.tool_length_offset[idx] = 0.0f;
|
||||
#ifndef N_TOOLS
|
||||
if(grbl.tool_table.n_tools == 0)
|
||||
gc_state.tool->offset[idx] = 0.0f;
|
||||
#endif
|
||||
} while(idx);
|
||||
break;
|
||||
|
||||
@@ -228,9 +218,8 @@ void gc_set_tool_offset (tool_offset_mode_t mode, uint_fast8_t idx, int32_t offs
|
||||
float new_offset = offset / settings.axis[idx].steps_per_mm;
|
||||
tlo_changed |= gc_state.tool_length_offset[idx] != new_offset;
|
||||
gc_state.tool_length_offset[idx] = new_offset;
|
||||
#ifndef N_TOOLS
|
||||
if(grbl.tool_table.n_tools == 0)
|
||||
gc_state.tool->offset[idx] = new_offset;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -275,21 +264,15 @@ void gc_init (void)
|
||||
{
|
||||
#if COMPATIBILITY_LEVEL > 1
|
||||
memset(&gc_state, 0, sizeof(parser_state_t));
|
||||
#if N_TOOLS
|
||||
gc_state.tool = &tool_table[0];
|
||||
#else
|
||||
memset(&tool_table, 0, sizeof(tool_table));
|
||||
gc_state.tool = &tool_table;
|
||||
#endif
|
||||
gc_state.tool = &grbl.tool_table.tool[0];
|
||||
if(grbl.tool_table.n_tools == 0)
|
||||
memset(grbl.tool_table.tool, 0, sizeof(tool_data_t));
|
||||
#else
|
||||
if(sys.cold_start) {
|
||||
memset(&gc_state, 0, sizeof(parser_state_t));
|
||||
#if N_TOOLS
|
||||
gc_state.tool = &tool_table[0];
|
||||
#else
|
||||
memset(&tool_table, 0, sizeof(tool_table));
|
||||
gc_state.tool = &tool_table;
|
||||
#endif
|
||||
gc_state.tool = &grbl.tool_table.tool[0];
|
||||
if(grbl.tool_table.n_tools == 0)
|
||||
memset(grbl.tool_table.tool, 0, sizeof(tool_data_t));
|
||||
} else {
|
||||
memset(&gc_state, 0, offsetof(parser_state_t, g92_coord_offset));
|
||||
gc_state.tool_pending = gc_state.tool->tool_id;
|
||||
@@ -335,7 +318,6 @@ void gc_init (void)
|
||||
grbl.on_parser_init(&gc_state);
|
||||
}
|
||||
|
||||
|
||||
// Set dynamic laser power mode to PPI (Pulses Per Inch)
|
||||
// Returns true if driver uses hardware implementation.
|
||||
// Driver support for pulsing the laser on signal is required for this to work.
|
||||
@@ -369,25 +351,23 @@ spindle_ptrs_t *gc_spindle_get (void)
|
||||
|
||||
static tool_data_t *tool_get_pending (tool_id_t tool_id)
|
||||
{
|
||||
#if N_TOOLS
|
||||
return &tool_table[tool_id];
|
||||
#else
|
||||
static tool_data_t tool_data = {0};
|
||||
|
||||
if(grbl.tool_table.n_tools)
|
||||
return &grbl.tool_table.tool[tool_id];
|
||||
|
||||
memcpy(&tool_data, gc_state.tool, sizeof(tool_data_t));
|
||||
tool_data.tool_id = tool_id;
|
||||
|
||||
return &tool_data;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void tool_set (tool_data_t *tool)
|
||||
{
|
||||
#if N_TOOLS
|
||||
if(grbl.tool_table.n_tools)
|
||||
gc_state.tool = tool;
|
||||
#else
|
||||
else
|
||||
gc_state.tool->tool_id = tool->tool_id;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Add output command to linked list
|
||||
@@ -414,6 +394,9 @@ static bool add_output_command (output_command_t *command)
|
||||
|
||||
static status_code_t init_sync_motion (plan_line_data_t *pl_data, float pitch)
|
||||
{
|
||||
if(pl_data->spindle.hal->get_data == NULL)
|
||||
FAIL(Status_GcodeUnsupportedCommand); // [Spindle not sync capable]
|
||||
|
||||
pl_data->condition.inverse_time = Off;
|
||||
pl_data->feed_rate = gc_state.distance_per_rev = pitch;
|
||||
pl_data->spindle.css = NULL; // Switch off CSS.
|
||||
@@ -655,11 +638,17 @@ status_code_t gc_execute_block (char *block)
|
||||
#ifdef C_AXIS
|
||||
, .c = On
|
||||
#endif
|
||||
#if LATHE_UVW_OPTION
|
||||
, .u = On
|
||||
, .v = On
|
||||
, .w = On
|
||||
#else
|
||||
#ifdef U_AXIS
|
||||
, .u = On
|
||||
#endif
|
||||
#ifdef V_AXIS
|
||||
, .v = On
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -1067,16 +1056,14 @@ status_code_t gc_execute_block (char *block)
|
||||
// there cannot be any axis motion or coordinate offsets updated. Meaning G43, G43.1, and G49
|
||||
// all are explicit axis commands, regardless if they require axis words or not.
|
||||
// NOTE: cannot find the NIST statement referenced above, changed to match LinuxCNC behaviour in build 20210513.
|
||||
if (int_value == 49) // G49
|
||||
if(int_value == 49) // G49
|
||||
gc_block.modal.tool_offset_mode = ToolLengthOffset_Cancel;
|
||||
#if N_TOOLS
|
||||
else if (mantissa == 0) // G43
|
||||
else if(mantissa == 0 && grbl.tool_table.n_tools) // G43
|
||||
gc_block.modal.tool_offset_mode = ToolLengthOffset_Enable;
|
||||
else if (mantissa == 20) // G43.2
|
||||
else if(mantissa == 20 && grbl.tool_table.n_tools) // G43.2
|
||||
gc_block.modal.tool_offset_mode = ToolLengthOffset_ApplyAdditional;
|
||||
#endif
|
||||
else if (mantissa == 10) { // G43.1
|
||||
if (axis_command)
|
||||
else if(mantissa == 10) { // G43.1
|
||||
if(axis_command)
|
||||
FAIL(Status_GcodeAxisCommandConflict); // [Axis word/command conflict] }
|
||||
axis_command = AxisCommand_ToolLengthOffset;
|
||||
gc_block.modal.tool_offset_mode = ToolLengthOffset_EnableDynamic;
|
||||
@@ -1446,13 +1433,33 @@ status_code_t gc_execute_block (char *block)
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
if (mantissa > 0)
|
||||
if(mantissa > 0)
|
||||
FAIL(Status_GcodeCommandValueNotInteger);
|
||||
if (int_value > MAX_TOOL_NUMBER)
|
||||
if(int_value > (grbl.tool_table.n_tools ? grbl.tool_table.n_tools : MAX_TOOL_NUMBER))
|
||||
FAIL(Status_GcodeIllegalToolTableEntry);
|
||||
word_bit.parameter.t = On;
|
||||
gc_block.values.t = isnan(value) ? 0xFFFFFFFF : int_value;
|
||||
break;
|
||||
#if LATHE_UVW_OPTION
|
||||
case 'U':
|
||||
axis_words.x = On;
|
||||
word_bit.parameter.x = word_bit.parameter.u = On;
|
||||
gc_block.values.uvw[X_AXIS] = value / 2.0f; // U is always a diameter
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
axis_words.y = On;
|
||||
word_bit.parameter.y = word_bit.parameter.v = On;
|
||||
gc_block.values.uvw[Y_AXIS] = value;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
axis_words.z = On;
|
||||
word_bit.parameter.z = word_bit.parameter.w = On;
|
||||
gc_block.values.uvw[Z_AXIS] = value;
|
||||
break;
|
||||
|
||||
#else
|
||||
|
||||
#ifdef U_AXIS
|
||||
case 'U':
|
||||
@@ -1469,7 +1476,7 @@ status_code_t gc_execute_block (char *block)
|
||||
gc_block.values.xyz[V_AXIS] = value;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
case 'X':
|
||||
axis_words.x = On;
|
||||
word_bit.parameter.x = On;
|
||||
@@ -1712,7 +1719,7 @@ status_code_t gc_execute_block (char *block)
|
||||
FAIL(Status_GcodeValueWordMissing);
|
||||
if (floorf(gc_block.values.q) - gc_block.values.q != 0.0f)
|
||||
FAIL(Status_GcodeCommandValueNotInteger);
|
||||
if ((uint32_t)gc_block.values.q > MAX_TOOL_NUMBER)
|
||||
if ((uint32_t)gc_block.values.q > (grbl.tool_table.n_tools ? grbl.tool_table.n_tools : MAX_TOOL_NUMBER))
|
||||
FAIL(Status_GcodeIllegalToolTableEntry);
|
||||
|
||||
gc_block.values.t = (uint32_t)gc_block.values.q;
|
||||
@@ -1720,13 +1727,13 @@ status_code_t gc_execute_block (char *block)
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
if(hal.stream.file) {
|
||||
gc_state.tool_pending = 0; // force set tool
|
||||
#if N_TOOLS
|
||||
if(grbl.tool_table.n_tools) {
|
||||
if(gc_state.g43_pending) {
|
||||
gc_block.values.h = gc_state.g43_pending;
|
||||
command_words.G8 = On;
|
||||
}
|
||||
gc_state.g43_pending = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (!gc_block.words.t)
|
||||
@@ -1893,11 +1900,18 @@ status_code_t gc_execute_block (char *block)
|
||||
if (gc_block.modal.units_imperial) do { // Axes indices are consistent, so loop may be used.
|
||||
idx--;
|
||||
#if N_AXIS > 3
|
||||
if (bit_istrue(axis_words.mask, bit(idx)) && bit_isfalse(settings.steppers.is_rotational.mask, bit(idx)))
|
||||
if (bit_istrue(axis_words.mask, bit(idx)) && bit_isfalse(settings.steppers.is_rotational.mask, bit(idx))) {
|
||||
#else
|
||||
if (bit_istrue(axis_words.mask, bit(idx)))
|
||||
if (bit_istrue(axis_words.mask, bit(idx))) {
|
||||
#endif
|
||||
gc_block.values.xyz[idx] *= MM_PER_INCH;
|
||||
#if LATHE_UVW_OPTION
|
||||
#if N_AXIS > 3
|
||||
if(idx <= Z_AXIS)
|
||||
#endif
|
||||
gc_block.values.uvw[idx] *= MM_PER_INCH;
|
||||
#endif
|
||||
}
|
||||
} while(idx);
|
||||
|
||||
if (command_words.G15 && gc_state.modal.diameter_mode != gc_block.modal.diameter_mode) {
|
||||
@@ -1987,6 +2001,12 @@ status_code_t gc_execute_block (char *block)
|
||||
gc_block.values.xyz[idx] *= scale_factor.ijk[idx];
|
||||
else
|
||||
gc_block.values.xyz[idx] = (gc_block.values.xyz[idx] - scale_factor.xyz[idx]) * scale_factor.ijk[idx] + scale_factor.xyz[idx];
|
||||
#if LATHE_UVW_OPTION
|
||||
#if N_AXIS > 3
|
||||
if(idx <= Z_AXIS)
|
||||
#endif
|
||||
gc_block.values.uvw[idx] *= scale_factor.ijk[idx];
|
||||
#endif
|
||||
}
|
||||
} while(idx);
|
||||
}
|
||||
@@ -1996,7 +2016,7 @@ status_code_t gc_execute_block (char *block)
|
||||
// NOTE: Since cutter radius compensation is never enabled, these G40 errors don't apply. Grbl supports G40
|
||||
// only for the purpose to not error when G40 is sent with a g-code program header to setup the default modes.
|
||||
|
||||
// [14. Tool length compensation ]: G43.1 and G49 are always supported, G43 and G43.2 if N_TOOLS defined.
|
||||
// [14. Tool length compensation ]: G43.1 and G49 are always supported, G43 and G43.2 if grbl.tool_table.n_tools > 0
|
||||
// [G43.1 Errors]: Motion command in same line.
|
||||
// [G43.2 Errors]: Tool number not in the tool table,
|
||||
if (command_words.G8) { // Indicates called in block.
|
||||
@@ -2014,30 +2034,36 @@ status_code_t gc_execute_block (char *block)
|
||||
switch(gc_block.modal.tool_offset_mode) {
|
||||
|
||||
case ToolLengthOffset_EnableDynamic:
|
||||
if (!axis_words.mask)
|
||||
if(!axis_words.mask)
|
||||
FAIL(Status_GcodeG43DynamicAxisError);
|
||||
break;
|
||||
#if N_TOOLS
|
||||
|
||||
case ToolLengthOffset_Enable:
|
||||
if (gc_block.words.h) {
|
||||
if(gc_block.values.h > MAX_TOOL_NUMBER)
|
||||
if(grbl.tool_table.n_tools) {
|
||||
if(gc_block.words.h) {
|
||||
if(gc_block.values.h > grbl.tool_table.n_tools)
|
||||
FAIL(Status_GcodeIllegalToolTableEntry);
|
||||
gc_block.words.h = Off;
|
||||
if(gc_block.values.h == 0)
|
||||
gc_block.values.h = gc_block.values.t;
|
||||
} else
|
||||
gc_block.values.h = gc_block.values.t;
|
||||
} else
|
||||
FAIL(Status_GcodeUnsupportedCommand);
|
||||
break;
|
||||
|
||||
case ToolLengthOffset_ApplyAdditional:
|
||||
if (gc_block.words.h) {
|
||||
if(gc_block.values.h == 0 || gc_block.values.h > MAX_TOOL_NUMBER)
|
||||
if(grbl.tool_table.n_tools) {
|
||||
if(gc_block.words.h) {
|
||||
if(gc_block.values.h == 0 || gc_block.values.h > grbl.tool_table.n_tools)
|
||||
FAIL(Status_GcodeIllegalToolTableEntry);
|
||||
gc_block.words.h = Off;
|
||||
} else
|
||||
FAIL(Status_GcodeValueWordMissing);
|
||||
} else
|
||||
FAIL(Status_GcodeUnsupportedCommand);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2078,7 +2104,7 @@ status_code_t gc_execute_block (char *block)
|
||||
// [G10 Errors]: L missing and is not 2 or 20. P word missing. (Negative P value done.)
|
||||
// [G10 L2 Errors]: R word NOT SUPPORTED. P value not 0 to N_WorkCoordinateSystems (max 9). Axis words missing.
|
||||
// [G10 L20 Errors]: P must be 0 to N_WorkCoordinateSystems (max 9). Axis words missing.
|
||||
// [G10 L1, L10, L11 Errors]: P must be 0 to MAX_TOOL_NUMBER (max 9). Axis words or R word missing.
|
||||
// [G10 L1, L10, L11 Errors]: P must be 0 to grbl.tool_table.n_tools. Axis words or R word missing.
|
||||
|
||||
if (!(axis_words.mask || (gc_block.values.l != 20 && gc_block.words.r)))
|
||||
FAIL(Status_GcodeNoAxisWords); // [No axis words (or R word for tool offsets)]
|
||||
@@ -2112,8 +2138,8 @@ status_code_t gc_execute_block (char *block)
|
||||
FAIL(Status_SettingReadFail); // [non-volatile storage read fail]
|
||||
|
||||
#if COMPATIBILITY_LEVEL <= 1
|
||||
if(settings.parking.flags.offset_lock && gc_block.values.coord_data.id >= CoordinateSystem_G59_1 && gc_block.values.coord_data.id <= CoordinateSystem_G59_3) {
|
||||
if(bit_istrue(settings.parking.flags.offset_lock, bit(gc_block.values.coord_data.id - CoordinateSystem_G59_1)))
|
||||
if(settings.offset_lock.mask && gc_block.values.coord_data.id >= CoordinateSystem_G59_1 && gc_block.values.coord_data.id <= CoordinateSystem_G59_3) {
|
||||
if(bit_istrue(settings.offset_lock.mask, bit(gc_block.values.coord_data.id - CoordinateSystem_G59_1)))
|
||||
FAIL(Status_GCodeCoordSystemLocked);
|
||||
}
|
||||
#endif
|
||||
@@ -2133,15 +2159,15 @@ status_code_t gc_execute_block (char *block)
|
||||
} while(idx);
|
||||
break;
|
||||
|
||||
#if N_TOOLS
|
||||
case 1: case 10: case 11:;
|
||||
if(p_value == 0 || p_value > MAX_TOOL_NUMBER)
|
||||
FAIL(Status_GcodeIllegalToolTableEntry); // [Greater than MAX_TOOL_NUMBER]
|
||||
case 1: case 10: case 11:
|
||||
if(grbl.tool_table.n_tools) {
|
||||
if(p_value == 0 || p_value > grbl.tool_table.n_tools)
|
||||
FAIL(Status_GcodeIllegalToolTableEntry); // [Greater than max allowed tool number]
|
||||
|
||||
tool_table[p_value].tool_id = (tool_id_t)p_value;
|
||||
grbl.tool_table.tool[p_value].tool_id = (tool_id_t)p_value;
|
||||
|
||||
if(gc_block.words.r) {
|
||||
tool_table[p_value].radius = gc_block.values.r;
|
||||
grbl.tool_table.tool[p_value].radius = gc_block.values.r;
|
||||
gc_block.words.r = Off;
|
||||
}
|
||||
|
||||
@@ -2150,30 +2176,31 @@ status_code_t gc_execute_block (char *block)
|
||||
FAIL(Status_SettingReadFail);
|
||||
|
||||
if(gc_block.values.l == 1)
|
||||
settings_read_tool_data(p_value, &tool_table[p_value]);
|
||||
grbl.tool_table.read(p_value, &grbl.tool_table.tool[p_value]);
|
||||
|
||||
idx = N_AXIS;
|
||||
do {
|
||||
if(bit_istrue(axis_words.mask, bit(--idx))) {
|
||||
if(gc_block.values.l == 1)
|
||||
tool_table[p_value].offset[idx] = gc_block.values.xyz[idx];
|
||||
grbl.tool_table.tool[p_value].offset[idx] = gc_block.values.xyz[idx];
|
||||
else if(gc_block.values.l == 10)
|
||||
tool_table[p_value].offset[idx] = gc_state.position[idx] - gc_state.modal.coord_system.xyz[idx] - gc_state.g92_coord_offset[idx] - gc_block.values.xyz[idx];
|
||||
grbl.tool_table.tool[p_value].offset[idx] = gc_state.position[idx] - gc_state.modal.coord_system.xyz[idx] - gc_state.g92_coord_offset[idx] - gc_block.values.xyz[idx];
|
||||
else if(gc_block.values.l == 11)
|
||||
tool_table[p_value].offset[idx] = g59_3_offset[idx] - gc_block.values.xyz[idx];
|
||||
// if(gc_block.values.l != 1)
|
||||
// tool_table[p_value].offset[idx] -= gc_state.tool_length_offset[idx];
|
||||
grbl.tool_table.tool[p_value].offset[idx] = g59_3_offset[idx] - gc_block.values.xyz[idx];
|
||||
// if(gc_block.values.l != 1)
|
||||
// tool_table[p_value].offset[idx] -= gc_state.tool_length_offset[idx];
|
||||
} else if(gc_block.values.l == 10 || gc_block.values.l == 11)
|
||||
tool_table[p_value].offset[idx] = gc_state.tool_length_offset[idx];
|
||||
grbl.tool_table.tool[p_value].offset[idx] = gc_state.tool_length_offset[idx];
|
||||
|
||||
// else, keep current stored value.
|
||||
} while(idx);
|
||||
|
||||
if(gc_block.values.l == 1)
|
||||
settings_write_tool_data(&tool_table[p_value]);
|
||||
|
||||
grbl.tool_table.write(&grbl.tool_table.tool[p_value]);
|
||||
} else
|
||||
FAIL(Status_GcodeUnsupportedCommand);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
FAIL(Status_GcodeUnsupportedCommand); // [Unsupported L]
|
||||
}
|
||||
@@ -2207,13 +2234,22 @@ status_code_t gc_execute_block (char *block)
|
||||
if (axis_words.mask && axis_command != AxisCommand_ToolLengthOffset) { // TLO block any axis command.
|
||||
idx = N_AXIS;
|
||||
do { // Axes indices are consistent, so loop may be used to save flash space.
|
||||
if (bit_isfalse(axis_words.mask, bit(--idx)))
|
||||
if(bit_isfalse(axis_words.mask, bit(--idx)))
|
||||
gc_block.values.xyz[idx] = gc_state.position[idx]; // No axis word in block. Keep same axis position.
|
||||
else if (gc_block.non_modal_command != NonModal_AbsoluteOverride) {
|
||||
else if(gc_block.non_modal_command != NonModal_AbsoluteOverride) {
|
||||
// Update specified value according to distance mode or ignore if absolute override is active.
|
||||
// NOTE: G53 is never active with G28/30 since they are in the same modal group.
|
||||
// Apply coordinate offsets based on distance mode.
|
||||
if (gc_block.modal.distance_incremental)
|
||||
#if LATHE_UVW_OPTION
|
||||
#if N_AXIS > 3
|
||||
if(idx <= Z_AXIS && bit_istrue(axis_words.mask, bit(idx)) && gc_block.values.uvw[idx] != 0.0f)
|
||||
#else
|
||||
if(bit_istrue(axis_words.mask, bit(idx)) && gc_block.values.uvw[idx] != 0.0f)
|
||||
#endif
|
||||
gc_block.values.xyz[idx] = gc_state.position[idx] + gc_block.values.uvw[idx];
|
||||
else
|
||||
#endif
|
||||
if(gc_block.modal.distance_incremental)
|
||||
gc_block.values.xyz[idx] += gc_state.position[idx];
|
||||
else // Absolute mode
|
||||
gc_block.values.xyz[idx] += gc_get_block_offset(&gc_block, idx);
|
||||
@@ -3066,12 +3102,10 @@ status_code_t gc_execute_block (char *block)
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
if((status_code_t)int_value != Status_Unhandled)
|
||||
tool_set(pending_tool);
|
||||
#if N_TOOLS
|
||||
else if(command_words.G8 && gc_block.modal.tool_offset_mode && ToolLengthOffset_Enable) {
|
||||
else if(grbl.tool_table.n_tools && command_words.G8 && gc_block.modal.tool_offset_mode && ToolLengthOffset_Enable) {
|
||||
gc_state.g43_pending = gc_block.values.h;
|
||||
command_words.G8 = Off;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
tool_set(pending_tool);
|
||||
#endif
|
||||
@@ -3164,7 +3198,7 @@ status_code_t gc_execute_block (char *block)
|
||||
// [13. Cutter radius compensation ]: G41/42 NOT SUPPORTED
|
||||
// gc_state.modal.cutter_comp = gc_block.modal.cutter_comp; // NOTE: Not needed since always disabled.
|
||||
|
||||
// [14. Tool length compensation ]: G43, G43.1 and G49 supported. G43 supported when N_TOOLS defined.
|
||||
// [14. Tool length compensation ]: G43, G43.1 and G49 supported. G43 supported when grbl.tool_table.n_tools > 0.
|
||||
// NOTE: If G43 were supported, its operation wouldn't be any different from G43.1 in terms
|
||||
// of execution. The error-checking step would simply load the offset value into the correct
|
||||
// axis of the block XYZ value array.
|
||||
@@ -3185,19 +3219,19 @@ status_code_t gc_execute_block (char *block)
|
||||
tlo_changed |= gc_state.tool_length_offset[idx] != 0.0f;
|
||||
gc_state.tool_length_offset[idx] = 0.0f;
|
||||
break;
|
||||
#if N_TOOLS
|
||||
|
||||
case ToolLengthOffset_Enable: // G43
|
||||
if (gc_state.tool_length_offset[idx] != tool_table[gc_block.values.h].offset[idx]) {
|
||||
if (gc_state.tool_length_offset[idx] != grbl.tool_table.tool[gc_block.values.h].offset[idx]) {
|
||||
tlo_changed = true;
|
||||
gc_state.tool_length_offset[idx] = tool_table[gc_block.values.h].offset[idx];
|
||||
gc_state.tool_length_offset[idx] = grbl.tool_table.tool[gc_block.values.h].offset[idx];
|
||||
}
|
||||
break;
|
||||
|
||||
case ToolLengthOffset_ApplyAdditional: // G43.2
|
||||
tlo_changed |= tool_table[gc_block.values.h].offset[idx] != 0.0f;
|
||||
gc_state.tool_length_offset[idx] += tool_table[gc_block.values.h].offset[idx];
|
||||
tlo_changed |= grbl.tool_table.tool[gc_block.values.h].offset[idx] != 0.0f;
|
||||
gc_state.tool_length_offset[idx] += grbl.tool_table.tool[gc_block.values.h].offset[idx];
|
||||
break;
|
||||
#endif
|
||||
|
||||
case ToolLengthOffset_EnableDynamic: // G43.1
|
||||
if (bit_istrue(axis_words.mask, bit(idx)) && gc_state.tool_length_offset[idx] != gc_block.values.xyz[idx]) {
|
||||
tlo_changed = true;
|
||||
@@ -3236,18 +3270,14 @@ status_code_t gc_execute_block (char *block)
|
||||
switch(gc_block.non_modal_command) {
|
||||
|
||||
case NonModal_SetCoordinateData:
|
||||
#if N_TOOLS
|
||||
if(gc_block.values.l == 2 || gc_block.values.l == 20) {
|
||||
#endif
|
||||
settings_write_coord_data(gc_block.values.coord_data.id, &gc_block.values.coord_data.xyz);
|
||||
// Update system coordinate system if currently active.
|
||||
if (gc_state.modal.coord_system.id == gc_block.values.coord_data.id) {
|
||||
memcpy(gc_state.modal.coord_system.xyz, gc_block.values.coord_data.xyz, sizeof(gc_state.modal.coord_system.xyz));
|
||||
system_flag_wco_change();
|
||||
}
|
||||
#if N_TOOLS
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case NonModal_GoHome_0:
|
||||
|
||||
10
gcode.h
10
gcode.h
@@ -385,6 +385,9 @@ typedef struct {
|
||||
float r; //!< Arc radius or retract position
|
||||
float s; //!< Spindle speed - single-meaning word
|
||||
float xyz[N_AXIS]; //!< X,Y,Z (and A,B,C,U,V when enabled) translational axes
|
||||
#if LATHE_UVW_OPTION
|
||||
float uvw[3]; //!< U,V,W lathe mode incremental mode motion
|
||||
#endif
|
||||
coord_system_t coord_data; //!< Coordinate data
|
||||
int32_t $; //!< Spindle id - single-meaning word
|
||||
int32_t n; //!< Line number - single-meaning word
|
||||
@@ -533,7 +536,7 @@ typedef struct {
|
||||
// float blending_tolerance; //!< Motion blending tolerance
|
||||
int32_t line_number; //!< Last line number sent
|
||||
tool_id_t tool_pending; //!< Tool to be selected on next M6
|
||||
#if N_TOOLS && NGC_EXPRESSIONS_ENABLE
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
uint32_t g43_pending; //!< Tool offset to be selected on next M6, for macro ATC
|
||||
#endif
|
||||
bool file_run; //!< Tracks % command
|
||||
@@ -557,11 +560,6 @@ typedef struct {
|
||||
} scale_factor_t;
|
||||
|
||||
extern parser_state_t gc_state;
|
||||
#if N_TOOLS
|
||||
extern tool_data_t tool_table[N_TOOLS + 1];
|
||||
#else
|
||||
extern tool_data_t tool_table;
|
||||
#endif
|
||||
|
||||
/*! \brief Parser block structure.
|
||||
|
||||
|
||||
2
grbl.h
2
grbl.h
@@ -42,7 +42,7 @@
|
||||
#else
|
||||
#define GRBL_VERSION "1.1f"
|
||||
#endif
|
||||
#define GRBL_BUILD 20231005
|
||||
#define GRBL_BUILD 20231210
|
||||
|
||||
#define GRBL_URL "https://github.com/grblHAL"
|
||||
|
||||
|
||||
@@ -292,6 +292,13 @@ int grbl_enter (void)
|
||||
grbl.on_execute_realtime = auto_realtime_report;
|
||||
}
|
||||
|
||||
if(hal.driver_cap.sd_card || hal.driver_cap.littlefs) {
|
||||
fs_options_t fs_options = {0};
|
||||
fs_options.lfs_hidden = hal.driver_cap.littlefs;
|
||||
fs_options.sd_mount_on_boot = hal.driver_cap.sd_card;
|
||||
setting_remove_elements(Setting_FSOptions, fs_options.mask);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
6
hal.h
6
hal.h
@@ -53,8 +53,10 @@ typedef union {
|
||||
control_pull_up :1, //!< Pullup resistors for control inputs are supported.
|
||||
probe_pull_up :1, //!< Pullup resistors for probe inputs are supported.
|
||||
amass_level :2, // 0...3 Deprecated?
|
||||
spindle_encoder :1, //!< Spindle encoder is supported.
|
||||
spindle_sync :1, //!< Spindle synced motion is supported.
|
||||
sd_card :1,
|
||||
littlefs :1,
|
||||
bluetooth :1,
|
||||
ethernet :1,
|
||||
wifi :1,
|
||||
@@ -66,7 +68,7 @@ typedef union {
|
||||
odometers :1,
|
||||
pwm_spindle :1,
|
||||
probe_latch :1,
|
||||
unassigned :11;
|
||||
unassigned :9;
|
||||
};
|
||||
} driver_cap_t;
|
||||
|
||||
@@ -599,7 +601,7 @@ typedef struct {
|
||||
enumerate_pins_ptr enumerate_pins; //!< Optional handler for enumerating pins used by the driver.
|
||||
bool (*driver_release)(void); //!< Optional handler for releasing hardware resources before exiting.
|
||||
uint32_t (*get_elapsed_ticks)(void); //!< Optional handler for getting number of elapsed 1 ms tics since startup. Rolls over every 49.71 days. Required by a number of plugins.
|
||||
uint32_t (*get_micros)(void); //!< Optional handler for getting number of elapsed 1 us tics since startup. Rolls over every 1.19 hours. Required by a number of plugins.
|
||||
uint64_t (*get_micros)(void); //!< Optional handler for getting number of elapsed 1 us tics since startup. Rolls over every 1.19 hours. Required by a number of plugins.
|
||||
pallet_shuttle_ptr pallet_shuttle; //!< Optional handler for performing a pallet shuttle on program end (M60).
|
||||
void (*reboot)(void); //!< Optoional handler for rebooting the controller. This will be called when #ASCII_ESC followed by #CMD_REBOOT is received.
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ bool ioport_can_claim_explicit (void)
|
||||
return !(hal.port.claim == NULL || hal.port.get_pin_info == NULL);
|
||||
}
|
||||
|
||||
bool ioports_enumerate (io_port_type_t type, io_port_direction_t dir, pin_mode_t filter, bool claimable, ioports_enumerate_callback_ptr callback)
|
||||
bool ioports_enumerate (io_port_type_t type, io_port_direction_t dir, pin_mode_t filter, bool claimable, ioports_enumerate_callback_ptr callback, void *data)
|
||||
{
|
||||
bool ok = false;
|
||||
uint8_t n_ports = ioports_available(type, dir);
|
||||
@@ -153,7 +153,7 @@ bool ioports_enumerate (io_port_type_t type, io_port_direction_t dir, pin_mode_t
|
||||
portinfo = hal.port.get_pin_info(type, dir, --n_ports);
|
||||
if(claimable && portinfo->mode.claimed)
|
||||
continue;
|
||||
if((portinfo->mode.mask & filter.mask) == filter.mask && (ok = callback(portinfo, n_ports)))
|
||||
if((portinfo->mode.mask & filter.mask) == filter.mask && (ok = callback(portinfo, n_ports, data)))
|
||||
break;
|
||||
} while(n_ports);
|
||||
|
||||
@@ -290,6 +290,8 @@ static inline uint_fast16_t invert_pwm (ioports_pwm_t *pwm_data, uint_fast16_t p
|
||||
*/
|
||||
bool ioports_precompute_pwm_values (pwm_config_t *config, ioports_pwm_t *pwm_data, uint32_t clock_hz)
|
||||
{
|
||||
pwm_data->f_clock = clock_hz;
|
||||
|
||||
if(config->max > config->min) {
|
||||
pwm_data->min = config->min;
|
||||
pwm_data->period = (uint_fast16_t)((float)clock_hz / config->freq_hz);
|
||||
|
||||
@@ -104,7 +104,7 @@ typedef void (*ioport_interrupt_callback_ptr)(uint8_t port, bool state);
|
||||
*/
|
||||
typedef bool (*ioport_register_interrupt_handler_ptr)(uint8_t port, pin_irq_mode_t irq_mode, ioport_interrupt_callback_ptr interrupt_callback);
|
||||
|
||||
typedef bool (*ioports_enumerate_callback_ptr)(xbar_t *properties, uint8_t port);
|
||||
typedef bool (*ioports_enumerate_callback_ptr)(xbar_t *properties, uint8_t port, void *data);
|
||||
|
||||
//! Properties and handlers for auxiliary digital and analog I/O.
|
||||
typedef struct {
|
||||
@@ -125,7 +125,7 @@ typedef struct {
|
||||
uint8_t ioports_available (io_port_type_t type, io_port_direction_t dir);
|
||||
bool ioport_claim (io_port_type_t type, io_port_direction_t dir, uint8_t *port, const char *description);
|
||||
bool ioport_can_claim_explicit (void);
|
||||
bool ioports_enumerate (io_port_type_t type, io_port_direction_t dir, pin_mode_t filter, bool claimable, ioports_enumerate_callback_ptr callback);
|
||||
bool ioports_enumerate (io_port_type_t type, io_port_direction_t dir, pin_mode_t filter, bool claimable, ioports_enumerate_callback_ptr callback, void *data);
|
||||
|
||||
//
|
||||
|
||||
@@ -146,6 +146,7 @@ typedef struct io_ports_data {
|
||||
|
||||
//!* \brief Precalculated values that may be set/used by HAL driver to speed up analog input to PWM conversions. */
|
||||
typedef struct {
|
||||
uint32_t f_clock;
|
||||
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;
|
||||
|
||||
@@ -176,7 +176,7 @@ bool mc_line (float *target, plan_line_data_t *pl_data)
|
||||
// if there is a coincident position passed.
|
||||
if(!plan_buffer_line(target, pl_data) && pl_data->spindle.hal->cap.laser && pl_data->spindle.state.on && !pl_data->spindle.state.ccw) {
|
||||
protocol_buffer_synchronize();
|
||||
pl_data->spindle.hal->set_state(pl_data->spindle.state, pl_data->spindle.rpm);
|
||||
pl_data->spindle.hal->set_state(pl_data->spindle.hal, pl_data->spindle.state, pl_data->spindle.rpm);
|
||||
}
|
||||
|
||||
#ifdef KINEMATICS_API
|
||||
@@ -287,9 +287,13 @@ void mc_arc (float *target, plan_line_data_t *pl_data, float *position, float *o
|
||||
// (2x) settings.arc_tolerance. For 99% of users, this is just fine. If a different arc segment fit
|
||||
// is desired, i.e. least-squares, midpoint on arc, just change the mm_per_arc_segment calculation.
|
||||
// For the intended uses of Grbl, this value shouldn't exceed 2000 for the strictest of cases.
|
||||
uint_fast16_t segments = (uint_fast16_t)floorf(fabsf(0.5f * angular_travel * radius) / sqrtf(settings.arc_tolerance * (2.0f * radius - settings.arc_tolerance)));
|
||||
|
||||
if (segments) {
|
||||
uint_fast16_t segments = 0;
|
||||
|
||||
if(2.0f * radius > settings.arc_tolerance)
|
||||
segments = (uint_fast16_t)floorf(fabsf(0.5f * angular_travel * radius) / sqrtf(settings.arc_tolerance * (2.0f * radius - settings.arc_tolerance)));
|
||||
|
||||
if(segments) {
|
||||
|
||||
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
|
||||
// by a number of discrete segments. The inverse feed_rate should be correct for the sum of
|
||||
@@ -602,7 +606,7 @@ void mc_canned_drill (motion_mode_t motion, float *target, plan_line_data_t *pl_
|
||||
mc_dwell(canned->dwell);
|
||||
|
||||
if(canned->spindle_off)
|
||||
pl_data->spindle.hal->set_state((spindle_state_t){0}, 0.0f);
|
||||
pl_data->spindle.hal->set_state(pl_data->spindle.hal, (spindle_state_t){0}, 0.0f);
|
||||
|
||||
// rapid retract
|
||||
switch(motion) {
|
||||
|
||||
25
nvs_buffer.c
25
nvs_buffer.c
@@ -102,7 +102,22 @@ static const emap_t target[] = {
|
||||
{TOOL_ADDR(15), NVS_GROUP_TOOLS, 15},
|
||||
#endif
|
||||
#if N_TOOLS > 16
|
||||
#error Increase number of tool entries!
|
||||
{TOOL_ADDR(16), NVS_GROUP_TOOLS, 16},
|
||||
{TOOL_ADDR(17), NVS_GROUP_TOOLS, 17},
|
||||
{TOOL_ADDR(18), NVS_GROUP_TOOLS, 18},
|
||||
{TOOL_ADDR(19), NVS_GROUP_TOOLS, 19},
|
||||
{TOOL_ADDR(20), NVS_GROUP_TOOLS, 20},
|
||||
{TOOL_ADDR(21), NVS_GROUP_TOOLS, 21},
|
||||
{TOOL_ADDR(22), NVS_GROUP_TOOLS, 22},
|
||||
{TOOL_ADDR(23), NVS_GROUP_TOOLS, 23},
|
||||
{TOOL_ADDR(24), NVS_GROUP_TOOLS, 24},
|
||||
{TOOL_ADDR(25), NVS_GROUP_TOOLS, 25},
|
||||
{TOOL_ADDR(26), NVS_GROUP_TOOLS, 26},
|
||||
{TOOL_ADDR(27), NVS_GROUP_TOOLS, 27},
|
||||
{TOOL_ADDR(28), NVS_GROUP_TOOLS, 28},
|
||||
{TOOL_ADDR(29), NVS_GROUP_TOOLS, 29},
|
||||
{TOOL_ADDR(30), NVS_GROUP_TOOLS, 30},
|
||||
{TOOL_ADDR(31), NVS_GROUP_TOOLS, 31},
|
||||
#endif
|
||||
#endif
|
||||
{0, 0, 0} // list termination - do not remove
|
||||
@@ -360,8 +375,13 @@ void nvs_buffer_sync_physical (void)
|
||||
settings_dirty.build_info;
|
||||
|
||||
} else if(physical_nvs.memcpy_to_flash) {
|
||||
if(!physical_nvs.memcpy_to_flash(nvsbuffer))
|
||||
uint_fast8_t retries = 4;
|
||||
do {
|
||||
if(physical_nvs.memcpy_to_flash(nvsbuffer))
|
||||
retries = 0;
|
||||
else if(--retries == 0)
|
||||
report_message("Settings write failed!", Message_Warning);
|
||||
} while(retries);
|
||||
memset(&settings_dirty, 0, sizeof(settings_dirty_t));
|
||||
}
|
||||
}
|
||||
@@ -421,4 +441,3 @@ void nvs_memmap (void)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
13
pid.h
13
pid.h
@@ -7,7 +7,7 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2020-2021 Terje Io
|
||||
Copyright (c) 2020-2023 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
|
||||
@@ -28,7 +28,16 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "settings.h"
|
||||
typedef struct {
|
||||
float p_gain;
|
||||
float i_gain;
|
||||
float d_gain;
|
||||
float p_max_error;
|
||||
float i_max_error;
|
||||
float d_max_error;
|
||||
float deadband;
|
||||
float max_error;
|
||||
} pid_values_t;
|
||||
|
||||
typedef struct {
|
||||
pid_values_t cfg;
|
||||
|
||||
@@ -226,15 +226,21 @@
|
||||
#endif
|
||||
|
||||
#if SPINDLE_SYNC_ENABLE
|
||||
#ifndef SPINDLE_INDEX_BIT
|
||||
#define SPINDLE_INDEX_BIT (1<<SPINDLE_INDEX_PIN)
|
||||
#endif
|
||||
#ifndef SPINDLE_PULSE_BIT
|
||||
#define SPINDLE_PULSE_BIT (1<<SPINDLE_PULSE_PIN)
|
||||
#endif
|
||||
#if defined(SPINDLE_INDEX_PIN) && defined(SPINDLE_PULSE_PIN)
|
||||
#ifndef SPINDLE_INDEX_BIT
|
||||
#define SPINDLE_INDEX_BIT (1<<SPINDLE_INDEX_PIN)
|
||||
#endif
|
||||
#ifndef SPINDLE_PULSE_BIT
|
||||
#define SPINDLE_PULSE_BIT (1<<SPINDLE_PULSE_PIN)
|
||||
#endif
|
||||
#else
|
||||
#define SPINDLE_INDEX_BIT 0
|
||||
#define SPINDLE_PULSE_BIT 0
|
||||
#error "Spindle sync requires SPINDLE_PULSE_PIN and SPINDLE_INDEX_PIN defined in the board map!"
|
||||
#endif
|
||||
#else
|
||||
#define SPINDLE_INDEX_BIT 0
|
||||
#define SPINDLE_PULSE_BIT 0
|
||||
#define SPINDLE_INDEX_BIT 0
|
||||
#define SPINDLE_PULSE_BIT 0
|
||||
#endif
|
||||
|
||||
#if QEI_ENABLE
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
plasma_init();
|
||||
#endif
|
||||
|
||||
#if MODBUS_ENABLE && MODBUS_ENABLE & 0x01
|
||||
#if MODBUS_ENABLE && (MODBUS_ENABLE & 0x01)
|
||||
extern void modbus_rtu_init (void);
|
||||
modbus_rtu_init();
|
||||
#endif
|
||||
@@ -43,6 +43,26 @@
|
||||
canbus_init();
|
||||
#endif
|
||||
|
||||
#if SPINDLE_ENABLE & (1<<SPINDLE_PWM0_CLONE)
|
||||
extern void cloned_spindle_init (void);
|
||||
cloned_spindle_init();
|
||||
#endif
|
||||
|
||||
#if SPINDLE_ENABLE & (1<<SPINDLE_STEPPER)
|
||||
extern void stepper_spindle_init (void);
|
||||
stepper_spindle_init();
|
||||
#endif
|
||||
|
||||
#if SPINDLE_ENABLE & ((1<<SPINDLE_ONOFF1)|(1<<SPINDLE_ONOFF1_DIR))
|
||||
extern void onoff_spindle_init (void);
|
||||
onoff_spindle_init();
|
||||
#endif
|
||||
|
||||
#if SPINDLE_ENABLE & (1<<SPINDLE_PWM2)
|
||||
extern void pwm_spindle_init (void);
|
||||
pwm_spindle_init();
|
||||
#endif
|
||||
|
||||
#if VFD_ENABLE
|
||||
extern void vfd_init (void);
|
||||
vfd_init();
|
||||
|
||||
76
report.c
76
report.c
@@ -614,17 +614,15 @@ void report_ngc_parameters (void)
|
||||
hal.stream.write(get_axis_values(gc_state.g92_coord_offset));
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
|
||||
#if N_TOOLS
|
||||
for (idx = 1; idx <= N_TOOLS; idx++) {
|
||||
for (idx = 1; idx <= grbl.tool_table.n_tools; idx++) {
|
||||
hal.stream.write("[T:");
|
||||
hal.stream.write(uitoa((uint32_t)idx));
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(get_axis_values(tool_table[idx].offset));
|
||||
hal.stream.write(get_axis_values(grbl.tool_table.tool[idx].offset));
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(get_axis_value(tool_table[idx].radius));
|
||||
hal.stream.write(get_axis_value(grbl.tool_table.tool[idx].radius));
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if COMPATIBILITY_LEVEL < 10
|
||||
if(settings.homing.flags.enabled)
|
||||
@@ -892,11 +890,7 @@ void report_build_info (char *line, bool extended)
|
||||
hal.stream.write(",");
|
||||
hal.stream.write(uitoa((uint32_t)N_AXIS));
|
||||
hal.stream.write(",");
|
||||
#if N_TOOLS
|
||||
hal.stream.write(uitoa((uint32_t)N_TOOLS));
|
||||
#else
|
||||
hal.stream.write("0");
|
||||
#endif
|
||||
hal.stream.write(uitoa(grbl.tool_table.n_tools));
|
||||
}
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
|
||||
@@ -940,8 +934,12 @@ void report_build_info (char *line, bool extended)
|
||||
if(hal.driver_cap.mpg_mode)
|
||||
strcat(buf, "MPG,");
|
||||
|
||||
#if LATHE_UVW_OPTION
|
||||
strcat(buf, "LATHE,LATHEUVW,");
|
||||
#else
|
||||
if(settings.mode == Mode_Lathe)
|
||||
strcat(buf, "LATHE,");
|
||||
#endif
|
||||
|
||||
if(hal.driver_cap.laser_ppi_mode)
|
||||
strcat(buf, "PPI,");
|
||||
@@ -1180,7 +1178,7 @@ void report_realtime_status (void)
|
||||
spindle_state_t spindle_0_state;
|
||||
|
||||
spindle_0 = spindle_get(0);
|
||||
spindle_0_state = spindle_0->get_state();
|
||||
spindle_0_state = spindle_0->get_state(spindle_0);
|
||||
|
||||
// Report realtime feed speed
|
||||
if(settings.status_report.feed_speed) {
|
||||
@@ -1201,7 +1199,7 @@ void report_realtime_status (void)
|
||||
spindle_state_t spindle_n_state;
|
||||
|
||||
if((spindle_n = spindle_get(idx))) {
|
||||
spindle_n_state = spindle_n->get_state();
|
||||
spindle_n_state = spindle_n->get_state(spindle_n);
|
||||
hal.stream.write_all(appendbuf(3, "|SP", uitoa(idx), ":"));
|
||||
hal.stream.write_all(appendbuf(3, uitoa(spindle_n_state.on ? lroundf(spindle_n->param->rpm_overridden) : 0), ",,", spindle_n_state.on ? (spindle_n_state.ccw ? "C" : "S") : ""));
|
||||
if(settings.status_report.overrides)
|
||||
@@ -2122,7 +2120,7 @@ status_code_t report_spindle_data (sys_state_t state, char *args)
|
||||
float apos = spindle->get_data(SpindleData_AngularPosition)->angular_position;
|
||||
spindle_data_t *data = spindle->get_data(SpindleData_Counters);
|
||||
|
||||
hal.stream.write("[SPINDLE:");
|
||||
hal.stream.write("[SPINDLEENCODER:");
|
||||
hal.stream.write(uitoa(data->index_count));
|
||||
hal.stream.write(",");
|
||||
hal.stream.write(uitoa(data->pulse_count));
|
||||
@@ -2203,6 +2201,49 @@ status_code_t report_time (void)
|
||||
|
||||
static void report_spindle (spindle_info_t *spindle, void *data)
|
||||
{
|
||||
if(data) {
|
||||
char *caps = buf;
|
||||
hal.stream.write("[SPINDLE:");
|
||||
hal.stream.write(uitoa(spindle->id));
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(spindle->enabled ? uitoa(spindle->num) : "-");
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(uitoa(spindle->hal->type));
|
||||
*caps++ = '|';
|
||||
#if N_SYS_SPINDLE == 1
|
||||
if(spindle->is_current)
|
||||
*caps++ = '*';
|
||||
#endif
|
||||
if(spindle->hal->cap.at_speed)
|
||||
*caps++ = 'S';
|
||||
if(spindle->hal->cap.direction)
|
||||
*caps++ = 'D';
|
||||
if(spindle->hal->cap.laser)
|
||||
*caps++ = 'L';
|
||||
if(spindle->hal->cap.pid)
|
||||
*caps++ = 'P';
|
||||
if(spindle->hal->cap.pwm_invert)
|
||||
*caps++ = 'I';
|
||||
if(spindle->hal->cap.pwm_linearization)
|
||||
*caps++ = 'N';
|
||||
if(spindle->hal->cap.rpm_range_locked)
|
||||
*caps++ = 'R';
|
||||
if(spindle->hal->cap.variable)
|
||||
*caps++ = 'V';
|
||||
if(spindle->hal->get_data)
|
||||
*caps++ = 'E';
|
||||
*caps++ = '|';
|
||||
*caps = '\0';
|
||||
hal.stream.write(buf);
|
||||
hal.stream.write(spindle->name);
|
||||
if(spindle->hal->rpm_max > 0.0f) {
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(ftoa(spindle->hal->rpm_min, 1));
|
||||
hal.stream.write(",");
|
||||
hal.stream.write(ftoa(spindle->hal->rpm_max, 1));
|
||||
}
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
} else {
|
||||
hal.stream.write(uitoa(spindle->id));
|
||||
hal.stream.write(" - ");
|
||||
hal.stream.write(spindle->name);
|
||||
@@ -2210,16 +2251,19 @@ static void report_spindle (spindle_info_t *spindle, void *data)
|
||||
#if N_SPINDLE > 1
|
||||
hal.stream.write(", enabled as spindle ");
|
||||
hal.stream.write(uitoa(spindle->num));
|
||||
#else
|
||||
#if N_SYS_SPINDLE == 1
|
||||
if(spindle->is_current)
|
||||
hal.stream.write(", active");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
hal.stream.write(ASCII_EOL);
|
||||
}
|
||||
}
|
||||
|
||||
status_code_t report_spindles (void)
|
||||
status_code_t report_spindles (bool machine_readable)
|
||||
{
|
||||
if(!spindle_enumerate_spindles(report_spindle, NULL))
|
||||
if(!spindle_enumerate_spindles(report_spindle, (void *)machine_readable) && !machine_readable)
|
||||
hal.stream.write("No spindles registered." ASCII_EOL);
|
||||
|
||||
return Status_OK;
|
||||
|
||||
2
report.h
2
report.h
@@ -99,7 +99,7 @@ status_code_t report_spindle_data (sys_state_t state, char *args);
|
||||
status_code_t report_pins (sys_state_t state, char *args);
|
||||
|
||||
// Prints registered spindles.
|
||||
status_code_t report_spindles (void);
|
||||
status_code_t report_spindles (bool machine_readable);
|
||||
|
||||
// Prints current RTC datetime in ISO8601 format (when available)
|
||||
status_code_t report_time (void);
|
||||
|
||||
160
settings.c
160
settings.c
@@ -367,6 +367,7 @@ static status_code_t set_spindle_invert (setting_id_t id, uint_fast16_t int_valu
|
||||
static status_code_t set_pwm_mode (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_pwm_options (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_spindle_type (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_encoder_spindle (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_control_disable_pullup (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_probe_disable_pullup (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_soft_limits_enable (setting_id_t id, uint_fast16_t int_value);
|
||||
@@ -375,7 +376,9 @@ static status_code_t set_jog_soft_limited (setting_id_t id, uint_fast16_t int_va
|
||||
static status_code_t set_homing_enable (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_enable_legacy_rt_commands (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_homing_cycle (setting_id_t id, uint_fast16_t int_value);
|
||||
#if !LATHE_UVW_OPTION
|
||||
static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value);
|
||||
#endif
|
||||
static status_code_t set_sleep_enable (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_hold_actions (setting_id_t id, uint_fast16_t int_value);
|
||||
static status_code_t set_force_initialization_alarm (setting_id_t id, uint_fast16_t int_value);
|
||||
@@ -422,6 +425,7 @@ static char control_signals[] = "Reset,Feed hold,Cycle start,Safety door,Block d
|
||||
static char spindle_signals[] = "Spindle enable,Spindle direction,PWM";
|
||||
static char coolant_signals[] = "Flood,Mist";
|
||||
static char ganged_axes[] = "X-Axis,Y-Axis,Z-Axis";
|
||||
static char fs_options[] = "Auto mount SD card,Hide LittleFS";
|
||||
static char spindle_types[100] = "";
|
||||
static char axis_dist[4] = "mm";
|
||||
static char axis_rate[8] = "mm/min";
|
||||
@@ -462,7 +466,7 @@ PROGMEM static const setting_detail_t setting_detail[] = {
|
||||
{ Setting_ReportInches, Group_General, "Report in inches", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_report_inches, get_int, NULL },
|
||||
{ Setting_ControlInvertMask, Group_ControlSignals, "Invert control pins", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExpandedFn, set_control_invert, get_int, NULL },
|
||||
{ Setting_CoolantInvertMask, Group_Coolant, "Invert coolant pins", NULL, Format_Bitfield, coolant_signals, NULL, NULL, Setting_IsExtended, &settings.coolant_invert.mask, NULL, NULL },
|
||||
{ Setting_SpindleInvertMask, Group_Spindle, "Invert spindle signals", NULL, Format_Bitfield, spindle_signals, NULL, NULL, Setting_IsExtendedFn, set_spindle_invert, get_int, NULL, { .reboot_required = On } },
|
||||
{ Setting_SpindleInvertMask, Group_Spindle, "Invert spindle signals", NULL, Format_Bitfield, spindle_signals, NULL, NULL, Setting_IsExtendedFn, set_spindle_invert, get_int, is_setting_available, { .reboot_required = On } },
|
||||
{ Setting_ControlPullUpDisableMask, Group_ControlSignals, "Pullup disable control pins", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExtendedFn, set_control_disable_pullup, get_int, NULL },
|
||||
{ Setting_LimitPullUpDisableMask, Group_Limits, "Pullup disable limit pins", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.limits.disable_pullup.mask, NULL, NULL },
|
||||
{ Setting_ProbePullUpDisable, Group_Probing, "Pullup disable probe pin", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_probe_disable_pullup, get_int, is_setting_available },
|
||||
@@ -490,7 +494,9 @@ PROGMEM static const setting_detail_t setting_detail[] = {
|
||||
{ Setting_PulseDelayMicroseconds, Group_Stepper, "Pulse delay", "microseconds", Format_Decimal, "#0.0", NULL, "10", Setting_IsExtended, &settings.steppers.pulse_delay_microseconds, NULL, NULL },
|
||||
{ Setting_RpmMax, Group_Spindle, "Maximum spindle speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.spindle.rpm_max, NULL, is_setting_available },
|
||||
{ Setting_RpmMin, Group_Spindle, "Minimum spindle speed", "RPM", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacy, &settings.spindle.rpm_min, NULL, is_setting_available },
|
||||
#if !LATHE_UVW_OPTION
|
||||
{ Setting_Mode, Group_General, "Mode of operation", NULL, Format_RadioButtons, "Normal,Laser mode,Lathe mode", NULL, NULL, Setting_IsLegacyFn, set_mode, get_int, NULL },
|
||||
#endif
|
||||
{ Setting_PWMFreq, Group_Spindle, "Spindle PWM frequency", "Hz", Format_Decimal, "#####0", NULL, NULL, Setting_IsExtended, &settings.spindle.pwm_freq, NULL, is_setting_available },
|
||||
{ Setting_PWMOffValue, Group_Spindle, "Spindle PWM off value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.spindle.pwm_off_value, NULL, is_setting_available },
|
||||
{ Setting_PWMMinValue, Group_Spindle, "Spindle PWM min value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.spindle.pwm_min_value, NULL, is_setting_available },
|
||||
@@ -549,7 +555,7 @@ PROGMEM static const setting_detail_t setting_detail[] = {
|
||||
{ Setting_PositionIGain, Group_Spindle_Sync, "Spindle sync I-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.i_gain, NULL, is_group_available },
|
||||
{ Setting_PositionDGain, Group_Spindle_Sync, "Spindle sync D-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.d_gain, NULL, is_group_available },
|
||||
{ Setting_PositionIMaxError, Group_Spindle_Sync, "Spindle sync PID max I error", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.i_max_error, NULL, is_group_available },
|
||||
{ Setting_AxisStepsPerMM, Group_Axis0, "-axis travel resolution", axis_steps, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
{ Setting_AxisStepsPerMM, Group_Axis0, "-axis travel resolution", axis_steps, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
{ Setting_AxisMaxRate, Group_Axis0, "-axis maximum rate", axis_rate, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
{ Setting_AxisAcceleration, Group_Axis0, "-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
{ Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
@@ -607,6 +613,8 @@ PROGMEM static const setting_detail_t setting_detail[] = {
|
||||
#if COMPATIBILITY_LEVEL <= 1
|
||||
{ Setting_OffsetLock, Group_General, "Lock coordinate systems", NULL, Format_Bitfield, "G59.1,G59.2,G59.3", NULL, NULL, Setting_IsExtendedFn, set_offset_lock, get_int, NULL },
|
||||
#endif
|
||||
{ Setting_EncoderSpindle, Group_Spindle, "Encoder spindle", NULL, Format_RadioButtons, spindle_types, NULL, NULL, Setting_IsExtendedFn, set_encoder_spindle, get_int, is_setting_available },
|
||||
{ Setting_FSOptions, Group_General, "File systems options", NULL, Format_Bitfield, fs_options, NULL, NULL, Setting_IsExtended, &settings.fs_options.mask, NULL, is_setting_available }
|
||||
};
|
||||
|
||||
#ifndef NO_SETTINGS_DESCRIPTIONS
|
||||
@@ -668,9 +676,11 @@ PROGMEM static const setting_descr_t setting_descr[] = {
|
||||
},
|
||||
{ Setting_RpmMax, "Maximum spindle speed, can be overridden by spindle plugins." },
|
||||
{ Setting_RpmMin, "Minimum spindle speed, can be overridden by spindle plugins." },
|
||||
#if !LATHE_UVW_OPTION
|
||||
{ Setting_Mode, "Laser mode: consecutive G1/2/3 commands will not halt when spindle speed is changed.\\n"
|
||||
"Lathe mode: allows use of G7, G8, G96 and G97."
|
||||
},
|
||||
#endif
|
||||
{ Setting_PWMFreq, "Spindle PWM frequency." },
|
||||
{ Setting_PWMOffValue, "Spindle PWM off value in percent (duty cycle)." },
|
||||
{ Setting_PWMMinValue, "Spindle PWM min value in percent (duty cycle)." },
|
||||
@@ -779,6 +789,8 @@ PROGMEM static const setting_descr_t setting_descr[] = {
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
{ Setting_NGCDebugOut, "Example: (debug, metric mode: #<_metric>, coord system: #5220)" },
|
||||
#endif
|
||||
{ Setting_EncoderSpindle, "Specifies which spindle has the encoder attached." },
|
||||
{ Setting_FSOptions, "Auto mount SD card on startup." }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -997,6 +1009,18 @@ static status_code_t set_spindle_type (setting_id_t id, uint_fast16_t int_value)
|
||||
return Status_OK;
|
||||
}
|
||||
|
||||
static status_code_t set_encoder_spindle (setting_id_t id, uint_fast16_t int_value)
|
||||
{
|
||||
if(spindle_get_count() < 2)
|
||||
return Status_SettingDisabled;
|
||||
else if(int_value >= spindle_get_count())
|
||||
return Status_SettingValueOutOfRange;
|
||||
|
||||
settings.offset_lock.encoder_spindle = int_value;
|
||||
|
||||
return Status_OK;
|
||||
}
|
||||
|
||||
static status_code_t set_spindle_invert (setting_id_t id, uint_fast16_t int_value)
|
||||
{
|
||||
settings.spindle.invert.mask = int_value;
|
||||
@@ -1062,7 +1086,9 @@ static status_code_t set_estop_unlock (setting_id_t id, uint_fast16_t int_value)
|
||||
|
||||
static status_code_t set_offset_lock (setting_id_t id, uint_fast16_t int_value)
|
||||
{
|
||||
settings.parking.flags.offset_lock = int_value & 0x07;
|
||||
settings.parking.flags.offset_lock = int_value & 0b111; // TODO: remove
|
||||
settings.offset_lock.mask &= ~0b111; // TODO: remove
|
||||
settings.offset_lock.mask |= settings.parking.flags.offset_lock;
|
||||
|
||||
return Status_OK;
|
||||
}
|
||||
@@ -1147,6 +1173,8 @@ static status_code_t set_homing_cycle (setting_id_t id, uint_fast16_t int_value)
|
||||
return Status_OK;
|
||||
}
|
||||
|
||||
#if !LATHE_UVW_OPTION
|
||||
|
||||
static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value)
|
||||
{
|
||||
switch((machine_mode_t)int_value) {
|
||||
@@ -1174,6 +1202,8 @@ static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value)
|
||||
return Status_OK;
|
||||
}
|
||||
|
||||
#endif // LATHE_UVW_OPTION
|
||||
|
||||
#ifndef NO_SAFETY_DOOR_SUPPORT
|
||||
|
||||
static status_code_t set_parking_enable (setting_id_t id, uint_fast16_t int_value)
|
||||
@@ -1190,7 +1220,7 @@ static status_code_t set_restore_overrides (setting_id_t id, uint_fast16_t int_v
|
||||
return Status_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // NO_SAFETY_DOOR_SUPPORT
|
||||
|
||||
static status_code_t set_sleep_enable (setting_id_t id, uint_fast16_t int_value)
|
||||
{
|
||||
@@ -1663,7 +1693,11 @@ static uint32_t get_int (setting_id_t id)
|
||||
break;
|
||||
|
||||
case Setting_OffsetLock:
|
||||
value = settings.parking.flags.offset_lock;
|
||||
value = settings.offset_lock.mask & 0b111;
|
||||
break;
|
||||
|
||||
case Setting_EncoderSpindle:
|
||||
value = settings.offset_lock.encoder_spindle;
|
||||
break;
|
||||
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
@@ -1878,6 +1912,10 @@ static bool is_setting_available (const setting_detail_t *setting)
|
||||
available = hal.driver_cap.pwm_spindle && spindle_get_caps(false).laser;
|
||||
break;
|
||||
|
||||
case Setting_SpindleInvertMask:
|
||||
available = spindle_get_caps(false).gpio_controlled;
|
||||
break;
|
||||
|
||||
case Setting_PWMFreq:
|
||||
case Setting_PWMOffValue:
|
||||
case Setting_PWMMinValue:
|
||||
@@ -1890,7 +1928,7 @@ static bool is_setting_available (const setting_detail_t *setting)
|
||||
break;
|
||||
|
||||
case Setting_SpindlePPR:
|
||||
available = hal.driver_cap.spindle_sync || hal.driver_cap.spindle_pid;
|
||||
available = hal.driver_cap.spindle_encoder;
|
||||
break;
|
||||
|
||||
case Setting_RpmMax:
|
||||
@@ -1922,7 +1960,7 @@ static bool is_setting_available (const setting_detail_t *setting)
|
||||
#endif
|
||||
|
||||
case Setting_SpindleAtSpeedTolerance:
|
||||
available = spindle_get_caps(true).at_speed || hal.driver_cap.spindle_sync;
|
||||
available = spindle_get_caps(true).at_speed || hal.driver_cap.spindle_encoder;
|
||||
break;
|
||||
|
||||
case Setting_SpindleOnDelay:
|
||||
@@ -1941,6 +1979,14 @@ static bool is_setting_available (const setting_detail_t *setting)
|
||||
available = hal.signals_cap.e_stop;
|
||||
break;
|
||||
|
||||
case Setting_EncoderSpindle:
|
||||
available = hal.driver_cap.spindle_encoder && spindle_get_count() > 1;
|
||||
break;
|
||||
|
||||
case Setting_FSOptions:
|
||||
available = hal.driver_cap.sd_card || hal.driver_cap.littlefs;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2021,25 +2067,22 @@ bool settings_read_coord_data (coord_system_id_t id, float (*coord_data)[N_AXIS]
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write selected tool data to persistent storage.
|
||||
bool settings_write_tool_data (tool_data_t *tool_data)
|
||||
{
|
||||
#if N_TOOLS
|
||||
|
||||
// Write selected tool data to persistent storage.
|
||||
static bool settings_write_tool_data (tool_data_t *tool_data)
|
||||
{
|
||||
assert(tool_data->tool_id > 0 && tool_data->tool_id <= N_TOOLS); // NOTE: idx 0 is a non-persistent entry for tools not in tool table
|
||||
|
||||
if(hal.nvs.type != NVS_None)
|
||||
hal.nvs.memcpy_to_nvs(NVS_ADDR_TOOL_TABLE + (tool_data->tool_id - 1) * (sizeof(tool_data_t) + NVS_CRC_BYTES), (uint8_t *)tool_data, sizeof(tool_data_t), true);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Read selected tool data from persistent storage.
|
||||
bool settings_read_tool_data (tool_id_t tool_id, tool_data_t *tool_data)
|
||||
static bool settings_read_tool_data (tool_id_t tool_id, tool_data_t *tool_data)
|
||||
{
|
||||
#if N_TOOLS
|
||||
assert(tool_id > 0 && tool_id <= N_TOOLS); // NOTE: idx 0 is a non-persistent entry for tools not in tool table
|
||||
|
||||
if (!(hal.nvs.type != NVS_None && hal.nvs.memcpy_from_nvs((uint8_t *)tool_data, NVS_ADDR_TOOL_TABLE + (tool_id - 1) * (sizeof(tool_data_t) + NVS_CRC_BYTES),
|
||||
@@ -2049,11 +2092,25 @@ bool settings_read_tool_data (tool_id_t tool_id, tool_data_t *tool_data)
|
||||
}
|
||||
|
||||
return tool_data->tool_id == tool_id;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Clear all tool data in persistent storage.
|
||||
static bool settings_clear_tool_data (void)
|
||||
{
|
||||
uint_fast8_t idx;
|
||||
|
||||
tool_data_t tool_data;
|
||||
memset(&tool_data, 0, sizeof(tool_data_t));
|
||||
for (idx = 1; idx <= N_TOOLS; idx++) {
|
||||
tool_data.tool_id = (tool_id_t)idx;
|
||||
settings_write_tool_data(&tool_data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // N_TOOLS
|
||||
|
||||
// Read global settings from persistent storage.
|
||||
// Checks version-byte of non-volatile storage and global settings copy.
|
||||
bool read_global_settings ()
|
||||
@@ -2061,16 +2118,17 @@ bool read_global_settings ()
|
||||
bool ok = hal.nvs.type != NVS_None && SETTINGS_VERSION == hal.nvs.get_byte(0) && hal.nvs.memcpy_from_nvs((uint8_t *)&settings, NVS_ADDR_GLOBAL, sizeof(settings_t), true) == NVS_TransferResult_OK;
|
||||
|
||||
// Sanity check of settings, board map could have been changed...
|
||||
#if LATHE_UVW_OPTION
|
||||
settings.mode = Mode_Lathe;
|
||||
#else
|
||||
if(settings.mode == Mode_Laser && !spindle_get_caps(false).laser)
|
||||
settings.mode = Mode_Standard;
|
||||
|
||||
if(settings.spindle.flags.type >= spindle_get_count())
|
||||
settings.spindle.flags.type = 0;
|
||||
#endif
|
||||
|
||||
if(settings.planner_buffer_blocks < 30 || settings.planner_buffer_blocks > 1000)
|
||||
settings.planner_buffer_blocks = 35;
|
||||
|
||||
if(!(hal.driver_cap.spindle_sync || hal.driver_cap.spindle_pid))
|
||||
if(!hal.driver_cap.spindle_encoder)
|
||||
settings.spindle.ppr = 0;
|
||||
|
||||
#if COMPATIBILITY_LEVEL > 1 && DEFAULT_DISABLE_G92_PERSISTENCE
|
||||
@@ -2134,12 +2192,7 @@ void settings_restore (settings_restore_t restore)
|
||||
settings_write_coord_data(CoordinateSystem_G92, &coord_data); // Clear G92 offsets
|
||||
|
||||
#if N_TOOLS
|
||||
tool_data_t tool_data;
|
||||
memset(&tool_data, 0, sizeof(tool_data_t));
|
||||
for (idx = 1; idx <= N_TOOLS; idx++) {
|
||||
tool_data.tool_id = (tool_id_t)idx;
|
||||
settings_write_tool_data(&tool_data);
|
||||
}
|
||||
settings_clear_tool_data();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2770,6 +2823,22 @@ void settings_init (void)
|
||||
grbl.on_set_axis_setting_unit = set_axis_setting_unit;
|
||||
#endif
|
||||
|
||||
#if N_TOOLS
|
||||
static tool_data_t tools[N_TOOLS + 1];
|
||||
|
||||
grbl.tool_table.n_tools = N_TOOLS;
|
||||
grbl.tool_table.tool = tools;
|
||||
grbl.tool_table.read = settings_read_tool_data;
|
||||
grbl.tool_table.write = settings_write_tool_data;
|
||||
grbl.tool_table.clear = settings_clear_tool_data;
|
||||
#else
|
||||
static tool_data_t tools;
|
||||
if(grbl.tool_table.tool == NULL) {
|
||||
grbl.tool_table.n_tools = 0;
|
||||
grbl.tool_table.tool = &tools;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!read_global_settings()) {
|
||||
|
||||
settings_restore_t settings = settings_all;
|
||||
@@ -2788,12 +2857,14 @@ void settings_init (void)
|
||||
changed.spindle = settings_changed_spindle();
|
||||
} else {
|
||||
|
||||
memset(&tool_table, 0, sizeof(tool_data_t)); // First entry is for tools not in tool table
|
||||
#if N_TOOLS
|
||||
memset(grbl.tool_table.tool, 0, sizeof(tool_data_t)); // First entry is for tools not in tool table
|
||||
|
||||
if(grbl.tool_table.n_tools) {
|
||||
uint_fast8_t idx;
|
||||
for (idx = 1; idx <= N_TOOLS; idx++)
|
||||
settings_read_tool_data(idx, &tool_table[idx]);
|
||||
#endif
|
||||
for(idx = 1; idx <= grbl.tool_table.n_tools; idx++)
|
||||
grbl.tool_table.read(idx, &grbl.tool_table.tool[idx]);
|
||||
}
|
||||
|
||||
report_init();
|
||||
|
||||
changed.spindle = settings_changed_spindle();
|
||||
@@ -2804,6 +2875,9 @@ void settings_init (void)
|
||||
hal.probe.configure(false, false);
|
||||
}
|
||||
|
||||
settings.offset_lock.mask &= ~0b111; // TODO: remove
|
||||
settings.offset_lock.mask |= settings.parking.flags.offset_lock; // TODO: remove
|
||||
|
||||
xbar_set_homing_source();
|
||||
|
||||
tmp_set_soft_limits();
|
||||
@@ -2812,14 +2886,16 @@ void settings_init (void)
|
||||
if(spindle_get_count() == 0)
|
||||
spindle_add_null();
|
||||
|
||||
spindle_state_t spindle_cap = {
|
||||
.on = On,
|
||||
};
|
||||
spindle_cap_t spindle_cap = spindle_get_caps(false);
|
||||
if(spindle_cap.gpio_controlled) {
|
||||
|
||||
spindle_cap.ccw = spindle_get_caps(false).direction;
|
||||
spindle_cap.pwm = spindle_get_caps(false).pwm_invert;
|
||||
spindle_state_t spindle_state = { .on = On };
|
||||
spindle_state.ccw = spindle_cap.direction;
|
||||
spindle_state.pwm = spindle_cap.pwm_invert;
|
||||
|
||||
setting_remove_elements(Setting_SpindleInvertMask, spindle_state.mask);
|
||||
}
|
||||
|
||||
setting_remove_elements(Setting_SpindleInvertMask, spindle_cap.mask);
|
||||
setting_remove_elements(Setting_ControlInvertMask, hal.signals_cap.mask);
|
||||
|
||||
if(hal.stepper.get_ganged)
|
||||
@@ -2838,4 +2914,10 @@ void settings_init (void)
|
||||
} while((details = details->next));
|
||||
|
||||
setting_details.on_changed = hal.settings_changed;
|
||||
|
||||
// Sanity checks for spindle configuration
|
||||
if(settings.spindle.flags.type >= spindle_get_count())
|
||||
settings.spindle.flags.type = 0;
|
||||
if(settings.offset_lock.encoder_spindle >= spindle_get_count())
|
||||
settings.offset_lock.encoder_spindle = 0;
|
||||
}
|
||||
|
||||
80
settings.h
80
settings.h
@@ -314,6 +314,9 @@ typedef enum {
|
||||
Setting_UnlockAfterEStop = 484,
|
||||
Setting_EnableToolPersistence = 485,
|
||||
Setting_OffsetLock = 486,
|
||||
Setting_Spindle_OnPort = 487,
|
||||
Setting_Spindle_DirPort = 488,
|
||||
Setting_Spindle_PWMPort = 489,
|
||||
|
||||
Setting_Macro0 = 490,
|
||||
Setting_Macro1 = 491,
|
||||
@@ -345,6 +348,7 @@ typedef enum {
|
||||
Setting_SpindleEnable5 = 515,
|
||||
Setting_SpindleEnable6 = 516,
|
||||
Setting_SpindleEnable7 = 517,
|
||||
Setting_EncoderSpindle = 519,
|
||||
|
||||
Setting_SpindleToolStart0 = 520,
|
||||
Setting_SpindleToolStart1 = 521,
|
||||
@@ -401,6 +405,23 @@ typedef enum {
|
||||
Setting_Kinematics8 = 648,
|
||||
Setting_Kinematics9 = 649,
|
||||
|
||||
Setting_FSOptions = 650,
|
||||
|
||||
Setting_RpmMax1 = 730,
|
||||
Setting_RpmMin1 = 731,
|
||||
Setting_Mode1 = 732,
|
||||
Setting_PWMFreq1 = 733,
|
||||
Setting_PWMOffValue1 = 734,
|
||||
Setting_PWMMinValue1 = 735,
|
||||
Setting_PWMMaxValue1 = 736,
|
||||
// Optional driver implemented settings for piecewise linear spindle PWM algorithm
|
||||
Setting_LinearSpindle1Piece1 = 737,
|
||||
Setting_LinearSpindle1Piece2 = 738,
|
||||
Setting_LinearSpindle1Piece3 = 739,
|
||||
Setting_LinearSpindle1Piece4 = 740,
|
||||
//
|
||||
// 900-999 - reserved for automatic tool changers (ATC)
|
||||
//
|
||||
Setting_SettingsMax,
|
||||
Setting_SettingsAll = Setting_SettingsMax,
|
||||
|
||||
@@ -538,44 +559,6 @@ typedef struct {
|
||||
float pullout_increment; // Spindle pull-out and plunge distance in mm. Incremental distance.
|
||||
} parking_settings_t;
|
||||
|
||||
typedef struct {
|
||||
float p_gain;
|
||||
float i_gain;
|
||||
float d_gain;
|
||||
float p_max_error;
|
||||
float i_max_error;
|
||||
float d_max_error;
|
||||
float deadband;
|
||||
float max_error;
|
||||
} pid_values_t;
|
||||
|
||||
typedef union {
|
||||
uint8_t value;
|
||||
uint8_t mask;
|
||||
struct {
|
||||
uint8_t enable_rpm_controlled :1, // PWM spindle only
|
||||
unused :1,
|
||||
type :5,
|
||||
pwm_disable :1; // PWM spindle only
|
||||
};
|
||||
} spindle_settings_flags_t;
|
||||
|
||||
typedef struct {
|
||||
float rpm_max;
|
||||
float rpm_min;
|
||||
float pwm_freq;
|
||||
float pwm_period;
|
||||
float pwm_off_value;
|
||||
float pwm_min_value;
|
||||
float pwm_max_value;
|
||||
float at_speed_tolerance;
|
||||
pwm_piece_t pwm_piece[SPINDLE_NPWM_PIECES];
|
||||
pid_values_t pid;
|
||||
uint16_t ppr; // Spindle encoder pulses per revolution
|
||||
spindle_state_t invert;
|
||||
spindle_settings_flags_t flags;
|
||||
} spindle_settings_t;
|
||||
|
||||
typedef struct {
|
||||
pid_values_t pid;
|
||||
} position_pid_t; // Used for synchronized motion
|
||||
@@ -657,6 +640,16 @@ typedef struct {
|
||||
// axes_signals_t soft_enabled; // TODO: add per axis soft limits, replace soft_enabled flag
|
||||
} limit_settings_t;
|
||||
|
||||
typedef union {
|
||||
uint8_t value;
|
||||
uint8_t mask;
|
||||
struct {
|
||||
uint8_t sd_mount_on_boot :1,
|
||||
lfs_hidden :1,
|
||||
unused :6;
|
||||
};
|
||||
} fs_options_t;
|
||||
|
||||
typedef union {
|
||||
uint8_t value;
|
||||
uint8_t mask;
|
||||
@@ -664,7 +657,7 @@ typedef union {
|
||||
uint8_t g59_1 :1,
|
||||
g59_2 :1,
|
||||
g59_3 :1,
|
||||
unused :5;
|
||||
encoder_spindle :5; // TODO: move to spindle settings
|
||||
};
|
||||
} offset_lock_t;
|
||||
|
||||
@@ -728,13 +721,14 @@ typedef struct {
|
||||
reportmask_t status_report; // Mask to indicate desired report data.
|
||||
settingflags_t flags; // Contains default boolean settings
|
||||
probeflags_t probe;
|
||||
offset_lock_t offset_lock;
|
||||
fs_options_t fs_options;
|
||||
homing_settings_t homing;
|
||||
limit_settings_t limits;
|
||||
parking_settings_t parking;
|
||||
safety_door_settings_t safety_door;
|
||||
position_pid_t position; // Used for synchronized motion
|
||||
ioport_signals_t ioport;
|
||||
// offset_lock_t offset_lock; // TODO: add in next settings version.
|
||||
} settings_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -961,12 +955,6 @@ void settings_write_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]
|
||||
// Reads selected coordinate data from persistent storage
|
||||
bool settings_read_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]);
|
||||
|
||||
// Writes selected tool data to persistent storage
|
||||
bool settings_write_tool_data (tool_data_t *tool_data);
|
||||
|
||||
// Read selected tool data from persistent storage
|
||||
bool settings_read_tool_data (uint32_t tool, tool_data_t *tool_data);
|
||||
|
||||
// Temporarily override acceleration, if 0 restore to configured setting value
|
||||
bool settings_override_acceleration (uint8_t axis, float acceleration);
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ static bool spindle_activate (spindle_id_t spindle_id, spindle_num_t spindle_num
|
||||
}
|
||||
|
||||
if((pwm_spindle->init_ok = pwm_spindle->hal.config == NULL || pwm_spindle->hal.config(&pwm_spindle->hal)))
|
||||
pwm_spindle->hal.set_state((spindle_state_t){0}, 0.0f);
|
||||
pwm_spindle->hal.set_state(&pwm_spindle->hal, (spindle_state_t){0}, 0.0f);
|
||||
}
|
||||
pwm_spindle = NULL;
|
||||
|
||||
@@ -97,10 +97,17 @@ static bool spindle_activate (spindle_id_t spindle_id, spindle_num_t spindle_num
|
||||
memcpy(&spindle_hal, &spindle->hal, sizeof(spindle_ptrs_t));
|
||||
|
||||
if(spindle->cfg->get_data == NULL) {
|
||||
if(settings.offset_lock.encoder_spindle == spindle_id) {
|
||||
spindle_hal.get_data = hal.spindle_data.get;
|
||||
spindle_hal.reset_data = hal.spindle_data.reset;
|
||||
if(!spindle->cfg->cap.at_speed)
|
||||
spindle_hal.cap.at_speed = !!spindle_hal.get_data;
|
||||
} else {
|
||||
spindle_hal.get_data = NULL;
|
||||
spindle_hal.reset_data = NULL;
|
||||
if(!spindle->cfg->cap.at_speed)
|
||||
spindle_hal.cap.at_speed = Off;
|
||||
}
|
||||
}
|
||||
|
||||
spindle_hal.cap.laser &= settings.mode == Mode_Laser;
|
||||
@@ -134,6 +141,9 @@ __NOTE:__ up to \ref N_SPINDLE spindles can be registered at a time.
|
||||
*/
|
||||
spindle_id_t spindle_register (const spindle_ptrs_t *spindle, const char *name)
|
||||
{
|
||||
if(n_spindle == 1 && spindles[0].cfg->type == SpindleType_Null)
|
||||
n_spindle = 0;
|
||||
|
||||
if(n_spindle < N_SPINDLE && settings_add_spindle_type(name)) {
|
||||
|
||||
spindles[n_spindle].cfg = spindle;
|
||||
@@ -323,9 +333,9 @@ bool spindle_enumerate_spindles (spindle_enumerate_callback_ptr callback, void *
|
||||
|
||||
spindle.id = idx;
|
||||
spindle.name = spindles[idx].name;
|
||||
spindle.hal = &spindles[idx].hal;
|
||||
spindle.num = spindle_get_num(idx);
|
||||
spindle.enabled = spindle.num != -1;
|
||||
spindle.hal = spindle.enabled && sys_spindle[spindle.num].hal.id == spindle.id ? &sys_spindle[spindle.num].hal : &spindles[idx].hal;
|
||||
spindle.is_current = spindle.enabled && sys_spindle[0].hal.id == idx;
|
||||
|
||||
callback(&spindle, data);
|
||||
@@ -366,32 +376,38 @@ spindle_ptrs_t *spindle_get (spindle_num_t spindle_num)
|
||||
// Null (dummy) spindle, automatically installed if no spindles are registered.
|
||||
//
|
||||
|
||||
static void null_set_state (spindle_state_t state, float rpm)
|
||||
static void null_set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
|
||||
{
|
||||
UNUSED(spindle);
|
||||
UNUSED(state);
|
||||
UNUSED(rpm);
|
||||
}
|
||||
|
||||
static spindle_state_t null_get_state (void)
|
||||
static spindle_state_t null_get_state (spindle_ptrs_t *spindle)
|
||||
{
|
||||
UNUSED(spindle);
|
||||
|
||||
return (spindle_state_t){0};
|
||||
}
|
||||
|
||||
// Sets spindle speed
|
||||
static void null_update_pwm (uint_fast16_t pwm_value)
|
||||
static void null_update_pwm (spindle_ptrs_t *spindle, uint_fast16_t pwm_value)
|
||||
{
|
||||
UNUSED(spindle);
|
||||
UNUSED(pwm_value);
|
||||
}
|
||||
|
||||
static uint_fast16_t null_get_pwm (float rpm)
|
||||
static uint_fast16_t null_get_pwm (spindle_ptrs_t *spindle, float rpm)
|
||||
{
|
||||
UNUSED(spindle);
|
||||
UNUSED(rpm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void null_update_rpm (float rpm)
|
||||
static void null_update_rpm (spindle_ptrs_t *spindle, float rpm)
|
||||
{
|
||||
UNUSED(spindle);
|
||||
UNUSED(rpm);
|
||||
}
|
||||
|
||||
@@ -478,14 +494,14 @@ static bool set_state (spindle_ptrs_t *spindle, spindle_state_t state, float rpm
|
||||
|
||||
if (!state.on) { // Halt or set spindle direction and rpm.
|
||||
spindle->param->rpm = rpm = 0.0f;
|
||||
spindle->set_state((spindle_state_t){0}, 0.0f);
|
||||
spindle->set_state(spindle, (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 (spindle->cap.laser && state.ccw)
|
||||
rpm = 0.0f; // TODO: May need to be rpm_min*(100/MAX_SPINDLE_RPM_OVERRIDE);
|
||||
|
||||
spindle->set_state(state, spindle_set_rpm(spindle, rpm, spindle->param->override_pct));
|
||||
spindle->set_state(spindle, state, spindle_set_rpm(spindle, rpm, spindle->param->override_pct));
|
||||
}
|
||||
|
||||
system_add_rt_report(Report_Spindle); // Set to report change immediately
|
||||
@@ -529,7 +545,7 @@ bool spindle_sync (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
|
||||
// Empty planner buffer to ensure spindle is set when programmed.
|
||||
if((ok = protocol_buffer_synchronize()) && set_state(spindle, state, rpm) && !at_speed) {
|
||||
float on_delay = 0.0f;
|
||||
while(!(at_speed = spindle->get_state().at_speed)) {
|
||||
while(!(at_speed = spindle->get_state(spindle).at_speed)) {
|
||||
delay_sec(0.2f, DelayMode_Dwell);
|
||||
on_delay += 0.2f;
|
||||
if(ABORTED)
|
||||
@@ -567,7 +583,7 @@ bool spindle_restore (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
|
||||
delay_sec(settings.safety_door.spindle_on_delay, DelayMode_SysSuspend);
|
||||
else if((ok == (settings.spindle.at_speed_tolerance <= 0.0f))) {
|
||||
float delay = 0.0f;
|
||||
while(!(ok = spindle->get_state().at_speed)) {
|
||||
while(!(ok = spindle->get_state(spindle).at_speed)) {
|
||||
delay_sec(0.1f, DelayMode_SysSuspend);
|
||||
delay += 0.1f;
|
||||
if(ABORTED)
|
||||
@@ -620,9 +636,9 @@ void spindle_all_off (void)
|
||||
spindle->param->rpm = spindle->param->rpm_overridden = 0.0f;
|
||||
spindle->param->state.value = 0;
|
||||
#ifdef GRBL_ESP32
|
||||
spindle->esp32_off();
|
||||
spindle->esp32_off(spindle);
|
||||
#else
|
||||
spindle->set_state((spindle_state_t){0}, 0.0f);
|
||||
spindle->set_state(spindle, (spindle_state_t){0}, 0.0f);
|
||||
#endif
|
||||
}
|
||||
} while(spindle_num);
|
||||
@@ -639,7 +655,7 @@ bool spindle_is_on (void)
|
||||
uint_fast8_t spindle_num = N_SYS_SPINDLE;
|
||||
do {
|
||||
if((spindle = spindle_get(--spindle_num)))
|
||||
on = spindle->get_state().on;
|
||||
on = spindle->get_state(spindle).on;
|
||||
} while(spindle_num && !on);
|
||||
|
||||
return on;
|
||||
@@ -659,43 +675,6 @@ static inline uint_fast16_t invert_pwm (spindle_pwm_t *pwm_data, uint_fast16_t p
|
||||
return pwm_data->invert_pwm ? pwm_data->period - pwm_value - 1 : pwm_value;
|
||||
}
|
||||
|
||||
/*! \brief Precompute PWM values for faster conversion.
|
||||
\param spindle pointer to a \ref spindle_ptrs_t structure.
|
||||
\param pwm_data pointer to a \a spindle_pwm_t structure, to hold the precomputed values.
|
||||
\param clock_hz timer clock frequency used for PWM generation.
|
||||
\returns \a true if successful, \a false if no PWM range possible - driver should then revert to simple on/off spindle control.
|
||||
*/
|
||||
bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_data, uint32_t clock_hz)
|
||||
{
|
||||
if(spindle->rpm_max > spindle->rpm_min) {
|
||||
pwm_data->rpm_min = 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) / (spindle->rpm_max - spindle->rpm_min);
|
||||
pwm_data->always_on = settings.spindle.pwm_off_value != 0.0f;
|
||||
}
|
||||
|
||||
#if 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));
|
||||
}
|
||||
|
||||
spindle->cap.pwm_linearization = pwm_data->n_pieces > 0;
|
||||
#endif
|
||||
|
||||
return spindle->rpm_max > spindle->rpm_min;
|
||||
}
|
||||
|
||||
/*! \brief Spindle RPM to PWM conversion.
|
||||
\param pwm_data pointer t a \a spindle_pwm_t structure.
|
||||
\param rpm spindle RPM.
|
||||
@@ -705,7 +684,7 @@ bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_
|
||||
__NOTE:__ \a spindle_precompute_pwm_values() must be called to precompute values before this function is called.
|
||||
Typically this is done by the spindle initialization code.
|
||||
*/
|
||||
uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, bool pid_limit)
|
||||
static uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, bool pid_limit)
|
||||
{
|
||||
uint_fast16_t pwm_value;
|
||||
|
||||
@@ -738,3 +717,63 @@ uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, boo
|
||||
|
||||
return pwm_value;
|
||||
}
|
||||
|
||||
/*! \internal \brief Dummy spindle RPM to PWM conversion, used if precompute fails.
|
||||
\param pwm_data pointer t a \a spindle_pwm_t structure.
|
||||
\param rpm spindle RPM.
|
||||
\param pid_limit boolean, \a true if PID based spindle sync is used, \a false otherwise.
|
||||
\returns the PWM value to use.
|
||||
*/
|
||||
static uint_fast16_t compute_dummy_pwm_value (spindle_pwm_t *pwm_data, float rpm, bool pid_limit)
|
||||
{
|
||||
return pwm_data->off_value;
|
||||
}
|
||||
|
||||
/*! \brief Precompute PWM values for faster conversion.
|
||||
\param spindle pointer to a \ref spindle_ptrs_t structure.
|
||||
\param pwm_data pointer to a \a spindle_pwm_t structure, to hold the precomputed values.
|
||||
\param clock_hz timer clock frequency used for PWM generation.
|
||||
\returns \a true if successful, \a false if no PWM range possible - driver should then revert to simple on/off spindle control.
|
||||
*/
|
||||
bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_data, spindle_settings_t *settings, uint32_t clock_hz)
|
||||
{
|
||||
pwm_data->settings = settings;
|
||||
spindle->rpm_min = pwm_data->rpm_min = settings->rpm_min;
|
||||
spindle->rpm_max = settings->rpm_max;
|
||||
spindle->cap.rpm_range_locked = On;
|
||||
|
||||
if((spindle->cap.variable = !settings->flags.pwm_disable && spindle->rpm_max > spindle->rpm_min)) {
|
||||
pwm_data->f_clock = clock_hz;
|
||||
pwm_data->period = (uint_fast16_t)((float)clock_hz / settings->pwm_freq);
|
||||
if(settings->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->pwm_off_value / 100.0f));
|
||||
pwm_data->min_value = (uint_fast16_t)(pwm_data->period * settings->pwm_min_value / 100.0f);
|
||||
pwm_data->max_value = (uint_fast16_t)(pwm_data->period * settings->pwm_max_value / 100.0f) + pwm_data->offset;
|
||||
pwm_data->pwm_gradient = (float)(pwm_data->max_value - pwm_data->min_value) / (spindle->rpm_max - spindle->rpm_min);
|
||||
pwm_data->always_on = settings->pwm_off_value != 0.0f;
|
||||
pwm_data->compute_value = spindle_compute_pwm_value;
|
||||
} else {
|
||||
pwm_data->off_value = 0;
|
||||
pwm_data->always_on = false;
|
||||
pwm_data->compute_value = compute_dummy_pwm_value;
|
||||
}
|
||||
|
||||
spindle->context = pwm_data;
|
||||
|
||||
#if ENABLE_SPINDLE_LINEARIZATION
|
||||
uint_fast8_t idx;
|
||||
|
||||
pwm_data->n_pieces = 0;
|
||||
|
||||
for(idx = 0; idx < SPINDLE_NPWM_PIECES; idx++) {
|
||||
if(!isnan(settings->pwm_piece[idx].rpm) && settings->pwm_piece[idx].start != 0.0f)
|
||||
memcpy(&pwm_data->piece[pwm_data->n_pieces++], &settings->pwm_piece[idx], sizeof(pwm_piece_t));
|
||||
}
|
||||
|
||||
spindle->cap.pwm_linearization = pwm_data->n_pieces > 0;
|
||||
#endif
|
||||
|
||||
return spindle->cap.variable;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,32 @@
|
||||
#ifndef _SPINDLE_CONTROL_H_
|
||||
#define _SPINDLE_CONTROL_H_
|
||||
|
||||
#include "pid.h"
|
||||
|
||||
#define SPINDLE_ALL -1
|
||||
#define SPINDLE_NONE 0
|
||||
#define SPINDLE_HUANYANG1 1
|
||||
#define SPINDLE_HUANYANG2 2
|
||||
#define SPINDLE_GS20 3
|
||||
#define SPINDLE_YL620A 4
|
||||
#define SPINDLE_MODVFD 5
|
||||
#define SPINDLE_H100 6
|
||||
#define SPINDLE_ONOFF0 7 // typically implemented by driver.c
|
||||
#define SPINDLE_ONOFF0_DIR 8 // typically implemented by driver.c
|
||||
#define SPINDLE_ONOFF1 9
|
||||
#define SPINDLE_ONOFF1_DIR 10
|
||||
#define SPINDLE_PWM0 11 // typically implemented by driver.c
|
||||
#define SPINDLE_PWM0_NODIR 12 // typically implemented by driver.c
|
||||
#define SPINDLE_PWM1 13 // typically implemented by driver.c
|
||||
#define SPINDLE_PWM1_NODIR 14
|
||||
#define SPINDLE_PWM2 15
|
||||
#define SPINDLE_PWM2_NODIR 16
|
||||
#define SPINDLE_PWM0_CLONE 17
|
||||
#define SPINDLE_SOLENOID 18
|
||||
#define SPINDLE_STEPPER 19
|
||||
#define SPINDLE_NOWFOREVER 20
|
||||
#define SPINDLE_MY_SPINDLE 30
|
||||
|
||||
typedef int8_t spindle_id_t;
|
||||
typedef int8_t spindle_num_t;
|
||||
|
||||
@@ -45,16 +71,19 @@ typedef union {
|
||||
|
||||
/*! \brief Bitmap flags for spindle capabilities. */
|
||||
typedef union {
|
||||
uint8_t value; //!< All bitmap flags.
|
||||
uint16_t value; //!< All bitmap flags.
|
||||
struct {
|
||||
uint8_t variable :1, //!< Variable spindle speed is supported.
|
||||
uint16_t variable :1, //!< Variable spindle speed is supported.
|
||||
direction :1, //!< Spindle direction (M4) is supported.
|
||||
at_speed :1, //!< Spindle at speed feedback is supported.
|
||||
laser :1, //!< Spindle can control a laser.
|
||||
pwm_invert :1, //!< Spindle PWM output can be inverted.
|
||||
pid :1,
|
||||
pwm_linearization :1,
|
||||
rpm_range_locked :1; //!< Spindle RPM range (min, max) not inherited from settings.
|
||||
rpm_range_locked :1, //!< Spindle RPM range (min, max) not inherited from settings.
|
||||
gpio_controlled :1, //!< On/off and direction is controlled by GPIO.
|
||||
cmd_controlled :1, //!< Command controlled, e.g. over ModBus.
|
||||
unassigned :6;
|
||||
};
|
||||
} spindle_cap_t;
|
||||
|
||||
@@ -92,16 +121,26 @@ typedef enum {
|
||||
SpindleHAL_Active, //!< 2
|
||||
} spindle_hal_t;
|
||||
|
||||
struct spindle_ptrs; // members defined below
|
||||
struct spindle_pwm; // members defined below
|
||||
struct spindle_param; // members defined below
|
||||
|
||||
/*! \brief Pointer to function for configuring a spindle.
|
||||
\param spindle a pointer to a \ref spindle_struct.
|
||||
\returns \a true if successful, \false if not.
|
||||
*/
|
||||
typedef bool (*spindle_config_ptr)(struct spindle_ptrs *spindle);
|
||||
|
||||
/*! \brief Pointer to function for setting the spindle state.
|
||||
\param state a \a spindle_state_t union variable.
|
||||
\param rpm spindle RPM.
|
||||
*/
|
||||
typedef void (*spindle_set_state_ptr)(spindle_state_t state, float rpm);
|
||||
typedef void (*spindle_set_state_ptr)(struct spindle_ptrs *spindle, spindle_state_t state, float rpm);
|
||||
|
||||
/*! \brief Pointer to function for getting the spindle state.
|
||||
\returns state in a \a spindle_state_t union variable.
|
||||
*/
|
||||
typedef spindle_state_t (*spindle_get_state_ptr)(void);
|
||||
typedef spindle_state_t (*spindle_get_state_ptr)(struct spindle_ptrs *spindle);
|
||||
|
||||
/*! \brief Pointer to function for converting a RPM value to a PWM value.
|
||||
|
||||
@@ -110,7 +149,7 @@ Typically this is a wrapper for the spindle_compute_pwm_value() function provide
|
||||
\param rpm spindle RPM.
|
||||
\returns the corresponding PWM value.
|
||||
*/
|
||||
typedef uint_fast16_t (*spindle_get_pwm_ptr)(float rpm);
|
||||
typedef uint_fast16_t (*spindle_get_pwm_ptr)(struct spindle_ptrs *spindle, float rpm);
|
||||
|
||||
/*! \brief Pointer to function for updating spindle speed on the fly.
|
||||
\param pwm new spindle PWM value.
|
||||
@@ -118,13 +157,12 @@ typedef uint_fast16_t (*spindle_get_pwm_ptr)(float rpm);
|
||||
|
||||
__NOTE:__ this function will be called from an interrupt context.
|
||||
*/
|
||||
typedef void (*spindle_update_pwm_ptr)(uint_fast16_t pwm);
|
||||
|
||||
typedef void (*spindle_update_pwm_ptr)(struct spindle_ptrs *spindle, uint_fast16_t pwm);
|
||||
|
||||
/*! \brief Pointer to function for updating spindle RPM.
|
||||
\param rpm spindle RPM.
|
||||
*/
|
||||
typedef void (*spindle_update_rpm_ptr)(float rpm);
|
||||
typedef void (*spindle_update_rpm_ptr)(struct spindle_ptrs *spindle, float rpm);
|
||||
|
||||
/*! \brief Pointer to function for getting spindle data.
|
||||
\param request request type as a \a #spindle_data_request_t enum.
|
||||
@@ -143,25 +181,25 @@ Used for Pulses Per Inch (PPI) laser mode.
|
||||
*/
|
||||
typedef void (*spindle_pulse_on_ptr)(uint_fast16_t pulse_length);
|
||||
|
||||
struct spindle_param; // members defined below
|
||||
|
||||
/*! \brief Handlers and data for spindle support. */
|
||||
struct spindle_ptrs {
|
||||
spindle_id_t id; //!< Spindle id, assingned on spindle registration .
|
||||
spindle_id_t id; //!< Spindle id, assingned on spindle registration.
|
||||
struct spindle_param *param; //!< Pointer to current spindle parameters, assigned when spindle is enabled.
|
||||
spindle_type_t type; //!< Spindle type.
|
||||
spindle_cap_t cap; //!< Spindle capabilities.
|
||||
void *context; //!< Optional pointer to spindle specific context data.
|
||||
uint_fast16_t pwm_off_value; //!< Value for switching PWM signal off.
|
||||
// struct spindle_pwm *pwm_data; //!< Optional pointer to PWM configuration.
|
||||
float rpm_min; //!< Minimum spindle RPM.
|
||||
float rpm_max; //!< Maximum spindle RPM.
|
||||
bool (*config)(struct spindle_ptrs *spindle); //!< Optional handler for configuring the spindle.
|
||||
spindle_config_ptr config; //!< Optional handler for configuring the spindle.
|
||||
spindle_set_state_ptr set_state; //!< Handler for setting spindle state.
|
||||
spindle_get_state_ptr get_state; //!< Handler for getting spindle state.
|
||||
spindle_get_pwm_ptr get_pwm; //!< Handler for calculating spindle PWM value from RPM.
|
||||
spindle_update_pwm_ptr update_pwm; //!< Handler for updating spindle PWM output.
|
||||
spindle_update_rpm_ptr update_rpm; //!< Handler for updating spindle RPM.
|
||||
#ifdef GRBL_ESP32
|
||||
void (*esp32_off)(void); //!< Workaround handler for snowflake ESP32 Guru awaken by floating point data in ISR context.
|
||||
void (*esp32_off)(struct spindle_ptrs *spindle); //!< Workaround handler for snowflake ESP32 Guru awaken by floating point data in ISR context.
|
||||
#endif
|
||||
// Optional entry points.
|
||||
spindle_pulse_on_ptr pulse_on; //!< Optional handler for Pulses Per Inch (PPI) mode. Required for the laser PPI plugin.
|
||||
@@ -196,11 +234,6 @@ typedef struct {
|
||||
spindle_reset_data_ptr reset; //!< Optional handler for resetting spindle data. Required for spindle sync.
|
||||
} spindle_data_ptrs_t;
|
||||
|
||||
/*! \brief Pointer to function for configuring the spindle.
|
||||
\returns state in a \a spindle_state_t union variable.
|
||||
*/
|
||||
typedef bool (*spindle_config_ptr)(spindle_ptrs_t *spindle);
|
||||
|
||||
/*! \brief Structure holding data passed to the callback function called by spindle_enumerate_spindles(). */
|
||||
typedef struct {
|
||||
spindle_id_t id;
|
||||
@@ -217,8 +250,37 @@ typedef struct {
|
||||
float end;
|
||||
} pwm_piece_t;
|
||||
|
||||
//!* \brief Precalculated values that may be set/used by HAL driver to speed up RPM to PWM conversions if variable spindle is supported. */
|
||||
typedef union {
|
||||
uint8_t value;
|
||||
uint8_t mask;
|
||||
struct {
|
||||
uint8_t enable_rpm_controlled :1, // PWM spindle only
|
||||
unused :1,
|
||||
type :5,
|
||||
pwm_disable :1; // PWM spindle only
|
||||
};
|
||||
} spindle_settings_flags_t;
|
||||
|
||||
typedef struct {
|
||||
float rpm_max;
|
||||
float rpm_min;
|
||||
float pwm_freq;
|
||||
float pwm_period; // currently unused
|
||||
float pwm_off_value;
|
||||
float pwm_min_value;
|
||||
float pwm_max_value;
|
||||
float at_speed_tolerance;
|
||||
pwm_piece_t pwm_piece[SPINDLE_NPWM_PIECES];
|
||||
pid_values_t pid;
|
||||
uint16_t ppr; // Spindle encoder pulses per revolution
|
||||
spindle_state_t invert;
|
||||
spindle_settings_flags_t flags;
|
||||
} spindle_settings_t;
|
||||
|
||||
//!* \brief Precalculated values that may be set/used by HAL driver to speed up RPM to PWM conversions if variable spindle is supported. */
|
||||
typedef struct spindle_pwm {
|
||||
uint32_t f_clock;
|
||||
spindle_settings_t *settings;
|
||||
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;
|
||||
@@ -227,9 +289,11 @@ typedef struct {
|
||||
float pwm_gradient;
|
||||
bool invert_pwm; //!< NOTE: set (by driver) when inversion is done in code
|
||||
bool always_on;
|
||||
bool cloned;
|
||||
int_fast16_t offset;
|
||||
uint_fast16_t n_pieces;
|
||||
pwm_piece_t piece[SPINDLE_NPWM_PIECES];
|
||||
uint_fast16_t (*compute_value)(struct spindle_pwm *pwm_data, float rpm, bool pid_limit);
|
||||
} spindle_pwm_t;
|
||||
|
||||
/*! \brief Pointer to callback function called by spindle_enumerate_spindles().
|
||||
@@ -257,9 +321,7 @@ void spindle_all_off (void);
|
||||
// The following functions are not called by the core, may be called by driver code.
|
||||
//
|
||||
|
||||
bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_data, uint32_t clock_hz);
|
||||
|
||||
uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, bool pid_limit);
|
||||
bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_data, spindle_settings_t *settings, uint32_t clock_hz);
|
||||
|
||||
spindle_id_t spindle_register (const spindle_ptrs_t *spindle, const char *name);
|
||||
|
||||
|
||||
@@ -378,7 +378,7 @@ void state_suspend_manager (void)
|
||||
grbl.on_override_changed(OverrideChanged_SpindleState);
|
||||
}
|
||||
|
||||
} else if (sys.step_control.update_spindle_rpm && restore_condition.spindle[0].hal->get_state().on) {
|
||||
} else if (sys.step_control.update_spindle_rpm && restore_condition.spindle[0].hal->get_state(restore_condition.spindle[0].hal).on) {
|
||||
// Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state.
|
||||
state_spindle_set_state(&restore_condition.spindle[restore_condition.spindle_num]);
|
||||
sys.step_control.update_spindle_rpm = Off;
|
||||
@@ -654,12 +654,12 @@ static void state_await_resume (uint_fast16_t rt_exec)
|
||||
|
||||
default:
|
||||
if (!settings.flags.restore_after_feed_hold) {
|
||||
if (!restore_condition.spindle[restore_condition.spindle_num].hal->get_state().on)
|
||||
if (!restore_condition.spindle[restore_condition.spindle_num].hal->get_state(restore_condition.spindle[restore_condition.spindle_num].hal).on)
|
||||
gc_spindle_off();
|
||||
sys.override.spindle_stop.value = 0; // Clear spindle stop override states
|
||||
} else {
|
||||
|
||||
if (restore_condition.spindle[restore_condition.spindle_num].state.on != restore_condition.spindle[restore_condition.spindle_num].hal->get_state().on) {
|
||||
if (restore_condition.spindle[restore_condition.spindle_num].state.on != restore_condition.spindle[restore_condition.spindle_num].hal->get_state(restore_condition.spindle[restore_condition.spindle_num].hal).on) {
|
||||
grbl.report.feedback_message(Message_SpindleRestore);
|
||||
state_spindle_restore(&restore_condition.spindle[restore_condition.spindle_num]);
|
||||
}
|
||||
@@ -747,7 +747,7 @@ static void state_await_waypoint_retract (uint_fast16_t rt_exec)
|
||||
// NOTE: Clear accessory state after retract and after an aborted restore motion.
|
||||
park.plan_data.spindle.state.value = 0;
|
||||
park.plan_data.spindle.rpm = 0.0f;
|
||||
park.plan_data.spindle.hal->set_state(park.plan_data.spindle.state, 0.0f); // De-energize
|
||||
park.plan_data.spindle.hal->set_state(park.plan_data.spindle.hal, park.plan_data.spindle.state, 0.0f); // De-energize
|
||||
|
||||
if (!settings.safety_door.flags.keep_coolant_on) {
|
||||
park.plan_data.condition.coolant.value = 0;
|
||||
|
||||
11
stepper.c
11
stepper.c
@@ -407,16 +407,16 @@ ISR_CODE void ISR_FUNC(stepper_driver_interrupt_handler)(void)
|
||||
#endif
|
||||
|
||||
if(st.exec_segment->update_pwm)
|
||||
st.exec_segment->update_pwm(st.exec_segment->spindle_pwm);
|
||||
st.exec_segment->update_pwm(st.exec_block->spindle, st.exec_segment->spindle_pwm);
|
||||
else if(st.exec_segment->update_rpm)
|
||||
st.exec_segment->update_rpm(st.exec_segment->spindle_rpm);
|
||||
st.exec_segment->update_rpm(st.exec_block->spindle, st.exec_segment->spindle_rpm);
|
||||
} else {
|
||||
// Segment buffer empty. Shutdown.
|
||||
st_go_idle();
|
||||
|
||||
// Ensure pwm is set properly upon completion of rate-controlled motion.
|
||||
if (st.exec_block->dynamic_rpm && st.exec_block->spindle->cap.laser)
|
||||
st.exec_block->spindle->update_pwm(st.exec_block->spindle->pwm_off_value);
|
||||
st.exec_block->spindle->update_pwm(st.exec_block->spindle, st.exec_block->spindle->pwm_off_value);
|
||||
|
||||
st.exec_block = NULL;
|
||||
system_set_exec_state_flag(EXEC_CYCLE_COMPLETE); // Flag main program for cycle complete
|
||||
@@ -732,6 +732,7 @@ void st_prep_buffer (void)
|
||||
// st_prep_block->r = pl_block->programmed_rate;
|
||||
st_prep_block->millimeters = pl_block->millimeters;
|
||||
st_prep_block->steps_per_mm = (float)pl_block->step_event_count / pl_block->millimeters;
|
||||
st_prep_block->spindle = pl_block->spindle.hal;
|
||||
st_prep_block->output_commands = pl_block->output_commands;
|
||||
st_prep_block->overrides = pl_block->overrides;
|
||||
st_prep_block->backlash_motion = pl_block->condition.backlash_motion;
|
||||
@@ -987,8 +988,6 @@ void st_prep_buffer (void)
|
||||
|
||||
float rpm;
|
||||
|
||||
st_prep_block->spindle = pl_block->spindle.hal;
|
||||
|
||||
if (pl_block->spindle.state.on) {
|
||||
if(pl_block->spindle.css) {
|
||||
float npos = (float)(pl_block->step_event_count - prep.steps_remaining) / (float)pl_block->step_event_count;
|
||||
@@ -1011,7 +1010,7 @@ void st_prep_buffer (void)
|
||||
if(pl_block->spindle.hal->get_pwm != NULL) {
|
||||
prep.current_spindle_rpm = rpm;
|
||||
prep_segment->update_pwm = pl_block->spindle.hal->update_pwm;
|
||||
prep_segment->spindle_pwm = pl_block->spindle.hal->get_pwm(rpm);
|
||||
prep_segment->spindle_pwm = pl_block->spindle.hal->get_pwm(pl_block->spindle.hal, rpm);
|
||||
} else {
|
||||
prep_segment->update_rpm = pl_block->spindle.hal->update_rpm;
|
||||
prep.current_spindle_rpm = prep_segment->spindle_rpm = rpm;
|
||||
|
||||
@@ -68,7 +68,7 @@ typedef struct st_segment {
|
||||
bool cruising; //!< True when in cruising part of profile, only set for spindle synced moves
|
||||
uint_fast8_t amass_level; //!< Indicates AMASS level for the ISR to execute this segment
|
||||
spindle_update_pwm_ptr update_pwm; //!< Valid pointer to spindle.update_pwm() if set spindle speed at the start of the segment execution
|
||||
spindle_update_rpm_ptr update_rpm; //!< Valid pointer to spindle.update_rmp() if set spindle speed at the start of the segment execution
|
||||
spindle_update_rpm_ptr update_rpm; //!< Valid pointer to spindle.update_rpm() if set spindle speed at the start of the segment execution
|
||||
} segment_t;
|
||||
|
||||
//! Stepper ISR data struct. Contains the running data for the main stepper ISR.
|
||||
|
||||
300
stepper2.c
300
stepper2.c
@@ -30,17 +30,23 @@
|
||||
#include "stepper2.h"
|
||||
|
||||
typedef enum {
|
||||
State_Idle = 0,
|
||||
State_Accel,
|
||||
State_Run,
|
||||
State_RunInfinite,
|
||||
State_DecelTo,
|
||||
State_Decel
|
||||
State_Idle = 0, //!< 0
|
||||
State_Accel, //!< 1
|
||||
State_Run, //!< 2
|
||||
State_RunInfinite, //!< 3
|
||||
State_DecelTo, //!< 4
|
||||
State_Decel //!< 5
|
||||
} st2_state_t;
|
||||
|
||||
/*! \brief Internal structure for holding motor configuration and keeping track of its status.
|
||||
|
||||
__NOTE:__ The contents of this structure should _not_ be accessed directly by user code.
|
||||
*/
|
||||
struct st2_motor {
|
||||
uint_fast8_t idx;
|
||||
axes_signals_t axis;
|
||||
bool is_spindle;
|
||||
bool position_lost;
|
||||
volatile int64_t position; // absolute step number
|
||||
position_t ptype; //
|
||||
st2_state_t state; // state machine state
|
||||
@@ -49,7 +55,7 @@ struct st2_motor {
|
||||
uint32_t step_run; //
|
||||
uint32_t step_down; // start of down-ramp
|
||||
uint64_t c64; // 24.16 fixed point delay count
|
||||
uint32_t delay; // integer delay count
|
||||
uint64_t delay; // integer delay count
|
||||
uint32_t first_delay; // integer delay count
|
||||
uint16_t min_delay; // integer delay count
|
||||
int32_t denom; // 4.n+1 in ramp algo
|
||||
@@ -58,30 +64,49 @@ struct st2_motor {
|
||||
float prev_speed; // speed steps/s
|
||||
float acceleration; // acceleration steps/s^2
|
||||
axes_signals_t dir; // current direction
|
||||
uint32_t next_step;
|
||||
uint64_t next_step;
|
||||
st2_motor_t *next;
|
||||
};
|
||||
|
||||
static st2_motor_t *motors = NULL;
|
||||
static uint8_t spindle_motors = 0;
|
||||
static settings_changed_ptr settings_changed;
|
||||
static on_set_axis_setting_unit_ptr on_set_axis_setting_unit;
|
||||
static on_setting_get_description_ptr on_setting_get_description;
|
||||
static on_reset_ptr on_reset;
|
||||
|
||||
/*! \brief Calculate basic motor configuration.
|
||||
|
||||
\param motor pointer to a \a st2_motor structure.
|
||||
*/
|
||||
static void st_motor_config (st2_motor_t *motor)
|
||||
{
|
||||
motor->acceleration = settings.axis[motor->idx].acceleration * settings.axis[motor->idx].steps_per_mm / 3600.0f;
|
||||
motor->first_delay = (uint32_t)(0.676f * sqrtf(2.0f / motor->acceleration) * 1000000.0f);
|
||||
}
|
||||
|
||||
/*! \brief Stop all motors.
|
||||
*
|
||||
This will be called on a soft reset and stops all running motors abruptly.
|
||||
|
||||
__NOTE:__ position will likely be lost for running motors.
|
||||
*/
|
||||
static void st2_reset (void)
|
||||
{
|
||||
st2_motor_t *motor = motors;
|
||||
|
||||
while(motor) {
|
||||
motor->position_lost = motor->state != State_Idle;
|
||||
motor->state = State_Idle;
|
||||
motor = motor->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Update basic motor configuration on settings changes.
|
||||
|
||||
\param settings pointer to a \a settings_t structure.
|
||||
\param changed a \a settings_changed_flags_t structure.
|
||||
*/
|
||||
static void st2_settings_changed (settings_t *settings, settings_changed_flags_t changed)
|
||||
{
|
||||
st2_motor_t *motor = motors;
|
||||
@@ -94,18 +119,118 @@ static void st2_settings_changed (settings_t *settings, settings_changed_flags_t
|
||||
}
|
||||
}
|
||||
|
||||
st2_motor_t *st2_motor_init (uint_fast8_t axis_idx)
|
||||
/*! \brief Override default axis settings units for stepper spindle motors.
|
||||
|
||||
\param setting_id id of setting.
|
||||
\param axis_idx axis index, X = 0, Y = 1, Z = 2, ...
|
||||
\returns pointer to new unit string or NULL if no change.
|
||||
*/
|
||||
static const char *st2_set_axis_setting_unit (setting_id_t setting_id, uint_fast8_t axis_idx)
|
||||
{
|
||||
const char *unit = NULL;
|
||||
|
||||
if(bit_istrue(spindle_motors, bit(axis_idx))) switch(setting_id) {
|
||||
|
||||
case Setting_AxisStepsPerMM:
|
||||
unit = "step/rev";
|
||||
break;
|
||||
|
||||
case Setting_AxisMaxRate:
|
||||
unit = "rev/min";
|
||||
break;
|
||||
|
||||
case Setting_AxisAcceleration:
|
||||
unit = "rev/sec^2";
|
||||
break;
|
||||
|
||||
case Setting_AxisMaxTravel:
|
||||
case Setting_AxisBacklash:
|
||||
unit = "--";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return unit == NULL && on_set_axis_setting_unit != NULL
|
||||
? on_set_axis_setting_unit(setting_id, axis_idx)
|
||||
: unit;
|
||||
}
|
||||
|
||||
/*! \brief Override default axis settings descriptions for stepper spindle motors.
|
||||
|
||||
\param setting_id id of setting.
|
||||
\returns pointer to new description string or original string if no change.
|
||||
*/
|
||||
static const char *st2_setting_get_description (setting_id_t id)
|
||||
{
|
||||
uint_fast8_t axis_idx;
|
||||
const char *descr = NULL;
|
||||
|
||||
switch(settings_get_axis_base(id, &axis_idx)) {
|
||||
|
||||
case Setting_AxisStepsPerMM:
|
||||
if(bit_istrue(spindle_motors, bit(axis_idx)))
|
||||
descr = "Stepper resolution in steps per revolution.";
|
||||
break;
|
||||
|
||||
case Setting_AxisMaxRate:
|
||||
if(bit_istrue(spindle_motors, bit(axis_idx)))
|
||||
descr = "Max RPM for stepper spindle.";
|
||||
break;
|
||||
|
||||
case Setting_AxisAcceleration:
|
||||
if(bit_istrue(spindle_motors, bit(axis_idx)))
|
||||
descr = "Acceleration in revolutions/sec^2.";
|
||||
break;
|
||||
|
||||
case Setting_AxisBacklash:
|
||||
case Setting_AxisMaxTravel:
|
||||
if(bit_istrue(spindle_motors, bit(axis_idx)))
|
||||
descr = "This setting is ignored for stepper spindles.";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return descr ? descr
|
||||
: (on_setting_get_description ? on_setting_get_description(id) : NULL);
|
||||
}
|
||||
|
||||
/*! \brief Bind and initialize a motor.
|
||||
|
||||
Allocates and initializes motor configuration/data structure.
|
||||
If \a is_spindle is set \a true then axis settings will be changed to step/rev etc.
|
||||
<br>__NOTE:__ X, Y or Z motor cannot be bound as a spindle.
|
||||
<br>__NOTE:__ currently any axis bound as a spindle should not be instructed to move via gcode commands.
|
||||
\param axis_idx axis index of motor to bind to. 0 = X, 1 = Y, 2 = Z, ...
|
||||
\param is_spindle set to \a true if axis is to be used as a spindle (infinite motion).
|
||||
\returns pointer to a \a st2_motor structure if successful, \a NULL if not.
|
||||
*/
|
||||
st2_motor_t *st2_motor_init (uint_fast8_t axis_idx, bool is_spindle)
|
||||
{
|
||||
st2_motor_t *motor, *new = motors;
|
||||
|
||||
if((motor = malloc(sizeof(st2_motor_t)))) {
|
||||
if((motor = calloc(sizeof(st2_motor_t), 1))) {
|
||||
|
||||
memset(motor, 0, sizeof(st2_motor_t));
|
||||
motor->idx = axis_idx;
|
||||
motor->axis.mask = 1 << axis_idx;
|
||||
motor->is_spindle = is_spindle;
|
||||
|
||||
st_motor_config(motor);
|
||||
|
||||
if(motor->is_spindle) {
|
||||
|
||||
spindle_motors |= motor->axis.mask;
|
||||
|
||||
on_set_axis_setting_unit = grbl.on_set_axis_setting_unit;
|
||||
grbl.on_set_axis_setting_unit = st2_set_axis_setting_unit;
|
||||
|
||||
on_setting_get_description = grbl.on_setting_get_description;
|
||||
grbl.on_setting_get_description = st2_setting_get_description;
|
||||
}
|
||||
|
||||
if(new == NULL) {
|
||||
motors = motor;
|
||||
|
||||
@@ -125,6 +250,14 @@ st2_motor_t *st2_motor_init (uint_fast8_t axis_idx)
|
||||
return motor;
|
||||
}
|
||||
|
||||
/*! \brief Set speed.
|
||||
|
||||
Change speed of a running motor. Typically used for motors bound as a spindle.
|
||||
Motor will be accelerated or decelerated to the new speed.
|
||||
\param motor pointer to a \a st2_motor structure.
|
||||
\param speed new speed.
|
||||
\returns new speed in steps/s.
|
||||
*/
|
||||
float st2_motor_set_speed (st2_motor_t *motor, float speed)
|
||||
{
|
||||
motor->speed = speed > settings.axis[motor->idx].max_rate ? settings.axis[motor->idx].max_rate : speed;
|
||||
@@ -134,7 +267,7 @@ float st2_motor_set_speed (st2_motor_t *motor, float speed)
|
||||
return motor->speed;
|
||||
|
||||
motor->min_delay = (uint32_t)(1000000.0f / motor->speed);
|
||||
motor->n = (uint32_t)(motor->speed * motor->speed) / (2.0f * motor->acceleration);
|
||||
motor->n = (uint32_t)((motor->speed * motor->speed) / (2.0f * motor->acceleration));
|
||||
|
||||
if(motor->n == 0)
|
||||
motor->n = 1;
|
||||
@@ -183,6 +316,18 @@ float st2_motor_set_speed (st2_motor_t *motor, float speed)
|
||||
return motor->prev_speed;
|
||||
}
|
||||
|
||||
/*! \brief Command a motor to move.
|
||||
|
||||
__NOTE:__ For all motions except single steps st2_motor_run() has to be called from
|
||||
the foreground process at a high frequency in order for steps to be generated.
|
||||
Typically this is done by registering a function with the hal.on_execute_realtime event
|
||||
that calls st2_motor_run().
|
||||
\param motor pointer to a \a st2_motor structure.
|
||||
\param move relative distance to move.
|
||||
\param speed speed
|
||||
\param type a #position_t enum.
|
||||
\returns \a true if command is accepted, \a false if not.
|
||||
*/
|
||||
bool st2_motor_move (st2_motor_t *motor, const float move, const float speed, position_t type)
|
||||
{
|
||||
bool dir = move < 0.0f;
|
||||
@@ -198,55 +343,48 @@ bool st2_motor_move (st2_motor_t *motor, const float move, const float speed, po
|
||||
switch(type) {
|
||||
|
||||
case Stepper2_Steps:
|
||||
motor->move = (uint32_t)fabs((int32_t)move);
|
||||
break;
|
||||
|
||||
case Stepper2_InfiniteSteps:
|
||||
motor->move = (uint32_t)fabs((int32_t)move);
|
||||
motor->move = (uint32_t)fabsf(move);
|
||||
break;
|
||||
|
||||
case Stepper2_mm:
|
||||
motor->move = (uint32_t)fabs(move * settings.axis[motor->idx].steps_per_mm);
|
||||
|
||||
motor->move = (uint32_t)lroundf(fabsf(move * settings.axis[motor->idx].steps_per_mm));
|
||||
break;
|
||||
}
|
||||
|
||||
st2_motor_set_speed(motor, speed);
|
||||
|
||||
motor->step_no = 0; // step counter
|
||||
if(motor->move == 1 && type == Stepper2_Steps) {
|
||||
if(motor->state == State_Idle) {
|
||||
|
||||
if(type == Stepper2_InfiniteSteps) {
|
||||
|
||||
motor->state = State_Accel;
|
||||
motor->step_run = motor->n;
|
||||
motor->step_down = motor->n + 1;
|
||||
motor->delay = motor->first_delay;
|
||||
motor->c64 = ((uint32_t)motor->delay) << 16; // keep delay in 24.16 fixed-point format for ramp calcs
|
||||
motor->denom = 1; // 4.n + 1, n = 0
|
||||
motor->next_step = hal.get_micros();
|
||||
} else if(motor->move == 1) {
|
||||
|
||||
motor->step_run = 1;
|
||||
motor->step_down = 1;
|
||||
motor->delay = motor->first_delay;
|
||||
motor->c64 = ((uint32_t)motor->delay) << 8; // keep delay in 24.16 fixed-point format for ramp calcs
|
||||
motor->denom = 1; // 4.n + 1, n = 0
|
||||
if(motor->dir.mask)
|
||||
motor->position--;
|
||||
else
|
||||
motor->position++;
|
||||
|
||||
hal.stepper.output_step(motor->axis, motor->dir);
|
||||
}
|
||||
|
||||
return motor->state == State_Idle;
|
||||
}
|
||||
|
||||
if(type == Stepper2_InfiniteSteps) {
|
||||
motor->step_run = motor->n;
|
||||
motor->step_down = motor->n + 1;
|
||||
} else if(motor->move != 0) {
|
||||
|
||||
motor->state = State_Accel;
|
||||
motor->step_run = (motor->move - ((motor->move & 0x0001) ? 1 : 0)) >> 1;
|
||||
if(motor->step_run > motor->n)
|
||||
motor->step_run = motor->n;
|
||||
motor->step_down = motor->move - motor->step_run;
|
||||
motor->delay = motor->first_delay;
|
||||
motor->c64 = ((uint32_t)motor->delay) << 8; // keep delay in 24.16 fixed-point format for ramp calcs
|
||||
motor->denom = 1; // 4.n + 1, n = 0
|
||||
motor->next_step = hal.get_micros();
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
|
||||
motor->state = State_Accel;
|
||||
motor->delay = motor->first_delay;
|
||||
motor->c64 = motor->delay << 16; // keep delay in 24.16 fixed-point format for ramp calcs
|
||||
motor->denom = 1; // 4.n + 1, n = 0
|
||||
motor->step_no = 0; // step counter
|
||||
motor->next_step = hal.get_micros();
|
||||
|
||||
#ifdef DEBUGOUT
|
||||
uint32_t nn = motor->n;
|
||||
@@ -268,55 +406,62 @@ bool st2_motor_move (st2_motor_t *motor, const float move, const float speed, po
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Get current position in steps.
|
||||
\param motor pointer to a \a st2_motor structure.
|
||||
\returns current position as number of steps.
|
||||
*/
|
||||
int64_t st2_get_position (st2_motor_t *motor)
|
||||
{
|
||||
return motor->position;
|
||||
}
|
||||
|
||||
/*! \brief Set current position in steps.
|
||||
|
||||
__NOTE:__ position will _not_ be set if motor is moving.
|
||||
\param motor pointer to a \a st2_motor structure.
|
||||
\param position position to set.
|
||||
\returns \a true if new position was accepted, \a false if not.
|
||||
*/
|
||||
bool st2_set_position (st2_motor_t *motor, int64_t position)
|
||||
{
|
||||
if(motor->state == State_Idle)
|
||||
if(motor->state == State_Idle) {
|
||||
motor->position = position;
|
||||
motor->position_lost = false;
|
||||
}
|
||||
|
||||
return motor->state == State_Idle;
|
||||
}
|
||||
|
||||
/*! \brief Execute a move commanded by st2_motor_move().
|
||||
|
||||
This should be called from the foreground process as often as possible.
|
||||
\param motor pointer to a \a st2_motor structure.
|
||||
\returns \a true if motor is moving (steps are output), \a false if not (motion is completed).
|
||||
*/
|
||||
bool st2_motor_run (st2_motor_t *motor)
|
||||
{
|
||||
uint32_t t = hal.get_micros();
|
||||
uint64_t t = hal.get_micros();
|
||||
|
||||
if(motor->state == State_Idle || t - motor->next_step < motor->delay)
|
||||
return motor->state != State_Idle;
|
||||
|
||||
// output step;
|
||||
|
||||
hal.stepper.output_step(motor->axis, motor->dir);
|
||||
|
||||
if(motor->dir.mask)
|
||||
motor->position--;
|
||||
else
|
||||
motor->position++;
|
||||
|
||||
motor->step_no++;
|
||||
|
||||
switch(motor->state) {
|
||||
|
||||
case State_Accel:
|
||||
if(motor->step_no == motor->step_run) {
|
||||
motor->state = motor->step_run == motor->step_down ? State_Decel : (motor->ptype == Stepper2_InfiniteSteps ? State_RunInfinite : State_Run);
|
||||
motor->denom -= 2;
|
||||
if(motor->state == State_Run || motor->state == State_RunInfinite)
|
||||
motor->delay = motor->min_delay;
|
||||
} else {
|
||||
if(motor->step_no != motor->step_run) {
|
||||
motor->denom += 4;
|
||||
motor->c64 -= (motor->c64 << 1) / motor->denom; // ramp algorithm
|
||||
motor->delay = (motor->c64 + 32768) >> 16; // round 24.16 format -> int16
|
||||
if (motor->delay < motor->min_delay) { // go to constant speed?
|
||||
motor->denom -= 6; // causes issues with speed override for infinite moves
|
||||
// motor->denom -= 6; // causes issues with speed override for infinite moves
|
||||
motor->state = motor->ptype == Stepper2_InfiniteSteps ? State_RunInfinite : State_Run;
|
||||
motor->step_down = motor->move - motor->step_no;
|
||||
motor->delay = motor->min_delay;
|
||||
}
|
||||
} else {
|
||||
motor->state = motor->step_run == motor->step_down ? State_Decel : (motor->ptype == Stepper2_InfiniteSteps ? State_RunInfinite : State_Run);
|
||||
if(motor->state != State_Decel)
|
||||
motor->delay = motor->min_delay;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -342,21 +487,38 @@ bool st2_motor_run (st2_motor_t *motor)
|
||||
|
||||
case State_DecelTo:
|
||||
if(motor->step_no != motor->step_run) {
|
||||
motor->c64 += (motor->c64 << 1) / motor->denom; // ramp algorithm
|
||||
motor->delay = (motor->c64 - 32768) >> 16; // round 24.16 format -> int16
|
||||
motor->denom -= 4;
|
||||
} else
|
||||
motor->c64 += (motor->c64 << 1) / motor->denom; // ramp algorithm
|
||||
motor->delay = (motor->c64 + 32768) >> 16; // round 24.16 format -> int16
|
||||
} else {
|
||||
motor->delay = motor->min_delay;
|
||||
motor->state = motor->ptype == Stepper2_InfiniteSteps ? State_RunInfinite : State_Run;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// output step;
|
||||
hal.stepper.output_step(motor->axis, motor->dir);
|
||||
|
||||
if(motor->dir.mask)
|
||||
motor->position--;
|
||||
else
|
||||
motor->position++;
|
||||
|
||||
motor->step_no++;
|
||||
motor->next_step = t;
|
||||
|
||||
return motor->state != State_Idle;
|
||||
}
|
||||
|
||||
/*! \brief Stop a move.
|
||||
This will initiate deceleration to stop the motor if it is running.
|
||||
\param motor pointer to a \a st2_motor structure.
|
||||
\returns \a true if motor was running, \a false if not.
|
||||
*/
|
||||
bool st2_motor_stop (st2_motor_t *motor)
|
||||
{
|
||||
switch(motor->state) {
|
||||
@@ -382,11 +544,19 @@ bool st2_motor_stop (st2_motor_t *motor)
|
||||
return motor->state != State_Idle;
|
||||
}
|
||||
|
||||
/*! \brief Check if motor is running.
|
||||
\param motor pointer to a \a st2_motor structure.
|
||||
\returns \a true if motor is running, \a false if not.
|
||||
*/
|
||||
bool st2_motor_running (st2_motor_t *motor)
|
||||
{
|
||||
return motor->state != State_Idle;
|
||||
}
|
||||
|
||||
/*! \brief Check if motor is running in cruising phase.
|
||||
\param motor pointer to a \a st2_motor structure.
|
||||
\returns \a true if motor is cruising (not acceleration or decelerating), \a false if not.
|
||||
*/
|
||||
bool st2_motor_cruising (st2_motor_t *motor)
|
||||
{
|
||||
return motor->state == State_Run || motor->state == State_RunInfinite;
|
||||
|
||||
@@ -23,15 +23,15 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
Stepper2_Steps = 0,
|
||||
Stepper2_InfiniteSteps,
|
||||
Stepper2_mm
|
||||
Stepper2_Steps = 0, //!< 0
|
||||
Stepper2_InfiniteSteps, //!< 1
|
||||
Stepper2_mm //!< 2
|
||||
} position_t;
|
||||
|
||||
struct st2_motor; // members defined in stepper2.c
|
||||
typedef struct st2_motor st2_motor_t;
|
||||
|
||||
st2_motor_t *st2_motor_init (uint_fast8_t axis_idx);
|
||||
st2_motor_t *st2_motor_init (uint_fast8_t axis_idx, bool is_spindle);
|
||||
float st2_motor_set_speed (st2_motor_t *motor, float speed);
|
||||
bool st2_motor_move (st2_motor_t *motor, const float move, const float speed, position_t type);
|
||||
bool st2_motor_run (st2_motor_t *motor);
|
||||
|
||||
17
system.h
17
system.h
@@ -338,33 +338,18 @@ typedef struct sys_commands_str {
|
||||
|
||||
extern system_t sys;
|
||||
|
||||
//! Executes an internal system command, defined as a string starting with a '$'
|
||||
status_code_t system_execute_line (char *line);
|
||||
|
||||
//! Execute the startup script lines stored in non-volatile storage upon initialization
|
||||
void system_execute_startup (void);
|
||||
|
||||
void system_flag_wco_change (void);
|
||||
|
||||
// Returns machine position of axis 'idx'. Must be sent a 'step' array.
|
||||
//float system_convert_axis_steps_to_mpos(int32_t *steps, uint_fast8_t idx);
|
||||
|
||||
//! Updates a machine 'position' array based on the 'step' array sent.
|
||||
void system_convert_array_steps_to_mpos (float *position, int32_t *steps);
|
||||
|
||||
//! Checks if XY position is within coordinate system XY with given tolerance.
|
||||
bool system_xy_at_fixture (coord_system_id_t id, float tolerance);
|
||||
|
||||
//! Raise and report alarm state
|
||||
void system_raise_alarm (alarm_code_t alarm);
|
||||
|
||||
//! Provide system command help
|
||||
void system_command_help (void);
|
||||
|
||||
void system_add_rt_report (report_tracking_t report);
|
||||
report_tracking_flags_t system_get_rt_report_flags (void);
|
||||
|
||||
// Special handlers for setting and clearing Grbl's real-time execution flags.
|
||||
// Special handlers for setting and clearing grblHAL's real-time execution flags.
|
||||
#define system_set_exec_state_flag(mask) hal.set_bits_atomic(&sys.rt_exec_state, (mask))
|
||||
#define system_clear_exec_state_flag(mask) hal.clear_bits_atomic(&sys.rt_exec_state, (mask))
|
||||
#define system_clear_exec_states() hal.set_value_atomic(&sys.rt_exec_state, 0)
|
||||
|
||||
@@ -92,17 +92,13 @@ static void reset (void)
|
||||
{
|
||||
if(next_tool) { //TODO: move to gc_xxx() function?
|
||||
// Restore previous tool if reset is during change
|
||||
#if N_TOOLS
|
||||
if(current_tool.tool_id != next_tool->tool_id) {
|
||||
if(grbl.tool_table.n_tools)
|
||||
memcpy(gc_state.tool, ¤t_tool, sizeof(tool_data_t));
|
||||
system_add_rt_report(Report_Tool);
|
||||
}
|
||||
#else
|
||||
if(current_tool.tool_id != next_tool->tool_id) {
|
||||
else
|
||||
memcpy(next_tool, ¤t_tool, sizeof(tool_data_t));
|
||||
system_add_rt_report(Report_Tool);
|
||||
}
|
||||
#endif
|
||||
gc_state.tool_pending = gc_state.tool->tool_id;
|
||||
next_tool = NULL;
|
||||
}
|
||||
|
||||
19
vfs.c
19
vfs.c
@@ -101,9 +101,6 @@ static char *fs_getcwd (char *buf, size_t size)
|
||||
}
|
||||
|
||||
static const vfs_t fs_null = {
|
||||
.mode.directory = true,
|
||||
.mode.hidden = true,
|
||||
.mode.read_only = true,
|
||||
.fopen = fs_open,
|
||||
.fclose = fs_close,
|
||||
.fread = fs_read,
|
||||
@@ -126,6 +123,7 @@ static const vfs_t fs_null = {
|
||||
static vfs_mount_t root = {
|
||||
.path = "/",
|
||||
.vfs = &fs_null,
|
||||
.mode = { .directory = true, .read_only = true, .hidden = true },
|
||||
.next = NULL
|
||||
};
|
||||
static vfs_mount_t *cwdmount = &root;
|
||||
@@ -342,7 +340,7 @@ vfs_dir_t *vfs_opendir (const char *path)
|
||||
|
||||
if((add_mount = root.next)) do {
|
||||
if(add_mount != mount && !strncmp(add_mount->path, path, strlen(path))) {
|
||||
if(!add_mount->vfs->mode.hidden && (mln = malloc(sizeof(vfs_mount_ll_entry_t)))) {
|
||||
if(!add_mount->mode.hidden && (mln = malloc(sizeof(vfs_mount_ll_entry_t)))) {
|
||||
mln->mount = add_mount;
|
||||
mln->next = NULL;
|
||||
if(dir->mounts == NULL)
|
||||
@@ -376,7 +374,7 @@ vfs_dirent_t *vfs_readdir (vfs_dir_t *dir)
|
||||
if((s = strrchr(dirent.name, '/')))
|
||||
*s = '\0';
|
||||
|
||||
dirent.st_mode = ml->mount->vfs->mode;
|
||||
dirent.st_mode = ml->mount->mode;
|
||||
dirent.st_mode.directory = true;
|
||||
dir->mounts = dir->mounts->next;
|
||||
free(ml);
|
||||
@@ -460,7 +458,7 @@ vfs_free_t *vfs_fgetfree (const char *path)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool vfs_mount (const char *path, const vfs_t *fs)
|
||||
bool vfs_mount (const char *path, const vfs_t *fs, vfs_st_mode_t mode)
|
||||
{
|
||||
vfs_mount_t *vfs;
|
||||
|
||||
@@ -474,6 +472,7 @@ bool vfs_mount (const char *path, const vfs_t *fs)
|
||||
strcat(vfs->path, "/");
|
||||
|
||||
vfs->vfs = fs;
|
||||
vfs->mode = mode;
|
||||
vfs->next = NULL;
|
||||
|
||||
vfs_mount_t *mount = &root;
|
||||
@@ -527,7 +526,7 @@ vfs_drive_t *vfs_get_drive (const char *path)
|
||||
vfs_mount_t *mount = get_mount(path);
|
||||
drive.name = mount->vfs->fs_name;
|
||||
drive.path = (const char *)mount->path;
|
||||
drive.mode = mount->vfs->mode;
|
||||
drive.mode = mount->mode;
|
||||
drive.removable = mount->vfs->removable;
|
||||
drive.fs = mount->vfs;
|
||||
|
||||
@@ -543,7 +542,7 @@ vfs_drives_t *vfs_drives_open (void)
|
||||
|
||||
handle->mount = NULL;
|
||||
do {
|
||||
if(mount->vfs->mode.hidden)
|
||||
if(mount->mode.hidden)
|
||||
mount = mount->next;
|
||||
else
|
||||
handle->mount = mount;
|
||||
@@ -568,14 +567,14 @@ vfs_drive_t *vfs_drives_read (vfs_drives_t *handle)
|
||||
|
||||
drive.name = handle->mount->vfs->fs_name;
|
||||
drive.path = (const char *)handle->mount->path;
|
||||
drive.mode = handle->mount->vfs->mode;
|
||||
drive.mode = handle->mount->mode;
|
||||
drive.removable = handle->mount->vfs->removable;
|
||||
drive.fs = handle->mount->vfs;
|
||||
|
||||
handle->mount = handle->mount->next;
|
||||
|
||||
if(handle->mount) do {
|
||||
if(!handle->mount->vfs->mode.hidden && handle->mount->vfs->fs_name)
|
||||
if(!handle->mount->mode.hidden && handle->mount->vfs->fs_name)
|
||||
break;
|
||||
} while((handle->mount = handle->mount->next));
|
||||
}
|
||||
|
||||
4
vfs.h
4
vfs.h
@@ -130,7 +130,6 @@ typedef struct
|
||||
{
|
||||
const char *fs_name;
|
||||
bool removable;
|
||||
vfs_st_mode_t mode;
|
||||
vfs_open_ptr fopen;
|
||||
vfs_close_ptr fclose;
|
||||
vfs_read_ptr fread;
|
||||
@@ -157,6 +156,7 @@ typedef struct vfs_mount
|
||||
{
|
||||
char path[64];
|
||||
const vfs_t *vfs;
|
||||
vfs_st_mode_t mode;
|
||||
struct vfs_mount *next;
|
||||
} vfs_mount_t;
|
||||
|
||||
@@ -188,7 +188,7 @@ extern int vfs_errno;
|
||||
|
||||
char *vfs_fixpath (char *path);
|
||||
|
||||
bool vfs_mount (const char *path, const vfs_t *fs);
|
||||
bool vfs_mount (const char *path, const vfs_t *fs, vfs_st_mode_t mode);
|
||||
bool vfs_unmount (const char *path);
|
||||
vfs_file_t *vfs_open (const char *filename, const char *mode);
|
||||
void vfs_close (vfs_file_t *file);
|
||||
|
||||
Reference in New Issue
Block a user