diff --git a/README.md b/README.md index b943d0c..2b61a31 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ ## grblHAL ## -Latest build date is 20241208, see the [changelog](changelog.md) for details. +Latest build date is 20241219, see the [changelog](changelog.md) for details. > [!NOTE] -> A settings reset will be performed on an update of builds prior to 20241217. Backup and restore of settings is recommended. +> A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended. > [!NOTE] > Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. @@ -93,4 +93,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. --- -20241217 +20241219 diff --git a/changelog.md b/changelog.md index 3c43501..d626aaa 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,26 @@ ## grblHAL changelog +Build 20241219 + +Core: + +* Added directory \(mounts\) listing capabilities to the default root file system when no real root file system \(SD card\) is mounted. + +Boards: + +* ESP32, iMXRT1062, RP2040: added option to mount littlefs as root filesystem when SD card is not enabled. +Ref. RP2040 issue [#103](https://github.com/grblHAL/RP2040/issues/103). + +* STM32F3xx: added serial port to `$pins` report. + +Plugins: + +* WebUI, Networking and SD card: updated to handle littlefs mounted as root filesystem. + +--- + +## grblHAL changelog + Build 20241217 Core: diff --git a/driver_opts.h b/driver_opts.h index a724b23..6ae061c 100644 --- a/driver_opts.h +++ b/driver_opts.h @@ -531,7 +531,7 @@ #endif #ifndef FTP_ENABLE #define FTP_ENABLE 0 -#elif !SDCARD_ENABLE +#elif !(SDCARD_ENABLE || LITTLEFS_ENABLE) #undef FTP_ENABLE #define FTP_ENABLE 0 #endif @@ -648,6 +648,19 @@ #define SDCARD_ENABLE 0 #endif +#if LITTLEFS_ENABLE == 2 && SDCARD_ENABLE +#undef LITTLEFS_ENABLE +#define LITTLEFS_ENABLE 1 +#endif + +#if LITTLEFS_ENABLE +#if LITTLEFS_ENABLE == 2 +#define LITTLEFS_MOUNT_DIR "/" +#else +#define LITTLEFS_MOUNT_DIR "/littlefs" +#endif +#endif + #ifndef SPI_ENABLE #if SDCARD_ENABLE || TRINAMIC_SPI_ENABLE #define SPI_ENABLE 1 diff --git a/grbl.h b/grbl.h index dfb2cf2..91f55e8 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20241217 +#define GRBL_BUILD 20241219 #define GRBL_URL "https://github.com/grblHAL" diff --git a/ngc_flowctrl.c b/ngc_flowctrl.c index 12abdf0..a7e8985 100644 --- a/ngc_flowctrl.c +++ b/ngc_flowctrl.c @@ -669,7 +669,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo if((subname = ngc_string_param_get((ngc_string_id_t)o_label))) { char filename[60]; vfs_file_t *file; -#if LITTLEFS_ENABLE +#if LITTLEFS_ENABLE == 1 sprintf(filename, "/littlefs/%s.macro", subname); if((file = stream_redirect_read(filename, onNamedSubError, onNamedSubEOF)) == NULL) { diff --git a/stream_file.c b/stream_file.c index e1eb9bd..391fa39 100644 --- a/stream_file.c +++ b/stream_file.c @@ -62,7 +62,7 @@ static int16_t stream_read_file (void) return ASCII_LF; // Return a linefeed if the last character was not a linefeed. } } else - c = SERIAL_NO_DATA; // TODO: close all streams? + return SERIAL_NO_DATA; // TODO: close all streams? return (int16_t)c; } @@ -120,6 +120,11 @@ static void onReportHandlersInit (void) grbl.report.status_message = trap_status_messages; } +bool stream_is_file (void) +{ + return hal.stream.type == StreamType_File; +} + vfs_file_t *stream_redirect_read (char *filename, status_message_ptr status_handler, on_file_end_ptr eof_handler) { static bool error_handler_ok = false; diff --git a/stream_file.h b/stream_file.h index 9776d5b..11d04ec 100644 --- a/stream_file.h +++ b/stream_file.h @@ -24,5 +24,6 @@ #include "vfs.h" #include "core_handlers.h" +bool stream_is_file (void); void stream_redirect_close (vfs_file_t *file); vfs_file_t *stream_redirect_read (char *filename, status_message_ptr status_handler, on_file_end_ptr eof_handler); diff --git a/vfs.c b/vfs.c index a55754c..dd8fe87 100644 --- a/vfs.c +++ b/vfs.c @@ -31,6 +31,28 @@ #undef feof #endif +static vfs_mount_t *get_rootfs (void); + +static inline vfs_mount_t *path_is_mount_dir (const char *path) +{ + size_t plen = strlen(path); + + vfs_mount_t *mount = get_rootfs(); + + if(*path == '/' && plen == 1) + return mount; + + size_t mlen; + + if((mount = mount->next)) do { + mlen = strlen(mount->path) - 1; + if(mlen == plen && !strncmp(mount->path, path, mlen)) + break; + } while((mount = mount->next)); + + return mount; +} + // NULL file system static vfs_file_t *fs_open (const char *filename, const char *mode) @@ -79,7 +101,38 @@ static int fs_dirop (const char *path) static vfs_dir_t *fs_opendir (const char *path) { - return NULL; + static vfs_dir_t *dir = NULL; + + if(dir == NULL) + dir = calloc(sizeof(vfs_dir_t) + 3, 1); + + if(dir) { + vfs_mount_t **mount = (vfs_mount_t **)&dir->handle; + *mount = get_rootfs()->next; + } + + return !strcmp(path, "/") ? dir : NULL; +} + +static char *fs_readdir (vfs_dir_t *dir, vfs_dirent_t *dirent) +{ + vfs_mount_t **mount = (vfs_mount_t **)&dir->handle; + + vfs_errno = 0; + + if(*mount) { + strcpy(dirent->name, (*mount)->path); + *(strchr(dirent->name, '\0') - 1) = '\0'; + dirent->st_mode = (*mount)->mode; + dirent->st_mode.directory = true; + while((*mount = (*mount)->next)) { + if(!(*mount)->mode.hidden) + break; + } + } else + *dirent->name = '\0'; + + return *dirent->name ? dirent->name : NULL; } static void fs_closedir (vfs_dir_t *dir) @@ -88,6 +141,22 @@ static void fs_closedir (vfs_dir_t *dir) static int fs_stat (const char *filename, vfs_stat_t *st) { + char path[64]; + vfs_mount_t *mount; + + if((mount = path_is_mount_dir(strcat(strcpy(path, "/"), filename)))) { + + st->st_size = 1024; + st->st_mode = mount->mode; + st->st_mode.directory = true; +#if ESP_PLATFORM + st->st_mtim = (time_t)0; +#else + st->st_mtime = (time_t)0; +#endif + return 0; + } + return -1; } @@ -114,6 +183,7 @@ static const vfs_t fs_null = { .fchdir = fs_chdir, .frmdir = fs_dirop, .fopendir = fs_opendir, + .readdir = fs_readdir, .fclosedir = fs_closedir, .fstat = fs_stat, .fgetcwd = fs_getcwd @@ -133,6 +203,11 @@ static char cwd[100] = "/"; int vfs_errno = 0; vfs_events_t vfs = {0}; +static vfs_mount_t *get_rootfs (void) +{ + return &root; +} + // Strip trailing directory separator, FatFS dont't like it (WinSCP adds it) char *vfs_fixpath (char *path) { @@ -143,25 +218,6 @@ char *vfs_fixpath (char *path) return path; } -static inline vfs_mount_t *path_is_mount_dir (const char *path) -{ - size_t plen = strlen(path); - - if(*path == '/' && plen == 1) - return &root; - - size_t mlen; - vfs_mount_t *mount = root.next; - - if(mount) do { - mlen = strlen(mount->path) - 1; - if(mlen == plen && !strncmp(mount->path, path, mlen)) - break; - } while((mount = mount->next)); - - return mount; -} - static vfs_mount_t *get_mount (const char *path) { vfs_errno = 0; @@ -324,7 +380,7 @@ int vfs_chdir (const char *path) vfs_errno = 0; - if(*path != '/') { + if(*path != '/' && strcmp(cwd, "/")) { if(strcmp(path, "..")) { if(strlen(cwd) > 1) strcat(cwd, "/"); @@ -336,24 +392,24 @@ int vfs_chdir (const char *path) } } else { - strcpy(cwd, path); + if(*path == '/') + strcpy(cwd, path); + else + strcat(strcpy(cwd, "/"), path); - if((cwdmount = get_mount(path)) && strchr(path + 1, '/') == NULL && cwdmount != &root) { + vfs_fixpath(cwd); + + if((cwdmount = get_mount(cwd)) && strchr(cwd + 1, '/') == NULL && cwdmount != &root) { strcpy(cwd, cwdmount->path); - char *s; - if((s = strrchr(cwd, '/'))) - *s = '\0'; + vfs_fixpath(cwd); return 0; } } - if((ret = cwdmount ? cwdmount->vfs->fchdir(path) : -1) != 0) { // + strlen(mount->path));)) - char *s = strrchr(cwd, '/'); - if(s) - *s = '\0'; - } + if((ret = cwdmount ? cwdmount->vfs->fchdir(path) : -1) != 0) // + strlen(mount->path));)) + vfs_fixpath(cwd); return ret; }