diff --git a/changelog.md b/changelog.md
index 73a97e1..78643be 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,26 @@
## grblHAL changelog
+20230714
+
+Core:
+
+* Added support for traversing directory structure across file system mounts. Allows access to littlefs mount via ftp.
+* Fixed inconsistent \(random\) real-time reporting of cycle start signal by adding a latch to ensure it is reported at least once.
+
+Drivers:
+
+* ESP32: added WiFi settings for country, AP channel and BSSID. Changed default AP password to make it legal, was too short.
+
+* STM32F7xx: added EStop signal handling. Driver now defaults to this for the reset input.
+
+Plugins:
+
+* Networking: improved telnet transmit handling.
+
+* WebUI: added file seek function for embedded files, may be used later by gcode macros.
+
+---
+
20230711
Core:
diff --git a/driver_opts.h b/driver_opts.h
index 0dca407..3ca8d0f 100644
--- a/driver_opts.h
+++ b/driver_opts.h
@@ -430,7 +430,7 @@
#define NETWORK_AP_SSID "grblHAL_AP"
#endif
#ifndef NETWORK_AP_PASSWORD
-#define NETWORK_AP_PASSWORD "grblHAL"
+#define NETWORK_AP_PASSWORD "grblHALpwd"
#endif
#ifndef NETWORK_AP_HOSTNAME
#define NETWORK_AP_HOSTNAME "grblHAL_AP"
diff --git a/gcode.c b/gcode.c
index ddbf297..6ed6b0c 100644
--- a/gcode.c
+++ b/gcode.c
@@ -1716,7 +1716,7 @@ status_code_t gc_execute_block (char *block)
gc_block.values.t = (uint32_t)gc_block.values.q;
gc_block.words.q = Off;
#if NGC_EXPRESSIONS_ENABLE
- if(sys.macro_file) {
+ if(hal.stream.file) {
gc_state.tool_pending = 0; // force set tool
#if N_TOOLS
if(gc_state.g43_pending) {
diff --git a/grbl.h b/grbl.h
index 16392fa..30807e2 100644
--- a/grbl.h
+++ b/grbl.h
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
-#define GRBL_BUILD 20230711
+#define GRBL_BUILD 20230714
#define GRBL_URL "https://github.com/grblHAL"
diff --git a/ngc_flowctrl.c b/ngc_flowctrl.c
index a30d7d9..394d7ca 100644
--- a/ngc_flowctrl.c
+++ b/ngc_flowctrl.c
@@ -170,7 +170,7 @@ static status_code_t stack_push (uint32_t o_label, ngc_cmd_t operation)
{
if(stack_idx < (NGC_STACK_DEPTH - 1)) {
stack[++stack_idx].o_label = o_label;
- stack[stack_idx].file = sys.macro_file;
+ stack[stack_idx].file = hal.stream.file;
stack[stack_idx].operation = operation;
return Status_OK;
}
@@ -259,9 +259,9 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo
break;
case NGCFlowCtrl_Do:
- if(sys.macro_file) {
+ if(hal.stream.file) {
if(!skipping && (status = stack_push(o_label, operation)) == Status_OK) {
- stack[stack_idx].file_pos = vfs_tell(sys.macro_file);
+ stack[stack_idx].file_pos = vfs_tell(hal.stream.file);
stack[stack_idx].skip = false;
}
} else
@@ -269,7 +269,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo
break;
case NGCFlowCtrl_While:
- if(sys.macro_file) {
+ if(hal.stream.file) {
char *expr = line + *pos;
if(stack[stack_idx].brk) {
if(last_op == NGCFlowCtrl_Do && o_label == stack[stack_idx].o_label)
@@ -286,8 +286,8 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo
if(!(stack[stack_idx].skip = value == 0.0f)) {
if((stack[stack_idx].expr = malloc(strlen(expr) + 1))) {
strcpy(stack[stack_idx].expr, expr);
- stack[stack_idx].file = sys.macro_file;
- stack[stack_idx].file_pos = vfs_tell(sys.macro_file);
+ stack[stack_idx].file = hal.stream.file;
+ stack[stack_idx].file_pos = vfs_tell(hal.stream.file);
} else
status = Status_FlowControlOutOfMemory;
}
@@ -298,7 +298,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo
break;
case NGCFlowCtrl_EndWhile:
- if(sys.macro_file) {
+ if(hal.stream.file) {
if(last_op == NGCFlowCtrl_While) {
if(o_label == stack[stack_idx].o_label) {
uint_fast8_t pos = 0;
@@ -316,12 +316,12 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo
break;
case NGCFlowCtrl_Repeat:
- if(sys.macro_file) {
+ if(hal.stream.file) {
if(!skipping && (status = ngc_eval_expression(line, pos, &value)) == Status_OK) {
if((status = stack_push(o_label, operation)) == Status_OK) {
if(!(stack[stack_idx].skip = value == 0.0f)) {
- stack[stack_idx].file = sys.macro_file;
- stack[stack_idx].file_pos = vfs_tell(sys.macro_file);
+ stack[stack_idx].file = hal.stream.file;
+ stack[stack_idx].file_pos = vfs_tell(hal.stream.file);
stack[stack_idx].repeats = (uint32_t)value;
}
}
@@ -331,7 +331,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo
break;
case NGCFlowCtrl_EndRepeat:
- if(sys.macro_file) {
+ if(hal.stream.file) {
if(last_op == NGCFlowCtrl_Repeat) {
if(o_label == stack[stack_idx].o_label) {
if(stack[stack_idx].repeats && --stack[stack_idx].repeats)
@@ -346,7 +346,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo
break;
case NGCFlowCtrl_Break:
- if(sys.macro_file) {
+ if(hal.stream.file) {
if(!skipping) {
while(o_label != stack[stack_idx].o_label && stack_pull());
last_op = stack_idx >= 0 ? stack[stack_idx].operation : NGCFlowCtrl_NoOp;
@@ -363,7 +363,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo
break;
case NGCFlowCtrl_Continue:
- if(sys.macro_file) {
+ if(hal.stream.file) {
if(!skipping) {
while(o_label != stack[stack_idx].o_label && stack_pull());
if(stack_idx >= 0 && o_label == stack[stack_idx].o_label) switch(stack[stack_idx].operation) {
diff --git a/report.c b/report.c
index 5e0dd39..2c10694 100644
--- a/report.c
+++ b/report.c
@@ -1205,6 +1205,9 @@ void report_realtime_status (void)
axes_signals_t lim_pin_state = limit_signals_merge(hal.limits.get_state());
control_signals_t ctrl_pin_state = hal.control.get_state();
+ if(sys.report.cycle_start)
+ ctrl_pin_state.cycle_start = On;
+
if (lim_pin_state.value | ctrl_pin_state.value | probe_state.triggered | !probe_state.connected | sys.flags.block_delete_enabled) {
char *append = &buf[4];
diff --git a/state_machine.c b/state_machine.c
index 4956ffa..e56d5fc 100644
--- a/state_machine.c
+++ b/state_machine.c
@@ -191,8 +191,10 @@ bool state_door_reopened (void)
void state_update (rt_exec_t rt_exec)
{
- if ((rt_exec & EXEC_SAFETY_DOOR) && sys_state != STATE_SAFETY_DOOR)
+ if((rt_exec & EXEC_SAFETY_DOOR) && sys_state != STATE_SAFETY_DOOR)
state_set(STATE_SAFETY_DOOR);
+ else if(rt_exec & EXEC_CYCLE_START)
+ sys.report.cycle_start = settings.status_report.pin_state;
stateHandler(rt_exec);
}
diff --git a/stream.h b/stream.h
index 91fb0b4..41e8225 100644
--- a/stream.h
+++ b/stream.h
@@ -247,7 +247,7 @@ typedef struct {
get_stream_buffer_count_ptr get_tx_buffer_count; //!< Optional handler for getting number of characters in the output buffer(s). Count shall include any unsent characters in any transmit FIFO and/or transmit register. Required for Modbus support.
flush_stream_buffer_ptr reset_write_buffer; //!< Optional handler for flushing the output buffer. Any transmit FIFO shall be flushed as well. Required for Modbus support.
set_baud_rate_ptr set_baud_rate; //!< Optional handler for setting the stream baud rate. Required for Modbus support, recommended for Bluetooth support.
-// vfs_file_t *file; //!< File handle, non-null if streaming from a file.
+ vfs_file_t *file; //!< File handle, non-null if streaming from a file.
} io_stream_t;
typedef const io_stream_t *(*stream_claim_ptr)(uint32_t baud_rate);
diff --git a/system.h b/system.h
index 5ba06dc..d3e5130 100644
--- a/system.h
+++ b/system.h
@@ -186,6 +186,7 @@ typedef enum {
Report_Encoder = (1 << 14),
Report_TLOReference = (1 << 15),
Report_Fan = (1 << 16),
+ Report_CycleStart = (1 << 30),
Report_All = 0x8001FFFF
} report_tracking_t;
@@ -207,17 +208,18 @@ typedef union {
pwm :1, //!< Add PWM information (optional: to be added by driver).
motor :1, //!< Add motor information (optional: to be added by driver).
encoder :1, //!< Add encoder information (optional: to be added by driver).
- tlo_reference :1, //!< Tool length offset reference changed
- fan :1, //!< Fan on/off changed
- unassigned :14, //
- all :1; //!< Set when CMD_STATUS_REPORT_ALL is requested, may be used by user code
+ tlo_reference :1, //!< Tool length offset reference changed.
+ fan :1, //!< Fan on/off changed.
+ unassigned :13, //
+ cycle_start :1, //!< Cycle start signal triggered. __NOTE:__ do __NOT__ add to Report_All enum above!
+ all :1; //!< Set when CMD_STATUS_REPORT_ALL is requested, may be used by user code.
};
} report_tracking_flags_t;
typedef struct {
override_t feed_rate; //!< Feed rate override value in percent
override_t rapid_rate; //!< Rapids override value in percent
- override_t spindle_rpm; //!< __NOTE:_ Not used by the core, it maintain per spindle override in \ref spindle_param_t
+ override_t spindle_rpm; //!< __NOTE:__ Not used by the core, it maintain per spindle override in \ref spindle_param_t
spindle_stop_t spindle_stop; //!< Tracks spindle stop override states
gc_override_flags_t control; //!< Tracks override control states.
} overrides_t;
@@ -286,9 +288,6 @@ typedef struct system {
volatile rt_exec_t rt_exec_state; //!< Realtime executor bitflag variable for state management. See EXEC bitmasks.
volatile uint_fast16_t rt_exec_alarm; //!< Realtime executor bitflag variable for setting various alarms.
int32_t var5399; //!< Last result from M66 - wait on input.
-#if NGC_EXPRESSIONS_ENABLE
- vfs_file_t *macro_file; //!< File handle of current G65 macro executing.
-#endif
#ifdef PID_LOG
pid_data_t pid_log;
#endif
diff --git a/vfs.c b/vfs.c
index f67ea34..46757cc 100644
--- a/vfs.c
+++ b/vfs.c
@@ -191,7 +191,7 @@ static const char *get_filename (vfs_mount_t *mount, const char *filename)
{
if(*filename == '/') {
size_t len = strlen(mount->path);
- return filename + (len == 1 ? 0 : len);
+ return filename + (len == 1 ? 0 : len - 1);
} else
return filename;
}
@@ -306,8 +306,18 @@ int vfs_chdir (const char *path)
*s = '\0';
}
} else {
+
strcpy(cwd, path);
- cwdmount = get_mount(cwd);
+
+ if((cwdmount = get_mount(path)) && strchr(path + 1, '/') == NULL && cwdmount != &root) {
+
+ strcpy(cwd, cwdmount->path);
+ char *s;
+ if((s = strrchr(cwd, '/')))
+ *s = '\0';
+
+ return 0;
+ }
}
if((ret = cwdmount ? cwdmount->vfs->fchdir(path) : -1) != 0) { // + strlen(mount->path));))
@@ -322,10 +332,30 @@ int vfs_chdir (const char *path)
vfs_dir_t *vfs_opendir (const char *path)
{
vfs_dir_t *dir = NULL;
- vfs_mount_t *mount = get_mount(path);
+ vfs_mount_t *mount = get_mount(path), *add_mount;
+ vfs_mount_ll_entry_t *ml = NULL, *mln;
+
+ if(mount && (dir = mount->vfs->fopendir(get_filename(mount, path)))) {
- if(mount && (dir = mount->vfs->fopendir(get_filename(mount, path))))
dir->fs = mount->vfs;
+ dir->mounts = NULL;
+ add_mount = root.next;
+
+ do {
+ if(add_mount != mount && !strncmp(add_mount->path, path, strlen(path))) {
+ if(!add_mount->vfs->mode.hidden && (mln = malloc(sizeof(vfs_mount_ll_entry_t)))) {
+ mln->mount = add_mount;
+ mln->next = NULL;
+ if(dir->mounts == NULL)
+ dir->mounts = ml = mln;
+ else {
+ ml->next = mln;
+ ml = mln;
+ }
+ }
+ }
+ } while((add_mount = add_mount->next));
+ }
return dir;
}
@@ -338,6 +368,21 @@ vfs_dirent_t *vfs_readdir (vfs_dir_t *dir)
((vfs_t *)dir->fs)->readdir(dir, &dirent);
+ if(*dirent.name == '\0' && dir->mounts) {
+
+ char *s;
+ vfs_mount_ll_entry_t *ml = dir->mounts;
+
+ strcpy(dirent.name, ml->mount->path + 1);
+ if((s = strrchr(dirent.name, '/')))
+ *s = '\0';
+
+ dirent.st_mode = ml->mount->vfs->mode;
+ dirent.st_mode.directory = true;
+ dir->mounts = dir->mounts->next;
+ free(ml);
+ }
+
return *dirent.name == '\0' ? NULL : &dirent;
}
@@ -345,29 +390,56 @@ void vfs_closedir (vfs_dir_t *dir)
{
vfs_errno = 0;
+ while(dir->mounts) {
+ vfs_mount_ll_entry_t *ml = dir->mounts;
+ dir->mounts = dir->mounts->next;
+ free(ml);
+ }
+
((vfs_t *)dir->fs)->fclosedir(dir);
}
char *vfs_getcwd (char *buf, size_t len)
{
- char *cwd = root.vfs->fgetcwd(NULL, len);
+ char *cwds = cwdmount->vfs->fgetcwd ? cwdmount->vfs->fgetcwd(NULL, len) : cwd;
vfs_errno = 0;
if(buf == NULL)
- buf = (char *)malloc(strlen(cwd) + 1);
+ buf = (char *)malloc(strlen(cwds) + 1);
if(buf)
- strcpy(buf, cwd);
+ strcpy(buf, cwds);
- return buf ? buf : cwd;
+ return buf ? buf : cwds;
}
int vfs_stat (const char *filename, vfs_stat_t *st)
{
vfs_mount_t *mount = get_mount(filename);
- return mount ? mount->vfs->fstat(get_filename(mount, filename), st) : -1;
+ int ret = mount ? mount->vfs->fstat(get_filename(mount, filename), st) : -1;
+
+ if(ret == -1 && strchr(filename, '/') == NULL && !strcmp("/", cwd)) {
+
+ strcat(cwd, filename);
+ mount = get_mount(cwd);
+ cwd[1] = '\0';
+
+ if(mount) {
+ st->st_size = 0;
+ st->st_mode.mode = 0;
+ st->st_mode.directory = true;
+#if defined(ESP_PLATFORM)
+ st->st_mtim = (time_t)0;
+#else
+ st->st_mtime = (time_t)0;
+#endif
+ ret = 0;
+ }
+ }
+
+ return ret;
}
int vfs_utime (const char *filename, struct tm *modified)
diff --git a/vfs.h b/vfs.h
index 4c160b8..69f3c77 100644
--- a/vfs.h
+++ b/vfs.h
@@ -80,10 +80,8 @@ typedef struct {
uint8_t handle; // first byte of file handle structure
} vfs_file_t;
-typedef struct {
- const void *fs;
- uint8_t handle;
-} vfs_dir_t;
+struct vfs_dir;
+typedef struct vfs_dir vfs_dir_t;
typedef struct {
char name[255];
@@ -159,6 +157,12 @@ typedef struct vfs_mount
struct vfs_mount *next;
} vfs_mount_t;
+typedef struct vfs_mount_ll_entry
+{
+ vfs_mount_t *mount;
+ struct vfs_mount_ll_entry *next;
+} vfs_mount_ll_entry_t;
+
typedef struct {
vfs_mount_t *mount;
} vfs_drives_t;
@@ -171,6 +175,12 @@ typedef struct {
const void *fs;
} vfs_drive_t;
+struct vfs_dir {
+ const void *fs;
+ vfs_mount_ll_entry_t *mounts;
+ uint8_t handle; // must be last!
+};
+
extern int vfs_errno;
char *vfs_fixpath (char *path);