diff --git a/README.md b/README.md
index d5e4337..515d6ca 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa
---
-Latest build date is 20240115, see the [changelog](changelog.md) for details.
+Latest build date is 20240123, see the [changelog](changelog.md) for details.
__NOTE:__ A settings reset will be performed on an update of builds earlier than 20230125. Backup and restore of settings is recommended.
---
@@ -89,4 +89,4 @@ G/M-codes not supported by [legacy Grbl](https://github.com/gnea/grbl/wiki) are
Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes.
---
-20240115
+20240124
diff --git a/changelog.md b/changelog.md
index cbda287..91c4d50 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,46 @@
-## grblHAL changelog
+Build 20240123
+Core:
+
+* Enhanced RGB and ioports APIs.
+
+* Allowed use of unused \(by the core\) axis words \(ABCUVW\) in M-code commands implemented by plugin code.
+
+* Added `$PINSTATE` command, for outputting auxillary pin states, modes and capabilities. Machine readable formatting.
+
+Drivers:
+
+* RP2040: refactored allocation/initialization of PIO state machines to allow a neopixel driver, and possibly user drivers, to be installed.
+
+* ESP32, RP2040, STM32F4xx: added Neopixel driver code exposed via the core RGB API.
+__NOTE:__ there is no official board support for this just yet.
+
+* Some: added full or partial support for new features in the ioports API.
+__NOTE:__ This work is not yet complete, final tuning and update of remaining drivers will be done later.
+
+Plugins:
+
+* Motors: added overridable symbol for specifying R sense for Trinamic drivers.
+
+Templates:
+
+* Added plugin for RGB LED control via [M150](https://marlinfw.org/docs/gcode/M150.html), sits on top of the new RGB API.
+
+Web Builder:
+
+* Added new tab for assigning optional and dedicated inputs to auxillary inputs.
+Some internal changes to simplify board specifications. Currently the ESP32 and STM32F1xx divers has been updated for this, more to follow later.
+__NOTE:__ Please report any unwanted/unexpected change in behaviour of the generated firmware.
+
+For info:
+
+I have plugings in the pipeline for PWM servo control via [M280](https://marlinfw.org/docs/gcode/M280.html) plus automatic BLTouch probe deployment.
+These are based on original work by @wakass and might be published by him if a PR I plan to submit is accepted.
+
+---
+
+## grblHAL changelog
+
Build 20240118
Core:
@@ -21,7 +62,7 @@ Added auxillary analog PWM out option for up to two channels. Can be configured
Plugins:
-* Spindle: fix for [issue #24](https://github.com/grblHAL/Plugins_spindle/issues/24) Typo, regression causing compilation failure for the MODVFD driver.
+* Spindle: fix for [issue #24](https://github.com/grblHAL/Plugins_spindle/issues/24) - typo, regression causing compilation failure for the MODVFD driver.
* Keypad: I2C display interface, [issue #9](https://github.com/grblHAL/Plugin_keypad/issues/9) - missing update to match core changes caused compilation failure.
diff --git a/crossbar.h b/crossbar.h
index 1294548..2f9f7af 100644
--- a/crossbar.h
+++ b/crossbar.h
@@ -449,9 +449,9 @@ typedef enum {
#endif
#define PINMODE_PULLUP (PullMode_Up<<3)
#define PINMODE_PULLDOWN (PullMode_Down<<3)
-#define PINMODE_ANALOG (1U<<10)
-#define PINMODE_PWM (1U<<11)
-#define PINMODE_PWM_SERVO (1U<<12)
+#define PINMODE_ANALOG (1U<<11)
+#define PINMODE_PWM (1U<<12)
+#define PINMODE_PWM_SERVO (1U<<13)
typedef union {
uint16_t mask;
@@ -461,11 +461,12 @@ typedef union {
open_drain :1,
pull_mode :2,
irq_mode :5,
+ invert :1,
analog :1,
pwm :1,
servo_pwm :1,
claimable :1,
- reserved :2;
+ reserved :1;
};
} pin_cap_t;
@@ -477,11 +478,12 @@ typedef union {
open_drain :1,
pull_mode :2,
irq_mode :5,
+ inverted :1,
analog :1,
pwm :1,
servo_pwm :1,
claimed :1,
- reserved :2;
+ reserved :1;
};
} pin_mode_t;
@@ -528,18 +530,18 @@ typedef struct {
} aux_ctrl_t;
typedef struct xbar {
- pin_function_t function;
- pin_group_t group;
- void *port;
- const char *description;
- uint_fast8_t pin;
- uint32_t bit;
- pin_cap_t cap; //!< Pin capabilities
- pin_mode_t mode; //!< Current pin configuration
- xbar_config_ptr config;
- xbar_get_value_ptr get_value;
- xbar_set_value_ptr set_value;
- xbar_event_ptr on_event; // ?? - remove?
+ 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.
+ xbar_get_value_ptr get_value; //!< Optional pointer to function to get current port value.
+ xbar_set_value_ptr set_value; //!< Optional pointer to function to set port value.
+ xbar_event_ptr on_event; //!< Not used - might be removed.
} xbar_t;
typedef struct {
diff --git a/gcode.c b/gcode.c
index 07aad75..67ba300 100644
--- a/gcode.c
+++ b/gcode.c
@@ -1328,6 +1328,11 @@ status_code_t gc_execute_block (char *block)
word_bit.parameter.a = On;
gc_block.values.xyz[A_AXIS] = value;
break;
+#else
+ case 'A':
+ word_bit.parameter.a = On;
+ gc_block.values.a = value;
+ break;
#endif
#ifdef B_AXIS
@@ -1340,6 +1345,11 @@ status_code_t gc_execute_block (char *block)
word_bit.parameter.b = On;
gc_block.values.xyz[B_AXIS] = value;
break;
+#else
+ case 'B':
+ word_bit.parameter.b = On;
+ gc_block.values.b = value;
+ break;
#endif
#ifdef C_AXIS
@@ -1352,6 +1362,11 @@ status_code_t gc_execute_block (char *block)
word_bit.parameter.c = On;
gc_block.values.xyz[C_AXIS] = value;
break;
+#else
+ case 'C':
+ word_bit.parameter.c = On;
+ gc_block.values.c = value;
+ break;
#endif
case 'D':
@@ -1463,22 +1478,39 @@ status_code_t gc_execute_block (char *block)
#else
#ifdef U_AXIS
- case 'U':
- axis_words.u = On;
- word_bit.parameter.u = On;
- gc_block.values.xyz[U_AXIS] = value;
- break;
+ case 'U':
+ axis_words.u = On;
+ word_bit.parameter.u = On;
+ gc_block.values.xyz[U_AXIS] = value;
+ break;
+#elif !AXIS_REMAP_ABC2UVW
+ case 'U':
+ word_bit.parameter.u = On;
+ gc_block.values.u = value;
+ break;
#endif
#ifdef V_AXIS
- case 'V':
- axis_words.v = On;
- word_bit.parameter.v = On;
- gc_block.values.xyz[V_AXIS] = value;
- break;
+ case 'V':
+ axis_words.v = On;
+ word_bit.parameter.v = On;
+ gc_block.values.xyz[V_AXIS] = value;
+ break;
+#elif !AXIS_REMAP_ABC2UVW
+ case 'V':
+ word_bit.parameter.v = On;
+ gc_block.values.v = value;
+ break;
#endif
+#endif // LATHE_UVW_OPTION
+
+#if !AXIS_REMAP_ABC2UVW
+ case 'W':
+ word_bit.parameter.w = On;
+ gc_block.values.w = value;
+ break;
#endif
- case 'X':
+ case 'X':
axis_words.x = On;
word_bit.parameter.x = On;
gc_block.values.xyz[X_AXIS] = value;
diff --git a/gcode.h b/gcode.h
index 8633803..dc95ab1 100644
--- a/gcode.h
+++ b/gcode.h
@@ -236,6 +236,7 @@ typedef enum {
LaserPPI_Enable = 126, //!< 126 - M126
LaserPPI_Rate = 127, //!< 127 - M127
LaserPPI_PulseLength = 128, //!< 128 - M128
+ RGB_WriteLEDs = 150, //!< 150 - M150, Marlin format
OpenPNP_SetAcceleration = 204, //!< 204 - M204
PWMServo_SetPosition= 280, //!< 280 - M280, Marlin format
RGB_Inspection_Light = 356, //!< 356 - M356
@@ -385,6 +386,24 @@ typedef struct {
float q; //!< User defined M-code parameter, M67 output value, G64 naive CAM tolerance, G83 delta increment
float r; //!< Arc radius or retract position
float s; //!< Spindle speed - single-meaning word
+#ifndef A_AXIS
+ float a;
+#endif
+#ifndef B_AXIS
+ float b;
+#endif
+#ifndef C_AXIS
+ float c;
+#endif
+#if !defined(U_AXIS) && !AXIS_REMAP_ABC2UVW
+ float u;
+#endif
+#if !defined(V_AXIS) && !AXIS_REMAP_ABC2UVW
+ float v;
+#endif
+#if !AXIS_REMAP_ABC2UVW
+ float w;
+#endif
float xyz[N_AXIS]; //!< X,Y,Z (and A,B,C,U,V when enabled) translational axes
#if LATHE_UVW_OPTION
float uvw[3]; //!< U,V,W lathe mode incremental mode motion
diff --git a/grbl.h b/grbl.h
index 22216b1..2aac8d8 100644
--- a/grbl.h
+++ b/grbl.h
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
-#define GRBL_BUILD 20240118
+#define GRBL_BUILD 20240123
#define GRBL_URL "https://github.com/grblHAL"
diff --git a/hal.h b/hal.h
index 5f3cd3e..84cab04 100644
--- a/hal.h
+++ b/hal.h
@@ -510,6 +510,18 @@ typedef struct {
* RGB (LED) API *
*******************/
+typedef union {
+ uint8_t value;
+ uint8_t mask;
+ struct {
+ uint8_t B :1,
+ G :1,
+ R :1,
+ W :1,
+ unused :4;
+ };
+} rgb_color_mask_t;
+
typedef union {
uint32_t value;
struct {
@@ -523,12 +535,24 @@ typedef union {
/*! \brief Pointer to function for setting RGB (LED) output.
\param color a \a rgb_color_t union.
*/
-typedef void (*rgb_set_color_ptr)(uint8_t device, rgb_color_t color);
+typedef void (*rgb_set_color_ptr)(uint16_t device, rgb_color_t color);
+
+/*! \brief Pointer to function for setting RGB (LED) output, with mask for which LEDs to change.
+\param color a \a rgb_color_t union.
+\param mask a \a rgb_color_mask_t union.
+*/
+typedef void (*rgb_set_color_masked_ptr)(uint16_t device, rgb_color_t color, rgb_color_mask_t mask);
+
+/*! \brief Pointer to function for outputting RGB (LED) data to Neopixel strip.
+*/
+typedef void (*rgb_write_ptr)(void);
typedef struct {
- rgb_set_color_ptr out; //!< Optional handler for setting device (LED) color.
- rgb_color_t cap; //!< Driver capability, color value: 0 - not available, 1 - on off, > 1 - intensity range 0 - n.
- uint8_t num_devices; //!< Number of devices (LEDs) available.
+ rgb_set_color_ptr out; //!< Optional handler for setting device (LED) color.
+ rgb_set_color_masked_ptr out_masked; //!< Optional handler for setting device (LED) color, with mask for which LEDs to change.
+ rgb_write_ptr write; //!< Optional handler for outputting data to Neopixel strip.
+ rgb_color_t cap; //!< Driver capability, color value: 0 - not available, 1 - on off, > 1 - intensity range 0 - n.
+ uint8_t num_devices; //!< Number of devices (LEDs) available.
} rgb_ptr_t;
/**/
diff --git a/ioports.h b/ioports.h
index b07c2a8..e318888 100644
--- a/ioports.h
+++ b/ioports.h
@@ -65,6 +65,7 @@ typedef int32_t (*wait_on_input_ptr)(io_port_type_t type, uint8_t port, wait_mod
typedef void (*set_pin_description_ptr)(io_port_type_t type, io_port_direction_t dir, uint8_t port, const char *s);
/*! \brief Pointer to function for getting information about a digital or analog port.
+
__NOTE:__ The port information pointed to will be overwritten by the next call to this function.
\param type as an \a #io_port_type_t enum value.
\param dir as an \a #io_port_direction_t enum value.
\param port port number.
diff --git a/report.c b/report.c
index a0af00a..2c66981 100644
--- a/report.c
+++ b/report.c
@@ -2171,6 +2171,131 @@ status_code_t report_pins (sys_state_t state, char *args)
return Status_OK;
}
+#ifndef NO_SETTINGS_DESCRIPTIONS
+
+static char *irq_mode (pin_irq_mode_t mode)
+{
+ switch(mode) {
+ case IRQ_Mode_Rising:
+ return "R";
+ case IRQ_Mode_Falling:
+ return "F";
+ case IRQ_Mode_Change:
+ return "C";
+ case IRQ_Mode_Edges:
+ return "E";
+ case IRQ_Mode_High:
+ return "H";
+ case IRQ_Mode_Low:
+ return "L";
+ case IRQ_Mode_All:
+ return "A";
+ default:
+ break;
+ }
+
+ return "-";
+}
+
+static char *pull_mode (pull_mode_t mode)
+{
+ switch(mode) {
+ case PullMode_Up:
+ return "U";
+ case PullMode_Down:
+ return "D";
+ case PullMode_UpDown:
+ return "B";
+ default:
+ break;
+ }
+
+ return "-";
+}
+
+
+status_code_t report_pin_states (sys_state_t state, char *args)
+{
+ xbar_t *port;
+ uint8_t idx, ports;
+
+ if((ports = ioports_available(Port_Digital, Port_Input))) {
+ 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("|");
+ hal.stream.write(uitoa(idx));
+ 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("|");
+ 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("|");
+ hal.stream.write(port->get_value ? uitoa((uint32_t)port->get_value(port)) : "?");
+ hal.stream.write("]" ASCII_EOL);
+ }
+ }
+ }
+
+ if((ports = ioports_available(Port_Digital, Port_Output))) {
+ for(idx = 0; idx < ports; idx++) {
+ if((port = hal.port.get_pin_info(Port_Digital, Port_Output, idx))) {
+ hal.stream.write("[PINSTATE:DOUT|");
+ hal.stream.write(port->description);
+ hal.stream.write("|");
+ hal.stream.write(uitoa(idx));
+ hal.stream.write("|");
+ hal.stream.write(port->mode.inverted ? "I" : "N");
+ hal.stream.write("|");
+ hal.stream.write(port->cap.invert ? "I" : "-");
+ hal.stream.write("|");
+ hal.stream.write(port->get_value ? uitoa((uint32_t)port->get_value(port)) : "?");
+ hal.stream.write("]" ASCII_EOL);
+ }
+ }
+ }
+
+ if((ports = ioports_available(Port_Analog, Port_Input))) {
+ for(idx = 0; idx < ports; idx++) {
+ if((port = hal.port.get_pin_info(Port_Analog, Port_Input, idx))) {
+ hal.stream.write("[PINSTATE:AIN|");
+ hal.stream.write(port->description);
+ hal.stream.write("|");
+ hal.stream.write(uitoa(idx));
+ hal.stream.write("|||");
+ hal.stream.write(port->get_value ? ftoa((uint32_t)port->get_value(port), 2) : "?");
+ hal.stream.write("]" ASCII_EOL);
+ }
+ }
+ }
+
+ if((ports = ioports_available(Port_Analog, Port_Output))) {
+ for(idx = 0; idx < ports; idx++) {
+ if((port = hal.port.get_pin_info(Port_Analog, Port_Output, idx))) {
+ hal.stream.write("[PINSTATE:AOUT|");
+ hal.stream.write(port->description);
+ hal.stream.write("|");
+ hal.stream.write(uitoa(idx));
+ hal.stream.write("|");
+ hal.stream.write(port->mode.pwm ? "P" : (port->mode.servo_pwm ? "S" : "N"));
+ hal.stream.write("|");
+ hal.stream.write(port->cap.pwm ? "P" : (port->cap.servo_pwm ? "S" : "N"));
+ hal.stream.write("|");
+ hal.stream.write(port->get_value ? ftoa((uint32_t)port->get_value(port), 2) : "?");
+ hal.stream.write("]" ASCII_EOL);
+ }
+ }
+ }
+
+ return Status_OK;
+}
+
+#endif
+
static void print_uito2a (char *prefix, uint32_t v)
{
hal.stream.write(prefix);
diff --git a/report.h b/report.h
index e91c650..11da13a 100644
--- a/report.h
+++ b/report.h
@@ -98,6 +98,8 @@ status_code_t report_spindle_data (sys_state_t state, char *args);
// Prints pin assignments.
status_code_t report_pins (sys_state_t state, char *args);
+status_code_t report_pin_states (sys_state_t state, char *args);
+
// Prints registered spindles.
status_code_t report_spindles (bool machine_readable);
diff --git a/stream.c b/stream.c
index 82b43e8..98ca12f 100644
--- a/stream.c
+++ b/stream.c
@@ -364,14 +364,24 @@ io_stream_flags_t stream_get_flags (io_stream_t stream)
return flags;
}
+bool stream_set_description (const io_stream_t *stream, const char *description)
+{
+ bool ok;
+
+ if((ok = stream->type == StreamType_Serial && !stream->state.is_usb && hal.periph_port.set_pin_description)) {
+ hal.periph_port.set_pin_description(Output_TX, (pin_group_t)(PinGroup_UART + stream->instance), description);
+ hal.periph_port.set_pin_description(Input_RX, (pin_group_t)(PinGroup_UART + stream->instance), description);
+ }
+
+ return ok;
+}
+
bool stream_connect (const io_stream_t *stream)
{
bool ok;
- if((ok = stream_select(stream, true)) && stream->type == StreamType_Serial && !stream->state.is_usb && hal.periph_port.set_pin_description) {
- hal.periph_port.set_pin_description(Input_RX, (pin_group_t)(PinGroup_UART + stream->instance), "Primary UART");
- hal.periph_port.set_pin_description(Output_TX, (pin_group_t)(PinGroup_UART + stream->instance), "Primary UART");
- }
+ if((ok = stream_select(stream, true)))
+ stream_set_description(stream, "Primary UART");
return ok;
}
@@ -454,10 +464,7 @@ bool stream_mpg_register (const io_stream_t *stream, bool rx_only, stream_write_
hal.stream.write_all = stream_write_all;
- if(hal.periph_port.set_pin_description) {
- hal.periph_port.set_pin_description(Output_TX, (pin_group_t)(PinGroup_UART + stream->instance), "MPG");
- hal.periph_port.set_pin_description(Input_RX, (pin_group_t)(PinGroup_UART + stream->instance), "MPG");
- }
+ stream_set_description(stream, "MPG");
}
return connection != NULL;
diff --git a/stream.h b/stream.h
index 41e8225..4950035 100644
--- a/stream.h
+++ b/stream.h
@@ -349,6 +349,8 @@ const io_stream_t *stream_null_init (uint32_t baud_rate);
io_stream_t const *stream_open_instance (uint8_t instance, uint32_t baud_rate, stream_write_char_ptr rx_handler);
+bool stream_set_description (const io_stream_t *stream, const char *description);
+
#ifdef DEBUGOUT
void debug_write (const char *s);
void debug_writeln (const char *s);
diff --git a/system.c b/system.c
index 29380bd..5e5529f 100644
--- a/system.c
+++ b/system.c
@@ -241,6 +241,15 @@ static status_code_t enumerate_pins (sys_state_t state, char *args)
return report_pins(state, args);
}
+#ifndef NO_SETTINGS_DESCRIPTIONS
+
+static status_code_t pin_state (sys_state_t state, char *args)
+{
+ return report_pin_states(state, args);
+}
+
+#endif
+
static status_code_t output_settings (sys_state_t state, char *args)
{
status_code_t retval = Status_OK;
@@ -770,6 +779,15 @@ const char *help_pins (const char *cmd)
return hal.enumerate_pins ? "enumerate pin bindings" : NULL;
}
+#ifndef NO_SETTINGS_DESCRIPTIONS
+
+const char *help_pin_state (const char *cmd)
+{
+ return hal.port.get_pin_info ? "output auxillary pin states" : NULL;
+}
+
+#endif
+
const char *help_switches (const char *cmd)
{
const char *help = NULL;
@@ -892,6 +910,9 @@ PROGMEM static const sys_command_t sys_commands[] = {
{ "ESH", enumerate_settings_halformatted, { .noargs = On, .allow_blocking = On }, { .str = "enumerate settings, grblHAL formatted" } },
{ "E*", enumerate_all, { .noargs = On, .allow_blocking = On }, { .str = "enumerate alarms, status codes and settings" } },
{ "PINS", enumerate_pins, { .noargs = On, .allow_blocking = On, .help_fn = On }, { .fn = help_pins } },
+#ifndef NO_SETTINGS_DESCRIPTIONS
+ { "PINSTATE", pin_state, { .noargs = On, .allow_blocking = On, .help_fn = On }, { .fn = help_pin_state } },
+#endif
{ "LEV", report_last_signals_event, { .noargs = On, .allow_blocking = On }, { .str = "output last control signal events" } },
{ "LIM", report_current_limit_state, { .noargs = On, .allow_blocking = On }, { .str = "output current limit pins" } },
{ "SD", report_spindle_data, { .help_fn = On }, { .fn = help_spindle } },