From 0c6f3f6dd722e70bc6100ff384d252a9f5bff500 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 16 Jul 2023 13:03:22 +0200 Subject: [PATCH] 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. --- changelog.md | 21 ++++++++++++ driver_opts.h | 2 +- gcode.c | 2 +- grbl.h | 2 +- ngc_flowctrl.c | 26 +++++++------- report.c | 3 ++ state_machine.c | 4 ++- stream.h | 2 +- system.h | 15 ++++----- vfs.c | 90 ++++++++++++++++++++++++++++++++++++++++++++----- vfs.h | 18 +++++++--- 11 files changed, 146 insertions(+), 39 deletions(-) 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);