diff --git a/README.md b/README.md
index 350c747..a8a6aa6 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ It has been written to complement grblHAL and has features such as proper keyboa
---
-Latest build date is 20211130, see the [changelog](changelog.md) for details.
+Latest build date is 20211213, see the [changelog](changelog.md) for details.
__NOTE:__ A settings reset will be performed on an update for versions earlier than 20211122. Backup and restore of settings is recommended.
__IMPORTANT!__ A new setting has been introduced for ganged axes motors in version 20211121.
I have only bench tested this for a couple of drivers, correct function should be verified after updating by those who have more than three motors configured.
@@ -83,4 +83,4 @@ List of Supported G-Codes:
Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes.
---
-2021-11-28
+2021-12-13
diff --git a/changelog.md b/changelog.md
index cbd2061..1d0a3b4 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,26 @@
## grblHAL changelog
+Build 20211213:
+
+Core:
+
+* Added generic stream switcher functions for driver use, to avoid duplicated code.
+* Added HAL entry point as workaround fix for random ESP32 crashes \(related to unreferenced float variable in ISR context\).
+
+Drivers:
+
+* Most: updated to use new core based stream switcher.
+* STM32F4xx: updates for BTT SKR 1.1 & 2.0 UART mode Trinamic stepper driver support.
+* LPC176x: Added tentative support for BTT SKR E3 board including soft UART mode Trinamic TMC2209 drivers. Code by Dimitris Zervas, somewhat modified by Terje Io.
+* ESP32: added driver support for ganged/auto squared axes and Trinamic SPI mode stepper drivers. Untested for now since hardware is not available.
+Added board map for xPro v5 controller with TMC5160 drivers. Untested.
+Fix for random Guru crashes when streaming gcode at high feedrates/accelerations.
+
+Plugins:
+* Trinamic: workaround for ESP32 enums always defaulting to 32bit(!)
+* Networking, Bluetooth: updated for core stream switcher.
+
+---
Core:
* Renamed unused function.
diff --git a/grbl.h b/grbl.h
index 0296976..b34deb6 100644
--- a/grbl.h
+++ b/grbl.h
@@ -34,7 +34,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
-#define GRBL_BUILD 20211203
+#define GRBL_BUILD 20211209
// The following symbols are set here if not already set by the compiler or in config.h
// Do NOT change here!
diff --git a/hal.h b/hal.h
index 71001b1..bbeb873 100644
--- a/hal.h
+++ b/hal.h
@@ -183,6 +183,9 @@ typedef struct {
spindle_update_pwm_ptr update_pwm; //!< Handler for updating spindle PWM output.
#else
spindle_update_rpm_ptr update_rpm; //!< Handler for updating spindle RPM.
+#endif
+#ifdef GRBL_ESP32
+ void (*esp32_off)(void); //!< Workaround handler for snowflake ESP32 Guru awaken by floating point data in ISR context.
#endif
// Optional entry points:
spindle_get_data_ptr get_data; //!< Optional handler for getting spindle data. Required for spindle sync.
diff --git a/plugins.h b/plugins.h
index 79afe72..4390be3 100644
--- a/plugins.h
+++ b/plugins.h
@@ -186,6 +186,6 @@ typedef struct {
} nvs_transfer_t;
extern nvs_transfer_result_t i2c_nvs_transfer (nvs_transfer_t *i2c, bool read);
-extern void my_plugin_init (void) __attribute__((weak));
+extern void my_plugin_init (void);
#endif
diff --git a/plugins_init.h b/plugins_init.h
index 3011454..983da14 100644
--- a/plugins_init.h
+++ b/plugins_init.h
@@ -65,7 +65,7 @@
openpnp_init();
#endif
-// ESP32 has its own webui_init and crashes at runtime if the weak my_plugin_init() is called...
+// ESP32 has its own webui_init
#ifndef GRBL_ESP32
#if WEBUI_ENABLE
@@ -73,10 +73,10 @@
webui_init();
#endif
- my_plugin_init();
-
#endif
+ my_plugin_init();
+
// Third party plugin definitions.
// The code for these has to be downloaded from the source and placed in the same folder as driver.c
// Note: Third party plugins may have more than one implementation, there is no "owner" of plugins listed here.
diff --git a/stepper.c b/stepper.c
index bd3cee4..662a983 100644
--- a/stepper.c
+++ b/stepper.c
@@ -404,9 +404,15 @@ ISR_CODE void stepper_driver_interrupt_handler (void)
} else {
// Segment buffer empty. Shutdown.
st_go_idle();
+
// Ensure pwm is set properly upon completion of rate-controlled motion.
- if (st.exec_block->dynamic_rpm && settings.mode == Mode_Laser)
+ if (st.exec_block->dynamic_rpm && settings.mode == Mode_Laser) {
+ #ifndef GRBL_ESP32
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
+ #else
+ hal.spindle.esp32_off();
+ #endif
+ }
st.exec_block = NULL;
system_set_exec_state_flag(EXEC_CYCLE_COMPLETE); // Flag main program for cycle complete
diff --git a/stream.c b/stream.c
index ef043a7..5ea98ee 100644
--- a/stream.c
+++ b/stream.c
@@ -1,5 +1,5 @@
/*
- stream.c - stream RX handling for tool change protocol
+ stream.c - high level (serial) stream handling
Part of grblHAL
@@ -19,6 +19,7 @@
along with Grbl. If not, see .
*/
+#include
#include
#include "hal.h"
@@ -33,8 +34,15 @@ typedef struct {
stream_rx_buffer_t *rxbuffer;
} stream_state_t;
+typedef struct stream_connection {
+ const io_stream_t *stream;
+ bool is_up;
+ struct stream_connection *next;
+} stream_connection_t;
+
static stream_state_t stream = {0};
static io_stream_details_t *streams = NULL;
+static stream_connection_t base = {0}, *connections = &base;
void stream_register_streams (io_stream_details_t *details)
{
@@ -168,6 +176,149 @@ ISR_CODE bool stream_enable_mpg (const io_stream_t *mpg_stream, bool mpg_mode)
return true;
}
+static void stream_write_all (const char *s)
+{
+ stream_connection_t *connection = connections;
+
+ while(connection) {
+ if(connection->is_up)
+ connection->stream->write(s);
+ connection = connection->next;
+ }
+}
+
+static bool stream_select (const io_stream_t *stream, bool add)
+{
+ static const io_stream_t *active_stream = NULL;
+
+ stream_connection_t *connection, *last = connections;
+
+ if(stream == base.stream) {
+ base.is_up = add;
+ return true;
+ }
+
+ if(add) {
+
+ if(base.stream == NULL) {
+ base.stream = stream;
+ base.is_up = stream->state.connected == On;
+ } else if((connection = malloc(sizeof(stream_connection_t)))) {
+ connection->stream = stream;
+ connection->is_up = stream->state.connected == On || stream->state.is_usb == On; // TODO: add connect/disconnect event to driver code
+ connection->next = NULL;
+ while(last->next) {
+ last = last->next;
+ if(last->stream == stream) {
+ free(connection);
+ return true;
+ }
+ }
+ last->next = connection;
+ } else
+ return false;
+
+ } else { // disconnect
+
+ stream_connection_t *prev;
+
+ while(last->next) {
+ prev = last;
+ last = last->next;
+ if(last->stream == stream) {
+ prev->next = last->next;
+ free(last);
+ if(prev->next)
+ return false;
+ else {
+ stream = prev->stream;
+ break;
+ }
+ }
+ }
+ }
+
+ bool webui_connected = hal.stream.state.webui_connected;
+
+ switch(stream->type) {
+
+ case StreamType_Serial:
+ if(active_stream && active_stream->type != StreamType_Serial && stream->state.connected) {
+ hal.stream.write = stream->write;
+ report_message("SERIAL STREAM ACTIVE", Message_Plain);
+ }
+ break;
+
+ case StreamType_Telnet:
+ if(hal.stream.state.connected)
+ report_message("TELNET STREAM ACTIVE", Message_Plain);
+ if(add && sys.driver_started) {
+ hal.stream.write_all = stream->write;
+ report_init_message();
+ }
+ break;
+
+ case StreamType_WebSocket:
+ if(hal.stream.state.connected)
+ report_message("WEBSOCKET STREAM ACTIVE", Message_Plain);
+ if(add && sys.driver_started && !hal.stream.state.webui_connected) {
+ hal.stream.write_all = stream->write;
+ report_init_message();
+ }
+ break;
+
+ case StreamType_Bluetooth:
+ if(hal.stream.state.connected)
+ report_message("BLUETOOTH STREAM ACTIVE", Message_Plain);
+ if(add && sys.driver_started) {
+ hal.stream.write_all = stream->write;
+ report_init_message();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ 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;
+
+ if(stream->type == StreamType_WebSocket)
+ hal.stream.state.webui_connected = webui_connected;
+
+ hal.stream.set_enqueue_rt_handler(protocol_enqueue_realtime_command);
+
+ if(hal.stream.disable_rx)
+ hal.stream.disable_rx(false);
+
+ if(grbl.on_stream_changed)
+ grbl.on_stream_changed(hal.stream.type);
+
+ active_stream = stream;
+
+ return true;
+}
+
+const io_stream_t *stream_get_base (void)
+{
+ return base.stream;
+}
+
+bool stream_connect (const io_stream_t *stream)
+{
+ return hal.stream_select ? hal.stream_select(stream) : stream_select(stream, true);
+}
+
+void stream_disconnect (const io_stream_t *stream)
+{
+ if(hal.stream_select)
+ hal.stream_select(NULL);
+ else if(stream)
+ stream_select(stream, false);
+}
+
#ifdef DEBUGOUT
static stream_write_ptr dbg_write = NULL;
diff --git a/stream.h b/stream.h
index ba3f577..9bd8638 100644
--- a/stream.h
+++ b/stream.h
@@ -1,5 +1,5 @@
/*
- stream.h - some ASCII control character definitions and optional structures for stream buffers
+ stream.h - high level (serial) stream handling
Part of grblHAL
@@ -211,7 +211,8 @@ typedef union {
struct {
uint8_t connected :1,
webui_connected :1,
- unused :6;
+ is_usb :1,
+ unused :5;
};
} io_stream_state_t;
@@ -324,6 +325,12 @@ void stream_register_streams (io_stream_details_t *details);
bool stream_enumerate_streams (stream_enumerate_callback_ptr callback);
+bool stream_connect (const io_stream_t *stream);
+
+void stream_disconnect (const io_stream_t *stream);
+
+const io_stream_t *stream_get_base (void);
+
#ifdef DEBUGOUT
void debug_write (const char *s);
bool debug_stream_init (void);