diff --git a/changelog.md b/changelog.md
index 12ad356..d33583b 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,10 +1,27 @@
## grblHAL changelog
+20230312
+
+Core:
+
+* Added event definition for SD card file open, fix for issue #118.
+
+Drivers:
+
+* ESP32: Added aux I/O and cycle start/feed hold inputs to MKS DLC32 board, expanded max aux out to 4.
+__NOTE:__ The aux input 0 port on the MKS DLC32 board does not have an internal pullup.
+
+Plugins:
+
+* SD card: added publish for file open event allowing plugins to take over stream handling. Added `$F+` command for listing all files on card.
+
+---
+
20230311
Core:
-* Fix for isisue #264, stepper motors not disabled when entering sleep mode.
+* Fix for issue #264, stepper motors not disabled when entering sleep mode.
__NOTE:__ all stepper motors will now be disabled even if the $37 setting is set to keep some enabled.
* Fix for recent regression that disabled G7/G8 handling in lathe mode.
diff --git a/core_handlers.h b/core_handlers.h
index f1092ad..8a91895 100644
--- a/core_handlers.h
+++ b/core_handlers.h
@@ -33,6 +33,7 @@
#include "report.h"
#include "planner.h"
#include "machine_limits.h"
+#include "vfs.h"
typedef enum {
OverrideChanged_FeedRate = 0,
@@ -107,6 +108,7 @@ typedef bool (*on_spindle_select_ptr)(spindle_ptrs_t *spindle);
typedef void (*on_spindle_selected_ptr)(spindle_ptrs_t *spindle);
typedef void (*on_gcode_message_ptr)(char *msg);
typedef void (*on_rt_reports_added_ptr)(report_tracking_flags_t report);
+typedef status_code_t (*on_file_open_ptr)(const char *fname, vfs_file_t *handle, bool stream);
typedef status_code_t (*on_unknown_sys_command_ptr)(sys_state_t state, char *line); // return Status_Unhandled.
typedef status_code_t (*on_user_command_ptr)(char *line);
typedef sys_commands_t *(*on_get_commands_ptr)(void);
@@ -148,9 +150,10 @@ typedef struct {
on_toolchange_ack_ptr on_toolchange_ack; //!< Called from interrupt context.
on_jog_cancel_ptr on_jog_cancel; //!< Called from interrupt context.
on_laser_ppi_enable_ptr on_laser_ppi_enable;
- on_spindle_select_ptr on_spindle_select; //!< Called before spindle is selected, hook in HAL overrides here
- on_spindle_selected_ptr on_spindle_selected; //!< Called when spindle is selected, do not change HAL pointers here!
+ on_spindle_select_ptr on_spindle_select; //!< Called before spindle is selected, hook in HAL overrides here
+ on_spindle_selected_ptr on_spindle_selected; //!< Called when spindle is selected, do not change HAL pointers here!
on_reset_ptr on_reset; //!< Called from interrupt context.
+ on_file_open_ptr on_file_open; //!< Called when a file is opened for streaming.
// core entry points - set up by core before driver_init() is called.
enqueue_gcode_ptr enqueue_gcode;
enqueue_realtime_command_ptr enqueue_realtime_command;
diff --git a/gcode.c b/gcode.c
index c583fef..d8c40ab 100644
--- a/gcode.c
+++ b/gcode.c
@@ -1014,7 +1014,7 @@ status_code_t gc_execute_block (char *block)
word_bit.modal_group.M7 = On;
gc_block.modal.spindle.state.on = !(int_value == 5);
gc_block.modal.spindle.state.ccw = int_value == 4;
- sys.flags.delay_overrides = On;
+ sys.override_delay.spindle = On;
break;
case 6:
@@ -1028,7 +1028,7 @@ status_code_t gc_execute_block (char *block)
case 7: case 8: case 9:
word_bit.modal_group.M8 = On;
- sys.flags.delay_overrides = On;
+ sys.override_delay.coolant = On;
gc_parser_flags.set_coolant = On;
switch(int_value) {
@@ -2856,7 +2856,7 @@ status_code_t gc_execute_block (char *block)
plan_data.condition.coolant = gc_state.modal.coolant; // Set condition flag for planner use.
- sys.flags.delay_overrides = Off;
+ sys.override_delay.flags = 0;
// [9. Override control ]:
if (gc_state.modal.override_ctrl.value != gc_block.modal.override_ctrl.value) {
diff --git a/grbl.h b/grbl.h
index 599bee5..e1542f5 100644
--- a/grbl.h
+++ b/grbl.h
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
-#define GRBL_BUILD 20230311
+#define GRBL_BUILD 20230312
#define GRBL_URL "https://github.com/grblHAL"
diff --git a/override.c b/override.c
index 6d47c08..490592b 100644
--- a/override.c
+++ b/override.c
@@ -5,7 +5,7 @@
Part of grblHAL
- Copyright (c) 2017-2019 Terje Io
+ Copyright (c) 2017-2023 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ typedef struct {
uint8_t buf[OVERRIDE_BUFSIZE];
} override_queue_t;
-static override_queue_t feed = {0}, accessory = {0};
+static override_queue_t feed = {0}, spindle = {0}, coolant = {0};
ISR_CODE void ISR_FUNC(enqueue_feed_override)(uint8_t cmd)
{
@@ -56,30 +56,55 @@ uint8_t get_feed_override (void)
return data;
}
-ISR_CODE void ISR_FUNC(enqueue_accessory_override)(uint8_t cmd)
+ISR_CODE void ISR_FUNC(enqueue_spindle_override)(uint8_t cmd)
{
- uint_fast8_t bptr = (accessory.head + 1) & (OVERRIDE_BUFSIZE - 1); // Get next head pointer
+ uint_fast8_t bptr = (spindle.head + 1) & (OVERRIDE_BUFSIZE - 1); // Get next head pointer
- if(bptr != accessory.tail) { // If not buffer full
- accessory.buf[accessory.head] = cmd; // add data to buffer
- accessory.head = bptr; // and update pointer
+ if(bptr != spindle.tail) { // If not buffer full
+ spindle.buf[spindle.head] = cmd; // add data to buffer
+ spindle.head = bptr; // and update pointer
}
}
// Returns 0 if no commands enqueued
-uint8_t get_accessory_override (void)
+uint8_t get_spindle_override (void)
{
uint8_t data = 0;
- uint_fast8_t bptr = accessory.tail;
+ uint_fast8_t bptr = spindle.tail;
- if(bptr != accessory.head) {
- data = accessory.buf[bptr++]; // Get next character, increment tmp pointer
- accessory.tail = bptr & (OVERRIDE_BUFSIZE - 1); // and update pointer
+ if(bptr != spindle.head) {
+ data = spindle.buf[bptr++]; // Get next character, increment tmp pointer
+ spindle.tail = bptr & (OVERRIDE_BUFSIZE - 1); // and update pointer
}
return data;
}
-void flush_override_buffers () {
- feed.head = feed.tail = accessory.head = accessory.tail = 0;
+ISR_CODE void ISR_FUNC(enqueue_coolant_override)(uint8_t cmd)
+{
+ uint_fast8_t bptr = (coolant.head + 1) & (OVERRIDE_BUFSIZE - 1); // Get next head pointer
+
+ if(bptr != coolant.tail) { // If not buffer full
+ coolant.buf[coolant.head] = cmd; // add data to buffer
+ coolant.head = bptr; // and update pointer
+ }
+}
+
+// Returns 0 if no commands enqueued
+uint8_t get_coolant_override (void)
+{
+ uint8_t data = 0;
+ uint_fast8_t bptr = coolant.tail;
+
+ if(bptr != coolant.head) {
+ data = coolant.buf[bptr++]; // Get next character, increment tmp pointer
+ coolant.tail = bptr & (OVERRIDE_BUFSIZE - 1); // and update pointer
+ }
+
+ return data;
+}
+
+void flush_override_buffers (void)
+{
+ feed.head = feed.tail = spindle.head = spindle.tail = coolant.head = coolant.tail = 0;
}
diff --git a/override.h b/override.h
index 990ccab..88ca449 100644
--- a/override.h
+++ b/override.h
@@ -5,7 +5,7 @@
Part of grblHAL
- Copyright (c) 2016-2019 Terje Io
+ Copyright (c) 2016-2023 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,7 +31,9 @@
void flush_override_buffers ();
void enqueue_feed_override (uint8_t cmd);
uint8_t get_feed_override (void);
-void enqueue_accessory_override (uint8_t cmd);
-uint8_t get_accessory_override (void);
+void enqueue_spindle_override (uint8_t cmd);
+uint8_t get_spindle_override (void);
+void enqueue_coolant_override (uint8_t cmd);
+uint8_t get_coolant_override (void);
#endif
diff --git a/plugins_init.h b/plugins_init.h
index da717b4..d73bd59 100644
--- a/plugins_init.h
+++ b/plugins_init.h
@@ -85,6 +85,11 @@
webui_init();
#endif
+#if EMBROIDERY_ENABLE
+ extern void embroidery_init (void);
+ embroidery_init();
+#endif
+
extern void my_plugin_init (void);
my_plugin_init();
diff --git a/protocol.c b/protocol.c
index 059bdcf..fc13514 100644
--- a/protocol.c
+++ b/protocol.c
@@ -495,7 +495,7 @@ bool protocol_exec_rt_system (void)
sys.cancel = true;
sys.step_control.flags = 0;
sys.flags.feed_hold_pending = Off;
- sys.flags.delay_overrides = Off;
+ sys.override_delay.flags = 0;
if(sys.override.control.sync)
sys.override.control = gc_state.modal.override_ctrl;
@@ -562,137 +562,152 @@ bool protocol_exec_rt_system (void)
grbl.on_execute_realtime(state_get());
- if(!sys.flags.delay_overrides) {
+ // Execute overrides.
- // Execute overrides.
+ if(!sys.override_delay.feedrate && (rt_exec = get_feed_override())) {
- if((rt_exec = get_feed_override())) {
+ override_t new_f_override = sys.override.feed_rate;
+ override_t new_r_override = sys.override.rapid_rate;
- override_t new_f_override = sys.override.feed_rate;
- override_t new_r_override = sys.override.rapid_rate;
+ do {
- do {
+ switch(rt_exec) {
- switch(rt_exec) {
+ case CMD_OVERRIDE_FEED_RESET:
+ new_f_override = DEFAULT_FEED_OVERRIDE;
+ break;
- case CMD_OVERRIDE_FEED_RESET:
- new_f_override = DEFAULT_FEED_OVERRIDE;
- break;
+ case CMD_OVERRIDE_FEED_COARSE_PLUS:
+ new_f_override += FEED_OVERRIDE_COARSE_INCREMENT;
+ break;
- case CMD_OVERRIDE_FEED_COARSE_PLUS:
- new_f_override += FEED_OVERRIDE_COARSE_INCREMENT;
- break;
+ case CMD_OVERRIDE_FEED_COARSE_MINUS:
+ new_f_override -= FEED_OVERRIDE_COARSE_INCREMENT;
+ break;
- case CMD_OVERRIDE_FEED_COARSE_MINUS:
- new_f_override -= FEED_OVERRIDE_COARSE_INCREMENT;
- break;
+ case CMD_OVERRIDE_FEED_FINE_PLUS:
+ new_f_override += FEED_OVERRIDE_FINE_INCREMENT;
+ break;
- case CMD_OVERRIDE_FEED_FINE_PLUS:
- new_f_override += FEED_OVERRIDE_FINE_INCREMENT;
- break;
+ case CMD_OVERRIDE_FEED_FINE_MINUS:
+ new_f_override -= FEED_OVERRIDE_FINE_INCREMENT;
+ break;
- case CMD_OVERRIDE_FEED_FINE_MINUS:
- new_f_override -= FEED_OVERRIDE_FINE_INCREMENT;
- break;
+ case CMD_OVERRIDE_RAPID_RESET:
+ new_r_override = DEFAULT_RAPID_OVERRIDE;
+ break;
- case CMD_OVERRIDE_RAPID_RESET:
- new_r_override = DEFAULT_RAPID_OVERRIDE;
- break;
+ case CMD_OVERRIDE_RAPID_MEDIUM:
+ new_r_override = RAPID_OVERRIDE_MEDIUM;
+ break;
- case CMD_OVERRIDE_RAPID_MEDIUM:
- new_r_override = RAPID_OVERRIDE_MEDIUM;
- break;
+ case CMD_OVERRIDE_RAPID_LOW:
+ new_r_override = RAPID_OVERRIDE_LOW;
+ break;
+ }
- case CMD_OVERRIDE_RAPID_LOW:
- new_r_override = RAPID_OVERRIDE_LOW;
- break;
- }
+ new_f_override = constrain(new_f_override, MIN_FEED_RATE_OVERRIDE, MAX_FEED_RATE_OVERRIDE);
- new_f_override = constrain(new_f_override, MIN_FEED_RATE_OVERRIDE, MAX_FEED_RATE_OVERRIDE);
+ } while((rt_exec = get_feed_override()));
- } while((rt_exec = get_feed_override()));
+ plan_feed_override(new_f_override, new_r_override);
+ }
- plan_feed_override(new_f_override, new_r_override);
- }
+ if(!sys.override_delay.spindle && (rt_exec = get_spindle_override())) {
- if((rt_exec = get_accessory_override())) {
+ bool spindle_stop = false;
+ spindle_ptrs_t *spindle = gc_spindle_get();
+ override_t last_s_override = spindle->param->override_pct;
- bool spindle_stop = false;
- spindle_ptrs_t *spindle = gc_spindle_get();
- override_t last_s_override = spindle->param->override_pct;
- coolant_state_t coolant_state = gc_state.modal.coolant;
+ do {
- do {
+ switch(rt_exec) {
- switch(rt_exec) {
+ case CMD_OVERRIDE_SPINDLE_RESET:
+ last_s_override = DEFAULT_SPINDLE_RPM_OVERRIDE;
+ break;
- case CMD_OVERRIDE_SPINDLE_RESET:
- last_s_override = DEFAULT_SPINDLE_RPM_OVERRIDE;
- break;
+ case CMD_OVERRIDE_SPINDLE_COARSE_PLUS:
+ last_s_override += SPINDLE_OVERRIDE_COARSE_INCREMENT;
+ break;
- case CMD_OVERRIDE_SPINDLE_COARSE_PLUS:
- last_s_override += SPINDLE_OVERRIDE_COARSE_INCREMENT;
- break;
+ case CMD_OVERRIDE_SPINDLE_COARSE_MINUS:
+ last_s_override -= SPINDLE_OVERRIDE_COARSE_INCREMENT;
+ break;
- case CMD_OVERRIDE_SPINDLE_COARSE_MINUS:
- last_s_override -= SPINDLE_OVERRIDE_COARSE_INCREMENT;
- break;
+ case CMD_OVERRIDE_SPINDLE_FINE_PLUS:
+ last_s_override += SPINDLE_OVERRIDE_FINE_INCREMENT;
+ break;
- case CMD_OVERRIDE_SPINDLE_FINE_PLUS:
- last_s_override += SPINDLE_OVERRIDE_FINE_INCREMENT;
- break;
+ case CMD_OVERRIDE_SPINDLE_FINE_MINUS:
+ last_s_override -= SPINDLE_OVERRIDE_FINE_INCREMENT;
+ break;
- case CMD_OVERRIDE_SPINDLE_FINE_MINUS:
- last_s_override -= SPINDLE_OVERRIDE_FINE_INCREMENT;
- break;
+ case CMD_OVERRIDE_SPINDLE_STOP:
+ spindle_stop = !spindle_stop;
+ break;
- case CMD_OVERRIDE_SPINDLE_STOP:
- spindle_stop = !spindle_stop;
- break;
+ default:
+ if(grbl.on_unknown_accessory_override)
+ grbl.on_unknown_accessory_override(rt_exec);
+ break;
+ }
- case CMD_OVERRIDE_COOLANT_MIST_TOGGLE:
- if (hal.driver_cap.mist_control && ((state_get() == STATE_IDLE) || (state_get() & (STATE_CYCLE | STATE_HOLD)))) {
- coolant_state.mist = !coolant_state.mist;
- }
- break;
+ last_s_override = constrain(last_s_override, MIN_SPINDLE_RPM_OVERRIDE, MAX_SPINDLE_RPM_OVERRIDE);
- case CMD_OVERRIDE_COOLANT_FLOOD_TOGGLE:
- if ((state_get() == STATE_IDLE) || (state_get() & (STATE_CYCLE | STATE_HOLD))) {
- coolant_state.flood = !coolant_state.flood;
- }
- break;
+ } while((rt_exec = get_spindle_override()));
- default:
- if(grbl.on_unknown_accessory_override)
- grbl.on_unknown_accessory_override(rt_exec);
- break;
- }
+ spindle_set_override(spindle, last_s_override);
- last_s_override = constrain(last_s_override, MIN_SPINDLE_RPM_OVERRIDE, MAX_SPINDLE_RPM_OVERRIDE);
+ if (spindle_stop && state_get() == STATE_HOLD && gc_state.modal.spindle.state.on) {
+ // Spindle stop override allowed only while in HOLD state.
+ // NOTE: Report flag is set in spindle_set_state() when spindle stop is executed.
+ if (!sys.override.spindle_stop.value)
+ sys.override.spindle_stop.initiate = On;
+ else if (sys.override.spindle_stop.enabled)
+ sys.override.spindle_stop.restore = On;
+ }
+ }
- } while((rt_exec = get_accessory_override()));
+ if(!sys.override_delay.coolant && (rt_exec = get_coolant_override())) {
- spindle_set_override(spindle, last_s_override);
+ coolant_state_t coolant_state = gc_state.modal.coolant;
- // NOTE: Since coolant state always performs a planner sync whenever it changes, the current
- // run state can be determined by checking the parser state.
- if(coolant_state.value != gc_state.modal.coolant.value) {
- coolant_set_state(coolant_state); // Report flag set in coolant_set_state().
- gc_state.modal.coolant = coolant_state;
- if(grbl.on_override_changed)
- grbl.on_override_changed(OverrideChanged_CoolantState);
- }
+ do {
+
+ switch(rt_exec) {
- if (spindle_stop && state_get() == STATE_HOLD && gc_state.modal.spindle.state.on) {
- // Spindle stop override allowed only while in HOLD state.
- // NOTE: Report flag is set in spindle_set_state() when spindle stop is executed.
- if (!sys.override.spindle_stop.value)
- sys.override.spindle_stop.initiate = On;
- else if (sys.override.spindle_stop.enabled)
- sys.override.spindle_stop.restore = On;
+ case CMD_OVERRIDE_COOLANT_MIST_TOGGLE:
+ if (hal.driver_cap.mist_control && ((state_get() == STATE_IDLE) || (state_get() & (STATE_CYCLE | STATE_HOLD)))) {
+ coolant_state.mist = !coolant_state.mist;
+ }
+ break;
+
+ case CMD_OVERRIDE_COOLANT_FLOOD_TOGGLE:
+ if ((state_get() == STATE_IDLE) || (state_get() & (STATE_CYCLE | STATE_HOLD))) {
+ coolant_state.flood = !coolant_state.flood;
+ }
+ break;
+
+ default:
+ if(grbl.on_unknown_accessory_override)
+ grbl.on_unknown_accessory_override(rt_exec);
+ break;
}
+
+ } while((rt_exec = get_coolant_override()));
+
+ // NOTE: Since coolant state always performs a planner sync whenever it changes, the current
+ // run state can be determined by checking the parser state.
+ if(coolant_state.value != gc_state.modal.coolant.value) {
+ coolant_set_state(coolant_state); // Report flag set in coolant_set_state().
+ gc_state.modal.coolant = coolant_state;
+ if(grbl.on_override_changed)
+ grbl.on_override_changed(OverrideChanged_CoolantState);
}
- } // End execute overrides.
+ }
+
+ // End execute overrides.
// Reload step segment buffer
if (state_get() & (STATE_CYCLE | STATE_HOLD | STATE_SAFETY_DOOR | STATE_HOMING | STATE_SLEEP| STATE_JOG))
@@ -876,11 +891,15 @@ ISR_CODE bool ISR_FUNC(protocol_enqueue_realtime_command)(char c)
case CMD_OVERRIDE_SPINDLE_FINE_PLUS:
case CMD_OVERRIDE_SPINDLE_FINE_MINUS:
case CMD_OVERRIDE_SPINDLE_STOP:
+ drop = true;
+ enqueue_spindle_override((uint8_t)c);
+ break;
+
case CMD_OVERRIDE_COOLANT_FLOOD_TOGGLE:
case CMD_OVERRIDE_COOLANT_MIST_TOGGLE:
case CMD_OVERRIDE_FAN0_TOGGLE:
drop = true;
- enqueue_accessory_override((uint8_t)c);
+ enqueue_coolant_override((uint8_t)c);
break;
case CMD_REBOOT:
diff --git a/settings.h b/settings.h
index 5f0130c..a5032d2 100644
--- a/settings.h
+++ b/settings.h
@@ -709,6 +709,7 @@ typedef enum {
Group_MotorDriver,
Group_VFD,
Group_CANbus,
+ Group_Embroidery,
Group_Axis,
// NOTE: axis groups MUST be sequential AND last
Group_Axis0,
diff --git a/state_machine.c b/state_machine.c
index b85ae00..ebfe0bb 100644
--- a/state_machine.c
+++ b/state_machine.c
@@ -163,7 +163,7 @@ static bool initiate_hold (uint_fast16_t new_state)
restore_condition.coolant.mask = gc_state.modal.coolant.mask | hal.coolant.get_state().mask;
if (restore_condition.spindle[restore_condition.spindle_num].hal->cap.laser && settings.flags.disable_laser_during_hold)
- enqueue_accessory_override(CMD_OVERRIDE_SPINDLE_STOP);
+ enqueue_spindle_override(CMD_OVERRIDE_SPINDLE_STOP);
if (sys_state & (STATE_CYCLE|STATE_JOG)) {
st_update_plan_block_parameters(); // Notify stepper module to recompute for hold deceleration.
diff --git a/system.h b/system.h
index cbef6f8..24ff621 100644
--- a/system.h
+++ b/system.h
@@ -219,21 +219,30 @@ typedef struct {
gc_override_flags_t control; //!< Tracks override control states.
} overrides_t;
+typedef union {
+ uint8_t flags;
+ struct {
+ uint16_t feedrate :1,
+ coolant :1,
+ spindle :1,
+ unused :5;
+ };
+} system_override_delay_t;
+
typedef union {
uint16_t value;
struct {
- uint16_t mpg_mode :1, //!< MPG mode flag. Set when switched to secondary input stream. (unused for now).
- probe_succeeded :1, //!< Tracks if last probing cycle was successful.
- soft_limit :1, //!< Tracks soft limit errors for the state machine.
- exit :1, //!< System exit flag. Used in combination with abort to terminate main loop.
- block_delete_enabled :1, //!< Set to true to enable block delete.
- feed_hold_pending :1,
- delay_overrides :1,
- optional_stop_disable :1,
- single_block :1, //!< Set to true to disable M1 (optional stop), via realtime command.
- keep_input :1, //!< Set to true to not flush stream input buffer on executing STOP.
- auto_reporting :1, //!< Set to true when auto real time reporting is enabled.
- unused :5;
+ uint16_t mpg_mode :1, //!< MPG mode flag. Set when switched to secondary input stream. (unused for now).
+ probe_succeeded :1, //!< Tracks if last probing cycle was successful.
+ soft_limit :1, //!< Tracks soft limit errors for the state machine.
+ exit :1, //!< System exit flag. Used in combination with abort to terminate main loop.
+ block_delete_enabled :1, //!< Set to true to enable block delete.
+ feed_hold_pending :1,
+ optional_stop_disable :1,
+ single_block :1, //!< Set to true to disable M1 (optional stop), via realtime command.
+ keep_input :1, //!< Set to true to not flush stream input buffer on executing STOP.
+ auto_reporting :1, //!< Set to true when auto real time reporting is enabled.
+ unused :6;
};
} system_flags_t;
@@ -260,6 +269,7 @@ typedef struct system {
axes_signals_t homing_axis_lock; //!< Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
axes_signals_t homing; //!< Axes with homing enabled.
overrides_t override; //!< Override values & states
+ system_override_delay_t override_delay; //!< Flags for delayed overrides.
report_tracking_flags_t report; //!< Tracks when to add data to status reports.
parking_state_t parking_state; //!< Tracks parking state
hold_state_t holding_state; //!< Tracks holding state
diff --git a/task.c b/task.c
new file mode 100644
index 0000000..bab016e
--- /dev/null
+++ b/task.c
@@ -0,0 +1,59 @@
+#include "core_handlers.h"
+/*
+typedef struct {
+ volatile uint_fast8_t head;
+ volatile uint_fast8_t tail;
+ on_execute_realtime_ptr fn[RT_QUEUE_SIZE];
+} realtime_queue_t;
+
+static realtime_queue_t realtime_queue = {0};
+
+// Enqueue a function to be called once by the
+// foreground process, typically enqueued from an interrupt handler.
+ISR_CODE bool ISR_FUNC(grbl_task_enqueue)(on_execute_realtime_ptr fn)
+{
+ bool ok;
+ uint_fast8_t bptr = (realtime_queue.head + 1) & (RT_QUEUE_SIZE - 1); // Get next head pointer
+
+ if((ok = bptr != realtime_queue.tail)) { // If not buffer full
+ realtime_queue.fn[realtime_queue.head] = fn; // add function pointer to buffer,
+ realtime_queue.head = bptr; // update pointer and
+ system_set_exec_state_flag(EXEC_RT_COMMAND); // flag it for execute
+ }
+
+ return ok;
+}
+
+// Enqueue a function to be called once by the
+// foreground process, typically enqueued from an interrupt handler.
+ISR_CODE bool ISR_FUNC(grbl_task_enqueue_delayed)(on_execute_realtime_ptr fn, uint32_t ms_delay, void *context)
+{
+ bool ok;
+ uint_fast8_t bptr = (realtime_queue.head + 1) & (RT_QUEUE_SIZE - 1); // Get next head pointer
+
+ if((ok = bptr != realtime_queue.tail)) { // If not buffer full
+ realtime_queue.fn[realtime_queue.head] = fn; // add function pointer to buffer,
+ realtime_queue.head = bptr; // update pointer and
+ system_set_exec_state_flag(EXEC_RT_COMMAND); // flag it for execute
+ }
+
+ return ok;
+}
+
+// Execute enqueued functions.
+static void grbl_task_execute (void)
+{
+ while(realtime_queue.tail != realtime_queue.head) {
+ uint_fast8_t bptr = realtime_queue.tail;
+ on_execute_realtime_ptr call;
+ if((call = realtime_queue.fn[bptr])) {
+ realtime_queue.fn[bptr] = NULL;
+ call(state_get());
+ }
+ realtime_queue.tail = (bptr + 1) & (RT_QUEUE_SIZE - 1);
+ }
+
+ if(!sys.driver_started)
+ while(true);
+}
+*/