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 } },