diff --git a/README.md b/README.md
index bb6c01f..cdb71ec 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 20240127, see the [changelog](changelog.md) for details.
+Latest build date is 20240205, 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.
---
-20240127
+20240205
diff --git a/changelog.md b/changelog.md
index 58675ec..e577461 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,29 @@
## grblHAL changelog
+20240205
+
+Core:
+
+* Added core support for new MPG mode that claims one serial stream and uses the `0x8B` real-time command character for switching mode. Does not require the keypad plugin.
+
+* Moved RGB API definitions to separate file and added some utilities for drivers and plugins. Fixed minor bug.
+
+* For developers: `stream_open_instance()`, signature change - added optional description string.
+
+Drivers:
+
+* 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.
+
+Plugins:
+
+* Bluetooth: updated for core signature change.
+
+---
+
20240202
Core:
diff --git a/driver_opts.h b/driver_opts.h
index 296906b..8f1c559 100644
--- a/driver_opts.h
+++ b/driver_opts.h
@@ -108,6 +108,8 @@
#if MPG_ENABLE == 1 && KEYPAD_ENABLE == 2
#define MPG_MODE 2
+#elif MPG_ENABLE == 2
+#define MPG_MODE 3
#elif MPG_ENABLE
#define MPG_MODE 1
#else
diff --git a/grbl.h b/grbl.h
index 03553f1..e377ae2 100644
--- a/grbl.h
+++ b/grbl.h
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
-#define GRBL_BUILD 20240202
+#define GRBL_BUILD 20240204
#define GRBL_URL "https://github.com/grblHAL"
diff --git a/hal.h b/hal.h
index 84cab04..5a866fc 100644
--- a/hal.h
+++ b/hal.h
@@ -38,6 +38,7 @@
#include "nvs.h"
#include "probe.h"
#include "ioports.h"
+#include "rgb.h"
#include "plugins.h"
#define HAL_VERSION 10
@@ -506,55 +507,6 @@ typedef struct {
rtc_set_datetime_ptr set_datetime; //!< Optional handler setting the current datetime.
} rtc_ptrs_t;
-/*******************
- * 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 {
- uint8_t B; //!< Blue
- uint8_t G; //!< Green
- uint8_t R; //!< Red
- uint8_t W; //!< White
- };
-} rgb_color_t;
-
-/*! \brief Pointer to function for setting RGB (LED) output.
-\param color a \a rgb_color_t union.
-*/
-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_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;
-
/**/
/*! \brief Pointer to function for performing a pallet shuttle.
diff --git a/protocol.c b/protocol.c
index 84e4ae6..39c7fde 100644
--- a/protocol.c
+++ b/protocol.c
@@ -931,7 +931,7 @@ ISR_CODE bool ISR_FUNC(protocol_enqueue_realtime_command)(char c)
case CMD_MPG_MODE_TOGGLE: // Switch off MPG mode
if(hal.stream.type == StreamType_MPG)
- stream_mpg_enable(false);
+ protocol_enqueue_foreground_task(stream_mpg_set_mode, NULL);
break;
case CMD_AUTO_REPORTING_TOGGLE:
diff --git a/report.c b/report.c
index 032c281..f45b059 100644
--- a/report.c
+++ b/report.c
@@ -2060,7 +2060,9 @@ status_code_t report_setting_group_details (bool by_id, char *prefix)
do {
for(idx = 0; idx < details->n_groups; idx++) {
- if(!group_is_dup(all_groups, details->groups[idx].id))
+ if(group_is_dup(all_groups, details->groups[idx].id))
+ n_groups--;
+ else
*group++ = (setting_group_detail_t *)&details->groups[idx];
}
} while((details = details->next));
diff --git a/rgb.h b/rgb.h
new file mode 100644
index 0000000..938986f
--- /dev/null
+++ b/rgb.h
@@ -0,0 +1,215 @@
+/*
+ rgb.h - typedefs, API structure and helper functions for RGB lights and LED strips
+
+ 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 .
+*/
+
+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 {
+ uint8_t B; //!< Blue
+ uint8_t G; //!< Green
+ uint8_t R; //!< Red
+ uint8_t W; //!< White
+ };
+} rgb_color_t;
+
+/*! \brief Pointer to function for setting RGB (LED) output.
+\param color a \a rgb_color_t union.
+*/
+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 setting RGB (LED) intensity.
+\param intensity in the range 0 - 255.
+\returns previuous intensity.
+*/
+typedef uint8_t (*rgb_set_intensity_ptr)(uint8_t intensity);
+
+/*! \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_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_set_intensity_ptr set_intensity; //!< Optional handler for setting intensity, range 0 - 255.
+ rgb_color_t cap; //!< Driver capability, color value: 0 - not available, 1 - on off, > 1 - intensity range 0 - n.
+ uint16_t num_devices; //!< Number of devices (LEDs) available.
+} rgb_ptr_t;
+
+// helper functions
+
+typedef struct {
+ uint16_t num_leds;
+ uint16_t num_bytes;
+ uint8_t *leds;
+ uint8_t intensity;
+} neopixel_cfg_t;
+
+// RGB to/from 3 bytes per pixel packed format
+
+static inline rgb_color_t rgb_set_intensity (rgb_color_t color, uint8_t intensity)
+{
+ color.R = (uint8_t)(((color.R + 1) * intensity) >> 8);
+ color.G = (uint8_t)(((color.G + 1) * intensity) >> 8);
+ color.B = (uint8_t)(((color.B + 1) * intensity) >> 8);
+
+ return color;
+}
+
+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;
+ uint8_t bitmask = 0b10000000;
+
+ color = rgb_set_intensity(color, intensity);
+
+ do {
+ R <<= 3;
+ R |= color.R & bitmask ? 0b110 : 0b100;
+ G <<= 3;
+ G |= color.G & bitmask ? 0b110 : 0b100;
+ B <<= 3;
+ B |= color.B & bitmask ? 0b110 : 0b100;
+ } while(bitmask >>= 1);
+
+ if(mask.G) {
+ *led++ = (uint8_t)(G >> 16);
+ *led++ = (uint8_t)(G >> 8);
+ *led++ = (uint8_t)G;
+ } else
+ led += 3;
+
+ if(mask.R) {
+ *led++ = (uint8_t)(R >> 16);
+ *led++ = (uint8_t)(R >> 8);
+ *led++ = (uint8_t)R;
+ } else
+ led += 3;
+
+ if(mask.B) {
+ *led++ = (uint8_t)(B >> 16);
+ *led++ = (uint8_t)(B >> 8);
+ *led = (uint8_t)B;
+ }
+}
+
+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};
+
+ if(intensity) {
+
+ uint32_t R = 0, G = 0, B = 0;
+ uint8_t bitmask = 0b00000001;
+
+ G = *led++ << 16;
+ G |= *led++ << 8;
+ G |= *led++;
+ R = *led++ << 16;
+ R |= *led++ << 8;
+ R |= *led++;
+ B = *led++ << 16;
+ B |= *led++ << 8;
+ B |= *led;
+
+ do {
+ if((R & 0b110) == 0b110)
+ color.R |= bitmask;
+ R >>= 3;
+ if((G & 0b110) == 0b110)
+ color.G |= bitmask;
+ G >>= 3;
+ if((B & 0b110) == 0b110)
+ color.B |= bitmask;
+ B >>= 3;
+ } while(bitmask <<= 1);
+
+ color = rgb_reset_intensity(color, intensity);
+ }
+
+ return color;
+}
+
+static inline void rgb_1bpp_assign (uint8_t *led, rgb_color_t color, rgb_color_mask_t mask)
+{
+ if(mask.G)
+ *led++ = color.G;
+ else
+ led++;
+
+ if(mask.R)
+ *led++ = color.R;
+ else
+ led++;
+
+ if(mask.B)
+ *led = color.B;
+}
+
+static inline void rgb_1bpp_pack (uint8_t *led, rgb_color_t color, rgb_color_mask_t mask, uint8_t intensity)
+{
+ color = rgb_set_intensity(color, intensity);
+ rgb_1bpp_assign(led, color, mask);
+}
+
+static inline rgb_color_t rgb_1bpp_unpack (uint8_t *led, uint8_t intensity)
+{
+ rgb_color_t color = {0};
+
+ if(intensity) {
+
+ color.G = *led++;
+ color.R = *led++;
+ color.B = *led;
+
+ color = rgb_reset_intensity(color, intensity);
+ }
+
+ return color;
+}
+
+//
diff --git a/settings.h b/settings.h
index 9f41b70..c2ce043 100644
--- a/settings.h
+++ b/settings.h
@@ -365,7 +365,9 @@ typedef enum {
Setting_MQTTBrokerPassword = 533,
Setting_NGCDebugOut = 534,
- Setting_NetworkMAC = 535,
+ Setting_NetworkMAC = 535,
+ Setting_RGB_StripLengt0 = 536,
+ Setting_RGB_StripLengt1 = 537,
Setting_Panel_SpindleSpeed = 540, // NOTE: Reserving settings values 540 to 579 for panel settings.
Setting_Panel_ModbusAddress = 541,
@@ -717,15 +719,19 @@ typedef struct {
control_signals_t control_invert;
control_signals_t control_disable_pullup;
coolant_state_t coolant_invert;
+ uint8_t hole_0;
+ uint16_t hole_1;
spindle_settings_t spindle;
stepper_settings_t steppers;
reportmask_t status_report; // Mask to indicate desired report data.
settingflags_t flags; // Contains default boolean settings
probeflags_t probe;
+ uint8_t rgb_strip0_length;
offset_lock_t offset_lock;
fs_options_t fs_options;
homing_settings_t homing;
limit_settings_t limits;
+ uint8_t rgb_strip1_length;
parking_settings_t parking;
safety_door_settings_t safety_door;
position_pid_t position; // Used for synchronized motion
diff --git a/stream.c b/stream.c
index bcf33d2..907d00e 100644
--- a/stream.c
+++ b/stream.c
@@ -415,20 +415,38 @@ void stream_disconnect (const io_stream_t *stream)
stream_select(stream, false);
}
-io_stream_t const *stream_open_instance (uint8_t instance, uint32_t baud_rate, stream_write_char_ptr rx_handler)
+io_stream_t const *stream_open_instance (uint8_t instance, uint32_t baud_rate, stream_write_char_ptr rx_handler, const char *description)
{
connection.instance = instance;
connection.baud_rate = baud_rate;
connection.stream = NULL;
- if(stream_enumerate_streams(_open_instance))
+ if(stream_enumerate_streams(_open_instance)) {
connection.stream->set_enqueue_rt_handler(rx_handler);
+ if(description)
+ stream_set_description(connection.stream, description);
+ }
return connection.stream;
}
// MPG stream
+void stream_mpg_set_mode (void *data)
+{
+ stream_mpg_enable(data != NULL);
+}
+
+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
+ protocol_enqueue_realtime_command(c);
+
+ return true;
+}
+
bool stream_mpg_register (const io_stream_t *stream, bool rx_only, stream_write_char_ptr write_char)
{
if(stream == NULL || stream->type != StreamType_Serial || stream->disable_rx == NULL)
diff --git a/stream.h b/stream.h
index 4950035..36b791a 100644
--- a/stream.h
+++ b/stream.h
@@ -325,6 +325,10 @@ bool stream_mpg_register (const io_stream_t *stream, bool rx_only, stream_write_
*/
bool stream_mpg_enable (bool on);
+void stream_mpg_set_mode (void *data);
+
+bool stream_mpg_check_enable (char c);
+
bool stream_buffer_all (char c);
bool stream_tx_blocking (void);
@@ -347,7 +351,7 @@ io_stream_flags_t stream_get_flags (io_stream_t stream);
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);
+io_stream_t const *stream_open_instance (uint8_t instance, uint32_t baud_rate, stream_write_char_ptr rx_handler, const char *description);
bool stream_set_description (const io_stream_t *stream, const char *description);