mirror of
https://github.com/grblHAL/core.git
synced 2026-09-21 02:05:07 +08:00
This build has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured.
The change is major and potentially dangerous, it may damage your probe, so please verify correct operation after installing. Fix for STM32F4xx issue 161, Ethernet connection unresponsive if USB port not powered. Enhanced ioPorts interface: New debounce option for input pins that are interrupt capable, currently only possible to enable via plugin code - later to be made available via a $-setting. Added some wrapper functions for simpler plugin code++ Added simple task scheduler to the core, allows interrupt routines to dispatch jobs to the foreground process, delayed tasks and repeating tasks attached to the 1 ms system timer. Some drivers and plugins now uses the scheduler for input pin debouncing, regular polling etc. The core uses it for stepper disabling and sleep monitoring.
This commit is contained in:
@@ -13,7 +13,11 @@ It has been written to complement grblHAL and has features such as proper keyboa
|
||||
|
||||
---
|
||||
|
||||
Latest build date is 20240205, see the [changelog](changelog.md) for details.
|
||||
Latest build date is 20240222, see the [changelog](changelog.md) for details.
|
||||
|
||||
__NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured.
|
||||
The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds.
|
||||
|
||||
__NOTE:__ A settings reset will be performed on an update of builds earlier than 20230125. Backup and restore of settings is recommended.
|
||||
|
||||
---
|
||||
@@ -89,4 +93,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.
|
||||
|
||||
---
|
||||
20240205
|
||||
20240222
|
||||
|
||||
+39
-3
@@ -1,6 +1,42 @@
|
||||
## grblHAL changelog
|
||||
|
||||
<a name="20240205"/>20240205
|
||||
<a name="20240222"/>Build 20240222
|
||||
|
||||
__NOTE:__ This build has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured.
|
||||
The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this build.
|
||||
There were basically two reasons for doing this, one is to free the input for general use if not needed and another is to be able to add advanced
|
||||
probe protection support, via plugin code, for probe inputs that has interrupt capability.
|
||||
|
||||
Core:
|
||||
|
||||
* Fix for STM32F4xx [issue #161](https://github.com/grblHAL/STM32F4xx/issues/161), Ethernet connection unresponsive if USB port not powered.
|
||||
|
||||
* Enhanced ioPorts interface: New debounce option for input pins that are interrupt capable, currently only possible to enable via plugin code - later to be made available via a $-setting.
|
||||
Added some wrapper functions for simpler plugin code++
|
||||
|
||||
|
||||
* Added simple task scheduler to the core, allows interrupt routines to dispatch jobs to the foreground process, delayed tasks and repeating tasks attached to the 1 ms system timer.
|
||||
Some drivers and plugins now uses the scheduler for input pin debouncing, regular polling etc. The core uses it for stepper disabling and sleep monitoring.
|
||||
|
||||
Drivers:
|
||||
|
||||
* Most: updated to support the enhanced ioPorts interface and using the new task scheduler for debouncing etc.
|
||||
Moved probe and safety door inputs to ioPorts pin pool, if not assigned at compile time they will be free to use by M66 or plugin code.
|
||||
Many board maps has been updated to take advantage of the new ioPorts capabilities. PLease report anny irregularities as I do not have access to all the boards for testing.
|
||||
|
||||
* ESP32: MKS Tinybee v1.0 map changed to use MT_DET \(pin 35\) for motor 3 limit input \(e.g. auto squared Y\) if probe input is not enabled. Ref. [issue #93}(https://github.com/grblHAL/ESP32/issues/93#issuecomment-1917467402).
|
||||
|
||||
Plugins:
|
||||
|
||||
* Some: updated to use the new task scheduler for polling etc.
|
||||
|
||||
* Networking: WizNet driver code updated to use the new task scheduler for interrupt handling, resulting in faster/smoother operation.
|
||||
|
||||
* WebUI: a bit of code "hardening", reduced memory requirement for some of the larger generated messages.
|
||||
|
||||
---
|
||||
|
||||
<a name="20240205"/>Build 20240205
|
||||
|
||||
Core:
|
||||
|
||||
@@ -12,11 +48,11 @@ Core:
|
||||
|
||||
Drivers:
|
||||
|
||||
* Many: Updated to support new MPG mode. Updated for core signature change.
|
||||
* Many: updated to support new MPG mode. Updated for core signature change.
|
||||
|
||||
* ESP32, RP2040, STM32F4xx: enhanced Neopixel support. __Note:__ Not yet used by any boards.
|
||||
|
||||
* STM32F7xx: Added missing MPG mode handlers.
|
||||
* STM32F7xx: added missing MPG mode handlers.
|
||||
|
||||
Plugins:
|
||||
|
||||
|
||||
+5
-5
@@ -5,18 +5,18 @@
|
||||
|
||||
Copyright (c) 2023-2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
@@ -145,7 +145,7 @@ control_signals_t xbar_fn_to_signals_mask (pin_function_t fn)
|
||||
{
|
||||
control_signals_t signals;
|
||||
|
||||
signals.mask = fn > Input_Probe ? 0 : 1 << (uint32_t)fn;
|
||||
signals.mask = fn >= Input_Probe ? 0 : 1 << (uint32_t)fn;
|
||||
|
||||
return signals;
|
||||
}
|
||||
|
||||
+127
-76
@@ -5,18 +5,18 @@
|
||||
|
||||
Copyright (c) 2021-2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CROSSBAR_H_
|
||||
@@ -71,16 +71,6 @@ typedef enum {
|
||||
Input_LimitV,
|
||||
Input_LimitV_Max,
|
||||
Input_HomeV,
|
||||
Input_MISO,
|
||||
Input_SPIIRQ,
|
||||
Input_RX,
|
||||
Input_KeypadStrobe, // To be deprecated? Use Input_I2CStrobe instead.
|
||||
Input_I2CStrobe,
|
||||
Input_SdCardDetect,
|
||||
Input_QEI_A,
|
||||
Input_QEI_B,
|
||||
Input_QEI_Select,
|
||||
Input_QEI_Index,
|
||||
Input_SpindleIndex,
|
||||
Input_SpindlePulse,
|
||||
Input_Aux0,
|
||||
@@ -99,8 +89,9 @@ typedef enum {
|
||||
Input_Analog_Aux5,
|
||||
Input_Analog_Aux6,
|
||||
Input_Analog_Aux7,
|
||||
Outputs,
|
||||
Output_StepX = Outputs,
|
||||
// Output pins
|
||||
Output_StepX,
|
||||
Outputs = Output_StepX,
|
||||
Output_StepX_2,
|
||||
Output_StepY,
|
||||
Output_StepY_2,
|
||||
@@ -148,13 +139,6 @@ typedef enum {
|
||||
Output_SpindlePWM,
|
||||
Output_CoolantMist,
|
||||
Output_CoolantFlood,
|
||||
Output_TX,
|
||||
Output_RTS,
|
||||
Output_SCK,
|
||||
Output_MOSI,
|
||||
Output_SPIRST,
|
||||
Output_SPICS,
|
||||
Output_SdCardCS,
|
||||
Output_Aux0,
|
||||
Output_Aux1,
|
||||
Output_Aux2,
|
||||
@@ -177,9 +161,32 @@ typedef enum {
|
||||
Output_LED_B,
|
||||
Output_LED_W,
|
||||
Output_LED_Adressable,
|
||||
Bidirectional,
|
||||
Bidirectional_SDA = Bidirectional,
|
||||
// Multipin peripherals
|
||||
Input_MISO,
|
||||
Multipin = Input_MISO,
|
||||
Output_MOSI,
|
||||
Output_SPICLK,
|
||||
Output_SPICS,
|
||||
Output_SdCardCS,
|
||||
Input_SdCardDetect,
|
||||
Output_SPIRST,
|
||||
Input_SPIIRQ,
|
||||
Output_SCK,
|
||||
Output_I2CSCK = Output_SCK,
|
||||
Bidirectional_SDA,
|
||||
Bidirectional_I2CSDA = Bidirectional_SDA,
|
||||
Input_KeypadStrobe, // To be deprecated? Use Input_I2CStrobe instead.
|
||||
Input_I2CStrobe,
|
||||
Input_RX,
|
||||
Output_TX,
|
||||
Output_RTS,
|
||||
Input_QEI_A,
|
||||
Input_QEI_B,
|
||||
Input_QEI_Select,
|
||||
Input_QEI_Index,
|
||||
// Single pin bidirectional peripherals
|
||||
Bidirectional_MotorUARTX,
|
||||
Bidirectional = Bidirectional_MotorUARTX,
|
||||
Bidirectional_MotorUARTY,
|
||||
Bidirectional_MotorUARTZ,
|
||||
Bidirectional_MotorUARTM3,
|
||||
@@ -226,16 +233,6 @@ PROGMEM static const pin_name_t pin_names[] = {
|
||||
{ .function = Input_LimitZ_2, .name = "Z limit min 2" },
|
||||
{ .function = Input_LimitZ_Max, .name = "Z limit max" },
|
||||
{ .function = Input_HomeZ, .name = "Z home" },
|
||||
{ .function = Input_MISO, .name = "MISO" },
|
||||
{ .function = Input_SPIIRQ, .name = "SPI IRQ" },
|
||||
{ .function = Input_RX, .name = "RX" },
|
||||
{ .function = Input_KeypadStrobe, .name = "Keypad strobe" },
|
||||
{ .function = Input_I2CStrobe, .name = "I2C strobe" },
|
||||
{ .function = Input_SdCardDetect, .name = "SD card detect" },
|
||||
{ .function = Input_QEI_A, .name = "QEI A" },
|
||||
{ .function = Input_QEI_B, .name = "QEI B" },
|
||||
{ .function = Input_QEI_Select, .name = "QEI select" },
|
||||
{ .function = Input_QEI_Index, .name = "QEI index" },
|
||||
{ .function = Input_SpindleIndex, .name = "Spindle index" },
|
||||
{ .function = Input_SpindlePulse, .name = "Spindle pulse" },
|
||||
{ .function = Input_Aux0, .name = "Aux input 0" },
|
||||
@@ -327,13 +324,6 @@ PROGMEM static const pin_name_t pin_names[] = {
|
||||
{ .function = Output_SpindlePWM, .name = "Spindle PWM" },
|
||||
{ .function = Output_CoolantMist, .name = "Mist" },
|
||||
{ .function = Output_CoolantFlood, .name = "Flood" },
|
||||
{ .function = Output_TX, .name = "TX" },
|
||||
{ .function = Output_RTS, .name = "RTS" },
|
||||
{ .function = Output_SCK, .name = "SCK" },
|
||||
{ .function = Output_MOSI, .name = "MOSI" },
|
||||
{ .function = Output_SPIRST, .name = "SPI reset" },
|
||||
{ .function = Output_SPICS, .name = "SPI CS" },
|
||||
{ .function = Output_SdCardCS, .name = "SD card CS" },
|
||||
{ .function = Output_Aux0, .name = "Aux out 0" },
|
||||
{ .function = Output_Aux1, .name = "Aux out 1" },
|
||||
{ .function = Output_Aux2, .name = "Aux out 2" },
|
||||
@@ -356,7 +346,25 @@ PROGMEM static const pin_name_t pin_names[] = {
|
||||
{ .function = Output_LED_B, .name = "LED B" },
|
||||
{ .function = Output_LED_W, .name = "LED W" },
|
||||
{ .function = Output_LED_Adressable, .name = "LED adressable" },
|
||||
{ .function = Bidirectional_SDA, .name = "SDA" },
|
||||
{ .function = Input_MISO, .name = "MISO" },
|
||||
{ .function = Output_MOSI, .name = "MOSI" },
|
||||
{ .function = Output_SPICLK, .name = "SPI CLK" },
|
||||
{ .function = Output_SPICS, .name = "SPI CS" },
|
||||
{ .function = Output_SdCardCS, .name = "SD card CS" },
|
||||
{ .function = Input_SdCardDetect, .name = "SD card detect" },
|
||||
{ .function = Output_SPIRST, .name = "SPI reset" },
|
||||
{ .function = Input_SPIIRQ, .name = "SPI IRQ" },
|
||||
{ .function = Output_I2CSCK, .name = "I2C SCK" },
|
||||
{ .function = Bidirectional_SDA, .name = "I2C SDA" },
|
||||
{ .function = Input_KeypadStrobe, .name = "Keypad strobe" },
|
||||
{ .function = Input_I2CStrobe, .name = "I2C strobe" },
|
||||
{ .function = Input_RX, .name = "RX" },
|
||||
{ .function = Output_TX, .name = "TX" },
|
||||
{ .function = Output_RTS, .name = "RTS" },
|
||||
{ .function = Input_QEI_A, .name = "QEI A" },
|
||||
{ .function = Input_QEI_B, .name = "QEI B" },
|
||||
{ .function = Input_QEI_Select, .name = "QEI select" },
|
||||
{ .function = Input_QEI_Index, .name = "QEI index" },
|
||||
{ .function = Bidirectional_MotorUARTX, .name = "UART X" },
|
||||
{ .function = Bidirectional_MotorUARTY, .name = "UART Y" },
|
||||
{ .function = Bidirectional_MotorUARTZ, .name = "UART Z" },
|
||||
@@ -385,8 +393,8 @@ typedef enum {
|
||||
PinGroup_MotorUART,
|
||||
PinGroup_I2C,
|
||||
PinGroup_SPI,
|
||||
PinGroup_UART,
|
||||
PinGroup_UART1 = PinGroup_UART,
|
||||
PinGroup_UART1,
|
||||
PinGroup_UART = PinGroup_UART1,
|
||||
PinGroup_UART2,
|
||||
PinGroup_UART3,
|
||||
PinGroup_UART4,
|
||||
@@ -411,14 +419,15 @@ typedef enum {
|
||||
|
||||
//! Pin interrupt modes, may be or'ed when reporting pin capability.
|
||||
typedef enum {
|
||||
IRQ_Mode_None = 0b00000, //!< 0b00000 (0x00)
|
||||
IRQ_Mode_Rising = 0b00001, //!< 0b00001 (0x01)
|
||||
IRQ_Mode_Falling = 0b00010, //!< 0b00010 (0x02)
|
||||
IRQ_Mode_Change = 0b00100, //!< 0b00100 (0x04)
|
||||
IRQ_Mode_Edges = 0b00111, //!< 0b00111 (0x07) - only used to report port capability.
|
||||
IRQ_Mode_High = 0b01000, //!< 0b01000 (0x08)
|
||||
IRQ_Mode_Low = 0b10000, //!< 0b10000 (0x10)
|
||||
IRQ_Mode_All = 0b11111 //!< 0b11111 (0x1F) - only used to report port capability.
|
||||
IRQ_Mode_None = 0b00000, //!< 0b00000 (0x00)
|
||||
IRQ_Mode_Rising = 0b00001, //!< 0b00001 (0x01)
|
||||
IRQ_Mode_Falling = 0b00010, //!< 0b00010 (0x02)
|
||||
IRQ_Mode_RisingFalling = 0b00011, //!< 0b00011 (0x03) - only used to report port capability.
|
||||
IRQ_Mode_Change = 0b00100, //!< 0b00100 (0x04)
|
||||
IRQ_Mode_Edges = 0b00111, //!< 0b00111 (0x07) - only used to report port capability.
|
||||
IRQ_Mode_High = 0b01000, //!< 0b01000 (0x08)
|
||||
IRQ_Mode_Low = 0b10000, //!< 0b10000 (0x10)
|
||||
IRQ_Mode_All = 0b11111 //!< 0b11111 (0x1F) - only used to report port capability.
|
||||
} pin_irq_mode_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -466,7 +475,7 @@ typedef union {
|
||||
pwm :1,
|
||||
servo_pwm :1,
|
||||
claimable :1,
|
||||
reserved :1;
|
||||
debounce :1;
|
||||
};
|
||||
} pin_cap_t;
|
||||
|
||||
@@ -483,11 +492,52 @@ typedef union {
|
||||
pwm :1,
|
||||
servo_pwm :1,
|
||||
claimed :1,
|
||||
reserved :1;
|
||||
debounce :1;
|
||||
};
|
||||
} pin_mode_t;
|
||||
|
||||
#define XBAR_SET_CAP(cap, mode) { cap.mask = mode.mask; cap.claimable = !mode.claimed; }
|
||||
#define XBAR_SET_DIN_INFO(pin, pin_id, src, cfg_fn, get_val_fn) { \
|
||||
pin.id = pin_id; \
|
||||
pin.mode = src.mode; \
|
||||
pin.cap = src.cap; \
|
||||
pin.cap.invert = On; \
|
||||
pin.cap.claimable = !src.mode.claimed; \
|
||||
pin.function = src.id; \
|
||||
pin.group = src.group; \
|
||||
pin.pin = src.pin; \
|
||||
pin.port = (void *)src.port; \
|
||||
pin.description = src.description; \
|
||||
pin.config = cfg_fn; \
|
||||
pin.get_value = get_val_fn; \
|
||||
}
|
||||
#define XBAR_SET_DOUT_INFO(pin, pin_id, src, cfg_fn, get_val_fn) { \
|
||||
pin.id = pin_id; \
|
||||
pin.mode = src.mode; \
|
||||
pin.cap.mask = src.mode.mask; \
|
||||
pin.cap.invert = On; \
|
||||
pin.cap.claimable = !src.mode.claimed; \
|
||||
pin.function = src.id; \
|
||||
pin.group = src.group; \
|
||||
pin.pin = src.pin; \
|
||||
pin.port = (void *)src.port; \
|
||||
pin.description = src.description; \
|
||||
pin.config = cfg_fn; \
|
||||
pin.get_value = get_val_fn; \
|
||||
}
|
||||
|
||||
//! /a cfg_data argument to /a xbar_config_ptr for gpio input pins
|
||||
typedef struct {
|
||||
bool inverted;
|
||||
bool debounce;
|
||||
pull_mode_t pull_mode;
|
||||
} gpio_in_config_t;
|
||||
|
||||
//! /a cfg_data argument to /a xbar_config_ptr for gpio output pins
|
||||
typedef struct {
|
||||
bool inverted;
|
||||
bool open_drain;
|
||||
} gpio_out_config_t;
|
||||
|
||||
//! /a cfg_data argument to /a xbar_config_ptr for PWM pins
|
||||
typedef struct {
|
||||
@@ -502,46 +552,36 @@ typedef struct {
|
||||
} pwm_config_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
// pin_mode_t *pin_mode;
|
||||
{
|
||||
pwm_config_t *pwm_config;
|
||||
} xbar_cfg_ptr_t __attribute__ ((__transparent_union__));
|
||||
gpio_in_config_t *gpio_in_config;
|
||||
gpio_out_config_t *gpio_out_config;
|
||||
} xbar_cfg_ptr_t __attribute__ ((__transparent_union__));
|
||||
|
||||
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 bool (*xbar_config_ptr)(struct xbar *pin, xbar_cfg_ptr_t cfg_data);
|
||||
|
||||
typedef enum {
|
||||
AuxCtrl_SafetyDoor = 0,
|
||||
AuxCtrl_MotorFault,
|
||||
AuxCtrl_MotorWarning,
|
||||
AuxCtrl_ProbeDisconnect,
|
||||
AuxCtrl_StopDisable,
|
||||
AuxCtrl_BlockDelete,
|
||||
AuxCtrl_SingleBlock,
|
||||
AuxCtrl_LimitsOverride,
|
||||
AuxCtrl_NumEntries,
|
||||
} aux_ctrl_signals_t;
|
||||
typedef bool (*xbar_config_ptr)(struct xbar *pin, xbar_cfg_ptr_t cfg_data, bool persistent);
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
volatile bool debouncing;
|
||||
uint8_t port;
|
||||
pin_function_t function;
|
||||
uint8_t aux_port;
|
||||
pin_irq_mode_t irq_mode;
|
||||
control_signals_t cap;
|
||||
pin_function_t function;
|
||||
uint8_t pin;
|
||||
void *port;
|
||||
void *input;
|
||||
} aux_ctrl_t;
|
||||
|
||||
typedef struct xbar {
|
||||
uint8_t id; //!< Pin id.
|
||||
pin_function_t function; //!< Pin function.
|
||||
pin_group_t group; //!< Pin group.
|
||||
void *port; //!< Optional pointer to the underlying peripheral or pin specific data.
|
||||
const char *description; //!< Optional pointer to description string.
|
||||
uint_fast8_t pin; //!< Pin number.
|
||||
uint32_t bit; //!< Pin bit, 1 << pin.
|
||||
pin_cap_t cap; //!< Pin capabilities.
|
||||
pin_mode_t mode; //!< Current pin configuration.
|
||||
xbar_config_ptr config; //!< Optional pointer to function for configuring the port.
|
||||
@@ -564,6 +604,17 @@ typedef struct periph_signal {
|
||||
struct periph_signal *next;
|
||||
} periph_signal_t;
|
||||
|
||||
typedef union {
|
||||
uint8_t mask;
|
||||
struct {
|
||||
uint8_t limits :1,
|
||||
aux_inputs :1,
|
||||
safety_door :1,
|
||||
qei_select :1,
|
||||
unassigned :4;
|
||||
};
|
||||
} pin_debounce_t;
|
||||
|
||||
void xbar_set_homing_source (void);
|
||||
limit_signals_t xbar_get_homing_source (void);
|
||||
limit_signals_t xbar_get_homing_source_from_cycle (axes_signals_t homing_cycle);
|
||||
|
||||
+8
-5
@@ -5,20 +5,20 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2020-2023 Terje Io
|
||||
Copyright (c) 2020-2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//
|
||||
@@ -360,6 +360,9 @@
|
||||
#ifndef QEI_ENABLE
|
||||
#define QEI_ENABLE 0
|
||||
#endif
|
||||
#ifndef QEI_SELECT_ENABLE
|
||||
#define QEI_SELECT_ENABLE 0
|
||||
#endif
|
||||
#ifndef ODOMETER_ENABLE
|
||||
#define ODOMETER_ENABLE 0
|
||||
#endif
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#else
|
||||
#define GRBL_VERSION "1.1f"
|
||||
#endif
|
||||
#define GRBL_BUILD 20240204
|
||||
#define GRBL_BUILD 20240222
|
||||
|
||||
#define GRBL_URL "https://github.com/grblHAL"
|
||||
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
Copyright (c) 2011-2015 Sungeun K. Jeon
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@@ -58,6 +58,8 @@
|
||||
#include "kinematics/polar.h"
|
||||
#endif
|
||||
|
||||
static void task_execute (sys_state_t state);
|
||||
|
||||
typedef union {
|
||||
uint8_t ok;
|
||||
struct {
|
||||
@@ -70,11 +72,23 @@ typedef union {
|
||||
};
|
||||
} driver_startup_t;
|
||||
|
||||
#ifndef CORE_TASK_POOL_SIZE
|
||||
#define CORE_TASK_POOL_SIZE 30
|
||||
#endif
|
||||
|
||||
typedef struct core_task {
|
||||
uint32_t time;
|
||||
foreground_task_ptr fn;
|
||||
void *data;
|
||||
struct core_task *next;
|
||||
} core_task_t;
|
||||
|
||||
struct system sys = {0}; //!< System global variable structure.
|
||||
grbl_t grbl;
|
||||
grbl_hal_t hal;
|
||||
static driver_startup_t driver = { .ok = 0xFF };
|
||||
static on_execute_realtime_ptr on_execute_realtime;
|
||||
static core_task_t task_pool[CORE_TASK_POOL_SIZE] = {0};
|
||||
static core_task_t *next_task = NULL, *immediate_task = NULL, *systick_task = NULL, *last_freed = NULL;
|
||||
|
||||
#ifdef KINEMATICS_API
|
||||
kinematics_t kinematics;
|
||||
@@ -109,21 +123,20 @@ static void report_driver_error (void *data)
|
||||
report_message(msg, Message_Plain);
|
||||
}
|
||||
|
||||
static void auto_realtime_report (sys_state_t state)
|
||||
static void auto_realtime_report (void *data);
|
||||
|
||||
static void realtime_report_check (void *data)
|
||||
{
|
||||
static uint32_t ms = 0;
|
||||
task_add_delayed(sys.flags.auto_reporting ? auto_realtime_report : realtime_report_check, NULL, settings.report_interval);
|
||||
}
|
||||
|
||||
static void auto_realtime_report (void *data)
|
||||
{
|
||||
if(sys.flags.auto_reporting) {
|
||||
|
||||
uint32_t t = hal.get_elapsed_ticks();
|
||||
|
||||
if(t - ms >= settings.report_interval) {
|
||||
ms = t;
|
||||
system_set_exec_state_flag(EXEC_STATUS_REPORT);
|
||||
}
|
||||
}
|
||||
|
||||
on_execute_realtime(state);
|
||||
system_set_exec_state_flag(EXEC_STATUS_REPORT);
|
||||
task_add_delayed(auto_realtime_report, NULL, settings.report_interval);
|
||||
} else if(settings.report_interval)
|
||||
task_add_delayed(realtime_report_check, NULL, settings.report_interval);
|
||||
}
|
||||
|
||||
// "Wire" homing signals to limit signals, used when max limit inputs not available.
|
||||
@@ -161,7 +174,7 @@ int grbl_enter (void)
|
||||
|
||||
// Clear all and set some core function pointers
|
||||
memset(&grbl, 0, sizeof(grbl_t));
|
||||
grbl.on_execute_realtime = grbl.on_execute_delay = protocol_execute_noop;
|
||||
grbl.on_execute_realtime = grbl.on_execute_delay = task_execute;
|
||||
grbl.enqueue_gcode = protocol_enqueue_gcode;
|
||||
grbl.enqueue_realtime_command = stream_enqueue_realtime_command;
|
||||
grbl.on_report_options = dummy_bool_handler;
|
||||
@@ -287,10 +300,8 @@ int grbl_enter (void)
|
||||
if(hal.homing.get_state == NULL)
|
||||
hal.homing.get_state = hal.limits_cap.max.mask ? get_homing_status2 : get_homing_status;
|
||||
|
||||
if(settings.report_interval) {
|
||||
on_execute_realtime = grbl.on_execute_realtime;
|
||||
grbl.on_execute_realtime = auto_realtime_report;
|
||||
}
|
||||
if(settings.report_interval)
|
||||
task_add_delayed(auto_realtime_report, NULL, settings.report_interval);
|
||||
|
||||
if(hal.driver_cap.sd_card || hal.driver_cap.littlefs) {
|
||||
fs_options_t fs_options = {0};
|
||||
@@ -365,3 +376,197 @@ int grbl_enter (void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline core_task_t *task_alloc (void)
|
||||
{
|
||||
core_task_t *task = NULL;
|
||||
uint_fast8_t idx = CORE_TASK_POOL_SIZE;
|
||||
|
||||
if(last_freed) {
|
||||
task = last_freed;
|
||||
last_freed = NULL;
|
||||
} else do {
|
||||
if(task_pool[--idx].fn == NULL)
|
||||
task = &task_pool[idx];
|
||||
} while(task == NULL && idx);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
static inline void task_free (core_task_t *task)
|
||||
{
|
||||
task->fn = NULL;
|
||||
if(last_freed == NULL)
|
||||
last_freed = task;
|
||||
}
|
||||
|
||||
static void task_execute (sys_state_t state)
|
||||
{
|
||||
static uint32_t last_ms = 0;
|
||||
|
||||
core_task_t *task;
|
||||
|
||||
if(immediate_task && sys.driver_started) {
|
||||
|
||||
hal.irq_disable();
|
||||
task = immediate_task;
|
||||
immediate_task = NULL;
|
||||
hal.irq_enable();
|
||||
|
||||
do {
|
||||
void *data = task->data;
|
||||
foreground_task_ptr fn = task->fn;
|
||||
task_free(task);
|
||||
fn(data);
|
||||
} while((task = task->next));
|
||||
}
|
||||
|
||||
uint32_t now = hal.get_elapsed_ticks();
|
||||
if(now == last_ms || next_task == systick_task)
|
||||
return;
|
||||
|
||||
last_ms = now;
|
||||
|
||||
if((task = systick_task)) do {
|
||||
task->fn(task->data);
|
||||
} while((task = task->next));
|
||||
|
||||
while(next_task && (int32_t)(next_task->time - now) <= 0) {
|
||||
|
||||
void *data = next_task->data;
|
||||
foreground_task_ptr fn = next_task->fn;
|
||||
task_free(next_task);
|
||||
next_task = next_task->next;
|
||||
|
||||
fn(data);
|
||||
}
|
||||
}
|
||||
|
||||
ISR_CODE bool ISR_FUNC(task_add_delayed)(foreground_task_ptr fn, void *data, uint32_t delay_ms)
|
||||
{
|
||||
core_task_t *task = NULL;
|
||||
|
||||
hal.irq_disable();
|
||||
|
||||
if(fn && (task = task_alloc())) {
|
||||
|
||||
task->time = hal.get_elapsed_ticks() + delay_ms;
|
||||
task->fn = fn;
|
||||
task->data = data;
|
||||
task->next = NULL;
|
||||
|
||||
if(next_task == NULL)
|
||||
next_task = task;
|
||||
else if((int32_t)(task->time - next_task->time) < 0) {
|
||||
task->next = next_task;
|
||||
next_task = task;
|
||||
} else {
|
||||
core_task_t *t = next_task;
|
||||
while(t) {
|
||||
if(t->next == NULL || (int32_t)(task->time - t->next->time) < 0) {
|
||||
task->next = t->next;
|
||||
t->next = task;
|
||||
break;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hal.irq_enable();
|
||||
|
||||
return task != NULL;
|
||||
}
|
||||
|
||||
void task_delete (foreground_task_ptr fn, void *data)
|
||||
{
|
||||
core_task_t *task, *prev = NULL;
|
||||
|
||||
if((task = next_task)) do {
|
||||
if(fn == task->fn && data == task->data) {
|
||||
if(prev)
|
||||
prev->next = task->next;
|
||||
else
|
||||
next_task = task->next;
|
||||
task_free(task);
|
||||
break;
|
||||
}
|
||||
prev = task;
|
||||
} while((task = task->next));
|
||||
}
|
||||
|
||||
ISR_CODE bool ISR_FUNC(task_add_systick)(foreground_task_ptr fn, void *data)
|
||||
{
|
||||
core_task_t *task = NULL;
|
||||
|
||||
hal.irq_disable();
|
||||
|
||||
if(fn && (task = task_alloc())) {
|
||||
|
||||
task->fn = fn;
|
||||
task->data = data;
|
||||
task->next = NULL;
|
||||
|
||||
if(systick_task == NULL)
|
||||
systick_task = task;
|
||||
else {
|
||||
core_task_t *t = systick_task;
|
||||
while(t->next)
|
||||
t = t->next;
|
||||
t->next = task;
|
||||
}
|
||||
}
|
||||
|
||||
hal.irq_enable();
|
||||
|
||||
return task != NULL;
|
||||
}
|
||||
|
||||
void task_delete_systick (foreground_task_ptr fn, void *data)
|
||||
{
|
||||
core_task_t *task, *prev = NULL;
|
||||
|
||||
if((task = systick_task)) do {
|
||||
if(fn == task->fn && data == task->data) {
|
||||
if(prev)
|
||||
prev->next = task->next;
|
||||
else
|
||||
systick_task = task->next;
|
||||
task_free(task);
|
||||
break;
|
||||
}
|
||||
prev = task;
|
||||
} while((task = task->next));
|
||||
}
|
||||
|
||||
/*! \brief Enqueue a function to be called once by the foreground process.
|
||||
\param fn pointer to a \a foreground_task_ptr type of function.
|
||||
\param data pointer to data to be passed to the callee.
|
||||
\returns true if successful, false otherwise.
|
||||
*/
|
||||
ISR_CODE bool ISR_FUNC(task_add_immediate)(foreground_task_ptr fn, void *data)
|
||||
{
|
||||
core_task_t *task = NULL;
|
||||
|
||||
hal.irq_disable();
|
||||
|
||||
if(fn && (task = task_alloc())) {
|
||||
|
||||
task->fn = fn;
|
||||
task->data = data;
|
||||
task->next = NULL;
|
||||
|
||||
if(immediate_task == NULL)
|
||||
immediate_task = task;
|
||||
else {
|
||||
core_task_t *t = immediate_task;
|
||||
while(t->next)
|
||||
t = t->next;
|
||||
t->next = task;
|
||||
}
|
||||
}
|
||||
|
||||
hal.irq_enable();
|
||||
|
||||
return task != NULL;
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
|
||||
Copyright (c) 2021-2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "hal.h"
|
||||
#include "settings.h"
|
||||
|
||||
typedef struct {
|
||||
io_ports_detail_t *ports;
|
||||
@@ -39,6 +40,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
io_ports_private_t in;
|
||||
io_ports_private_t out;
|
||||
ioport_bus_t inx;
|
||||
ioport_bus_t outx;
|
||||
} io_ports_cfg_t;
|
||||
|
||||
@@ -135,6 +137,24 @@ bool ioport_claim (io_port_type_t type, io_port_direction_t dir, uint8_t *port,
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*! \brief Reassign pin function.
|
||||
\param port pointer to an \a aux_ctrl_t structure with a valid port number.
|
||||
\param function pointer to a \a #pin_function_t enum value to be updated.
|
||||
*/
|
||||
void ioport_assign_function (aux_ctrl_t *aux_ctrl, pin_function_t *function)
|
||||
{
|
||||
xbar_t *input;
|
||||
|
||||
if((input = hal.port.get_pin_info(Port_Digital, Port_Input, aux_ctrl->aux_port))) {
|
||||
|
||||
*function = aux_ctrl->function;
|
||||
hal.signals_cap.mask |= aux_ctrl->cap.mask;
|
||||
|
||||
if(aux_ctrl->function == Input_Probe || xbar_fn_to_signals_mask(aux_ctrl->function).mask)
|
||||
setting_remove_elements(Settings_IoPort_InvertIn, digital.inx.mask & ~(1 << input->id));
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Check if ports can be claimed by aux number or not.
|
||||
\returns true if ports can be claimed by aux number, false if claimed ports are allocated by the API.
|
||||
*/
|
||||
@@ -158,6 +178,44 @@ bool ioports_enumerate (io_port_type_t type, io_port_direction_t dir, pin_cap_t
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool ioport_analog_out_config (uint8_t port, pwm_config_t *config)
|
||||
{
|
||||
bool ok;
|
||||
xbar_t *pin;
|
||||
|
||||
if((ok = (pin = hal.port.get_pin_info(Port_Analog, Port_Output, port)) && pin->config))
|
||||
pin->config(pin, config, false);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool ioport_digital_in_config (uint8_t port, gpio_in_config_t *config)
|
||||
{
|
||||
bool ok;
|
||||
xbar_t *pin;
|
||||
|
||||
if((ok = (pin = hal.port.get_pin_info(Port_Digital, Port_Input, port)) && pin->config))
|
||||
pin->config(pin, config, false);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool ioport_enable_irq (uint8_t port, pin_irq_mode_t irq_mode, ioport_interrupt_callback_ptr handler)
|
||||
{
|
||||
return hal.port.register_interrupt_handler && hal.port.register_interrupt_handler(port, irq_mode, handler);
|
||||
}
|
||||
|
||||
bool ioport_digital_out_config (uint8_t port, gpio_out_config_t *config)
|
||||
{
|
||||
bool ok;
|
||||
xbar_t *pin;
|
||||
|
||||
if((ok = (pin = hal.port.get_pin_info(Port_Digital, Port_Output, port)) && pin->config))
|
||||
pin->config(pin, config, false);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* experimental code follows */
|
||||
|
||||
static char *get_pnum (io_ports_data_t *ports, uint8_t port)
|
||||
@@ -230,6 +288,7 @@ bool ioports_add (io_ports_data_t *ports, io_port_type_t type, uint8_t n_in, uin
|
||||
if(hal.port.set_pin_description)
|
||||
hal.port.set_pin_description(type, Port_Input, i, get_pnum(ports, i));
|
||||
if(i < 8) {
|
||||
cfg->inx.mask = (cfg->inx.mask << 1) + 1;
|
||||
strcat(cfg->in.port_names, i == 0 ? "Aux " : ",Aux ");
|
||||
strcat(cfg->in.port_names, uitoa(i));
|
||||
}
|
||||
@@ -335,6 +394,42 @@ uint_fast16_t ioports_compute_pwm_value (ioports_pwm_t *pwm_data, float value)
|
||||
return pwm_value;
|
||||
}
|
||||
|
||||
static void sync_input_settings (pin_function_t function, gpio_in_config_t *config)
|
||||
{
|
||||
if(function == Input_Probe)
|
||||
settings.probe.invert_probe_pin = config->inverted;
|
||||
else if(function < Input_Probe) {
|
||||
control_signals_t ctrl;
|
||||
if((ctrl = xbar_fn_to_signals_mask(function)).mask) {
|
||||
if(config->inverted)
|
||||
settings.control_invert.mask |= ctrl.mask;
|
||||
else
|
||||
settings.control_invert.mask &= ~ctrl.mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ioport_save_input_settings (xbar_t *xbar, gpio_in_config_t *config)
|
||||
{
|
||||
if(config->inverted)
|
||||
settings.ioport.invert_in.mask |= (1 << xbar->id);
|
||||
else
|
||||
settings.ioport.invert_in.mask &= ~(1 << xbar->id);
|
||||
|
||||
sync_input_settings(xbar->function, config);
|
||||
|
||||
settings_write_global();
|
||||
}
|
||||
|
||||
void ioport_save_output_settings (xbar_t *xbar, gpio_out_config_t *config)
|
||||
{
|
||||
if(config->inverted)
|
||||
settings.ioport.invert_out.mask |= (1 << xbar->id);
|
||||
else
|
||||
settings.ioport.invert_out.mask &= ~(1 << xbar->id);
|
||||
|
||||
settings_write_global();
|
||||
}
|
||||
|
||||
static bool is_setting_available (const setting_detail_t *setting)
|
||||
{
|
||||
@@ -361,21 +456,113 @@ static bool is_setting_available (const setting_detail_t *setting)
|
||||
|
||||
static status_code_t aux_set_value (setting_id_t id, uint_fast16_t value)
|
||||
{
|
||||
ioport_bus_t invert;
|
||||
xbar_t *xbar;
|
||||
uint8_t port = 0;
|
||||
ioport_bus_t change, changed;
|
||||
|
||||
switch(id) {
|
||||
|
||||
case Settings_IoPort_InvertIn:
|
||||
settings.ioport.invert_in.mask = value;
|
||||
|
||||
change.mask = (uint8_t)value & digital.inx.mask;
|
||||
|
||||
if((changed.mask = settings.ioport.invert_in.mask ^ change.mask)) {
|
||||
|
||||
gpio_in_config_t config = {0};
|
||||
|
||||
do {
|
||||
if((changed.mask & 0x01) && (xbar = hal.port.get_pin_info(Port_Digital, Port_Input, ioports_map_reverse(digital.in.ports, port)))) {
|
||||
if(xbar->config) {
|
||||
config.pull_mode = (pull_mode_t)xbar->mode.pull_mode;
|
||||
config.inverted = !!(change.mask & (1 << xbar->id));
|
||||
xbar->config(xbar, &config, false);
|
||||
sync_input_settings(xbar->function, &config);
|
||||
}
|
||||
}
|
||||
port++;
|
||||
} while(changed.mask >>= 1);
|
||||
}
|
||||
|
||||
settings.ioport.invert_in.mask = change.mask;
|
||||
|
||||
if(on_setting_changed)
|
||||
on_setting_changed(id);
|
||||
break;
|
||||
|
||||
case Settings_IoPort_Pullup_Disable:
|
||||
|
||||
change.mask = (uint8_t)value & digital.inx.mask;
|
||||
|
||||
if((changed.mask = settings.ioport.pullup_disable_in.mask ^ change.mask)) {
|
||||
|
||||
gpio_in_config_t config = {0};
|
||||
|
||||
do {
|
||||
if((changed.mask & 0x01) && (xbar = hal.port.get_pin_info(Port_Digital, Port_Input, ioports_map_reverse(digital.in.ports, port)))) {
|
||||
if(xbar->config) {
|
||||
config.pull_mode = change.mask & (1 << xbar->id) ? PullMode_Down : PullMode_Up;
|
||||
config.inverted = xbar->mode.inverted;
|
||||
config.debounce = xbar->mode.inverted;
|
||||
xbar->config(xbar, &config, false);
|
||||
sync_input_settings(xbar->function, &config);
|
||||
}
|
||||
}
|
||||
port++;
|
||||
} while(changed.mask >>= 1);
|
||||
}
|
||||
|
||||
settings.ioport.pullup_disable_in.mask = change.mask;
|
||||
|
||||
if(on_setting_changed)
|
||||
on_setting_changed(id);
|
||||
break;
|
||||
|
||||
case Settings_IoPort_InvertOut:
|
||||
invert.mask = (uint8_t)value & digital.outx.mask;
|
||||
if(settings.ioport.invert_out.mask != invert.mask) {
|
||||
|
||||
settings.ioport.invert_out.mask = invert.mask;
|
||||
change.mask = (uint8_t)value & digital.outx.mask;
|
||||
|
||||
if((changed.mask = settings.ioport.invert_out.mask ^ change.mask)) {
|
||||
|
||||
gpio_out_config_t config = {0};
|
||||
|
||||
do {
|
||||
if((changed.mask & 0x01) && (xbar = hal.port.get_pin_info(Port_Digital, Port_Output, ioports_map_reverse(digital.out.ports, port)))) {
|
||||
if(xbar->config) {
|
||||
config.inverted = !!(change.mask & (1 << xbar->id));
|
||||
config.open_drain = xbar->mode.open_drain;
|
||||
xbar->config(xbar, &config, false);
|
||||
}
|
||||
}
|
||||
port++;
|
||||
} while(changed.mask >>= 1);
|
||||
|
||||
settings.ioport.invert_out.mask = change.mask;
|
||||
|
||||
if(on_setting_changed)
|
||||
on_setting_changed(id);
|
||||
}
|
||||
break;
|
||||
|
||||
case Settings_IoPort_OD_Enable:
|
||||
|
||||
change.mask = (uint8_t)value & digital.outx.mask;
|
||||
|
||||
if((changed.mask = settings.ioport.od_enable_out.mask ^ change.mask)) {
|
||||
|
||||
gpio_out_config_t config = {0};
|
||||
|
||||
do {
|
||||
if((changed.mask & 0x01) && (xbar = hal.port.get_pin_info(Port_Digital, Port_Output, ioports_map_reverse(digital.out.ports, port)))) {
|
||||
if(xbar->config) {
|
||||
config.inverted = xbar->mode.inverted;
|
||||
config.open_drain = !!(change.mask & (1 << xbar->id));
|
||||
xbar->config(xbar, &config, false);
|
||||
}
|
||||
}
|
||||
port++;
|
||||
} while(changed.mask >>= 1);
|
||||
|
||||
settings.ioport.od_enable_out.mask = change.mask;
|
||||
|
||||
if(on_setting_changed)
|
||||
on_setting_changed(id);
|
||||
@@ -399,10 +586,18 @@ static uint32_t aux_get_value (setting_id_t id)
|
||||
value = settings.ioport.invert_in.mask;
|
||||
break;
|
||||
|
||||
case Settings_IoPort_Pullup_Disable:
|
||||
value = settings.ioport.pullup_disable_in.mask;
|
||||
break;
|
||||
|
||||
case Settings_IoPort_InvertOut:
|
||||
value = settings.ioport.invert_out.mask;
|
||||
break;
|
||||
|
||||
case Settings_IoPort_OD_Enable:
|
||||
value = settings.ioport.od_enable_out.mask;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -416,9 +611,11 @@ static const setting_group_detail_t ioport_groups[] = {
|
||||
|
||||
static const setting_detail_t ioport_settings[] = {
|
||||
{ Settings_IoPort_InvertIn, Group_AuxPorts, "Invert I/O Port inputs", NULL, Format_Bitfield, digital.in.port_names, NULL, NULL, Setting_NonCoreFn, aux_set_value, aux_get_value, is_setting_available },
|
||||
// { Settings_IoPort_Pullup_Disable, Group_AuxPorts, "I/O Port inputs pullup disable", NULL, Format_Bitfield, "Port 0,Port 1,Port 2,Port 3,Port 4,Port 5,Port 6,Port 7", NULL, NULL },
|
||||
#ifdef AUX_SETTINGS_PULLUP
|
||||
{ Settings_IoPort_Pullup_Disable, Group_AuxPorts, "I/O Port inputs pullup disable", NULL, Format_Bitfield, digital.in.port_names, NULL, NULL, Setting_NonCoreFn, aux_set_value, aux_get_value, is_setting_available },
|
||||
#endif
|
||||
{ Settings_IoPort_InvertOut, Group_AuxPorts, "Invert I/O Port outputs", NULL, Format_Bitfield, digital.out.port_names, NULL, NULL, Setting_NonCoreFn, aux_set_value, aux_get_value, is_setting_available },
|
||||
// { Settings_IoPort_OD_Enable, Group_AuxPorts, "I/O Port outputs as open drain", NULL, Format_Bitfield, "Port 0,Port 1,Port 2,Port 3,Port 4,Port 5,Port 6,Port 7", NULL, NULL }
|
||||
// { Settings_IoPort_OD_Enable, Group_AuxPorts, "I/O Port outputs as open drain", NULL, Format_Bitfield, digital.out.port_names, NULL, NULL, Setting_NonCoreFn, aux_set_value, aux_get_value, is_setting_available }
|
||||
};
|
||||
|
||||
#ifndef NO_SETTINGS_DESCRIPTIONS
|
||||
@@ -434,6 +631,54 @@ static const setting_descr_t ioport_settings_descr[] = {
|
||||
|
||||
static void ioport_settings_load (void)
|
||||
{
|
||||
uint8_t port;
|
||||
xbar_t *xbar;
|
||||
gpio_in_config_t in_config = {0};
|
||||
gpio_out_config_t out_config = {0};
|
||||
|
||||
// TODO: change labels for mapped settings?
|
||||
|
||||
if(digital.in.ports && (port = digital.in.ports->n_ports)) do {
|
||||
if((xbar = hal.port.get_pin_info(Port_Digital, Port_Input, ioports_map_reverse(digital.in.ports, --port)))) {
|
||||
if(xbar->config) {
|
||||
|
||||
in_config.debounce = xbar->mode.debounce;
|
||||
#ifdef AUX_SETTINGS_PULLUP
|
||||
in_config.pull_mode = settings.ioport.pullup_disable_in.mask & (1 << xbar->id) ? PullMode_None : PullMode_Up;
|
||||
#else
|
||||
in_config.pull_mode = (pull_mode_t)xbar->mode.pull_mode;
|
||||
#endif
|
||||
in_config.inverted = !!(settings.ioport.invert_in.mask & (1 << xbar->id));
|
||||
|
||||
// For probe and control signals higher level config takes priority
|
||||
if(xbar->function == Input_Probe)
|
||||
in_config.inverted = settings.probe.invert_probe_pin;
|
||||
else if(xbar->function < Input_Probe) {
|
||||
control_signals_t ctrl;
|
||||
if((ctrl = xbar_fn_to_signals_mask(xbar->function)).mask)
|
||||
in_config.inverted = !!(settings.control_invert.mask & ctrl.mask);
|
||||
}
|
||||
|
||||
if(in_config.inverted)
|
||||
settings.ioport.invert_in.mask |= (1 << xbar->id);
|
||||
else
|
||||
settings.ioport.invert_in.mask &= ~(1 << xbar->id);
|
||||
|
||||
xbar->config(xbar, &in_config, false);
|
||||
}
|
||||
}
|
||||
} while(port);
|
||||
|
||||
if(digital.out.ports && (port = digital.out.ports->n_ports)) do {
|
||||
if((xbar = hal.port.get_pin_info(Port_Digital, Port_Output, ioports_map_reverse(digital.in.ports, --port)))) {
|
||||
if(xbar->config) {
|
||||
out_config.inverted = !!(settings.ioport.invert_out.mask & (1 << xbar->id));
|
||||
out_config.open_drain = !!(settings.ioport.od_enable_out.mask & (1 << xbar->id));
|
||||
xbar->config(xbar, &out_config, false);
|
||||
}
|
||||
}
|
||||
} while(port);
|
||||
|
||||
if(on_settings_loaded)
|
||||
on_settings_loaded();
|
||||
}
|
||||
@@ -455,6 +700,72 @@ void ioport_setting_changed (setting_id_t id)
|
||||
{
|
||||
if(on_setting_changed)
|
||||
on_setting_changed(id);
|
||||
|
||||
else switch(id) {
|
||||
|
||||
case Setting_InvertProbePin:
|
||||
case Setting_ProbePullUpDisable:
|
||||
{
|
||||
xbar_t *xbar;
|
||||
gpio_in_config_t in_config = {0};
|
||||
uint8_t port = digital.in.ports->n_ports;
|
||||
|
||||
do {
|
||||
if((xbar = hal.port.get_pin_info(Port_Digital, Port_Input, ioports_map_reverse(digital.in.ports, --port)))) {
|
||||
if(xbar->config && xbar->function == Input_Probe) {
|
||||
|
||||
in_config.debounce = Off;
|
||||
in_config.inverted = settings.probe.invert_probe_pin;
|
||||
in_config.pull_mode = settings.probe.disable_probe_pullup ? PullMode_None : PullMode_Up;
|
||||
|
||||
if(in_config.inverted)
|
||||
settings.ioport.invert_in.mask |= (1 << xbar->id);
|
||||
else
|
||||
settings.ioport.invert_in.mask &= ~(1 << xbar->id);
|
||||
|
||||
xbar->config(xbar, &in_config, false);
|
||||
}
|
||||
}
|
||||
} while(port);
|
||||
}
|
||||
break;
|
||||
|
||||
case Setting_ControlInvertMask:
|
||||
case Setting_ControlPullUpDisableMask:
|
||||
{
|
||||
xbar_t *xbar;
|
||||
gpio_in_config_t in_config = {0};
|
||||
control_signals_t ctrl;
|
||||
uint8_t port = digital.in.ports->n_ports;
|
||||
|
||||
do {
|
||||
if((xbar = hal.port.get_pin_info(Port_Digital, Port_Input, ioports_map_reverse(digital.in.ports, --port)))) {
|
||||
if(xbar->config && xbar->function < Input_Probe) {
|
||||
|
||||
in_config.debounce = xbar->mode.debounce;
|
||||
in_config.inverted = !!(settings.ioport.invert_in.mask & (1 << xbar->id));
|
||||
in_config.pull_mode = (pull_mode_t)xbar->mode.pull_mode;
|
||||
|
||||
if((ctrl = xbar_fn_to_signals_mask(xbar->function)).mask) {
|
||||
in_config.inverted = !!(settings.control_invert.mask & ctrl.mask);
|
||||
in_config.pull_mode = (settings.control_disable_pullup.mask & ctrl.mask) ? PullMode_None : PullMode_Up;
|
||||
}
|
||||
|
||||
if(in_config.inverted)
|
||||
settings.ioport.invert_in.mask |= (1 << xbar->id);
|
||||
else
|
||||
settings.ioport.invert_in.mask &= ~(1 << xbar->id);
|
||||
|
||||
xbar->config(xbar, &in_config, false);
|
||||
}
|
||||
}
|
||||
} while(port);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ioports_add_settings (driver_settings_load_ptr settings_loaded, setting_changed_ptr setting_changed)
|
||||
@@ -463,7 +774,7 @@ void ioports_add_settings (driver_settings_load_ptr settings_loaded, setting_cha
|
||||
on_settings_loaded = settings_loaded;
|
||||
|
||||
if(setting_changed)
|
||||
on_setting_changed = setting_changed,
|
||||
on_setting_changed = setting_changed;
|
||||
|
||||
settings_register(&setting_details);
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
|
||||
Copyright (c) 2021-2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -127,6 +127,11 @@ 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_cap_t filter, ioports_enumerate_callback_ptr callback, void *data);
|
||||
void ioport_assign_function (aux_ctrl_t *aux_ctrl, pin_function_t *function);
|
||||
bool ioport_analog_out_config (uint8_t port, pwm_config_t *config);
|
||||
bool ioport_digital_in_config (uint8_t port, gpio_in_config_t *config);
|
||||
bool ioport_enable_irq (uint8_t port, pin_irq_mode_t irq_mode, ioport_interrupt_callback_ptr handler);
|
||||
bool ioport_digital_out_config (uint8_t port, gpio_out_config_t *config);
|
||||
|
||||
//
|
||||
|
||||
@@ -160,6 +165,8 @@ typedef struct {
|
||||
|
||||
bool ioports_add (io_ports_data_t *ports, io_port_type_t type, uint8_t n_in, uint8_t n_out);
|
||||
void ioports_add_settings (driver_settings_load_ptr settings_loaded, setting_changed_ptr setting_changed);
|
||||
void ioport_save_input_settings (xbar_t *xbar, gpio_in_config_t *config);
|
||||
void ioport_save_output_settings (xbar_t *xbar, gpio_out_config_t *config);
|
||||
void ioport_setting_changed (setting_id_t id);
|
||||
#define iports_get_pnum(type, port) type.get_pnum(&type, port)
|
||||
#define ioports_map(type, port) ( type.map ? type.map[port] : port )
|
||||
|
||||
+7
-6
@@ -3,21 +3,21 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2017-2023 Terje Io
|
||||
Copyright (c) 2017-2024 Terje Io
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
@@ -45,7 +45,8 @@ PROGMEM static const message_t messages[] = {
|
||||
{ .id = Message_TPCycleStart2Continue, .text = "Remove any touch plate and press cycle start to continue." },
|
||||
{ .id = Message_ProbeFailedRetry, .text = "Probe failed, try again." },
|
||||
{ .id = Message_ExecuteTPW, .text = "Perform a probe with $TPW first!", .type = Message_Warning},
|
||||
{ .id = Message_ProbeProtected, .text = "Probe protection activated."}
|
||||
{ .id = Message_ProbeProtected, .text = "Probe protection activated."},
|
||||
{ .id = Message_Stop, .text = "Stop"}
|
||||
};
|
||||
|
||||
const message_t *message_get (message_code_t id)
|
||||
|
||||
+7
-6
@@ -3,20 +3,20 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2017-2023 Terje Io
|
||||
Copyright (c) 2017-2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MESSAGES_H_
|
||||
@@ -46,7 +46,8 @@ typedef enum {
|
||||
Message_ProbeFailedRetry = 19, //!< 19
|
||||
Message_ExecuteTPW = 20, //!< 20
|
||||
Message_ProbeProtected = 21, //!< 21
|
||||
Message_NextMessage //!< 22 - next unassigned message number.
|
||||
Message_Stop = 22, //!< 22
|
||||
Message_NextMessage //!< 23 - next unassigned message number.
|
||||
} message_code_t;
|
||||
|
||||
typedef enum {
|
||||
|
||||
+276
-70
@@ -7,20 +7,50 @@
|
||||
|
||||
Copyright (c) 2021-2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Sanity checks
|
||||
|
||||
#if PROBE_ENABLE && !defined(PROBE_PIN)
|
||||
#error "Probe input is not supported in this configuration!"
|
||||
#endif
|
||||
|
||||
#if SAFETY_DOOR_ENABLE && !defined(SAFETY_DOOR_PIN)
|
||||
#error "Safety door input is not supported in this configuration!"
|
||||
#endif
|
||||
|
||||
#if MOTOR_FAULT_ENABLE && !defined(MOTOR_FAULT_PIN)
|
||||
#error "Motor fault input is not supported in this configuration!"
|
||||
#endif
|
||||
|
||||
#if MOTOR_WARNING_ENABLE && !defined(MOTOR_WARNING_PIN)
|
||||
#error "Motor warning input is not supported in this configuration!"
|
||||
#endif
|
||||
|
||||
#if I2C_STROBE_ENABLE && !defined(I2C_STROBE_PIN)
|
||||
#error "I2C keypad/strobe is not supported in this configuration!"
|
||||
#endif
|
||||
|
||||
#if MPG_MODE == 1 && !defined(MPG_MODE_PIN)
|
||||
#error "MPG mode input is not supported in this configuration!"
|
||||
#endif
|
||||
|
||||
#if QEI_SELECT_ENABLE && !defined(QEI_SELECT_PIN)
|
||||
#error "Encoder select input is not supported in this configuration!"
|
||||
#endif
|
||||
|
||||
// Control input signals
|
||||
|
||||
// Define the CONTROL_PORT symbol as a shorthand in the *_map.h file if all control inputs share the same port.
|
||||
@@ -100,24 +130,20 @@
|
||||
// Optional control signals
|
||||
|
||||
#ifndef SAFETY_DOOR_BIT
|
||||
#if defined(SAFETY_DOOR_PIN) && !SAFETY_DOOR_ENABLE
|
||||
#if defined(SAFETY_DOOR_PIN) && !defined(AUX_DEVICES)
|
||||
#define SAFETY_DOOR_BIT (1<<SAFETY_DOOR_PIN)
|
||||
#else
|
||||
#define SAFETY_DOOR_BIT 0
|
||||
#if !defined(SAFETY_DOOR_PIN) && SAFETY_DOOR_ENABLE
|
||||
#warning "SAFETY_DOOR_PIN is not defined!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Optional control signals, assigned to auxillary input pins
|
||||
|
||||
#ifndef MOTOR_FAULT_BIT
|
||||
#if defined(MOTOR_FAULT_PIN) && !MOTOR_FAULT_ENABLE
|
||||
#define MOTOR_FAULT_BIT (1<<MOTOR_FAULT_PIN)
|
||||
#else
|
||||
#define MOTOR_FAULT_BIT 0
|
||||
#if !defined(MOTOR_FAULT_PIN) && MOTOR_FAULT_ENABLE
|
||||
#warning "MOTOR_FAULT_PIN is not defined!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -126,9 +152,6 @@
|
||||
#define MOTOR_WARNING_BIT (1<<MOTOR_WARNING_PIN)
|
||||
#else
|
||||
#define MOTOR_WARNING_BIT 0
|
||||
#if !defined(MOTOR_WARNING_PIN) && MOTOR_WARNING_ENABLE
|
||||
#warning "MOTOR_WARNING_PIN is not defined!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -173,33 +196,197 @@
|
||||
#endif
|
||||
|
||||
#if SAFETY_DOOR_ENABLE || MOTOR_FAULT_ENABLE || MOTOR_WARNING_ENABLE || PROBE_DISCONNECT_ENABLE || \
|
||||
STOP_DISABLE_ENABLE || BLOCK_DELETE_ENABLE || SINGLE_BLOCK_ENABLE || LIMITS_OVERRIDE_ENABLE || defined __DOXYGEN__
|
||||
STOP_DISABLE_ENABLE || BLOCK_DELETE_ENABLE || SINGLE_BLOCK_ENABLE || LIMITS_OVERRIDE_ENABLE || \
|
||||
(defined(AUX_DEVICES) && (PROBE_ENABLE || I2C_STROBE_ENABLE || MPG_MODE == 1 || QEI_SELECT_ENABLE)) || defined __DOXYGEN__
|
||||
|
||||
#define AUX_CONTROLS_ENABLED 1
|
||||
|
||||
#if PROBE_DISCONNECT_ENABLE || STOP_DISABLE_ENABLE || BLOCK_DELETE_ENABLE || SINGLE_BLOCK_ENABLE || LIMITS_OVERRIDE_ENABLE
|
||||
#define AUX_CONTROLS_SCAN 3 // start index for scanned inputs
|
||||
#define AUX_CONTROLS_SCAN 1
|
||||
#else
|
||||
#define AUX_CONTROLS_SCAN 0
|
||||
#endif
|
||||
|
||||
#if SAFETY_DOOR_ENABLE || MOTOR_FAULT_ENABLE || MOTOR_WARNING_ENABLE
|
||||
#define AUX_CONTROLS_XMAP 1
|
||||
#else
|
||||
#define AUX_CONTROLS_XMAP 0
|
||||
#endif
|
||||
|
||||
static aux_ctrl_t aux_ctrl[] = {
|
||||
{ .enabled = SAFETY_DOOR_ENABLE, .port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .safety_door_ajar = On }, .function = Input_SafetyDoor },
|
||||
{ .enabled = MOTOR_FAULT_ENABLE, .port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .motor_fault = On }, .function = Input_MotorFault },
|
||||
{ .enabled = MOTOR_WARNING_ENABLE, .port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .motor_warning = On }, .function = Input_MotorWarning },
|
||||
{ .enabled = PROBE_DISCONNECT_ENABLE, .port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .motor_fault = On }, .function = Input_ProbeDisconnect },
|
||||
{ .enabled = STOP_DISABLE_ENABLE, .port = 0xFF, .irq_mode = IRQ_Mode_Change, .cap = { .stop_disable = On }, .function = Input_StopDisable },
|
||||
{ .enabled = BLOCK_DELETE_ENABLE, .port = 0xFF, .irq_mode = IRQ_Mode_Change, .cap = { .block_delete = On }, .function = Input_BlockDelete },
|
||||
{ .enabled = SINGLE_BLOCK_ENABLE, .port = 0xFF, .irq_mode = IRQ_Mode_Change, .cap = { .single_block = On }, .function = Input_SingleBlock },
|
||||
{ .enabled = LIMITS_OVERRIDE_ENABLE, .port = 0xFF, .irq_mode = IRQ_Mode_None, .cap = { .limits_override = On }, .function = Input_LimitsOverride }
|
||||
// The following pins are bound explicitly to aux pins
|
||||
#if PROBE_ENABLE && defined(PROBE_PIN) && defined(AUX_DEVICES)
|
||||
#ifdef PROBE_PORT
|
||||
{ .function = Input_Probe, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .value = 0 }, .pin = PROBE_PIN, .port = PROBE_PORT },
|
||||
#else
|
||||
{ .function = Input_Probe, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .value = 0 }, .pin = PROBE_PIN, .port = NULL },
|
||||
#endif
|
||||
#endif
|
||||
#if SAFETY_DOOR_ENABLE && defined(SAFETY_DOOR_PIN)
|
||||
#ifdef SAFETY_DOOR_PORT
|
||||
{ .function = Input_SafetyDoor, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .safety_door_ajar = On }, .pin = SAFETY_DOOR_PIN, .port = SAFETY_DOOR_PORT },
|
||||
#else
|
||||
{ .function = Input_SafetyDoor, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .safety_door_ajar = On }, .pin = SAFETY_DOOR_PIN, .port = NULL },
|
||||
#endif
|
||||
#endif
|
||||
#if MOTOR_FAULT_ENABLE && defined(MOTOR_FAULT_PIN)
|
||||
#ifdef MOTOR_FAULT_PORT
|
||||
{ .function = Input_MotorFault, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .motor_fault = On }, .pin = MOTOR_FAULT_PIN, .port = MOTOR_FAULT_PORT },
|
||||
#else
|
||||
{ .function = Input_MotorFault, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .motor_fault = On }, .pin = MOTOR_FAULT_PIN, .port = NULL },
|
||||
#endif
|
||||
#if MOTOR_WARNING_ENABLE && defined(MOTOR_WARNING_PIN)
|
||||
#ifdef MOTOR_WARNING_PORT
|
||||
{ .function = Input_MotorWarning, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .motor_fault = On }, .pin = MOTOR_WARNING_PIN, .port = MOTOR_WARNING_PORT },
|
||||
#else
|
||||
{ .function = Input_MotorWarning, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .motor_warning = On }, .pin = MOTOR_WARNING_PIN, .port = NULL },
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if I2C_STROBE_ENABLE && defined(I2C_STROBE_PIN) && defined(AUX_DEVICES)
|
||||
#ifdef I2C_STROBE_PORT
|
||||
{ .function = Input_I2CStrobe, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Change), .cap = { .value = 0 }, .pin = I2C_STROBE_PIN, .port = I2C_STROBE_PORT },
|
||||
#else
|
||||
{ .function = Input_I2CStrobe, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Change), .cap = { .value = 0 }, .pin = I2C_STROBE_PIN, .port = NULL },
|
||||
#endif
|
||||
#endif
|
||||
#if MPG_MODE == 1 && defined(MPG_MODE_PIN) && defined(AUX_DEVICES)
|
||||
#ifdef MPG_MODE_PORT
|
||||
{ .function = Input_MPGSelect, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Change), .cap = { .value = 0 }, .pin = MPG_MODE_PIN, .port = MPG_MODE_PORT },
|
||||
#else
|
||||
{ .function = Input_MPGSelect, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Change), .cap = { .value = 0 }, .pin = MPG_MODE_PIN, .port = NULL },
|
||||
#endif
|
||||
#endif
|
||||
#if QEI_SELECT_ENABLE && defined(QEI_SELECT_PIN) && defined(AUX_DEVICES)
|
||||
#ifdef QEI_SELECT_PORT
|
||||
{ .function = Input_QEI_Select, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .value = 0 }, .pin = QEI_SELECT_PIN, .port = QEI_SELECT_PORT },
|
||||
#else
|
||||
{ .function = Input_QEI_Select, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .value = 0 }, .pin = QEI_SELECT_PIN, .port = NULL },
|
||||
#endif
|
||||
#endif
|
||||
// The following pins are allocated from remaining aux inputs pool
|
||||
#if LIMITS_OVERRIDE_ENABLE
|
||||
{ .function = Input_LimitsOverride, .aux_port = 0xFF, .irq_mode = IRQ_Mode_None, .cap = { .limits_override = On }, .pin = 0xFF, .port = NULL },
|
||||
#endif
|
||||
#if STOP_DISABLE_ENABLE
|
||||
{ .function = Input_StopDisable, .aux_port = 0xFF, .irq_mode = IRQ_Mode_Change, .cap = { .stop_disable = On }, .pin = 0xFF, .port = NULL },
|
||||
#endif
|
||||
#if BLOCK_DELETE_ENABLE
|
||||
{ .function = Input_BlockDelete, .aux_port = 0xFF, .irq_mode = IRQ_Mode_Change, .cap = { .block_delete = On }, .pin = 0xFF, .port = NULL },
|
||||
#endif
|
||||
#if SINGLE_BLOCK_ENABLE
|
||||
{ .function = Input_SingleBlock, .aux_port = 0xFF, .irq_mode = IRQ_Mode_Change, .cap = { .single_block = On }, .pin = 0xFF, .port = NULL },
|
||||
#endif
|
||||
#if PROBE_DISCONNECT_ENABLE
|
||||
{ .function = Input_ProbeDisconnect, .aux_port = 0xFF, .irq_mode = (pin_irq_mode_t)(IRQ_Mode_Rising|IRQ_Mode_Falling), .cap = { .probe_disconnected = On }, .pin = 0xFF, .port = NULL },
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline aux_ctrl_t *aux_ctrl_remap_explicit (void *port, uint8_t pin, uint8_t aux_port, void *input)
|
||||
{
|
||||
aux_ctrl_t *ctrl_pin = NULL;
|
||||
|
||||
uint_fast8_t idx = sizeof(aux_ctrl) / sizeof(aux_ctrl_t);
|
||||
|
||||
do {
|
||||
idx--;
|
||||
if(aux_ctrl[idx].port == port && aux_ctrl[idx].pin == pin) {
|
||||
ctrl_pin = &aux_ctrl[idx];
|
||||
ctrl_pin->aux_port = aux_port;
|
||||
ctrl_pin->input = input;
|
||||
}
|
||||
} while(idx && ctrl_pin == NULL);
|
||||
|
||||
return ctrl_pin;
|
||||
}
|
||||
|
||||
static inline aux_ctrl_t *aux_ctrl_get_pin (uint8_t aux_port)
|
||||
{
|
||||
aux_ctrl_t *ctrl_pin = NULL;
|
||||
|
||||
uint_fast8_t idx = sizeof(aux_ctrl) / sizeof(aux_ctrl_t);
|
||||
|
||||
do {
|
||||
if(aux_ctrl[--idx].aux_port == aux_port)
|
||||
ctrl_pin = &aux_ctrl[idx];
|
||||
} while(idx && ctrl_pin == NULL);
|
||||
|
||||
return ctrl_pin;
|
||||
}
|
||||
|
||||
static inline void aux_ctrl_irq_enable (settings_t *settings, ioport_interrupt_callback_ptr aux_irq_handler)
|
||||
{
|
||||
uint_fast8_t idx = sizeof(aux_ctrl) / sizeof(aux_ctrl_t);
|
||||
|
||||
if(idx) do {
|
||||
if(aux_ctrl[--idx].aux_port != 0xFF) {
|
||||
#if PROBE_ENABLE && defined(PROBE_PIN) && defined(AUX_DEVICES)
|
||||
if(aux_ctrl[idx].function == Input_Probe) {
|
||||
xbar_t *xbar;
|
||||
if((xbar = hal.port.get_pin_info(Port_Digital, Port_Input, aux_ctrl[idx].aux_port))) {
|
||||
gpio_in_config_t cfg;
|
||||
cfg.inverted = settings->probe.invert_probe_pin;
|
||||
cfg.debounce = xbar->mode.debounce;
|
||||
cfg.pull_mode = settings->probe.disable_probe_pullup ? PullMode_None : PullMode_Up;
|
||||
xbar->config(xbar, &cfg, false);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if(aux_ctrl[idx].irq_mode != IRQ_Mode_None) {
|
||||
if(aux_ctrl[idx].irq_mode & (IRQ_Mode_Falling|IRQ_Mode_Rising))
|
||||
aux_ctrl[idx].irq_mode = (settings->control_invert.mask & aux_ctrl[idx].cap.mask) ? IRQ_Mode_Falling : IRQ_Mode_Rising;
|
||||
hal.port.register_interrupt_handler(aux_ctrl[idx].aux_port, aux_ctrl[idx].irq_mode, aux_irq_handler);
|
||||
}
|
||||
}
|
||||
} while(idx);
|
||||
}
|
||||
|
||||
typedef bool (*aux_claim_explicit_ptr)(aux_ctrl_t *aux_ctrl);
|
||||
|
||||
static bool aux_ctrl_claim_port (xbar_t *properties, uint8_t port, void *data)
|
||||
{
|
||||
if(ioport_claim(Port_Digital, Port_Input, &properties->id, xbar_fn_to_pinname(((aux_ctrl_t *)data)->function)))
|
||||
((aux_ctrl_t *)data)->aux_port = properties->id;
|
||||
|
||||
return ((aux_ctrl_t *)data)->aux_port != 0xFF;
|
||||
}
|
||||
|
||||
static inline void aux_ctrl_claim_ports (aux_claim_explicit_ptr aux_claim_explicit, ioports_enumerate_callback_ptr aux_claim)
|
||||
{
|
||||
uint_fast8_t idx;
|
||||
|
||||
if(aux_claim == NULL)
|
||||
aux_claim = aux_ctrl_claim_port;
|
||||
|
||||
for(idx = 0; idx < sizeof(aux_ctrl) / sizeof(aux_ctrl_t); idx++) {
|
||||
if(aux_ctrl[idx].pin == 0xFF) {
|
||||
if(ioports_enumerate(Port_Digital, Port_Input, (pin_cap_t){ .irq_mode = aux_ctrl[idx].irq_mode, .claimable = On }, aux_claim, (void *)&aux_ctrl[idx]))
|
||||
hal.signals_cap.mask |= aux_ctrl[idx].cap.mask;
|
||||
} else if(aux_ctrl[idx].aux_port != 0xFF)
|
||||
aux_claim_explicit(&aux_ctrl[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
#if AUX_CONTROLS_SCAN
|
||||
|
||||
static inline control_signals_t aux_ctrl_scan_status (control_signals_t signals)
|
||||
{
|
||||
uint_fast8_t idx = sizeof(aux_ctrl) / sizeof(aux_ctrl_t);
|
||||
|
||||
if(idx) do {
|
||||
if(aux_ctrl[--idx].pin != 0xFF)
|
||||
break;
|
||||
if(aux_ctrl[idx].aux_port != 0xFF) {
|
||||
signals.mask &= ~aux_ctrl[idx].cap.mask;
|
||||
#ifdef GRBL_ESP32 // Snowflake guru workaround
|
||||
if(hal.port.wait_on_input(Port_Digital, aux_ctrl[idx].aux_port, WaitMode_Immediate, FZERO) == 1)
|
||||
signals.mask |= aux_ctrl[idx].cap.mask;
|
||||
#else
|
||||
if(hal.port.wait_on_input(Port_Digital, aux_ctrl[idx].aux_port, WaitMode_Immediate, 0.0f) == 1)
|
||||
signals.mask |= aux_ctrl[idx].cap.mask;
|
||||
#endif
|
||||
}
|
||||
} while(idx);
|
||||
|
||||
return signals;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define AUX_CONTROLS_ENABLED 0
|
||||
#define AUX_CONTROLS_SCAN 0
|
||||
@@ -217,12 +404,6 @@ static aux_ctrl_t aux_ctrl[] = {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Probe input signal
|
||||
|
||||
#if defined(PROBE_PIN) && !defined(PROBE_BIT)
|
||||
#define PROBE_BIT (1<<PROBE_PIN)
|
||||
#endif
|
||||
|
||||
// Output Signals
|
||||
|
||||
#if defined(SPINDLE_ENABLE_PIN) && !defined(SPINDLE_ENABLE_BIT)
|
||||
@@ -245,41 +426,26 @@ static aux_ctrl_t aux_ctrl[] = {
|
||||
|
||||
// IRQ enabled input singnals
|
||||
|
||||
#ifndef MPG_MODE_PIN
|
||||
#define MPG_MODE_BIT 0
|
||||
#elif !defined(MPG_MODE_BIT)
|
||||
#ifndef AUX_DEVICES
|
||||
|
||||
// IRQ capability for the probe input is optional
|
||||
#if defined(PROBE_PIN) && !defined(PROBE_BIT)
|
||||
#define PROBE_BIT (1<<PROBE_PIN)
|
||||
#endif
|
||||
|
||||
#if defined(MPG_MODE_PIN) && !defined(MPG_MODE_BIT)
|
||||
#define MPG_MODE_BIT (1<<MPG_MODE_PIN)
|
||||
#endif
|
||||
|
||||
#ifndef I2C_STROBE_PIN
|
||||
#define I2C_STROBE_BIT 0
|
||||
#elif !defined(I2C_STROBE_BIT)
|
||||
#if defined(I2C_STROBE_PIN) && !defined(I2C_STROBE_BIT)
|
||||
#define I2C_STROBE_BIT (1<<I2C_STROBE_PIN)
|
||||
#endif
|
||||
|
||||
#ifndef SPI_IRQ_PIN
|
||||
#define SPI_IRQ_BIT 0
|
||||
#elif !defined(SPI_IRQ_BIT)
|
||||
#define SPI_IRQ_BIT (1<<SPI_IRQ_PIN)
|
||||
#if defined(QEI_SELECT_PIN) && !defined(QEI_SELECT_BIT)
|
||||
#define QEI_SELECT_BIT (1<<QEI_SELECT_PIN)
|
||||
#endif
|
||||
|
||||
#if SPINDLE_SYNC_ENABLE
|
||||
#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
|
||||
#endif
|
||||
#endif // !AUX_DEVICES
|
||||
|
||||
#if QEI_ENABLE
|
||||
#ifndef QEI_A_BIT
|
||||
@@ -288,20 +454,60 @@ static aux_ctrl_t aux_ctrl[] = {
|
||||
#ifndef QEI_B_BIT
|
||||
#define QEI_B_BIT (1<<QEI_B_PIN)
|
||||
#endif
|
||||
#ifndef QEI_SELECT_PIN
|
||||
#define QEI_SELECT_BIT 0
|
||||
#elif !defined(QEI_SELECT_BIT)
|
||||
#define QEI_SELECT_BIT (1<<QEI_SELECT_PIN)
|
||||
#endif
|
||||
#else
|
||||
#define QEI_A_BIT 0
|
||||
#define QEI_B_BIT 0
|
||||
#endif
|
||||
|
||||
#ifndef QEI_SELECT_BIT
|
||||
#define QEI_SELECT_BIT 0
|
||||
#endif
|
||||
#ifndef MPG_MODE_BIT
|
||||
#define MPG_MODE_BIT 0
|
||||
#endif
|
||||
#ifndef I2C_STROBE_BIT
|
||||
#define I2C_STROBE_BIT 0
|
||||
#endif
|
||||
|
||||
// Do NOT #define PROBE_BIT 0 here!
|
||||
|
||||
#if SPINDLE_ENCODER_ENABLE
|
||||
#ifndef SPINDLE_PULSE_PIN
|
||||
#error "Spindle encoder requires at least SPINDLE_PULSE_PIN defined in the board map!"
|
||||
#endif
|
||||
#if !defined(SPINDLE_PULSE_BIT) && defined(SPINDLE_PULSE_PIN)
|
||||
#define SPINDLE_PULSE_BIT (1<<SPINDLE_PULSE_PIN)
|
||||
#endif
|
||||
#if !defined(SPINDLE_INDEX_BIT) && defined(SPINDLE_INDEX_PIN)
|
||||
#define SPINDLE_INDEX_BIT (1<<SPINDLE_INDEX_PIN)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SPINDLE_INDEX_BIT
|
||||
#define SPINDLE_INDEX_BIT 0
|
||||
#endif
|
||||
#ifndef SPINDLE_PULSE_BIT
|
||||
#define SPINDLE_PULSE_BIT 0
|
||||
#endif
|
||||
|
||||
#if SPINDLE_SYNC_ENABLE && (SPINDLE_INDEX_BIT + SPINDLE_PULSE_BIT) == 0
|
||||
#error "Spindle sync requires SPINDLE_PULSE_PIN and SPINDLE_INDEX_PIN defined in the board map!"
|
||||
#endif
|
||||
|
||||
#ifndef SPI_IRQ_PIN
|
||||
#define SPI_IRQ_BIT 0
|
||||
#elif !defined(SPI_IRQ_BIT)
|
||||
#define SPI_IRQ_BIT (1<<SPI_IRQ_PIN)
|
||||
#endif
|
||||
|
||||
#ifndef DEVICES_IRQ_MASK
|
||||
#define DEVICES_IRQ_MASK (MPG_MODE_BIT|I2C_STROBE_BIT|SPI_IRQ_BIT|SPINDLE_INDEX_BIT|QEI_A_BIT|QEI_B_BIT|QEI_SELECT_BIT)
|
||||
#define DEVICES_IRQ_MASK_SUM (MPG_MODE_BIT+I2C_STROBE_BIT+SPI_IRQ_BIT+SPINDLE_INDEX_BIT+QEI_A_BIT+QEI_B_BIT+QEI_SELECT_BIT)
|
||||
#ifdef AUX_DEVICES
|
||||
#define DEVICES_IRQ_MASK (SPI_IRQ_BIT|SPINDLE_INDEX_BIT|QEI_A_BIT|QEI_B_BIT)
|
||||
#define DEVICES_IRQ_MASK_SUM (SPI_IRQ_BIT+SPINDLE_INDEX_BIT+QEI_A_BIT+QEI_B_BIT)
|
||||
#else
|
||||
#define DEVICES_IRQ_MASK (MPG_MODE_BIT|I2C_STROBE_BIT|QEI_SELECT_BIT|SPI_IRQ_BIT|SPINDLE_INDEX_BIT|QEI_A_BIT|QEI_B_BIT)
|
||||
#define DEVICES_IRQ_MASK_SUM (MPG_MODE_BIT+I2C_STROBE_BIT+QEI_SELECT_BIT+SPI_IRQ_BIT+SPINDLE_INDEX_BIT+QEI_A_BIT+QEI_B_BIT)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Auxillary input signals
|
||||
|
||||
@@ -3,20 +3,20 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2020 Terje Io
|
||||
Copyright (c) 2020-2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _PROBE_H_
|
||||
@@ -36,7 +36,8 @@ typedef union {
|
||||
connected :1, //<! Set to true when probe is connected. Always set to true if the driver does not have a probe connected input.
|
||||
inverted :1, //<! For driver use
|
||||
is_probing :1, //<! For driver use
|
||||
unassigned :4;
|
||||
irq_enabled :1, //<! For driver use
|
||||
unassigned :3;
|
||||
};
|
||||
} probe_state_t;
|
||||
|
||||
|
||||
+46
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
protocol.c - controls Grbl execution protocol and procedures
|
||||
protocol.c - controls grblHAL execution protocol and procedures
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -51,10 +51,7 @@ typedef union {
|
||||
|
||||
typedef struct {
|
||||
void *data;
|
||||
union {
|
||||
foreground_task_ptr fn;
|
||||
on_execute_realtime_ptr fn_deprecated;
|
||||
};
|
||||
fg_task_ptr task;
|
||||
} delayed_task_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -68,9 +65,10 @@ static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
|
||||
static char xcommand[LINE_BUFFER_SIZE];
|
||||
static bool keep_rt_commands = false;
|
||||
static realtime_queue_t realtime_queue = {0};
|
||||
static on_execute_realtime_ptr on_execute_delay;
|
||||
|
||||
static void protocol_execute_rt_commands (sys_state_t state);
|
||||
static void protocol_exec_rt_suspend (sys_state_t state);
|
||||
static void protocol_execute_rt_commands (void);
|
||||
|
||||
// add gcode to execute not originating from normal input stream
|
||||
bool protocol_enqueue_gcode (char *gcode)
|
||||
@@ -88,6 +86,16 @@ bool protocol_enqueue_gcode (char *gcode)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void protocol_on_execute_delay (sys_state_t state)
|
||||
{
|
||||
if(sys.rt_exec_state & EXEC_RT_COMMAND) {
|
||||
system_clear_exec_state_flag(EXEC_RT_COMMAND);
|
||||
protocol_execute_rt_commands(0);
|
||||
}
|
||||
|
||||
on_execute_delay(state);
|
||||
}
|
||||
|
||||
static bool recheck_line (char *line, line_flags_t *flags)
|
||||
{
|
||||
bool keep_rt_commands = false, first_char = true;
|
||||
@@ -150,7 +158,7 @@ bool protocol_main_loop (void)
|
||||
grbl.report.feedback_message(Message_ProbeProtected);
|
||||
} else if (limits_homing_required()) {
|
||||
// Check for power-up and set system alarm if homing is enabled to force homing cycle
|
||||
// by setting Grbl's alarm state. Alarm locks out all g-code commands, including the
|
||||
// by setting grblHAL's alarm state. Alarm locks out all g-code commands, including the
|
||||
// startup scripts, but allows access to settings and internal commands.
|
||||
// Only a successful homing cycle '$H' will disable the alarm.
|
||||
// NOTE: The startup script will run after successful completion of the homing cycle. Prevents motion startup
|
||||
@@ -197,13 +205,15 @@ bool protocol_main_loop (void)
|
||||
hal.coolant.set_state((coolant_state_t){0});
|
||||
if(realtime_queue.head != realtime_queue.tail)
|
||||
system_set_exec_state_flag(EXEC_RT_COMMAND); // execute any boot up commands
|
||||
on_execute_delay = grbl.on_execute_delay;
|
||||
grbl.on_execute_delay = protocol_on_execute_delay;
|
||||
sys.cold_start = false;
|
||||
} else // TODO: if flushing entries from the queue that has allocated data associated then these will be orphaned/leaked.
|
||||
memset(&realtime_queue, 0, sizeof(realtime_queue_t));
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Primary loop! Upon a system abort, this exits back to main() to reset the system.
|
||||
// This is also where Grbl idles while waiting for something to do.
|
||||
// This is also where grblHAL idles while waiting for something to do.
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
int16_t c;
|
||||
@@ -254,7 +264,7 @@ bool protocol_main_loop (void)
|
||||
gc_state.last_error = Status_Overflow;
|
||||
else if(*line == '\0') // Empty line. For syncing purposes.
|
||||
gc_state.last_error = Status_OK;
|
||||
else if(*line == '$') {// Grbl '$' system command
|
||||
else if(*line == '$') {// grblHAL '$' system command
|
||||
if((gc_state.last_error = system_execute_line(line)) == Status_LimitsEngaged) {
|
||||
system_raise_alarm(Alarm_LimitsEngaged);
|
||||
grbl.report.feedback_message(Message_CheckLimits);
|
||||
@@ -333,7 +343,7 @@ bool protocol_main_loop (void)
|
||||
// Handle extra command (internal stream)
|
||||
if(xcommand[0] != '\0') {
|
||||
|
||||
if (xcommand[0] == '$') // Grbl '$' system command
|
||||
if (xcommand[0] == '$') // grblHAL '$' system command
|
||||
system_execute_line(xcommand);
|
||||
else if (state_get() & (STATE_ALARM|STATE_ESTOP|STATE_JOG)) // Everything else is gcode. Block if in alarm, eStop or jog state.
|
||||
grbl.report.status_message(Status_SystemGClock);
|
||||
@@ -386,7 +396,7 @@ void protocol_auto_cycle_start (void)
|
||||
}
|
||||
|
||||
|
||||
// This function is the general interface to Grbl's real-time command execution system. It is called
|
||||
// This function is the general interface to grblHAL's real-time command execution system. It is called
|
||||
// from various check points in the main program, primarily where there may be a while loop waiting
|
||||
// for a buffer to clear space or any point where the execution time from the last check point may
|
||||
// be more than a fraction of a second. This is a way to execute realtime commands asynchronously
|
||||
@@ -438,8 +448,8 @@ static void protocol_poll_cmd (void)
|
||||
}
|
||||
}
|
||||
|
||||
// Executes run-time commands, when required. This function primarily operates as Grbl's state
|
||||
// machine and controls the various real-time features Grbl has to offer.
|
||||
// Executes run-time commands, when required. This function primarily operates as grblHAL's state
|
||||
// machine and controls the various real-time features grblHAL has to offer.
|
||||
// NOTE: Do not alter this unless you know exactly what you are doing!
|
||||
bool protocol_exec_rt_system (void)
|
||||
{
|
||||
@@ -456,7 +466,7 @@ bool protocol_exec_rt_system (void)
|
||||
}
|
||||
|
||||
// System alarm. Everything has shutdown by something that has gone severely wrong. Report
|
||||
// the source of the error to the user. If critical, Grbl disables by entering an infinite
|
||||
// the source of the error to the user. If critical, grblHAL disables by entering an infinite
|
||||
// loop until system reset/abort.
|
||||
system_raise_alarm((alarm_code_t)rt_exec);
|
||||
|
||||
@@ -564,12 +574,12 @@ bool protocol_exec_rt_system (void)
|
||||
|
||||
gc_init();
|
||||
plan_reset();
|
||||
/* if(sys.alarm_pending == Alarm_ProbeProtect) {
|
||||
if(sys.alarm_pending == Alarm_ProbeProtect) {
|
||||
st_go_idle();
|
||||
system_set_exec_alarm(sys.alarm_pending);
|
||||
sys.alarm_pending = Alarm_None;
|
||||
} else*/
|
||||
st_reset();
|
||||
} else
|
||||
st_reset();
|
||||
sync_position();
|
||||
|
||||
// Kill spindle and coolant. TODO: Check Mach3 behaviour?
|
||||
@@ -577,8 +587,10 @@ bool protocol_exec_rt_system (void)
|
||||
gc_coolant_off();
|
||||
|
||||
flush_override_buffers();
|
||||
if(!((state_get() == STATE_ALARM) && (sys.alarm == Alarm_LimitsEngaged || sys.alarm == Alarm_HomingRequired)))
|
||||
if(!((state_get() == STATE_ALARM) && (sys.alarm == Alarm_LimitsEngaged || sys.alarm == Alarm_HomingRequired))) {
|
||||
state_set(hal.control.get_state().safety_door_ajar ? STATE_SAFETY_DOOR : STATE_IDLE);
|
||||
grbl.report.feedback_message(Message_Stop);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute and print status to output stream
|
||||
@@ -596,7 +608,7 @@ bool protocol_exec_rt_system (void)
|
||||
report_pid_log();
|
||||
|
||||
if(rt_exec & EXEC_RT_COMMAND)
|
||||
protocol_execute_rt_commands();
|
||||
protocol_execute_rt_commands(0);
|
||||
|
||||
rt_exec &= ~(EXEC_STOP|EXEC_STATUS_REPORT|EXEC_GCODE_REPORT|EXEC_PID_REPORT|EXEC_TLO_REPORT|EXEC_RT_COMMAND); // clear requests already processed
|
||||
|
||||
@@ -768,9 +780,9 @@ bool protocol_exec_rt_system (void)
|
||||
return !ABORTED;
|
||||
}
|
||||
|
||||
// Handles Grbl system suspend procedures, such as feed hold, safety door, and parking motion.
|
||||
// Handles grblHAL system suspend procedures, such as feed hold, safety door, and parking motion.
|
||||
// The system will enter this loop, create local variables for suspend tasks, and return to
|
||||
// whatever function that invoked the suspend, such that Grbl resumes normal operation.
|
||||
// whatever function that invoked the suspend, such that grblHAL resumes normal operation.
|
||||
// This function is written in a way to promote custom parking motions. Simply use this as a
|
||||
// template.
|
||||
static void protocol_exec_rt_suspend (sys_state_t state)
|
||||
@@ -1026,14 +1038,14 @@ static const uint32_t dummy_data = 0;
|
||||
\param data pointer to data to be passed to the callee.
|
||||
\returns true if successful, false otherwise.
|
||||
*/
|
||||
bool protocol_enqueue_foreground_task (foreground_task_ptr fn, void *data)
|
||||
ISR_CODE bool ISR_FUNC(protocol_enqueue_foreground_task)(fg_task_ptr fn, void *data)
|
||||
{
|
||||
bool ok;
|
||||
uint_fast8_t bptr = (realtime_queue.head + 1) & (RT_QUEUE_SIZE - 1); // Get next head pointer
|
||||
|
||||
if((ok = bptr != realtime_queue.tail)) { // If not buffer full
|
||||
realtime_queue.task[realtime_queue.head].data = data;
|
||||
realtime_queue.task[realtime_queue.head].fn = fn; // add function pointer to buffer,
|
||||
realtime_queue.task[realtime_queue.head].task = fn; // add function pointer to buffer,
|
||||
realtime_queue.head = bptr; // update pointer and
|
||||
system_set_exec_state_flag(EXEC_RT_COMMAND); // flag it for execute
|
||||
}
|
||||
@@ -1048,22 +1060,22 @@ __NOTE:__ Deprecated, use protocol_enqueue_foreground_task instead.
|
||||
*/
|
||||
ISR_CODE bool ISR_FUNC(protocol_enqueue_rt_command)(on_execute_realtime_ptr fn)
|
||||
{
|
||||
return protocol_enqueue_foreground_task((foreground_task_ptr)fn, (void *)&dummy_data);
|
||||
return protocol_enqueue_foreground_task(fn, (void *)&dummy_data);
|
||||
}
|
||||
|
||||
// Execute enqueued functions.
|
||||
static void protocol_execute_rt_commands (void)
|
||||
static void protocol_execute_rt_commands (sys_state_t state)
|
||||
{
|
||||
while(realtime_queue.tail != realtime_queue.head) {
|
||||
uint_fast8_t bptr = realtime_queue.tail;
|
||||
if(realtime_queue.task[bptr].fn) {
|
||||
if(realtime_queue.task[bptr].task.fn) {
|
||||
if(realtime_queue.task[bptr].data == (void *)&dummy_data) {
|
||||
on_execute_realtime_ptr call = realtime_queue.task[bptr].fn_deprecated;
|
||||
realtime_queue.task[bptr].fn = NULL;
|
||||
on_execute_realtime_ptr call = realtime_queue.task[bptr].task.fn_deprecated;
|
||||
realtime_queue.task[bptr].task.fn_deprecated = NULL;
|
||||
call(state_get());
|
||||
} else {
|
||||
foreground_task_ptr call = realtime_queue.task[bptr].fn;
|
||||
realtime_queue.task[bptr].fn = NULL;
|
||||
foreground_task_ptr call = realtime_queue.task[bptr].task.fn;
|
||||
realtime_queue.task[bptr].task.fn = NULL;
|
||||
call(realtime_queue.task[bptr].data);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-7
@@ -3,26 +3,29 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2016-2024 Terje Io
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _PROTOCOL_H_
|
||||
#define _PROTOCOL_H_
|
||||
|
||||
#include "task.h"
|
||||
|
||||
// Line buffer size from the input stream to be executed.
|
||||
// NOTE: Not a problem except for extreme cases, but the line buffer size can be too small
|
||||
// and g-code blocks can get truncated. Officially, the g-code standards support up to 256
|
||||
@@ -33,9 +36,12 @@
|
||||
#define LINE_BUFFER_SIZE 257 // 256 characters plus terminator
|
||||
#endif
|
||||
|
||||
typedef void (*foreground_task_ptr)(void *data);
|
||||
typedef union {
|
||||
foreground_task_ptr fn;
|
||||
on_execute_realtime_ptr fn_deprecated;
|
||||
} fg_task_ptr __attribute__ ((__transparent_union__));
|
||||
|
||||
// Starts Grbl main loop. It handles all incoming characters from the input stream and executes
|
||||
// Starts grblHAL main loop. It handles all incoming characters from the input stream and executes
|
||||
// them as they complete. It is also responsible for finishing the initialization procedures.
|
||||
bool protocol_main_loop (void);
|
||||
|
||||
@@ -44,7 +50,7 @@ bool protocol_execute_realtime (void);
|
||||
bool protocol_exec_rt_system (void);
|
||||
void protocol_execute_noop (uint_fast16_t state);
|
||||
bool protocol_enqueue_rt_command (on_execute_realtime_ptr fn);
|
||||
bool protocol_enqueue_foreground_task (foreground_task_ptr fn, void *data);
|
||||
bool protocol_enqueue_foreground_task (fg_task_ptr fn, void *data);
|
||||
|
||||
// Executes the auto cycle feature, if enabled.
|
||||
void protocol_auto_cycle_start (void);
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
Copyright (c) 2017-2024 Terje Io
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -252,24 +252,27 @@ static alarm_code_t report_alarm_message (alarm_code_t alarm_code)
|
||||
// Prints feedback message, typically from gcode.
|
||||
void report_message (const char *msg, message_type_t type)
|
||||
{
|
||||
hal.stream.write("[MSG:");
|
||||
if(hal.stream.is_connected()) {
|
||||
|
||||
switch(type) {
|
||||
hal.stream.write("[MSG:");
|
||||
|
||||
case Message_Info:
|
||||
hal.stream.write("Info: ");
|
||||
break;
|
||||
switch(type) {
|
||||
|
||||
case Message_Warning:
|
||||
hal.stream.write("Warning: ");
|
||||
break;
|
||||
case Message_Info:
|
||||
hal.stream.write("Info: ");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
case Message_Warning:
|
||||
hal.stream.write("Warning: ");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
hal.stream.write(msg);
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
}
|
||||
|
||||
hal.stream.write(msg);
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
}
|
||||
|
||||
// Message helper to be run as foreground task
|
||||
@@ -311,6 +314,7 @@ static message_code_t report_feedback_message (message_code_t id)
|
||||
static void report_init_message (void)
|
||||
{
|
||||
override_counter = wco_counter = 0;
|
||||
|
||||
#if COMPATIBILITY_LEVEL == 0
|
||||
hal.stream.write_all(ASCII_EOL "GrblHAL " GRBL_VERSION " ['$' or '$HELP' for help]" ASCII_EOL);
|
||||
#else
|
||||
@@ -2168,11 +2172,27 @@ status_code_t report_spindle_data (sys_state_t state, char *args)
|
||||
return spindle->get_data ? Status_OK : Status_InvalidStatement;
|
||||
}
|
||||
|
||||
static void report_pin (xbar_t *pin, void *data)
|
||||
// Prints info about registered pins.
|
||||
|
||||
typedef struct {
|
||||
uint8_t pin;
|
||||
pin_function_t function;
|
||||
char port[14];
|
||||
const char *description;
|
||||
uint32_t sortkey;
|
||||
} pin_info_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t idx;
|
||||
uint32_t n_pins;
|
||||
pin_info_t *pins;
|
||||
} pin_data_t;
|
||||
|
||||
static void report_pin_info (pin_info_t *pin)
|
||||
{
|
||||
hal.stream.write("[PIN:");
|
||||
if(pin->port)
|
||||
hal.stream.write((char *)pin->port);
|
||||
if(*pin->port)
|
||||
hal.stream.write(pin->port);
|
||||
hal.stream.write(uitoa(pin->pin));
|
||||
hal.stream.write(",");
|
||||
hal.stream.write(xbar_fn_to_pinname(pin->function));
|
||||
@@ -2183,10 +2203,63 @@ static void report_pin (xbar_t *pin, void *data)
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
}
|
||||
|
||||
static pin_info_t *get_pin_info (xbar_t *pin, pin_info_t *info)
|
||||
{
|
||||
info->function = pin->function;
|
||||
info->pin = pin->pin;
|
||||
info->description = pin->description;
|
||||
info->sortkey = (pin->function << 8) | pin->id | (pin->group >= PinGroup_UART1 && pin->group <= PinGroup_UART4 ? pin->group << 16 : 0);
|
||||
if(pin->port)
|
||||
strcpy(info->port, (char *)pin->port);
|
||||
else
|
||||
*info->port = '\0';
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void count_pins (xbar_t *pin, void *data)
|
||||
{
|
||||
((pin_data_t *)data)->n_pins++;
|
||||
}
|
||||
|
||||
static void get_pins (xbar_t *pin, void *data)
|
||||
{
|
||||
get_pin_info(pin, &((pin_data_t *)data)->pins[((pin_data_t *)data)->idx++]);
|
||||
}
|
||||
|
||||
static int cmp_pins (const void *a, const void *b)
|
||||
{
|
||||
return ((pin_info_t *)a)->sortkey - ((pin_info_t *)b)->sortkey;
|
||||
}
|
||||
|
||||
static void report_pin (xbar_t *pin, void *data)
|
||||
{
|
||||
pin_info_t info;
|
||||
|
||||
report_pin_info(get_pin_info(pin, &info));
|
||||
}
|
||||
|
||||
status_code_t report_pins (sys_state_t state, char *args)
|
||||
{
|
||||
if(hal.enumerate_pins)
|
||||
hal.enumerate_pins(false, report_pin, NULL);
|
||||
pin_data_t pin_data = {0};
|
||||
|
||||
if(hal.enumerate_pins) {
|
||||
|
||||
hal.enumerate_pins(false, count_pins, (void *)&pin_data);
|
||||
|
||||
if((pin_data.pins = malloc(pin_data.n_pins * sizeof(pin_info_t)))) {
|
||||
|
||||
hal.enumerate_pins(false, get_pins, (void *)&pin_data);
|
||||
|
||||
qsort(pin_data.pins, pin_data.n_pins, sizeof(pin_info_t), cmp_pins);
|
||||
for(pin_data.idx = 0; pin_data.idx < pin_data.n_pins; pin_data.idx++)
|
||||
report_pin_info(&pin_data.pins[pin_data.idx]);
|
||||
|
||||
free(pin_data.pins);
|
||||
|
||||
} else
|
||||
hal.enumerate_pins(false, report_pin, NULL);
|
||||
}
|
||||
|
||||
return Status_OK;
|
||||
}
|
||||
@@ -2200,6 +2273,8 @@ static char *irq_mode (pin_irq_mode_t mode)
|
||||
return "R";
|
||||
case IRQ_Mode_Falling:
|
||||
return "F";
|
||||
case IRQ_Mode_RisingFalling:
|
||||
return "T";
|
||||
case IRQ_Mode_Change:
|
||||
return "C";
|
||||
case IRQ_Mode_Edges:
|
||||
@@ -2233,7 +2308,6 @@ static char *pull_mode (pull_mode_t mode)
|
||||
return "-";
|
||||
}
|
||||
|
||||
|
||||
status_code_t report_pin_states (sys_state_t state, char *args)
|
||||
{
|
||||
xbar_t *port;
|
||||
@@ -2243,17 +2317,19 @@ status_code_t report_pin_states (sys_state_t state, char *args)
|
||||
for(idx = 0; idx < ports; idx++) {
|
||||
if((port = hal.port.get_pin_info(Port_Digital, Port_Input, idx))) {
|
||||
hal.stream.write("[PINSTATE:DIN|");
|
||||
hal.stream.write(port->description);
|
||||
hal.stream.write(port->description ? port->description : xbar_fn_to_pinname(port->function));
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(uitoa(idx));
|
||||
hal.stream.write(uitoa(port->id));
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(port->mode.inverted ? "I" : "N");
|
||||
hal.stream.write(pull_mode(port->mode.pull_mode));
|
||||
hal.stream.write(irq_mode(port->mode.irq_mode));
|
||||
hal.stream.write(pull_mode((pull_mode_t)port->mode.pull_mode));
|
||||
hal.stream.write(irq_mode((pin_irq_mode_t)port->mode.irq_mode));
|
||||
hal.stream.write(port->mode.debounce ? "D" : "-");
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(port->cap.invert ? "I" : "-");
|
||||
hal.stream.write(pull_mode(port->cap.pull_mode));
|
||||
hal.stream.write(irq_mode(port->cap.irq_mode));
|
||||
hal.stream.write(pull_mode((pull_mode_t)port->cap.pull_mode));
|
||||
hal.stream.write(irq_mode((pin_irq_mode_t)port->cap.irq_mode));
|
||||
hal.stream.write(port->cap.debounce ? "D" : "-");
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(port->get_value ? uitoa((uint32_t)port->get_value(port)) : "?");
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
@@ -2267,11 +2343,13 @@ status_code_t report_pin_states (sys_state_t state, char *args)
|
||||
hal.stream.write("[PINSTATE:DOUT|");
|
||||
hal.stream.write(port->description);
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(uitoa(idx));
|
||||
hal.stream.write(uitoa(port->id));
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(port->mode.inverted ? "I" : "N");
|
||||
// hal.stream.write(port->mode.open_drain ? "O" : "-");
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(port->cap.invert ? "I" : "-");
|
||||
// hal.stream.write(port->cap.open_drain ? "O" : "-");
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(port->get_value ? uitoa((uint32_t)port->get_value(port)) : "?");
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
@@ -2285,7 +2363,7 @@ status_code_t report_pin_states (sys_state_t state, char *args)
|
||||
hal.stream.write("[PINSTATE:AIN|");
|
||||
hal.stream.write(port->description);
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(uitoa(idx));
|
||||
hal.stream.write(uitoa(port->id));
|
||||
hal.stream.write("|||");
|
||||
hal.stream.write(port->get_value ? ftoa((uint32_t)port->get_value(port), 2) : "?");
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
@@ -2299,7 +2377,7 @@ status_code_t report_pin_states (sys_state_t state, char *args)
|
||||
hal.stream.write("[PINSTATE:AOUT|");
|
||||
hal.stream.write(port->description);
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(uitoa(idx));
|
||||
hal.stream.write(uitoa(port->id));
|
||||
hal.stream.write("|");
|
||||
hal.stream.write(port->mode.pwm ? "P" : (port->mode.servo_pwm ? "S" : "N"));
|
||||
hal.stream.write("|");
|
||||
|
||||
@@ -71,7 +71,7 @@ typedef struct {
|
||||
uint16_t num_devices; //!< Number of devices (LEDs) available.
|
||||
} rgb_ptr_t;
|
||||
|
||||
// helper functions
|
||||
// helper structure and functions, not used by the core
|
||||
|
||||
typedef struct {
|
||||
uint16_t num_leds;
|
||||
@@ -80,7 +80,7 @@ typedef struct {
|
||||
uint8_t intensity;
|
||||
} neopixel_cfg_t;
|
||||
|
||||
// RGB to/from 3 bytes per pixel packed format
|
||||
// Intensity conversions
|
||||
|
||||
static inline rgb_color_t rgb_set_intensity (rgb_color_t color, uint8_t intensity)
|
||||
{
|
||||
@@ -91,6 +91,17 @@ static inline rgb_color_t rgb_set_intensity (rgb_color_t color, uint8_t intensit
|
||||
return color;
|
||||
}
|
||||
|
||||
static inline rgb_color_t rgb_reset_intensity (rgb_color_t color, uint8_t intensity)
|
||||
{
|
||||
color.R = (uint8_t)((color.R << 8) / (intensity + 1));
|
||||
color.G = (uint8_t)((color.G << 8) / (intensity + 1));
|
||||
color.B = (uint8_t)((color.B << 8) / (intensity + 1));
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// RGB to/from 3 bytes per pixel packed format
|
||||
|
||||
static inline void rgb_3bpp_pack (uint8_t *led, rgb_color_t color, rgb_color_mask_t mask, uint8_t intensity)
|
||||
{
|
||||
uint32_t R = 0, G = 0, B = 0;
|
||||
@@ -128,15 +139,6 @@ static inline void rgb_3bpp_pack (uint8_t *led, rgb_color_t color, rgb_color_ma
|
||||
}
|
||||
}
|
||||
|
||||
static inline rgb_color_t rgb_reset_intensity (rgb_color_t color, uint8_t intensity)
|
||||
{
|
||||
color.R = (uint8_t)((color.R << 8) / (intensity + 1));
|
||||
color.G = (uint8_t)((color.G << 8) / (intensity + 1));
|
||||
color.B = (uint8_t)((color.B << 8) / (intensity + 1));
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static inline rgb_color_t rgb_3bpp_unpack (uint8_t *led, uint8_t intensity)
|
||||
{
|
||||
rgb_color_t color = {0};
|
||||
@@ -174,6 +176,8 @@ static inline rgb_color_t rgb_3bpp_unpack (uint8_t *led, uint8_t intensity)
|
||||
return color;
|
||||
}
|
||||
|
||||
// RGB to/from 1 byte per pixel packed format
|
||||
|
||||
static inline void rgb_1bpp_assign (uint8_t *led, rgb_color_t color, rgb_color_mask_t mask)
|
||||
{
|
||||
if(mask.G)
|
||||
|
||||
+15
-7
@@ -7,18 +7,18 @@
|
||||
Copyright (c) 2011-2015 Sungeun K. Jeon
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
@@ -679,7 +679,8 @@ PROGMEM static const setting_descr_t setting_descr[] = {
|
||||
"Normally leave this at 0 as there is an implicit delay on direction changes when AMASS is active."
|
||||
},
|
||||
{ Setting_RpmMax, "Maximum spindle speed, can be overridden by spindle plugins." },
|
||||
{ Setting_RpmMin, "Minimum spindle speed, can be overridden by spindle plugins." },
|
||||
{ Setting_RpmMin, "Minimum spindle speed, can be overridden by spindle plugins.\\n\\n"
|
||||
"When set > 0 $35 (PWM min value) may have to be set to get the configured RPM."},
|
||||
#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."
|
||||
@@ -904,6 +905,9 @@ static status_code_t set_probe_invert (setting_id_t id, uint_fast16_t int_value)
|
||||
return Status_SettingDisabled;
|
||||
|
||||
settings.probe.invert_probe_pin = int_value != 0;
|
||||
|
||||
ioport_setting_changed(id);
|
||||
|
||||
hal.probe.configure(false, false);
|
||||
|
||||
return Status_OK;
|
||||
@@ -1043,6 +1047,8 @@ static status_code_t set_control_disable_pullup (setting_id_t id, uint_fast16_t
|
||||
{
|
||||
settings.control_disable_pullup.mask = int_value & hal.signals_cap.mask;
|
||||
|
||||
ioport_setting_changed(id);
|
||||
|
||||
return Status_OK;
|
||||
}
|
||||
|
||||
@@ -1053,6 +1059,8 @@ static status_code_t set_probe_disable_pullup (setting_id_t id, uint_fast16_t in
|
||||
|
||||
settings.probe.disable_probe_pullup = int_value != 0;
|
||||
|
||||
ioport_setting_changed(id);
|
||||
|
||||
return Status_OK;
|
||||
}
|
||||
|
||||
@@ -2319,8 +2327,8 @@ bool settings_iterator (const setting_detail_t *setting, setting_output_ptr call
|
||||
if(grbl.on_set_axis_setting_unit)
|
||||
set_axis_unit(setting, grbl.on_set_axis_setting_unit(setting->id, axis_idx));
|
||||
|
||||
if(callback(setting, axis_idx, data))
|
||||
ok = true;
|
||||
if(!(ok = callback(setting, axis_idx, data)))
|
||||
break;
|
||||
}
|
||||
} else if(setting->flags.increment) {
|
||||
setting_details_t *set;
|
||||
|
||||
@@ -3,39 +3,40 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2018-2023 Terje Io
|
||||
Copyright (c) 2018-2024 Terje Io
|
||||
Copyright (c) 2016 Sungeun K. Jeon
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
#include "task.h"
|
||||
#include "state_machine.h"
|
||||
|
||||
static volatile bool slumber;
|
||||
|
||||
static void fall_asleep()
|
||||
static void fall_asleep (void *data)
|
||||
{
|
||||
slumber = false;
|
||||
}
|
||||
|
||||
// Starts sleep timer if running conditions are satisfied. When elapsed, sleep mode is executed.
|
||||
static void sleep_execute()
|
||||
static void sleep_execute (void)
|
||||
{
|
||||
// Enable sleep timeout
|
||||
slumber = true;
|
||||
hal.delay_ms((uint32_t)(SLEEP_DURATION * 1000.0f * 60.0f), fall_asleep);
|
||||
if(!(slumber = task_add_delayed(fall_asleep, NULL, (uint32_t)(SLEEP_DURATION * 1000.0f * 60.0f))))
|
||||
return;
|
||||
|
||||
// Fetch current number of buffered characters in input stream buffer.
|
||||
uint16_t rx_initial = hal.stream.get_rx_buffer_free();
|
||||
@@ -43,9 +44,10 @@ static void sleep_execute()
|
||||
do {
|
||||
grbl.on_execute_realtime(state_get());
|
||||
// Monitor for any new input stream data or external events (queries, buttons, alarms) to exit.
|
||||
if ((hal.stream.get_rx_buffer_free() != rx_initial) || sys.rt_exec_state || sys.rt_exec_alarm ) {
|
||||
if((hal.stream.get_rx_buffer_free() != rx_initial) || sys.rt_exec_state || sys.rt_exec_alarm ) {
|
||||
// Disable sleep timeout and return to normal operation.
|
||||
hal.delay_ms(0, NULL);
|
||||
slumber = false;
|
||||
task_delete(fall_asleep, NULL);
|
||||
return;
|
||||
}
|
||||
} while(slumber);
|
||||
@@ -56,18 +58,24 @@ static void sleep_execute()
|
||||
system_set_exec_state_flag(EXEC_SLEEP);
|
||||
}
|
||||
|
||||
|
||||
// Checks running conditions for sleep. If satisfied, enables sleep timeout and executes
|
||||
// sleep mode upon elapse.
|
||||
// NOTE: Sleep procedures can be blocking, since Grbl isn't receiving any commands, nor moving.
|
||||
// NOTE: Sleep procedures can be blocking, since grblHAL isn't receiving any commands, nor moving.
|
||||
// Hence, make sure any valid running state that executes the sleep timer is not one that is moving.
|
||||
void sleep_check()
|
||||
void sleep_check (void)
|
||||
{
|
||||
static uint32_t last_check = 0;
|
||||
|
||||
if(hal.get_elapsed_ticks() - last_check < 50)
|
||||
return;
|
||||
|
||||
last_check = hal.get_elapsed_ticks();
|
||||
|
||||
// The sleep execution feature will continue only if the machine is in an IDLE or HOLD state and
|
||||
// has any powered components enabled.
|
||||
// NOTE: With overrides or in laser mode, modal spindle and coolant state are not guaranteed. Need
|
||||
// to directly monitor and record running state during parking to ensure proper function.
|
||||
if (!sys.steppers_deenergize && (gc_state.modal.spindle.state.value || gc_state.modal.coolant.value)) {
|
||||
if (!(slumber || sys.steppers_deenergize || sys.flags.auto_reporting) && (gc_state.modal.spindle.state.value || gc_state.modal.coolant.value)) {
|
||||
switch(state_get()) {
|
||||
|
||||
case STATE_IDLE:
|
||||
|
||||
+4
-2
@@ -754,8 +754,10 @@ bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_
|
||||
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;
|
||||
if((pwm_data->min_value = (uint_fast16_t)(pwm_data->period * settings->pwm_min_value / 100.0f)) == 0 && spindle->rpm_min > 0.0f)
|
||||
pwm_data->min_value = (uint_fast16_t)((float)pwm_data->max_value * 0.004f);
|
||||
|
||||
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;
|
||||
@@ -765,7 +767,7 @@ bool spindle_precompute_pwm_values (spindle_ptrs_t *spindle, spindle_pwm_t *pwm_
|
||||
pwm_data->compute_value = compute_dummy_pwm_value;
|
||||
}
|
||||
|
||||
spindle->context = pwm_data;
|
||||
spindle->context.pwm = pwm_data;
|
||||
|
||||
#if ENABLE_SPINDLE_LINEARIZATION
|
||||
uint_fast8_t idx;
|
||||
|
||||
+58
-54
@@ -185,15 +185,71 @@ Used for Pulses Per Inch (PPI) laser mode.
|
||||
*/
|
||||
typedef void (*spindle_pulse_on_ptr)(uint_fast16_t pulse_length);
|
||||
|
||||
typedef struct {
|
||||
float rpm;
|
||||
float start;
|
||||
float end;
|
||||
} pwm_piece_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; // 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;
|
||||
uint_fast16_t max_value;
|
||||
float rpm_min; //!< Minimum spindle RPM.
|
||||
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;
|
||||
|
||||
typedef union
|
||||
{
|
||||
spindle_pwm_t *pwm;
|
||||
} spindle_context_ptr_t __attribute__ ((__transparent_union__));
|
||||
|
||||
/*! \brief Handlers and data for spindle support. */
|
||||
struct spindle_ptrs {
|
||||
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.
|
||||
spindle_context_ptr_t context; //!< Optional pointer to spindle specific context.
|
||||
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.
|
||||
spindle_config_ptr config; //!< Optional handler for configuring the spindle.
|
||||
@@ -248,58 +304,6 @@ typedef struct {
|
||||
const spindle_ptrs_t *hal;
|
||||
} spindle_info_t;
|
||||
|
||||
typedef struct {
|
||||
float rpm;
|
||||
float start;
|
||||
float end;
|
||||
} pwm_piece_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; // 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;
|
||||
uint_fast16_t max_value;
|
||||
float rpm_min; //!< Minimum spindle RPM.
|
||||
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().
|
||||
\param spindle prointer to a \a spindle_info_t struct.
|
||||
*/
|
||||
|
||||
@@ -180,7 +180,7 @@ extern void gc_output_message (char *message);
|
||||
//
|
||||
|
||||
// Callback from delay to deenergize steppers after movement, might been cancelled
|
||||
void st_deenergize (void)
|
||||
void st_deenergize (void *data)
|
||||
{
|
||||
if(sys.steppers_deenergize) {
|
||||
hal.stepper.enable(settings.steppers.deenergize);
|
||||
@@ -192,15 +192,10 @@ void st_deenergize (void)
|
||||
// enabled. Startup init and limits call this function but shouldn't start the cycle.
|
||||
void st_wake_up (void)
|
||||
{
|
||||
if(sys.steppers_deenergize) {
|
||||
sys.steppers_deenergize = false;
|
||||
// hal.delay_ms(0, st_deenergize); // Cancel any pending steppers deenergize
|
||||
}
|
||||
|
||||
// Initialize stepper data to ensure first ISR call does not step and
|
||||
// cancel any pending steppers deenergize
|
||||
//st.exec_block = NULL;
|
||||
|
||||
sys.steppers_deenergize = false;
|
||||
hal.stepper.wake_up();
|
||||
}
|
||||
|
||||
@@ -220,8 +215,8 @@ ISR_CODE void ISR_FUNC(st_go_idle)(void)
|
||||
else {
|
||||
// Force stepper dwell to lock axes for a defined amount of time to ensure the axes come to a complete
|
||||
// stop and not drift from residual inertial forces at the end of the last movement.
|
||||
sys.steppers_deenergize = true;
|
||||
hal.delay_ms(settings.steppers.idle_lock_time, st_deenergize);
|
||||
task_delete(st_deenergize, NULL); // Cancel any pending steppers deenergize task
|
||||
sys.steppers_deenergize = task_add_delayed(st_deenergize, NULL, settings.steppers.idle_lock_time);
|
||||
}
|
||||
} else
|
||||
hal.stepper.enable(settings.steppers.idle_lock_time == 255 ? (axes_signals_t){AXES_BITMASK} : settings.steppers.deenergize);
|
||||
|
||||
+43
-21
@@ -3,23 +3,23 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2023 Terje Io
|
||||
Copyright (c) 2023-2024 Terje Io
|
||||
|
||||
Algorithm based on article/code by David Austin:
|
||||
https://www.embedded.com/generate-stepper-motor-speed-profiles-in-real-time/
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
@@ -46,6 +46,7 @@ struct st2_motor {
|
||||
uint_fast8_t idx;
|
||||
axes_signals_t axis;
|
||||
bool is_spindle;
|
||||
bool is_bound;
|
||||
bool position_lost;
|
||||
volatile int64_t position; // absolute step number
|
||||
position_t ptype; //
|
||||
@@ -114,7 +115,8 @@ static void st2_settings_changed (settings_t *settings, settings_changed_flags_t
|
||||
settings_changed(settings, changed);
|
||||
|
||||
while(motor) {
|
||||
st_motor_config(motor);
|
||||
if(motor->is_bound)
|
||||
st_motor_config(motor);
|
||||
motor = motor->next;
|
||||
}
|
||||
}
|
||||
@@ -200,9 +202,37 @@ static const char *st2_setting_get_description (setting_id_t id)
|
||||
|
||||
/*! \brief Bind and initialize a motor.
|
||||
|
||||
Binds motor 0 as a spindle.
|
||||
\param axis_idx axis index of motor to bind to. 3 = A, 4 = B, ...
|
||||
\returns \a true if successful, \a false if not.
|
||||
*/
|
||||
bool st2_motor_bind_spindle (uint_fast8_t axis_idx)
|
||||
{
|
||||
if(motors && axis_idx > Z_AXIS) {
|
||||
|
||||
motors->idx = axis_idx;
|
||||
motors->axis.mask = 1 << axis_idx;
|
||||
motors->is_bound = motors->is_spindle = true;
|
||||
|
||||
spindle_motors |= motors->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;
|
||||
|
||||
st_motor_config(motors);
|
||||
}
|
||||
|
||||
return motors && axis_idx > Z_AXIS;
|
||||
}
|
||||
|
||||
/*! \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.
|
||||
If \a is_spindle is set \a true then axis settings will be changed to step/rev etc. when bound.
|
||||
<br>__NOTE:__ X, Y or Z motors 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).
|
||||
@@ -214,21 +244,13 @@ st2_motor_t *st2_motor_init (uint_fast8_t axis_idx, bool is_spindle)
|
||||
|
||||
if((motor = calloc(sizeof(st2_motor_t), 1))) {
|
||||
|
||||
motor->idx = axis_idx;
|
||||
motor->axis.mask = 1 << axis_idx;
|
||||
motor->is_spindle = is_spindle;
|
||||
if(!is_spindle) {
|
||||
|
||||
st_motor_config(motor);
|
||||
motor->idx = axis_idx;
|
||||
motor->axis.mask = 1 << axis_idx;
|
||||
motor->is_bound = true;
|
||||
|
||||
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;
|
||||
st_motor_config(motor);
|
||||
}
|
||||
|
||||
if(new == NULL) {
|
||||
|
||||
+6
-5
@@ -3,20 +3,20 @@
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2023 Terje Io
|
||||
Copyright (c) 2023 - 2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -32,6 +32,7 @@ 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, bool is_spindle);
|
||||
bool st2_motor_bind_spindle (uint_fast8_t axis_idx);
|
||||
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);
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
|
||||
Copyright (c) 2021-2024 Terje Io
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -244,6 +244,8 @@ static bool stream_select (const io_stream_t *stream, bool add)
|
||||
{
|
||||
static const io_stream_t *active_stream = NULL;
|
||||
|
||||
bool send_init_message = false;
|
||||
|
||||
if(stream == base.stream) {
|
||||
base.is_up = add ? (stream->is_connected ? stream->is_connected : is_connected) : is_not_connected;
|
||||
return true;
|
||||
@@ -288,28 +290,22 @@ static bool stream_select (const io_stream_t *stream, bool add)
|
||||
case StreamType_Telnet:
|
||||
if(connection_is_up(&hal.stream))
|
||||
report_message("TELNET STREAM ACTIVE", Message_Plain);
|
||||
if(add && sys.driver_started) {
|
||||
if((send_init_message = add && sys.driver_started))
|
||||
hal.stream.write_all = stream->write;
|
||||
grbl.report.init_message();
|
||||
}
|
||||
break;
|
||||
|
||||
case StreamType_WebSocket:
|
||||
if(connection_is_up(&hal.stream))
|
||||
report_message("WEBSOCKET STREAM ACTIVE", Message_Plain);
|
||||
if(add && sys.driver_started && !hal.stream.state.webui_connected) {
|
||||
if((send_init_message = add && sys.driver_started && !hal.stream.state.webui_connected))
|
||||
hal.stream.write_all = stream->write;
|
||||
grbl.report.init_message();
|
||||
}
|
||||
break;
|
||||
|
||||
case StreamType_Bluetooth:
|
||||
if(connection_is_up(&hal.stream))
|
||||
report_message("BLUETOOTH STREAM ACTIVE", Message_Plain);
|
||||
if(add && sys.driver_started) {
|
||||
if((send_init_message = add && sys.driver_started))
|
||||
hal.stream.write_all = stream->write;
|
||||
grbl.report.init_message();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -317,13 +313,14 @@ static bool stream_select (const io_stream_t *stream, bool add)
|
||||
}
|
||||
|
||||
memcpy(&hal.stream, stream, sizeof(io_stream_t));
|
||||
|
||||
if(!hal.stream.write_all)
|
||||
hal.stream.write_all = base.next != NULL ? stream_write_all : hal.stream.write;
|
||||
hal.stream.write_all = stream_write_all;
|
||||
|
||||
if(stream == base.stream && base.is_up == is_not_connected)
|
||||
base.is_up = is_connected;
|
||||
|
||||
if(hal.stream.is_connected == NULL)
|
||||
hal.stream.is_connected = stream == base.stream ? base.is_up : is_connected;
|
||||
|
||||
if(stream->type == StreamType_WebSocket && !stream->state.webui_connected)
|
||||
hal.stream.state.webui_connected = webui_connected;
|
||||
|
||||
@@ -332,6 +329,9 @@ static bool stream_select (const io_stream_t *stream, bool add)
|
||||
if(hal.stream.disable_rx)
|
||||
hal.stream.disable_rx(false);
|
||||
|
||||
if(send_init_message)
|
||||
grbl.report.init_message();
|
||||
|
||||
if(grbl.on_stream_changed)
|
||||
grbl.on_stream_changed(hal.stream.type);
|
||||
|
||||
@@ -441,8 +441,11 @@ ISR_CODE bool ISR_FUNC(stream_mpg_check_enable)(char c)
|
||||
{
|
||||
if(c == CMD_MPG_MODE_TOGGLE)
|
||||
protocol_enqueue_foreground_task(stream_mpg_set_mode, (void *)1);
|
||||
else
|
||||
else {
|
||||
protocol_enqueue_realtime_command(c);
|
||||
if((c == CMD_CYCLE_START || c == CMD_CYCLE_START_LEGACY) && settings.status_report.pin_state)
|
||||
sys.report.cycle_start |= state_get() == STATE_IDLE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
#include "core_handlers.h"
|
||||
/*
|
||||
typedef struct {
|
||||
volatile uint_fast8_t head;
|
||||
volatile uint_fast8_t tail;
|
||||
on_execute_realtime_ptr fn[RT_QUEUE_SIZE];
|
||||
} realtime_queue_t;
|
||||
|
||||
static realtime_queue_t realtime_queue = {0};
|
||||
|
||||
// Enqueue a function to be called once by the
|
||||
// foreground process, typically enqueued from an interrupt handler.
|
||||
ISR_CODE bool ISR_FUNC(grbl_task_enqueue)(on_execute_realtime_ptr fn)
|
||||
{
|
||||
bool ok;
|
||||
uint_fast8_t bptr = (realtime_queue.head + 1) & (RT_QUEUE_SIZE - 1); // Get next head pointer
|
||||
|
||||
if((ok = bptr != realtime_queue.tail)) { // If not buffer full
|
||||
realtime_queue.fn[realtime_queue.head] = fn; // add function pointer to buffer,
|
||||
realtime_queue.head = bptr; // update pointer and
|
||||
system_set_exec_state_flag(EXEC_RT_COMMAND); // flag it for execute
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Enqueue a function to be called once by the
|
||||
// foreground process, typically enqueued from an interrupt handler.
|
||||
ISR_CODE bool ISR_FUNC(grbl_task_enqueue_delayed)(on_execute_realtime_ptr fn, uint32_t ms_delay, void *context)
|
||||
{
|
||||
bool ok;
|
||||
uint_fast8_t bptr = (realtime_queue.head + 1) & (RT_QUEUE_SIZE - 1); // Get next head pointer
|
||||
|
||||
if((ok = bptr != realtime_queue.tail)) { // If not buffer full
|
||||
realtime_queue.fn[realtime_queue.head] = fn; // add function pointer to buffer,
|
||||
realtime_queue.head = bptr; // update pointer and
|
||||
system_set_exec_state_flag(EXEC_RT_COMMAND); // flag it for execute
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Execute enqueued functions.
|
||||
static void grbl_task_execute (void)
|
||||
{
|
||||
while(realtime_queue.tail != realtime_queue.head) {
|
||||
uint_fast8_t bptr = realtime_queue.tail;
|
||||
on_execute_realtime_ptr call;
|
||||
if((call = realtime_queue.fn[bptr])) {
|
||||
realtime_queue.fn[bptr] = NULL;
|
||||
call(state_get());
|
||||
}
|
||||
realtime_queue.tail = (bptr + 1) & (RT_QUEUE_SIZE - 1);
|
||||
}
|
||||
|
||||
if(!sys.driver_started)
|
||||
while(true);
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
task.h - delayed task handling
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2024 Terje Io
|
||||
|
||||
grblHAL is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
grblHAL is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CORE_TASK_H_
|
||||
#define _CORE_TASK_H_
|
||||
|
||||
typedef void (*foreground_task_ptr)(void *data);
|
||||
|
||||
bool task_add_immediate (foreground_task_ptr fn, void *data);
|
||||
bool task_add_delayed (foreground_task_ptr fn, void *data, uint32_t delay_ms);
|
||||
void task_delete (foreground_task_ptr fn, void *data);
|
||||
bool task_add_systick (foreground_task_ptr fn, void *data);
|
||||
void task_delete_systick (foreground_task_ptr fn, void *data);
|
||||
|
||||
#endif // _CORE_TASK_H_
|
||||
Reference in New Issue
Block a user