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.
This commit is contained in:
Terje Io
2024-01-24 18:38:08 +01:00
parent cf98ec7778
commit f0ef77435e
13 changed files with 321 additions and 45 deletions
+2 -2
View File
@@ -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
+43 -2
View File
@@ -1,5 +1,46 @@
## grblHAL changelog
<a name="20240123"/>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
<a name="20240118"/>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.
+19 -17
View File
@@ -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 {
+43 -11
View File
@@ -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;
+19
View File
@@ -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
+1 -1
View File
@@ -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"
+28 -4
View File
@@ -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;
/**/
+1
View File
@@ -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.
<br>__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.
+125
View File
@@ -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);
+2
View File
@@ -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);
+15 -8
View File
@@ -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;
+2
View File
@@ -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);
+21
View File
@@ -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 } },